[关闭]
@liuhui0803 2016-08-05T08:47:03.000000Z 字数 5789 阅读 2624

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

Netflix AWS 云计算 DevOps


本文是Netflix计费系统迁移至云中系列文章的后续。此次迁移项目的概述早前已发布在这里。本篇详细介绍了将计费应用程序和数据存储从本地数据中心迁移至AWS云的技术细节。

你可能已经从早前发布的Netflix云迁移博客文章中了解到,Netflix的所有流媒体基础结构现已完全在云中运行。随着Netflix规模不断扩大,尤其是Netflix Everywhere业务即将正式登场,我们已经意识到计费系统迟早也需要迁入云中,因为现有的本地系统已经无法继续扩展了。

毫无疑问,在不中断业务的情况下迁移高度敏感的应用程序和重要数据库是一项意义深远的工作,与此同时我们还将继续构建新的业务功能和服务。

计费系统的一些重要用途和面临的挑战包括:

当我们着手进行该项目时,计费系统是这样的:

此处输入图片的描述

本次项目的目标在于将所有这一切都搬入云中,不在数据中心内运行任何计费应用程序或数据库。但所有操作不能影响业务的正常运转。我们的前路十分艰巨!

规划

我们制订了一个三步规划:

从每个国家迁移过程的每一步操作中学习经验,进行迭代和完善,确保后续工作能取得更好的成绩。

第1步 – 将新落地国家重定向至云中,将数据同步回数据中心

Netflix很快将在6个新国家落地。我们决定利用这一机会直接通过云环境运行这些国家的部分计费系统。这意味着面向用户的数据和应用程序将从云中运行,但依然需要将数据同步回数据中心,这样数据中心内的批处理应用程序才能继续运行,不至于影响到业务运转。这些新落地国家客户的数据将保存在云中,但批处理任务依然在数据中心内处理。这是我们的第一步。

我们将2个面向用户的应用程序中的所有API移植到使用Spring Boot和Spring Integration开发的云应用程序中。通过使用Spring Boot可以快速着手创建新应用程序,这个产品内建了开发工作所需的基础结构和组件,可以让我们更专注业务逻辑本身。通过使用Spring Integration,只需一次开发码即可重复使用大部分工作流风格的代码。借助这些产品对Header以及基于Header的路由技术提供的支持,我们可以在应用程序内部实现Pub-sub模式,将消息放入一个渠道(Channel),并让每个用户通过各自独立的方式使用。在将数据存储于Cassandra的情况下,现在可以通过任意AWS区域处理这6个新国家会员的API调用。就算某个AWS区域彻底故障,这些国家的计费操作也不会受到影响,而这也是我们首次真正意义上认识到云计算的威力!

我们在AWS多个区域的EC2实例上部署了自己的应用程序,另外为现有的云代理应用程序增加了一个重定向层,以便将新落地国家用户的计费调用切换至云中新部署的计费API,并让原有国家用户的计费调用继续由数据中心内原有的计费API处理。我们从一个AWS区域建立了到数据中心内现有Oracle数据库的直接连接,并开发了一个程序,通过SQS将另外3个区域中的Cassandra数据与这个建立了直接连接的区域进行同步。我们还使用SQS队列和Dead Letter Queues(DLQ)在故障的区域和过程之间移动数据。

在新国家落地通常意味着会员数量的激增。我们也明白,为了确保数据中心不超载,还必须将现有的续订应用程序从数据中心搬入云中。因此对于通过云服务运行的6个新落地国家,我们编写了一个爬虫程序,可以每天一次遍历Cassandra中的所有客户,借此找出所有当天需要收费的会员。这种“逐行迭代”的方法目前在这些国家很好用,但我们也清楚,在将其他国家,尤其是美国(目前我们的绝大部分会员都在美国)的数据迁移到云中之后这种方式将会失效。但我们想先行一步试试水有多深。这也是目前这一阶段唯一在云中运行的批处理应用程序。

为了能够在任何一个区域执行写操作,并将写操作快速复制到其他区域,我们选择用Cassandra作为数据存储。我们定义了一种数据模型,在其中使用customerId作为行,并创建了一系列复合的Cassandra列借此体现数据之间的关系性。下图展示了这些项之间的关系,以及我们是如何在Cassandra中使用单列族(Single column family)进行体现的。用单列族形式设计这样的关系使得我们能为相关项提供事务支持。

此处输入图片的描述

通过对应用程序的逻辑进行设计,只需要在任何操作开始执行时读取一次,随后即可在内存中更新对象,并在操作结束后将其以单列族的形式持久存储。在操作过程中读取或写入Cassandra的操作会被看作一种反模式(Anti-pattern)。我们使用Astyanax(Netflix自行开发并已开源的Cassandra客户端)编写了自定义的ORM,这样就可以针对Cassandra读/写域对象。

我们通过这种方式将服务落地到新的国家,虽然遇到了几个小问题,但在迅速修复后整个系统运转很稳定。目前来说一切都挺不错的!

经过第1步工作后计费系统的体系结构如下图所示:

此处输入图片的描述

第2步 – 迁移所有应用程序,并将原有国家迁移至云中

第1步成功完成后,我们开始考虑在不迁移数据库的情况下将其他应用迁至云中。大部分业务逻辑位于批处理应用程序中,多年来已经发展得极为成熟,但这也意味着必须深入到每个条件的代码中并花费大量时间重写。这些应用程序无法“照原样”直接搬到云中运行。同时我们也借助这次机会尽量移除了所有不再使用的代码,将不同功能拆分为多个专用的小应用程序,并为了更好的扩展性重构了现有代码。这些遗留应用程序被我们设计为会在启动时读取磁盘上的配置文件,并使用了其他一些静态资源,例如从Weblogic队列读取消息,由于实例与生俱来的“短暂”本质,这些特征在云环境中都是反模式的。因此为了让应用程序在云平台上顺利运行,只能重新实现这些模块。为了通过异步模式将消息穿过队列移动到不同区域,我们还更改了一些API,并在这些区域建立了到数据中心的安全连接。

