BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

Evernote从自有数据中心到Google云的迁移-第2篇

| 作者 薛命灯 关注 24 他的粉丝 发布于 2017年4月5日. 估计阅读时间: 18 分钟 | 如何结合区块链技术,帮助企业降本增效?让我们深度了解几个成功的案例。

前文请见《Evernote从自有数据中心到Google云平台的迁移》第1篇

第三部分:GCP上的Evernote架构和我们的技术转型

我们的系统架构

下一个重大决定是如何在即将实施的系统架构方案上达成一致。下面是一些重要的考虑点。

  • Evernote服务可以运行在多个数据中心上(不包括中国地区的服务)。
  • 将用户数据的两个副本保存在不同的地理区域。
  • 最小化加州北部数据中心和GCP之间的网络延迟,为迁移工作带来更多的灵活性。而且如果有可能,在短期内还能支持多站点运行。

基于这些考虑,我们达成了以下方案。

  • 主要位置(处理生产流量):US-West1
  • 次要位置(灾备站点):US-Central1

后续我们还会把US-West1的服务拆分成两个区域,进一步提升故障防护能力。

正如Google所说的,“Google把区域设计成相互独立的:每个区域有自己的供电系统、冷却系统、网络和控制面板,大部分的故障只会影响到单个区域”。

基于上述的架构,我们可以处理US-West1之外的流量,并在US-Central1保存用户数据的第二个副本。如果US-West1发生故障,我们可以使用US-Central1的数据进行恢复。

我们以后还要想办法对我们的应用进行重构,提升它们的弹性。还要考虑如何同时处理多个区域的流量,以便进一步减少从故障中恢复的时间。我们也会考虑如何更好地利用GCP的全球基础设施来改善用户的延迟体验。

到现在为止,我们定义了清晰的需求,并做出了很多决策。接下来开始进入具体的实现阶段。

技术转型

最大化从数据中心到GCP的网络连接

我们在一开始就意识到,从数据中心到GCP的网络连接是决定这次迁移成功与否的关键因素,同时也是主要的约束所在。为了能够灵活地对数据和服务进行迁移,网络互连计划需要实现如下几个目标。

  1. 对从数据中心流向CGP的流量进行加密。
  2. 将两个区域中的任意一个作为用户流量的“前门”,如果有必要,可以基于这两个“前门”来分割流量。
  3. 对每个区域的服务进行分割,让它们部分运行在物理数据中心里,部分运行在GCP上。
  4. 最大化站点间的带宽,以支持大块数据的拷贝。

在GCP上运行Evernote后端服务,并向CGP拷贝3PB的数据。在这种情况下,为了让100%的“前门”流量流经数据中心和物理负载均衡器系统,我们需要进一步提升灵活性。

我们已有的外部网络连接可以处理峰值负载,而且留有余量。不过,它的容量仍然无法满足及时清退数据的要求。

另外,我们的内部网络结构并不支持将如此大规模的请求导出到外部设备(比如Google云存储)上。基于目前的情况,要将所有的数据上传到云端,可能需要超过一年的时间,而且会影响用户体验。所以我们还有很多工作要做。

首先,我们需要建立私有网络互连(PNI),或者直接在Evernote的网络和GCP之间建立连接。这样可以将可用带宽增加一倍,而且这些连接独立于用户流量。这就在Evernote和GCP之间建立起了一个快速的私有通道。

其次,我们需要确定数据中心的哪些地方需要输出数据。我们的数据有多个副本,所以需要确定该使用哪个副本。我们需要开辟出一条网路,在不影响系统正常运行的情况下,将成千上百台服务器的数据通过私有通道移动到GCP。我们需要小心地协调数据拷贝作业,让这些请求正确地流经一系列负载均衡器和代理服务器。

在项目启动后的头一个月,我们的网络工程团队争取在数据拷贝启动之前完成准备工作。因为如果他们的工作无法按时交付,整个迁移工程都会受到影响。

我们可以多站点运行吗?

