将时间线拨到2021年11月18日周四,Dropbox服务将照常营业。用户并不觉得有什么奇怪的,就像无数个安静的日子。但真的是这样吗?当然不会。当天下午五点,一群Dropbox的员工在Zoom频道吵了起来,因为他们突然被命令直接断开圣何塞数据中心与Dropbox网络的连接。
但这是一件大事。毕竟灾难恢复(DR)团队已经准备了一年多,影响它的是Dropbox六年多积累的工作结晶。
然而,面对一个自然灾害越来越常见的世界,我们必须考虑数据中心受到这种灾害影响的可能性。也就是说,我们不仅要仔细规划数据中心的位置,还要建立应对策略,以帮助降低风险。
自2015年搬出AWS以来,Dropbox的基础设施一直集中在圣何塞。尽管用户的元数据已经跨地区复制了很多年,但必须承认,我们的大部分服务都是在圣何塞诞生并成熟的。这是一块宝地,但它也靠近圣安德烈亚斯断层,所以我们必须确保突然发生的地震不会不小心使Dropbox离线。
我们如何向客户证明我们已经为灾难做好了准备?答案是恢复时间目标(RTO),它用于衡量我们从灾难性事件中恢复需要多长时间。多年来,我们一直在通过工作流缩短预期RTO,希望能更从容地应对包括地震在内的可能发生的灾难。
也正是依靠2020年和2021年的跨职能协作,灾难准备团队最终决定完全断开圣何塞数据中心,看看Dropbox是否真的能把r to降低到目前的水平。接下来,我们来回顾一下这个惊心动魄的故事。
一切都要从架构设计开始。
为了更好地理解如何缩短r to周期,我们必须先了解Dropbox是如何设计其架构的。
Dropbox有两个核心服务栈:一个用于块(文件)数据,另一个用于元数据。很多关注Dropbox技术动态的朋友可能都知道,我们的块存储解决方案叫做Magic Pocket,它的设计就是通过多宿主机来提高可靠性。所谓多宿服务,就是这种服务可以被设计成依靠多个数据中心保持运行。
Magic也是所谓的双活系统。也就是说,除了多宿设计,还可以同时独立为多个数据中心的块数据提供服务。Magic Pocket设计包括内置的复制和冗余机制,可以确保块故障对业务的影响保持在最低限度。这种架构还具有灾难恢复能力,因此用户可以清楚地看到数据中心出了什么问题,但服务体验不会受到太大影响。部署Magic Pocket后,Dropbox推出了三阶段计划,首先增强元数据栈的灵活性,最后在元数据层面建立双活架构。
具体来说,该计划的第一阶段是实现主动-被动架构。也就是说,在进行必要的更改后,我们可以将元数据从当前的主动大都市区-圣何塞数据中心(SJC)-转移到另一个被动大都市区。这个过程称为故障转移。
我们的第一次故障转移在2015年成功完成,但这只是实现最终目标的一小步。之后开始构建元数据栈的主动-主动主动架构,希望以独立的方式为来自多个数据中心的用户元数据提供服务。此时,麻烦开始出现了。
元数据让问题变得更加复杂。
我们的元数据栈建立在两个大的分散的MySQL部署之上。一个是使用内部数据库Edgestore承载通用元数据,另一个负责承载文件系统元数据。集群中的每个片由六个物理设备组成:两个核心区域、一个主主机和两个副本主机。
但是,MySQL层的两个取舍,加上Edgestore中数据建模的复杂性,迫使我们重新考虑整个备灾方案。
MySQL中的第一个权衡是如何处理复制操作。以前,我们使用半同步复制来平衡数据完整性和写入延迟。但是,由于这种设计,区域之间的复制只能异步完成,这意味着远程副本总是落后于主要主机。这种复制级别的滞后使我们很难处理主要领域的突发故障。鉴于此,我们通过设计来预测可能出现的故障,确保主区域在事件下仍能保持正常运行一段时间。冗余电源和网络系统已经部署到位,实际效果我们比较满意。
MySQ中的第二个权衡是一致性级别。我们的MySQL采用了读取和提交的隔离模式,方便了开发者处理数据,但同时也限制了数据库的扩展能力。目前常见的扩展方法是引入缓存降低整体一致性,但同时增加读取吞吐量。在我们的系统中,虽然Dropbox建立了缓存层,但其设计仍然与数据库保持了很强的一致性。这个决定使得设计变得相当复杂,同时也限制了数据库缓存内容的可容忍延迟。
最后,由于Edgestore是一个大型的多用途多租户图数据库,所以往往很难搞清楚其中数据的所有权。这种复杂的所有权模型使得我们几乎不可能简单地将特定的用户数据子集转移到其他领域。
这些权衡设计的存在,直接决定了我们后续构建主动-主动系统的基本思路。开发者已经适应了前一种权衡带来的高编写性能和后一种权衡的强一致性。总而言之,这些选择严重限制了我们在设计主动-主动系统时的架构选择,也导致最终的系统变得越来越复杂。到2017年,灾难准备工作已经停滞,但制定强有力的故障响应计划的压力并未减少。为了在发生灾难时确保良好的业务连续性,我们决定改变方向,探索主动-被动故障模式。
我们的灾难准备团队
在决定切换到主动-被动方案后,我们开始为更频繁的故障转移设计必要的工具。2019年,我们完成了第一次正式的故障切换,之后我们将每季度再次尝试故障切换,并以此为契机完善整个流程。2020年是一个重要的转折点——除了新冠肺炎疫情的爆发,我们Dropbox的防灾水平从那时起真的上升到了一个新的水平。
2020年5月,我们的故障转移工具出现了严重故障,导致停机,业务瘫痪了47分钟。负责驱动故障转移的脚本在执行过程中出错,导致我们处于半中断状态。这次失败也暴露了我们灾难准备策略中的几个主要问题:
驱动故障转移的系统本身缺乏故障弹性。各服务团队使用自己的故障转移流程与工具,互不相通。我们的故障转移频度不足,因此对方案的实践考查不够全面。为了解决第一个问题,我们开始对现有故障转移工具和流程开展紧急审计。我们还做出必要变更,确保工具拥有良好的故障弹性;同时建立起新的清单,确保能够以更严格的方式执行故障转移演习。
对于第二个和第三个问题,我们成立了一个专门的故障转移团队,也就是上面提到的灾难准备(DR)团队。有了这样的专业团队,我们可以将季度故障转移的频率提高到每月故障转移。更频繁的故障转移不仅可以帮助我们积累经验和增强信心,还可以使我们以前所未有的速度实现灾难响应和恢复。
有了明确的使命和新组建的七人团队,我们有信心制定更高的目标。到2021年底,Dropbox必须将RTO控制在更短的水平。
故障转移带来了实质性的改进。
2020年5月的停电给我们凸显了一个重要的问题——我们总想用一个Go二进制文件来完成城域之间的故障转移。虽然这种方法一开始效果很好,但随着我们对故障转移提出更高的要求,整个想法变得越来越不可持续。
因此,我们决定从头开始重写这个工具,以提高它的模块化和可配置性。我们从脸书的Maelstrom论文中得到启发,该论文详细阐述了一个巧妙的对外交通引导思路,足以承担庞大的数据中心灾难恢复需求。虽然有了参考对象,但还是从最小可行的产品入手,希望整个方案更适合Dropbox自己的系统。
我们从Maelstrom借用了Runbook的概念。Run包含一个或多个任务,每个任务负责执行一个特定的操作。这些任务共同构成了一个有向无环图,它不仅使我们能够描述故障转移练习中的每个必要步骤,还能总结所有常见的灾难恢复场景。在此基础上,我们可以使用易于解析和编辑的配置语言,整理出专门的描述各种故障转移情况的Runbook,这样后续的故障转移调整就会像编辑配置文件一样简单快捷。
与直接编辑Go二进制文件相比,新方法不仅更加轻便,而且提高了Runbook的可重用性,帮助灾备团队轻松完成一次又一次的周期性测试。下图显示了Runbook流程及其任务。
运行状态机。一本操作手册由多项任务组成。
任务状态机。任务负责执行特定的操作,例如数据库集群的故障转移、更改流量权重或发送Slack消息。
我们还编写了一个内部调度程序,用于接收Runbook的定义并向每个工作进程发出任务。在最不可行的产品中,调度器和工作器位于同一个进程中,并通过Go通道进行通信。这种灵活的体系结构允许我们在后续使用增加时,快速地将每个任务分割成单独的服务。
更新后的故障转移工具由一个调度程序goroutine和多个工作程序goroutine组成,并通过多个通道保持通信,以确保Runbook中的任务按照正确的顺序被分配和执行。
在这种新架构的支持下,我们可以很容易地观察故障转移Runbook的执行状态,清楚地判断哪些任务失败了,哪些任务成功完成了。显式的图结构还允许我们在出现故障时优先考虑任务,同时确保在前面的操作失败时暂停一些重要的操作。此外,运维人员的操作灵活性也得到了提升,比如轻松重新运行Runbook,跳过已完成或不必要的任务。随着Runbook的日益复杂,这种简单性和可靠性将有助于我们保持程序的可管理性。
除了对工具的深入改进,我们还配合以下变化来降低风险,进一步提升客户体验:
对关键故障转移规程开展例行测试。使用重构后的工具,我们现在可以在更小范围内定期自动运行故障转移测试。例如,我们可以只执行单一数据库集群的故障转移,或者只将百分之一的流量导引至另一城域再返回。这些小测试让我们对变更更有信心,也保证那些导致故障转移失败的问题永远不会再次发生。运营规程改进。灾难准备团队还受到 NASA 火箭发射项目中的实践启发。例如,我们制定了正式的通过/未通过决策点,同时设计出倒计时检查。另外,我们还引入了定义明确的职能角色——例如“按钮控制人”和“事件管理人”,同时尽可能提升自动化水平,成功将每轮故障转移演习的参与者数量从 30 人减少到 5 人以内。如此一来,我们也就降低了演习成本、让高频度演习成为可能。明确定义中止标准与规程。我们还定义了明确的中止标准和规程,希望为最糟糕的情况做好准备。以此为基础,我们不仅知晓调用何时中止,同时也知道该如何中止——这样就能加快恢复速度、把对于用户体验的影响控制到最低。增加故障转移演习频度、延长演习时间。在良好工具和规程的支持下,再配合透明的故障转移可见性,我们得以将故障转移的频率从每季度一次提升至每月一次,而且不断尝试延长每轮演习的持续时间。如此一来,我们就能快速发现可能在故障转移期间引发问题的代码部署、配置变量或新服务,减少每轮演习所需解决的问题数量。在经历了多次 1 小时故障转移之后,我们尝试将被动城域的宕机时间增加到 4 小时、之后是 24 小时,以此类推——最终,我们的被动城域成功离线达一个月。我们还通过“计划外”故障转移向灾难准备团队提出挑战,要求他们在一个小时的准备时间后直面突如其来的难题。
回顾2020年5月以来的改进,我们正在一步步向理想的故障转移目标迈进。在运营层面,我们已经将故障切换的实施和持续改进作为企业文化的一部分。故障转移服务也逐渐自动化,对备灾团队的前期准备要求大大降低,人工工作量也比以前低很多。此外,工具的改进还将我们的平均每月停机时间从2021年初的每次故障切换8到9分钟减少到下半年的4到5分钟。
不断打破新记录:Dropbox故障转移练习中的停机时间越来越长。
此时,我们认为准备工作已经就绪,接下来是真正的困难——完全断开圣何塞数据中心的连接。
新的里程碑
从2020年到2021年,我们的故障转移能力不断提高,灾难准备团队已经着手推进第二个关键里程碑:过渡到真正的主动-被动架构。
虽然故障转移练习已经证明我们有能力将元数据服务堆栈迁移到被动大都市区,但仍需要从主动大都市区(即我们的圣何塞数据中心)提供其他几项关键服务。直到那时,我们才意识到,测试活跃大都市区真正恢复能力的最佳方法是进行一波灾难恢复测试。在测试中,我们必须直接断开圣何塞数据中心与Dropbox运营网络的连接。如果事实证明整个数据中心的断网不会对运营造成太大影响,至少Dropbox可以正常运行几个小时,那就大功告成了。于是这个计划被提上日程,命名为“黑洞计划”。
多主机
虽然用于支持实时用户流量的元数据和块堆栈不会受到黑洞项目的影响,但我们知道,如果内部服务降级或无法正常工作,以前的努力仍然没有真正成功。更可怕的是,如此独特的测试设计,可能会给我们带来无法挽回的生产问题。所以我们至少要保证圣何塞数据中心运行的所有关键服务都是多宿的,或者至少暂时依托圣何塞以外的大都会区实现单宿运行。
前期的技术投入降低了多宿改造的门槛,也让我们很容易完成单宿的业务检测。在流量团队和Envoy流量负载平衡器的帮助下,我们可以控制从POP到数据中心的所有关键网络路由流量。Courier迁移使我们能够构建一个公共的故障转移RPC客户端,从而将客户端发出的服务请求重定向到另一个大都市地区的相应部署。此外,Courier的标准遥测功能还可以测量服务之间的流量数据,并帮助我们准确识别单宿服务。在网络层,我们使用带有自定义标签的Kentik网络流量数据来验证快递服务的依赖性,并及时捕获持续的非快递流量。最后,几乎所有的服务都是由Bazel配置的,因此我们可以建立并推广多metro部署的做法,然后借助另一个数据源来验证服务metro的适应性。确定有风险的服务后,灾难准备团队将提供建议和资源,以确保服务所有者可以对服务架构进行更改,并减少他们对圣何塞数据中心的依赖。
有时,我们直接与团队合作,将他们的服务集成到我们每月的故障转移中。通过减少圣何塞数据中心的单宿服务数量,并将其引入定期测试,我们越来越有信心这些服务可以在另一个大都市地区继续正常运行。在这个阶段,故障转移列表中的关键服务是CAPE和ATF异步任务执行框架。对于一些团队,我们会直接协助他们以空的健康方式,将过去只由圣何塞数据中心运行的组件转化为多宿主形式。最后,在实施黑洞项目之前,我们完成了圣何塞数据中心所有主要服务的多宿主改造,最大限度地减少了设施断开可能带来的影响。
“黑洞”就在眼前,最后的准备
在确定了圣何塞数据中心关键服务的调整后,我们开始为黑洞项目做最后的准备。
在实施日期前大约两个月,我们与网络工程团队合作,决定采取渐进的方法进行测试准备。在合作中,我们确定了三个主要目标:
设计规程,模拟圣何塞数据中心完全瘫痪的场景(但要求易于恢复)。先在风险较低、影响较小的城域内开展测试。根据测试结果,为黑洞项目做好万全准备。
检查法
最初,我们打算清除空大都市地区的网络路由器,以便将圣何塞数据中心与网络隔离。虽然这样可以,但我们最终还是决定采用一种纯物理的方法,可以更好的模拟真实的灾难场景:拔掉网络光纤!在决定采用这种方式后,我们开始总结具体的协议操作(MOP),即在“黑洞”到来的那一天,如何按部就班地进行。总的来说,我们的拖把基本上有以下几个步骤:
安装流量导引程序,把所有滞留流量全都引向其他城域。禁用所有警报和自动修复功能。拔掉网线!执行验证(ping 各台设备、监控关键指标等)。启动 30 分钟倒计时,安静等待。重新接上网线。执行验证。重新启用警报和自动修复功能。恢复流量。
在确定了整个计划后,我们在达拉斯沃斯(DFW)地铁区开始了两轮试运营。选择这个大都市区是因为它更符合低风险要求:它几乎不承载任何关键服务,所有服务都是多宿主的,设施极其灵活。
在DFW都会区有两个数据中心设施,即DFW4和DFW5。我们决定从单个数据中心开始第一轮测试,然后测试双设施断开连接的场景。
为了做好准备,网络和数据中心团队拍了照片,以确保网络光纤处于正常状态。他们还订购了备用硬件,以防止设施因意外故障而无法及时恢复。此外,备灾小组还明确了暂停标准,协调各小组进行交通疏导、报警/自动修复禁用等事宜。
DFW第一轮测试
第一轮DFW测试的日子终于到来了。我们20多个人聚集在Zoom会议室,盯着屏幕上的MOP计划。每个人都知道自己的角色,一切都准备好了。按照计划,我们果断拔掉了DFW4的光纤网线。
在验证过程中,我们很快发现外部可用性下降了——这是意料之外的。等了四分钟左右,我们接通了测试终端电话,重新连接了网络光纤。在这一点上,第一轮测试可以说是失败了,因为我们只是简单的坚持了离线网络不到30分钟的目标。
失败的核心原因是脱离网络的DFW4数据中心是我们S3代理商所在的设施。因此,在DFW5中运行的服务将继续尝试与本地S3代理通信,但它将继续失败,这将影响服务并最终降低全局可用性。
测试前我们误以为DFW4和DFW5应该没有区别,所以断开一个地方应该不会影响到另一个。但测试结果表明,不同设施之间总会存在一些难以想象的依赖关系,因此不能将目标设施粗略理解为完全独立的故障点。所以相对于直接断开整个都市圈设施,单个设施的断开影响会更大。
另外,需要注意的是,灾难恢复测试的意义在于帮助我们吸取教训。在第一轮测试中,备灾小组和其他部门学到了宝贵的经验。包括:
需要针对整个城域、而非单处数据中心设施开展黑洞测试。需要针对具体测试类型,制定更加严格准确的中止标准。需要与当地服务所有者合作,确保清空相应服务。
因此,我们在下一个测试MOP中引入了两个新步骤:
清空所有本地服务(例如 S3 代理)。安装流量导引程序,把所有滞留流量全都引向其他城域。禁用所有警报和自动修复功能。拔掉网线!执行验证(ping 各台设备、监控关键指标等)。启动 30 分钟倒计时,安静等待。重新接上网线。执行验证。恢复本地服务并验证其运行状况。重新启用警报和自动修复功能。恢复流量。
DFW第二轮测验
利用积累的知识,几周后我们又试了一次。这一次,我们决定直接断开整个DFW设施。现场照片拍完,备用硬件到位后,我们紧张地等待着第一次真正的全城测试。
首先,我们清除了空本地关键服务,然后按照上面的过程执行剩余的步骤。两名Dropbox人员已经前往设施现场,按照命令迅速拔掉网络……这一次,我们没有观察到任何明显的可用性影响,整个黑洞测试成功持续了30分钟。取得了很大进展,成绩喜人。我们认为同样的惯例应该在圣何塞实行。
DFW测试的一个重要教训是,非关键服务(包括部署系统、提交系统和内部安全工具等)的所有者。)必须开始批判性地思考SJC黑洞测试的影响。我们创建了一个影响文档,希望以一致的方式了解在SJC黑洞测试期间哪些服务可能无法正常工作。
在考虑后续测试的具体进展时,我们发现了另一个显著的优势:这些测试帮助我们培训了关键的服务团队和等待命运的人,他们也更加了解我们是如何进行黑洞测试的。有了这些积累,我们完全有信心SJC的大行动会取得成功。
重要的一天
2021年11月18日星期四,SJC的网线已经在瑟瑟发抖了。SJC的三个数据中心都有一名Dropbox员工。再次,他们拍了照片,并准备了备用硬件,以防止拔下或重新连接光纤网线时损坏端口。约30人聚集在Zoom会议室,更多的同事加入了Slack频道。在发射月球火箭之前,公司充满了紧张感。
最后,在太平洋时间下午5点,三个设施同时与网络断开。正如在第二轮DFW测试中,我们仍然没有看到全球可用性的太大波动——30分钟的目标——SJC黑洞测试也成功实现了!
呃,好吧,我知道听起来好像少了点戏剧性。但没错。我们为测试做了这么多准备,结果应该是平稳无声的。
虽然我们关注的一些内服受到了一些意外的影响,但总体来说,测试还是取得了很大的成功。事实证明,即使面对全城域完全断网的极低概率,我们的故障转移积累在人员和流程配置得当的情况下,仍然可以显著缩短RTO,Dropbox的业务也可以在另一个区域继续顺利运行。更重要的是,我们的黑洞演习也证明了,即使没有SJC,Dropbox业务依然屹立不倒!
从左到右,埃迪、维克托和吉米三个同事同时拔掉SJC数据中心的网络光纤。
了解更加灵活可靠的Dropbox
JSC都会区的30分钟离线代表了Dropbox在备灾方面迈出的重要一步。我们证明,Dropbox已经拥有必要的工具、知识和经验,即使在灾难严重到整个大都市地区完全断电的情况下,也能保持业务运营。这些改进也使我们能够在服务可靠性和灵活性方面继续为整个行业感到自豪。
这是一个需要很多年的努力,离不开各个Dropbox团队的精心策划和协调。考虑到Dropbox服务和依赖关系的复杂系统,这样的故障转移肯定是有风险的。然而,凭借尽职调查、频繁测试和程序改进,我们成功地将这些风险降至最低。
更重要的是,黑洞测试的经历还帮助我们强化了备灾的核心原则:和肌肉一样,备灾的能力也需要不断的训练和锻炼。随着黑洞测试频率的增加,我们的备灾能力将不断提高。只要准备工作到位,用户绝对不会感觉到任何异常情况。q玩可靠的Dropbox是一个好的值得信赖的Dropbox。
最后,我们要感谢Dropbox的每一个人,感谢他们为黑洞测试所做的努力,感谢你们为这个新的里程碑做出的贡献。没有几十支队伍的每个成员打赢的几百场小仗,我们不可能达到这样的里程碑。
原始链接:
https://Dropbox . tech/infra structure/灾难准备-测试-故障转移-黑洞-sjc
想了解更多关于软件开发和相关领域的知识,点击访问InfoQ官方网站:https://www.infoq.cn/获取更多精彩内容!
飞机跑道长多少米
