[关闭]
@liuhui0803 2016-10-09T08:55:09.000000Z 字数 6537 阅读 2503

Netflix计费系统迁移到AWS的实践 – 第3篇

云体系结构 体系结构 计费 数据库


摘要:

对任何公司来说账务都是一种关键服务,这一点大部分人都不会否认。在任何迁移项目中,数据库的迁移都是最基本要素,数据库能否成功迁移直接决定了整个项目能否成功。Netflix CDE(云数据库工程)团队最近对这一最重要的数据库子系统进行了迁移。本文将介绍为确保迁移项目成功完成我们所采取的一些关键措施。

正文:

在几周前发布的计费系统迁移博文中,我们概括介绍了将计费系统迁移至云中所采用的方法。本文将深入介绍数据库的迁移过程。希望我们的经验能帮你顺利完成自己的迁移任务。

你是否考虑过为了顺利完成复杂的数据库迁移任务,都需要考虑并解决哪些问题?但你可能也会问,“这有什么复杂的?”

想想数据库迁移过程中遇到的下列挑战吧,我们本次迁移几乎遇到了所有这些问题:

对任何公司来说账务都是一种关键服务,这一点大部分人都不会否认。在任何迁移项目中,数据库的迁移都是最基本要素,数据库能否成功迁移直接决定了整个项目能否成功。Netflix CDE(云数据库工程)团队最近对这一最重要的数据库子系统进行了迁移。下文将介绍为确保迁移项目成功完成我们所采取的一些关键措施。

数据库的选择

为顺利处理付款过程中产生的事务,计费应用程序的事务须符合ACID(原子性、一致性、隔离性、持久性)要求。RDBMS似乎是此类数据存储的最佳选择。

此处输入图片的描述

Oracle:由于源数据库使用了Oracle产品,直接迁移至云中运行的Oracle数据库可避免进行跨数据库迁移,降低代码开发和配置工作量。我们过去在生产环境中使用Oracle产品的体验也让自己对该产品的性能和伸缩性更有信心。然而考虑到许可成本以及“依原样”迁移遗留数据所要产生的技术债,最终只能寻求其他解决方案。

AWS RDS MySQL:理想情况下我们会选择MySQL RDS作为后端,毕竟亚马逊在关系型数据库即服务产品的管理和升级方面做的挺好,为了实现高可用还提供了多可用区(AZ)支持。然而RDS的主要不足之处在于存储容量有着6TB上限。我们迁移时的容量已接近10TB。

AWS Aurora:AWS Aurora可以满足我们对存储容量的需求,但目前还是Beta测试版。

PostgreSQL:PostgreSQL是一种强大的对象-关系开源数据库系统,但我们团队内部缺乏足够的PostgreSQL使用经验。在自己的数据中心内我们主要使用Oracle和MySQL作为后端数据库,更重要的是选择PostgreSQL会导致未来无法无缝迁移至Aurora,因为Aurora使用了基于MySQL的引擎。

EC2 MySQL:最终我们的计费系统选择使用EC2 MySQL,这种技术无须许可成本,同时未来可以直接迁移至Aurora。该方式需要在i2.8xlarge实例上使用InnoDB引擎配置MySQL。

生产数据库体系结构

为确保计费应用程序可以承受基础结构、区域和地域故障,并将可能的停机时间降至最低,高可用性和伸缩性是我们设计整个体系结构时最主要的考虑因素。

通过在另一个区域内为数据库主副本创建DRBD副本,即可承受区域故障,节点出错等基础结构故障,以及EBS卷故障。当本地和远程写操作均完成后,会使用“同步复制协议”将主要节点上的写操作标记为已完成。借此可确保一个节点的故障绝对不会导致数据丢失。虽然这样的设计会影响写操作的延迟,但延迟依然在SLA可接受的范围内。