到目前为止,我们的应用只在单个数据中心里运行。在单个数据中心里,节点间的延迟通常是亚毫秒级的。如果我们能够成功地在数据中心和GCP上运行应用,我们需要知道该如何将节点间的延迟保持在20毫秒到50毫秒之间。延迟的增加有两方面的原因,一方面是受光缆的速度限制,另一方面是受数据中心和GCP之间距离的影响。

很显然,我们不希望在迁移过程中发生此类问题。为了避免给用户带来延迟,我们需要先进行自测。在项目计划期间,我们决定使用一种服务端工具(tc)引入人为的网络延迟,并模拟出因地域和光缆速度限制所带来的延迟。我们逐渐将NoteStore的延迟增加到50毫秒,并保持4天不变。在此期间,我们对应用的KPI进行监控,并将它们与我们的基准数据进行比较。我们发现,大部分API调用有轻微的减慢,不过都在可接受的范围之内,而且没有对用户体验造成影响。

这是一个里程碑式的阶段性胜利:我们确信我们的应用可以跨站点运行,也就是说,我们的“增速阶段性切换”方案是可行的。

负载均衡(从物理均衡器到HAProxy)

我们的数据中心运行着一个高可用的负载均衡器集群。在迁移到云端之后,就无法使用物理的负载均衡器,所以我们开始调研虚拟的负载均衡解决方案。

理想情况下,我们可以在GCP上部署单个负载均衡层。不过从现实来看,这个是不可行的。我们根据cookie、消息头和URL将请求消息路由到特定的分片上,但我们无法在GCP负载均衡平台上做这些解析工作。最后,我们基于Google网络均衡器和一个基于Linux的HAProxy集群构建了新方案。

Google网络均衡器将成为用户流量的入口点,并将流量均衡地分发到HAProxy集群上,然后HAProxy集群将流量路由到特定的分片上。

在通过实验测试之后,我们想使用真实的流量来对新方案进行测试。我们采取阶段性测试,在前一个测试通过之后才会增加更多的流量。到目前为止,后端的Evernote服务仍然在物理数据中心里运行,而跨站点的负载流量会通过私有VPN连接路由到那里。我们打算这样做:

  1. 将Evernote员工流量重定向到新的“前门”。我们更新了公司的DNS,从而将Evernote员工流量引导到新的前门。
  2. 使用Dyn Traffic Manager逐步将用户流量导入到新前门。

我们通过上述的两个方法对我们的新负载均衡平台进行测试。与跨站点测试一样,我们庆幸我们能够单独完成组件的测试,并确信这个方案是可行的。

Reco服务(从UDP到发布订阅)

当用户将附件或资源上传至Evernote,有个后端服务会尝试提取图像或PDF里的文本信息,这个服务被称为Reco(“recognition”的缩写)。

因为之前的架构存在种种限制,Reco服务器只能通过轮询的方式拉取资源。可以想象得到,多台Reco服务器定期向NoteStore服务器发起轮询,会给NoteStore服务器和资源存储服务器带来很大的压力。随着用户附件的增加,需要添加更多的Reco服务器,从而让情况愈加恶化。

为了减少因Reco服务器的增加而带来的开销和延迟,我们对Reco服务器进行了重新设计,通过使用多路广播,当NoteStore增加新的资源时,Reco服务器就会收到通知。

不过GCP的网络并不支持多路广播,所以我们使用新的通信模型对应用进行了重新设计。

我们移除了轮询机制和多路广播机制,取而代之的是基于发布订阅模型的队列机制,这种机制不仅可靠而且可伸缩。NoteStore向队列里发布任务,Reco服务器订阅队列,并获取任务,在处理完任务后进行确认。我们创建了多个优先级队列,Reco服务根据队列的优先级来处理任务。

我们使用基于云的队列机制极大简化了原先的架构,现在能够影响Reco服务的因素只有两个:队列里是否有需要处理的任务以及通知的速度。除此之外,我们正进一步改造Reco服务,让它支持自动伸缩,这样我们就可以把注意力放在如何管理和维护附件资源上。

用户附件存储(从多WebDev到Google云存储)

我们需要将120亿个用户附件和元数据文件从原先的WebDav服务器拷贝到Google云存储上。

