编辑手记:Evernote在短暂的时间里完成了向云端的迁移,其战果可喜可贺,然而每一次成功,都是背后的默默的努力和付出支撑起来的。在迁移的过程中,面对网络、硬件、软件、用户各方面的问题,Evernote是如何处理,并设计新的架构的,我们一起来学习。
注:本文来自Evernote官方文档翻译,若有不对的地方请参考原文。
系列文章回顾:
1、用户零感知到达云端: Evernote顺利完成向 Google 云平台的迁移
系统架构
当我们确保了迁移过程的数据安全之后,下一个重要的决定是关于将要建立的整体系统架构。关于架构,我们有以下几点重要的考虑:
Evernote 应用是为所有服务构建的,用于在全球客户服务的单个数据中心站点(此处不包含Evernote在中国的服务)
对于用户数据,永远要保证在不同的地理数据中心有两个副本。
由于旧的数据中心位于加州北部,而新的产品构建在GCP上,因此要尽可能减少网络延迟。
考虑以上的条件,我们做出了如下决定:
Primary location (serving production traffic): US-West1
Secondary location (disaster recovery site): US-Central1
我们将在US-West1的两个区域之间进一步拆分所有生产服务,以进一步防止故障。
正如Google的声明,我们熟知以下事实:Google将区域设计为彼此独立:区域通常具有与其他区域隔离的电源,冷却设备,网络和控制平面,大多数单个故障事件将仅影响单个区域。
这意味着我们将为US-West1提供流量,并在US-Central1中保留所有客户数据的第二个副本。 如果灾难场景击中US-West1,我们将能够使用US-Central1中的数据做恢复服务。
关于未来的考虑围绕着如何重新构建应用程序以更有弹性,以及如何能够同时服务多个区域的流量,以进一步减少从灾难场景中恢复所需的时间。同时还在考虑如何更好地利用GCP的全球足迹来提高访问Evernote服务时的用户延迟。
在这一点上,我们已经定义了需求,并做出了一些战略决策。现在需要的是进入具体的工程。
架构设计与技术转型
最大程度地降低网络连接延时
我们很早就在项目中明确,我们现有的数据中心和GCP之间的网络连接将是我们成功的关键和制约性条件。 为了使我们能够最大限度地灵活迁移数据和服务,网络互连计划需要实现以下目标:
对原来的数据中心与GCP上的数据中心之间的数据流量进行加密
当两个数据中心并存的时候,能够支持将任何一个站点作为用户流量的主接收站点,并能根据需求在两个站点之间实现自由地切换。
能够将我们的服务根据需要分配到原物理数据中心和GCP上。
保证两个站点间的带宽最大化,并允许进行大批数据的复制。
我们需要最大的灵活性,以确保在将3PB的数据迁移到GCP的过程中时,可以通过我们现有数据中心和物理负载均衡承担所有的用户流量,作为主接收站点,而所有后端Evernote服务都从GCP运行(反之,当需要CGP作为主接收站点的时候也能够承载所有的用户流量。)
我们现有的外部网络连接旨在处理我们的峰值负载,具有足够的headroom,然而,但其容量并不足以保证我们在短时间内完成所有数据的迁移。
此外,我们的内部网络的结构并不适用于将这么多的请求提供给外部服务(例如Google云端存储)。 鉴于当前的状况,上传我们的所有数据将需要一年多的时间,同时可能对我们的用户体验造成负面影响。 因此整个项目还有很多工作要做。
1、首先,我们必须建立专用网络互连(PNI),或Evernote的网络和GCP之间的直接链接。 这有效地将我们可以使用的带宽量增加了一倍,并为我们提供了独立于用户流量的专用链接,在Evernote和Google之间建立了一条私人公路。
2、其次,我们需要决定在我们的数据中心中数据的来源。对于所有数据,我们都保存了多个副本,因此需要决定这次的迁移过程我们要使用哪一个数据副本作为数据源。同时我们需要制定一个方案,在对正常的操作不产生影响的情况下,将数据从多个服务器迁移到与GCP的专用网络通道上。
在项目的第一个月,我们的网络工程团队以最快的速度投入到对数据的备份和其他准备工作中,如果他们没有及时交付,整个项目将面临风险。
是否可以分站点进行
我们的应用之前只在单一的数据中心运行过,在这样的环境中,在节点之间传输的往返延时经常是亚毫秒级的,如果我们期望将应用分开在原有的物理数据中心和GCP上同时运行的话,我们将要考虑如果节点间的传输延时达到20-50毫秒的话,会对应用产生什么影响。这些延迟是由于光速和原数据中心与GCP之间的物理距离的双重因素导致的。
显然,在我们的迁移过程中并不希望遇到这些问题, 为了尽量减少可能给客户带来的负面影响,我们决定先做测试。 在项目的规划阶段,我们决定使用服务器端工具(tc)来引入人工网络延迟并模拟预期的地理和光速延迟。 我们这样做是通过逐步升级我们的NoteStore舰队达到50毫秒的模拟延迟,并留在原地4天。 在此期间,监控应用程序KPI,并将其与基线数据进行比较。 结果显示,测试的大多数API调用都会稍慢一些,但仍在可接受的范围内,并且不会影响用户体验。
该测试对于我们的项目等影响是巨大的,我们知道了应用程序可以在两个分开的数据中心的服务支持下运行。这就意味着我们前面制定的方案是可实现的。
物理连接到HAProxy的负载均衡
在原有的数据中心,我们运行和管理传统负载均衡设备下的高可用集群。 当进入云环境时,使用物理负载均衡器并不可取,因此我们开始研究虚拟负载均衡解决方案。
在理想情况下,我们可以部署一个仅基于GCP服务的单一负载平衡(LB)层,但这个方案当前并不可取,因为我们依赖于检查cookie,标题和URL模式来将请求路由到正确的分片。 这种解析并不是我们目前只能在Google负载平衡平台中进行的解析。 我们对这些选项进行了评估和基准测试,并确定了使用Google网络负载均衡器产品和基于Linux的HAProxy服务器场构建的解决方案。
Google网络负载平衡器将成为客户流量的入口点,并将流量均衡到我们的HAProxy服务器站点,这样就能够将客户流量路由到其特定的分片。
完成了所有常规的实验室测试和验证后,我们希望使用真实的流量测试我们的新解决方案,而不必通过新的前门“摆动”所有的流量。 我们需要一种方法来进行部分/分阶段测试,如果前一次测试成功,后面只需要增加测试用户集。 此时,Evernote服务的后端仍然在我们的旧物理数据中心内运行,分离站点LB流量将通过我们的私有VPN链路路由到那里。
有以下两种途径:
1、通过新的“前门”直接引导Evernote员工。我们更新了公司的DNS,将Evernote员工指向新的前门。
2、利用Dyn流量管理器逐步增加用户流量以使用新的前门(流量主接收站点)。
使用这两种方法,我们能够在任何其他服务被确认为在GCP中成功运行之前测试我们的新负载均衡平台。 与拆分站点测试一样,我们能够单独完成组件测试。这也让我们对迁移之后对系统运行更有信心。
Reco 服务(UDP -> PubSub)
当用户向Evernote添加附件或者参考资料的时候,如果是PDF 或者图片的话,GCP会尝试读取器中的文本信息。实现这一功能的是一个叫做“Reco”的服务。(也就是'recognition’的缩写)
由于过去的各种架构限制,Reco服务器使用轮询模式来获取要处理的新资源的列表。 然而,正如人们想象的,使多个Reco服务器定期轮询每个NoteStore服务器可能会导致NoteStores和支持它们的资源数据存储器的显着开销。 而且为了支持对新加附件提供服务,就需要增加Reco服务器,这严重增加了系统的复杂度。
为了减少开销以及随着添加更多Reco服务器而发生的后续延迟,Reco服务器被重新设计为使用多播来了解NoteStore上的新资源何时可用。
但是,GCP Compute Engine网络不支持多播。 因此,我们将应用程序重新设计为具有不同的通信体系结构。
我们重新构建了应用程序,并删除了跟踪作业的必要性,并通过附件来广播NoteStores的状态以识别。同时使用可靠的可扩展排队机制PubSub,NoteStores现在通过在PubSub队列中生成job来通知Reco服务器要完成的工作。 每个Reco服务器通过简单地订阅特定的PubSub队列并确认他们何时完成资源上的识别作业的方式处理新添加到队列上的内容。 同时,还支持通过创建多个优先级较高的队列,并使Reco服务器根据通道的优先级处理资源。
这样,我们通过使用基于云的排队机制和重新设计应用程序来简化架构,从而依赖于队列中job的可用性和通知速度。 此外,为了仅管理和维护正在使用的资源,我们将对Reco服务进行迁移,使其支持自动扩展。
用户附件存储 (从多个 WebDavs 到 Google 云存储)
我们有120亿个用户附件和元数据文件,可以从原始的WebDavs复制到Google云端存储中的新家。
考虑到我们需要复制的数据量很大,我们立即在后台启动这个海量的数据复制工作。 该服务目前(2月14日)仍在读取和写入现有的WebDav服务器场,而我们在后台将资源复制到他们的新家。
在复制过程中,必须解决的第一个障碍是,我们当前的数据中心网络不是为每天在数千个节点上复制数百TB而设计的, 因此,需要时间来建立到GCP网络的多条安全出口路径。 由于我们一次要从数百个服务器复制,我们还必须小心不要DDoS自己,并确保我们保护我们的用户的服务。
资源迁移器(The resource-migrator)
我们开发了一个可以直接在每个文件服务器(WebDav)上运行的Java应用程序。 WebDavs根据其物理RAID阵列分为目录树, 资源迁移器会遍历目录树并将每个资源文件上传到Google云端存储(GCS)。
为了确保成功上传给定资源,我们将本地计算的散列以及文件的内容传递给GCS API,GCS具有独立计算其自己的散列并将其与提供的散列进行比较的特征。 在不匹配的情况下,GCS API返回HTTP 400 BAD REQUEST错误代码,资源迁移器将重试。 如果发生重复的错误,则故障将被记录为稍后要固定的东西,并且资源迁移器将继续移动。
通过性能测试,发现我们受到RAID阵列上的IOPS(每秒输入输出操作)以及WebDav的CPU的约束。 为了避免影响客户体验,我们找到了资源迁移器的两个并发实例(每个RAID阵列一个实例)的平衡,每个并行实例运行在40个线程。 这使我们能够轻松地同时上传80个资源文件,而不会对生产用户流量产生负面影响。
现在我们在资源迁移器上植入了工作代码,然后需要创建一个控制层来管理它,输入migration-orchestrator。
The migration-orchestrator
resource-migrator本身是一个小应用程序,只能在WebDav集群中的每个目录树启动和停止。 考虑到要迁移的数百棵树,我们需要一个控制层来编排跨群集的迁移。
使用shell脚本,我们能够与我们现有的库存和车队管理工具集成,以跟踪,启动,停止和恢复整个WebDavs中的资源迁移器实例。
另外考虑到每个WebDav不超过两个实例,每个物理服务器机柜不超过20个实例(由于网络限制)的约束,迁移协调器必须是数据中心感知的,并且能够智能地启动/停止/恢复n个实例 的资源迁移者,基于能处理的最小单元。
在更高级别上,迁移协调器需要完成以下工作:
提供中央控制台以管理所有资源迁移器job(启动/停止/重新启动)
维护所有job的列表,并确定迁移的候选对象(正在积极进行写入的文件系统不能首先迁移)
注意数据中心和主机感知,以避免资源过载和影响生产流量
提供一致的24/7吞吐量和并发运行job
在最快速度下,我们能够并行运行100到120个资源迁移器实例,所有这些实例都由迁移协调器控制。
将应用升级并迁移至GCS
最后,我们需要考虑如何更新我们的应用程序代码,以使用GCS读取和写入资源,而不是WebDav。 我们决定添加多个开关,允许打开和关闭特定的GCS读/写功能。 这些开关也可以在分片子集上启用,从而以安全和受控的方式转出更新的代码。
如果您有任何问题,欢迎您访问印象笔记论坛,技术团队的成员将会给您专业的解答。
加入"云和恩墨大讲堂"微信群,参与讨论学习
联系客服