云数据库工程(CDE)团队为我们的数据需求搭建了多节点Cassandra集群。我们也清楚,在将所有Netflix会员的计费数据迁移到Cassandra之后,以前用来为最早的6个国家的客户提供续订服务所用的“全行(Row)式”Cassandra迭代器续订解决方案将无法很好地伸缩。因此我们使用Aegisthus设计了一个系统,可从Cassandra SSTable拉取数据并将其转换为JSON格式的行,将其暂存在S3 Bucket中。随后我们写了一些Pig脚本,借此每天针对大量数据集运行Mapreduce作业,找出需要续订的客户清单并向他们收费。我们还写了Sqoop作业以便从Cassandra和Oracle中拉取数据,并将其以可查询格式写入Hive,这样就可以将这两套数据集汇总至Hive,实现更快速的排错。

为了让DVD服务器能够连接云环境,我们为DVD设置了负载平衡端点(包含SSL客户端证书),DVD服务器可以通过云代理对所有调用进行路由,在迁移美国系统之前可以借此将调用重新发回数据中心。美国系统的数据迁移完成后,即可断开云和数据中心之间的通信链路。

为了对这一大规模数据迁移的结果进行验证,我们编写了对已迁往云中的数据,以及数据中心内部现有数据进行比较和验证的对比工具。反复运行该对比工具可找出迁移过程中可能存在的Bug,修复发现的问题,清理数据并再次运行。随着运行结果愈发整洁,完全没有出现任何错误,这也进一步增强了我们对数据迁移工作的信心。对于针对各国数据进行的迁移工作我们感到十分激动。最开始我们选择了一个Netflix会员数量比较少的国家,并通过下列步骤将数据迁入云中:

在确认一切正常后开始迁移下一个国家。随后我们开始突击对所有类似国家一起进行迁移。最后迁移的是美国,因为美国的会员数量最多,并且还提供有DVD订阅服务。至此所有面向Netflix会员客户的数据都已通过云环境提供。对我们来说这是一个巨大的里程碑!

经过第2步工作后,我们的体系结构如下图所示:

此处输入图片的描述

第3步 – 再见,数据中心!

至此还有最后(并且最重要)的一件事:数据中心内运行的Oracle数据库。Oracle中存储的数据集具有高度的关系性,我们觉得这些数据并不适合以NoSQL的方式进行建模。这种数据不能像以前处理面向客户的订阅数据那样构造为单列族的形式,因此我们评估了Oracle和Aurora RDS这两种选项。但Oracle作为云数据库运行的许可成本,以及Aurora依然是Beta测试版这一现状使得则两种方式都不适合我们。

在计费团队忙于执行前两个步骤时,我们的云数据库工程团队正在创建用于将计费数据迁移至EC2上MySQL实例所需的基础结构。在开始执行第三步操作时,在他们的帮助下数据库基础结构部分已经就绪。因为一些应用程序使用了不包含任何ORM的纯JDBC,我们还需要将批处理应用程序的代码基转换为兼容MySQL的格式。另外我们处理了大量遗留的Pl-sql代码,并重写了应用程序中的逻辑,同时尽可能去除了不再使用的代码。

至此我们的数据库体系结构已经由部署在某一AWS区域内EC2实例上的MySQL主数据库组成。我们还搭建了一个从主数据库复制数据的灾难恢复数据库,如果主数据库故障,该数据库将成为新的主数据。另外我们还在在其他AWS区域设置了从数据库,这些数据库主要为应用程序提供只读访问。

至此我们的计费系统已经全部搬入云中,现在看起来是下面这个样子:

此处输入图片的描述

可想而知,我们从这个大型项目中获益良多。为了帮助自己调试/排错并改善开发者的生产力,我们还编写了几个工具。我们移除了老旧的以及不再需要的代码,清理了一些功能并对其他功能进行了力所能及的完善。这个项目得到了Netflix内部很多工程团队的支持。来自云数据库工程团队、订户和帐户工程团队、支付工程团队,以及消息工程团队的成员与我们一起用2周乃至数月的时间帮助我们一起完成这一重大举措。Netflix文化最棒的地方正在于,所有人心中有着相同的目标:为全球会员提供更精彩的体验。如果将计费解决方案迁入云中对此有帮助,不管大家属于哪个团队,都会为这一目标贡献自己的力量!

前路 …

将计费系统迁入云中后,Netflix流媒体基础结构已经完全在云中运行。我们可以按需对Netflix的任何服务进行缩放,根据使用模式进行预测式缩放,使用Spinnaker进行一键点击部署,并在不同的Netflix应用程序之间实现一致的部署体系结构。计费基础结构现在可以使用Netflix平台的所有二进制程序和框架进行监控,并通过云平台获得所需的工具支持。目前我们已经可以为全球超过190个国家和地区,8100万Netflix会员的计费任务提供支持。为了完成所有计费事件,每天我们会生成并处理数TB数据。为了实现全球扩张并顺利迎接业务挑战,我们计划在未来对会员工作流进行重构。作为全新体系结构的一部分,我们将重新设计现有服务,以便在云环境中以原生的方式实现伸缩。随着服务在全球发布,我们可以借此机会为新落地的市场研究并改进计费和支付方法,将其与全球合作伙伴以及不同区域的本地支付流程进行集成。我们正在面向未来努力打造功能更丰富,缩放能力更强的体系结构。

本文作者Subir Parulekar, Rahul Pilani阅读英文原文Netflix Billing Migration to AWS - Part II

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