因为数据量巨大,拷贝文件是整个迁移项目的关键一环。在进行拷贝的过程中,我们的服务仍然会对WebDav服务器读写数据。

我们碰到的第一个障碍是我们的网络,我们无法每天从几千个节点拷贝几百TB的数据。所以,我们不得不花一些时间建立了多条到GCP的网络通道。在进行数据拷贝的同时,我们要确保不会对自己造成DDoS攻击,还要保护好用户服务。

资源迁移器

我们开发了一个Java应用程序,它可以直接运行在WebDav服务器上。WebDav服务器根据它们的物理RAID情况被拆分成目录树。资源迁移器遍历目录树,并将每个资源文件上传到Google云存储(GCS)。

为了确保文件能够上传成功,我们在本地为每个文件生成了一个散列值,这个散列值连同文件一起发送给GCS。GCS有独立计算散列值的功能,它将自己计算的散列值与收到的散列值进行比较。如果散列值不匹配,GCS会返回一个HTTP 400 BAD REQUEST错误码,资源迁移器会进行重试。如果连续几次重试失败,错误会被记录到日志里,用于后续的修复之用,而资源迁移器会继续上传其他文件。

通过性能测试,我们发现拷贝过程主要受RAID阵列的IOPS(每秒输入输出操作)和WebDav服务器CPU的影响。为了避免对用户体验造成影响,我们使用了两个并行的资源迁移器实例(每个RAID阵列使用一个迁移器),每个实例使用40个并行线程。这样我们就可以同时上传80个资源文件而不会对用户造成负面影响。

有了资源迁移器,接下来需要创建一个控制层来管理这些迁移器。

迁移编排器

资源迁移器是一个小型的应用,WebDav集群上的每个目录树都需要一个迁移器实例。因为有几百个目录树需要迁移,所以需要一个控制层来管理这些迁移器。

我们在shell脚本里集成了现有的目录管理工具,实现了对资源迁移器实例的启动、停止和追踪。

因为受每个WebDav服务器最多只能运行两个实例和每个物理服务器机柜最多只能运行20个实例(受网络限制)的限制,迁移编排器必须能够智能地管理好资源迁移器实例,尽量减少人工的干预。

从高层面看,迁移编排器需要满足如下要求。

  • 提供一个集中式的控制台用于管理所有的资源迁移器
  • 维护任务清单,并识别出可迁移的任务(正在写入的目录是不能进行迁移的)
  • 了解数据中心和主机的情况,避免出现资源过载或影响到生产流量
  • 提供稳定的24/7吞吐和并发任务

如果速度全开,我们可以同时运行100到120个迁移器实例,这些实例完全由迁移编排器来控制。

让应用与GCS发生交互

接下来,我们要考虑如何更新我们的应用程序,以便从GCS读写数据。我们决定加入一些开关,用于切换GCS的读写功能。有了这些开关,我们可以先在部分分片上打开这个功能,让新功能的发布更安全、更可控。

服务切换

将服务迁移到新的存储后端是一个敏感的操作。我们在开发环境和测试环境进行过大量的测试,在进入生产环境之前我们能做的也只有这些了。

为了做到干净安全的切换,并最小化对用户的影响,我们把迁移分成几个独立的步骤。为了方便理解,我们先来了解下最初的资源上传过程。

  1. 用户向Evernote服务发送保存资源的请求。
  2. 服务收到用户的资源,并启动两个进程:
    1. 确保资源的两个副本被保存到WebDav服务器上
    2. 将资源添加到异步任务队列
  3. 在完成了上述两个步骤之后,向用户返回保存成功的消息。
  4. 后台处理异步任务,资源的第三个副本被拷贝到远程的WebDav服务器上。

第一阶段

GCS异步写入