读取副本可设置为本地或跨区域配置,这样不仅可以满足对高可用的需求,而且有助于增强伸缩性。来自ETL作业的读取流量会分流至读取副本,借此降低主要数据库执行繁重ETL批处理的负担。

一旦主要MySQL数据库故障,工作负载将被故障转移至使用同步模式进行复制的DRBD辅助节点。辅助节点开始承担主节点的角色后,会更改数据库主机的route53 DNS记录将其指向新的主节点。按照设计,计费应用程序与生俱来的“批处理”特性可顺利应对此类停机事件。CNAME记录传播工作完成后,客户端连接不会回退(Fallback),而是会建立指向新主节点的连接。

此处输入图片的描述

迁移工具的选择

我们在迁移工具的选择方面花费了大量时间和精力。概念验证工作成功与否的最主要条件在于能否重启动批载荷(Bulk load)、双向复制,以及数据完整性。在评估迁移工具时我们主要侧重于下列几个条件。

GoldenGate以丰富的功能脱颖而出,该产品很好地满足了我们的需求。GoldenGate可以在遇到故障后重启动批载荷(很少的几张表就达到数百GB容量),该产品的双向复制功能可以让我们从MySQL轻松回滚到Oracle。

GoldenGate的主要不足在于了解该工具工作原理所面临的学习曲线。此外该产品使用了易于出错的手工配置过程,这也增大了项目难度。如果源表没有主键或唯一键,GoldenGate会使用所有列作为提取和复制操作的增补日志键对。但我们发现了一些问题,例如复制到目标的数据仅仅是相关表的增量载荷,因此决定在切换这些表的过程中执行不预定义主键或唯一键的完整加载。GoldenGate的优势和包含的功能远远超过了所造成的困难,我们最终选择使用该工具。

架构转换和验证

由于源和目标数据库存在差异,数据类型和长度也有所不同,为了在迁移数据的同时确保数据完整性,验证工作变得必不可少。

数据类型误配造成的问题需要花些时间来修复。例如因为一些历史遗留原因,Oracle中的很多数值已定义为Number数据类型,MySQL缺少类似的类型。Oracle中的Number数据类型会存储定数和浮点数,这一点比较难以处理。一些源表中的列使用Number代表整数,另一些情况则会代表十进制数值,其中一些值的长度甚至达到38位。作为对比,MySQL使用了明确的数据类型,例如Int、bigInt、decimal、double等,而bigInt不能超过18位。因此必须确保通过恰当的映射以便在MySQL中反应精确的值。

分区表(Partitioned table)需要特殊处理,与Oracle的做法不同,MySQL会将分区键视作主键和唯一键的一部分。为确保不对应用逻辑和查询产生影响,必须用恰当的分区键重新定义目标架构。

默认值的处理在MySQL和Oracle之间也有不同。对于包含NOT NULL值的列,MySQL会确定该列暗含的默认值,在MySQL中启用Strict模式即可看到此类数据转换问题,这样的事务会执行失败并显示在GoldenGate的错误日志中。

架构转换工具:为了实现架构转换并进行验证,我们评估了多种工具,但由于原有架构设计中所存在的问题,这些工具默认提供的架构转换功能无法使用。即使GoldenGate也无法将Oracle架构转换为相应的MySQL版本,因此只能首先由应用程序的所有者重新定义架构。优化架构也是我们此次迁移的目标之一,数据库和应用程序团队合作审阅了数据类型,并通过多次迭代找出了所有误配的内容。在存在误配的情况下,GoldenGate会对这些值进行截断以符合MySQL数据类型的要求。为了缓解这一问题,我们主要借助数据对比工具和GoldenGate错误日志找出源和目标之间数据类型的误配。

数据完整性

完整加载和增量加载执行完毕后,又遇到另一个让人气馁的问题:必须核实目标副本的数据完整性。由于Oracle和MySQL使用了不同数据类型,无法通过用普通封装脚本对比行键(Rowkey)哈希值的方式保证数据的精确性。虽然有几个第三方工具能跨越不同数据库对实际值进行数据对比,但总量10TB的数据集比较起来也不容易。最终我们使用这些工具对比了样本数据集,借此找出了少数由于架构映射错误导致的不一致问题。

测试刷新:确保数据完整性的方法之一是使用应用程序对生产数据库的副本进行测试。为此可安排从MySQL生产数据库进行刷新并用于测试。考虑到生产环境使用EBS作为存储,只要创建EBS快照即可轻松创建测试环境,同时可在测试中执行时间点恢复。为确保足够高的数据质量,这一过程重复了多次。

Sqoop作业:我们在数据校正过程中使用了ETL作业和报表,并使用Sqoop作业从Oracle中拉取创建报表所需的数据。此外还针对MySQL配置了这些作业。在源和目标之间进行持续复制的过程中,会在ETL的特定时间窗口内运行报表,这样即可找出增量加载过程中产生的变化。

行计数(Row count):是用于对源/目标进行比较和匹配的另一种方法。为此需要首先暂停目标的增量加载,并对Oracle和MySQL的行数进行匹配。在使用GoldenGate完整加载表之后也会对行计数的结果进行比较。

性能调优

基础结构:计费应用程序将数据持久保存在数据中心内两个Oracle数据库中,运行数据库的计算机性能极为强大,使用了IBM Power 7,32颗双核心64位处理器,750GB内存,通过SVC MCS集群分配TB级别的存储,集群使用了4GB/s接口,运行RAID10配置的8G4集群。

迁移过程中最大的顾虑是性能,目标数据库将整合到一个装备有32颗vCPU和244GB内存的i2.8xlarge服务器上。为了优化查询性能,应用程序团队在应用层进行了大量调优。在Vector的帮助下,性能团队可以方便地发现性能瓶颈,通过调整特定的系统和内核参数解决这些问题。详细信息请参阅附件。

我们用EBS供应的IOPS卷组建RAID0实现了极高的读写性能。为了通过每个卷获得更高吞吐率,共使用5个容量各4TB的卷,而没有使用更大容量的单个卷。这样做也可以加快创建快照和还原的速度。

数据库:对于MySQL的使用我们还有一个比较大的顾虑,担心计费应用程序在对数据执行批处理过程中MySQL的吞吐率无法满足数据规模的需求。Percona为此提供了顾问支持,在迁移过程中以及迁移之后,MySQL数据库的性能表现都让我们感到满意。这里的诀窍在于使用两个cnf文件,一个用于迁移数据的过程中对innodb_log_file_size之类的参数进行优化,以便执行批量插入;第二个cnf文件用于在实时生产应用程序工作负载中对innodb_buffer_pool_instances之类的参数进行调整,借此促进事务的实时加载。详情请参阅附件。

数据加载:在概念验证过程中,我们针对开启和关闭索引两种情况测试了表的初始加载,并决定在加载前启用所有索引。这样做的原因在于MySQL中索引是通过单线程方式创建的(大部分表有多个索引),因此我们改为使用GoldenGate的并行加载功能在合理的时间内为表中填入索引。最后一次割接过程中还启用了外键约束。

我们学到的另一个窍门是按照实例的内核数量执行相同遍数的完整和增量加载过程。如果这些过程的执行遍数超过内核数量,数据加载性能将大幅降低,因为实例需要花费更多时间进行上下文切换。通过完整加载和增量加载将10TB数据装入目标MySQL数据库,这一过程用了大约两周时间。

结论

虽然对任何迁移项目来说,数据库的迁移都是最大挑战,但真正决定项目成功与否的关键在于要确保一开始就选择了正确的方法,并且在整个执行过程中与应用程序团队密切合作。回顾整个迁移过程,这个项目的成功完全是组织内部不同团队通力合作的成果,大家一起制定的整个迁移计划是促成这一切的关键!为了在不影响业务的前提下顺利完成整个充满挑战的迁移项目,除了人员和团队之间的相互协调,自由的文化和责任感也是促成这一切必不可少的要素。

附件

批量插入时对数据库的调节

调节 备注
innodb_log_file_size 日志组中每个日志文件大小的字节数。为了实现较高写入吞吐率增大了默认值。
innodb_lru_scan_depth 每秒执行一次的后台操作。如果典型的工作负载还有剩余I/O容量可增大该值。
innodb_adaptive_hash_index 为改善性能动态启用或禁用自适应哈希索引,批量插入时可禁用该参数。
innodb_flush_neighbors 决定从InnoDB缓冲池清空页面的同时是否同时清空相同范围(Extend)内其他脏页面。执行写操作时可将其关闭,这样有助于提高I/O性能。
transaction-isolation READ-COMMITTED- 可以为每个一致性读取,甚至同一事务内的读取设置并读取自己的新鲜(Fresh)快照。
query_cache_size 关闭query_cache可以让我们的这个用例获益。
innodb_doublewrite 如果启用该变量(默认设置),InnoDB会将所有数据存储两次,第一次存储到二次写(Doublewrite)缓冲,随后写入到实际的数据文件。可在批量插入过程中将其关闭。

高事务吞吐率的数据库调节

调节 备注
innodb_log_file_size 日志组中每个日志文件大小的字节数。
innodb_max_dirty_pages_pct innodb_max_dirty_pages_pct参数为清空活动建立了目标。
innodb_buffer_pool_instances InnoDB缓冲池拆分成的区域数量。对于数GB规模缓冲池的系统,通过减少不同线程读写缓冲页面的争用,将缓冲池拆分为不同实例有助于改善并发性。
query_cache_size 关闭query_cache可以让我们的这个用例获益。
innodb_adaptive_hash_index 为改善性能动态启用或禁用自适应的哈希索引,高事务加载时可禁用该参数。
innodb_log_buffer_size InnoDB用于将日志文件写入磁盘时的缓冲区大小字节数。为了实现较高写入吞吐率可增大该参数的默认值。

存储

CPU调度器方面的调节

调节 备注
kernel.numa_balancing Linux支持的自动化Numa平衡功能会造成较高内核开销,因为需要频繁地对应用程序的内存页面进行映射和撤销映射。可将该参数禁用并改为在应用程序中使用Numa API,或通过系统管理工具numactl告知内核如何处理内存的分配。

虚拟机的调节

调节 备注
dirty_ratio 当文件系统缓存中的脏(已修改)页面总量达到物理内存的40%时可对写入进行限制,增大该参数可改善应用程序的写入吞吐率。
swappiness 禁用Linux定期进行的页面移出(Page out)操作。将其设置为0会导致位于文件系统缓存中的页面当应用程序需要更多内存时的常规操作过程中被移出。
dirty_background_ratio 当脏页面总量达到物理内存的10%时唤醒清空程序(Flusher)的内核线程。降低该值(5%)会提前唤醒清空程序线程,进而导致脏页面的增长受到抑制。

文件系统和IO存储指标

调节 备注
aio-max-nr 增大内核中AIO(异步请求)数量的限制。
rq_affinity 可通过多个CPU对IO完成(Completion)的块层处理(Block layer processing)进行调度,而无需只使用提供中断的那个CPU。将该值设置为2会迫使由最初发起该IO的CPU处理IO的完成,借此可将IO的完成交由对应用程序来说属于“本地”的CPU处理,进而获得最大化伸缩性和缓存亲和性。
scheduler 选择使用的IO调度器。Cfq是一种公平分享的IO调度器,可用于对提交至存储的IO设置服务质量。

作者:Jyoti Shandil, Ravi Nyalakonda, Rajesh Matkar, Roopa Tangirala,阅读英文原文Netflix Billing Migration to AWS - Part III

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注