第一步,我们往异步队列里写入需要上传到GCS的资源。这样做有如下几个好处。

  1. 新的资源将会被自动上传到GCS,为我们节省了使用资源迁移器的时间。
  2. 另外,我们可以将生产环境的写入流量导向GCS API。这对于测试我们的代码是否能够处理大量数据来说非常关键。我们也因此对一些故障场景和GCS的评估有了更深入的了解。
  3. 更重要的是,以上过程全部发生在用户的视野之外。这里所发生的故障对于用户来说都是100%透明的,所以我们可以自由地进行迭代,不断改进我们的代码,而不会对用户体验造成负面影响。

GCS伺机读取

到现在为止,我们对写入性能充满了信心,并对我们的代码和GCS有了正确的评估。下一步是如何让读操作的性能也能达到相同的等级。

我们伺机从GCS读取资源数据,如果有些资源还没有被迁移过来,或者出现了故障,我们的服务会立即转向主WebDav服务器读取数据。

因为下载资源处在用户的关键路径上,在读取资源时发生转向有可能会造成一些延迟。不过这些延迟一般在毫秒级别,用户感知不到。

初步结论

头两轮的测试让我们对新的存储后端和代码有了更多了解。我们发现了一些罕见的故障(1:1,000,000的比率),而且发现GCS Java SDK内置的重试机制无法满足我们的要求。我们通过快速迭代改进了我们的代码,解决了这些故障,让服务更加健壮。

第二阶段

在经过几轮迭代之后,我们准备进行全面的提交。下一步要移除对WebDav服务器的依赖。不过,我们对资源的迁移流程还在进行中,所以伺机读取资源的机制还要保留,不过对于新的资源来说,就没必要再使用WebDev了。

关键路径上的GCS写入

首先,我们要改变资源上传流程。之前,资源会被上传到两个主WebDav服务器上,而现在它们直接被上传到GCS,而且我们将WebDav服务器的位置数量减至一个。

  1. 如果GCS发生重大故障,所有的重试都会失败,用户最终会收到“上传失败”的错误信息(不过我们的客户端会再次重试,所以不用太担心)。这也就是我们能得到的最糟糕的结果。
  2. 虽然我们减少了WebDav的写入,但并不会降低数据的持久性。GCS提供了更好的数据冗余,所以这是一个很大的进步!
  3. 减少WebDav数量有助于降低延迟(两次写入与三次写入的对比),同时,仍然保留单个主WebDav拷贝让我们感觉到很安全。

全面禁用WebDav写入

我们对系统的性能和健康情况进行了深切的监控,在运行了一段时间之后,我们准备全面停止向WebDav服务器写入数据。

  1. 禁用离岸灾备中心的异步备份作业(GCS不仅为每个资源维护多个副本,还会将它们存储在不同的地理区域,为我们提供了很好的弹性,以便应对灾难性故障和自然灾害)。
  2. 禁用主WebDav写入。

现在的上传流程更简单了。

  1. 用户像Evernote服务发送保存资源的请求。
  2. 服务接收资源并将其写入GCS。
  3. 服务向用户返回成功信息。

在后台,GCS负责保存资源的多个副本,并保存在多个地理位置。

最后的验证

在撰写本文时,我们已经完成99.2%的资源迁移,这一过程是整个迁移项目非常重要的一部分。可以说,我们即将看到胜利的曙光!

GCS伺机读取机制还会继续存在,直到我们进行一次最终的完整性检查,确保所有的资源都已成功迁移。

为了完成最终的完整性检查,我们遍历了资源数据库,然后向GCS查询这些资源是否存在,并再次验证每个文件的散列值。与资源迁移过程相比,完整性检查完成得会快很多。我们按周而不是按月来检查资源,确保120亿个资源都安全地进行了迁移。

在云端生产环境测试分片

进行云端分片测试也需要经过一些步骤。在迁移项目启动之初,我们就定义了一些迭代流程用于测试运行在GCP上的Evernote服务。在进行全面迁移之前,我们需要确保在用户负载全开的情况下,单个分片能够成功地运行在GCP上。我们要找出之前的测试没能覆盖到的边界情况。

在感恩节之前,我们成功地将两个用户分片迁移到GCP上,并让它们运行了几个小时,最后再回退到物理数据中心。我们完成了最后的预迁移检查,为后续的全面迁移亮起了绿灯。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT