暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

异地多活痛点和设计漫谈

yangyidba 2022-10-02
595

摘录自《禧云异地多活技术白皮书》


1.仅靠横向扩容是不行的

我们从2011年开始做交易系统,至今(2020年)整整做了十年。在这十年间,经历了各种事故、各种攻击,可谓是法宝齐出。从中学到一点,如果想支撑日活千万级以上交易,想确保SLA达到四个九,仅仅靠横向扩容是不可能的。

如下所述,支付交易系统的高可靠性有两种方法,单IDC内做到可伸缩,和多IDC间的可伸缩。

第一种,单IDC架构下的可伸缩,指的是应用分层(Web层,缓存层,中心层,中间件层,存储层),每一层在单机房内可伸缩,比如订单中心可以横向加节点,10个不够,加到20个。这里的节点,在2015年以前指的是虚拟机,在2015年之后已变成Docker容器。

随着业务量持续攀升,这个模式的缺点会愈来愈凸显。节点不可能无限制地增加下去。流量入口的负载均衡节点将成为瓶颈。服务可能出现雪崩,一损俱损,连累其他的用户和商户,连累其他的业务。

第二种,多IDC架构的可伸缩和失效转移,一般指的是将业务封闭在一个个逻辑单元内,然后在多地部署多个这样的逻辑单元,同时满足业务对容量和容灾的需求。简而言之,到了一定的业务量,就需要多IDC的单元格部署方式,也就是异地多活。
 

2.在双活之前遇到的单机房经典问题

当业务到一定规模之后,公司就需要大力重视风险控制,绝不允许出现单节点故障隐患。并不是说只有单个Nginx节点,单个应用节点,单个数据库节点才叫单节点风险。单机房也属于单节点风险。

我们所共同见证过的,单个IDC机房曾出现过以下风险:

1)机房空调故障:
  • 2011年5月和6月连续两次,我们租用的某知名IDC机房,空调机组故障,造成托管机房温度过高。
  • 2013年5月18日,我们租用的某知名IDC机房的空调机组因杨柳絮堵塞室外机而停机,随后我们的托管服务器因超温保护而自动关机。

2)机房缆线被挖断:这种事故比比皆是,属于高发事故。
  • 2011年11月17日,我们短信通道所在的天津某IDC机房电缆被铲车挖断,备用电源坚持不了太久,机房断电,导致我们无法使用短信通道,同机房的遨游、新浪邮箱、豌豆荚等公司的服务也因此中断。
  • 2012年7月25日晚间至21点40分,北京暴雨抢修时某IDC机房的光纤被挖断,导致美团网一度不能访问。
  • 2012年10月18日上午至11点40分,酒仙桥某IDC机房断电,凡客诚品(刚好赶上凡客五周年生日促销)、亚马逊中国等网站无法访问。
  • 2013年7月22日上午,因市政道路施工导致通信光缆被挖断,导致微信全国范围不可用。
  • 2017年1月,公有云 UCloud 公司正在开年会,结果在他们北京B可用区的数据中心外3公里处,架空光缆线杆被卡车撞倒导致光缆断裂,工程师们只好在年会现场紧急处理。

  • 2019年3月23日下午,银联和网联与微信支付上海机房的物理连接被挖断,虽然银联快速切换了备用线路,但下游业务(支付宝支付、微信支付、云闪付)均受到影响。

如是种种,触目惊心,所以日常工作一定要假设单机房物理毁灭,做相应演练。

3)通讯硬件故障造成的网络中断:
  • 2013年4月10日,腾讯微信所在IDC机房的一台交换机出现硬件故障,导致少部分微信用户约十分钟发送消息失败,一度轰动了社交网络。
  • 2013年6月17日,因长话大楼机房核心设备硬件故障造成网络中断,我们租用的IDC机房网络出现异常。

4)单机房遭遇DDoS攻击:
2014年1月17日下午18点开始,我们租用的某IDC机房由于托管用户触某科技被 DDoS 攻击,造成大网受到影响,机房内到外 PING 丢包严重,丢包最严重时丢包率 100%,我们的应用无法正常访问。这种现象在1月18、19、20日仍继续发生,该IDC机房采取的措施是,一旦发现触某科技被打,就关闭它的端口,保证其他公司业务不受影响,所以每次都是几分钟的波动。

所以,很多大型互联网公司都会在多个城市同时支撑客户交易,能做到在一个城市所有机房瘫痪的情况下,在几分钟内恢复(或者继续新的)所有的交易。
 
以上谈及的都是IDC机房遭遇的灾难性事件,那么像阿里云这样的公有云能独善其身吗?不能,它也有单机房风险:

1)绝无仅有的供电引发的大灾难:
2015年6月21日上午9点到10点之间,一些使用阿里云香港数据中心的用户发现服务出了问题,此后阿里云公告称由于运营商电力问题造成香港机房故障。因为供电系统故障导致数据中心大楼整体断电,并触发了消防报警。根据当地的消防规定,必须彻底排查隐患并完全消除后,才能获准进场做电力抢修。直至当晚21点22分机房正式恢复稳定供电,阿里云立即执行既定预案逐项恢复服务,21点32分安全防护服务恢复正常,各项服务陆续恢复,截至23点39分全部服务恢复。


2)软件组件引发的灾难性事件:
  • 2015年9月1日,阿里云官方发布致歉公告,称“因云盾安骑士server组件的恶意文件查杀功能升级触发了bug,导致部分服务器的少量可执行文件被误隔离”。
  • 2018年6月27日下午,阿里云在运维上的一个变更操作,触发了一个未知代码bug,错误代码禁用了部分内部IP,导致部分产品访问链路不通,受影响范围包括阿里云官网控制台,以及MQ、NAS、OSS等产品功能。
  • 2019年12月25日至27日,我们做了RDS数据库降配,实例内核小版本为rds_20191212,这个版本有BUG,因而在大访问量的情况下引发了主备频繁切换。如下图所示,事发后,阿里云发布了公告,随后做了紧急修复,关闭了thread pool默认特性。但此事并没有完结,进入2020年后,RDS的内核小版本rds_20200331版本中该参数沿用了优化后的参数模板,所以thread pool特性又被打开了。

图 RDS云数据库线程池特性有问题
 
  • 2020年5月29日,我们将阿里云华北和华东机房的主力RDS数据库做了升配,我们升配升到了rds_20200331这个小版本之后,由于访问量大,很快暴露了这个固有问题,主库性能下降。两个机房的主力RDS数据库,均出现了CPU使用率不高、IO正常、但连接数飙升、连接耗时过长、处理能力下降的现象,连累我们支付网关以及上游支付应用堵塞,交易失败率升高。

3)硬件故障引发的灾难:
  • 2016年7月6日上午10点22分,阿里云华北2地域可用区A由于网络设备出现异常,导致部分产品访问受到影响,故障持续约1小时。
  • 2016年10月11日下午16点40分,阿里云华东一区部分服务器故障,导致部分网站无法运行。

所以,千万不要以为阿里云经营多年就是稳定可靠的,灾难随时都会到来,必须做好两手准备,预防单节点故障。
 

3 双活需要考虑的六个要点

并不是开发了一套管理系统就万事大吉的,尤其是异地双活这种流量乾坤大挪移。

首先,多IDC机房之间的关系到底应该是灾备/主备还是多活?
多年前,大家往往做成了灾备机房,一主一备。结果是,真正灾难发生的时候,最高负责人却下不了决心切机房,因为无法预料切换后果,灾难总是不期而遇,切过去很可能切不回来了。

所以一定是多个数据中心同时运行着同样的应用,拥有同样的数据,任何一个客户的交易可以在分钟级路由到另一个数据中心并对外提供服务,这样才不至于说等到灾难来临的时候才发现备用集群无法工作。

所以,异地双活的第一大要点就是:
是双活,不是主备,不是灾备!
 
2019年3月3日凌晨零点突发灾难,阿里云华北机房整体不可用竟然长达三小时,没有人敢于预测这种大规模不可用能够在早餐前得到解决。所以我们紧急召唤社餐和团餐的技术小伙伴们,要求将华北机房所有商户一键切换到阿里云华东机房。

虽然社餐小伙伴们在此之前也做过几次流量迁移演练,但没有演练过单机房整体不可用的场景,又赶上了深更半夜,很多人都联系不上,一时间头大如斗。当然最后还是切换机房成功了。
所以,异地双活的第二大要点就是:
做好预案,做好演练,切不可临时抱佛脚!

此事之后,我要求技术骨干们:
  • 写好双活切换的各种预案,事先准备好验证切换成功所需要的数据,如验证交易成功与否的门店ID和收款二维码,不要临时抱佛脚。
  • 所有业务线的双活管理入口、域名切换入口,都要提前准备好,不要临时在群里问。
  • 每隔一段时间就要认真做一次演练。
  • 一定要保证双机房都有测试商户,而不是临时找测试商户。
  • 日常就要做到双机房商户流量七三开或六四开,确保真的是双活,而不是主备。
记住,灾难随时会来临。
 
2018年团餐刚上双活体系的时候,平常我们会设定一个测试商户,在阿里云华北机房和华东机房之间切换,确认异地双活随时可用,如下图所示。

图 双活的单元格关系

2018年5月29日晚间,在一次切换测试商户到华东机房的时候,异地双活控制程序误以为华北机房不可用。于是它修改 HTTPDNS,将华北子域名均解析指向华东机房的IP地址,并通知所有收银设备域名更新即时生效。

就这样,从5月29日晚间到5月30日上午,支付宝的所有支付成功通知回调,都进入到了华东机房。

由于华北机房和华东机房之间有我们的中间件做数据双向同步,所以业务正常,无人察觉,但这是不对的。

所以,异地双活的第三大要点是:
禁止程序自动切换机房,切换机房这种指令,只能由人来下达!
 
波音737MAX在过去几年里连续两次航空灾难都是因为同样的原因:
波音的MCAS,自动防失速系统,这个系统的主要功能是检测到飞机仰角过大、速度过低时,自动进入俯冲状态增速。这是737MAX上新增的系统,优先级极高,一旦传感器发生故障,该系统会误判飞机姿态,绕过飞行员直接进行俯冲加速。
系统的优先级高到失事的机长几十次与它搏斗,反复争夺飞机的控制权。

从这个灾难性事件中我们深刻领悟到,关键时刻,人下达的指令一定要高于系统。

其实,我们的异地双活之前也进入过相似的窘境:
一次,当阿里云华北机房的RDS主数据库突然 CPU 100% 的时候,我们试图紧急切换华北机房的所有商户到华东机房,竟然遭到了异地双活系统的阻止……
异地双活控制系统认为双活机房之间的数据库同步不能延时超过N分钟,如果超过了就禁止切换……
但就是因为 RDS CPU 100%,谁也连不进去,无法恢复服务,才切机房的,凭什么阻止呢?!
所以,异地双活的第四大要点是:
人下达的命令就是最终裁决,系统不要自以为是!

关键时刻人的指令要高于系统。
真正灾难发生的时候,机房已物理不可访问了,这时候就是要立刻地、全部地切换流量,人下达的命令就是最终裁决。拼着损失一分钟的交易和脏数据,也要把交易切到另一个机房。
 
下一个问题是所有业务都双活吗?
异地双活的第五大要点是:
基于互联网公司常用的基本可用性保障原则,只是保障核心业务双活。
怎么定义核心业务?即不能容忍中断的服务。
用户注册,商户进件,这些都属于能容忍临时性中断的服务。
非核心业务应用都被标记为非多活业务,非多活数据库与多活数据库要严格区分开来。
 
最后,切机房的时候能直接切吗?

双活意味着两个机房都不需要维护一个能承载所有流量的集群,否则太费钱了。所以日常模拟切机房流量的时候,一定要测试与核心业务有关的所有应用自动扩容,扩容之后再切换流量。

异地双活的第六大要点是:
搞清楚扩容的效率,是否能做到分钟级扩容完毕。

所以大家的应用最好都是部署在 Docker 容器集群上的,这样才能做到扩容秒级或分钟级。

大家如果是混合云部署,应用分布在不同的云平台上,那么你的应用部署底层基础最好一模一样,方便你扩容和切换,不要过于依赖某一个公有云的底层。
 

4 双活的设计原则

我们总体的系统设计思路遵从风险分散设计原则和异地双活设计原则。设计原则表述的是架构师对整个系统的核心设计思想,并且要求把这个设计思想贯穿到所有子系统的概要和详细设计中,下面对这两个原则进行具体解析:

(1)风险分散设计原则
云服务实际上是相当脆弱的,因此需要预先做好后备方案,确保系统对客户提供的服务尽可能不中断。
基于这样的考虑,我们做了主机房、从机房、应急机房的设计,主机房与从机房形成双活架构。主机房和从机房依托的系统服务或第三方支付服务如果不可用,还有一套应急机房做备用。
 
(2)异地双活设计原则
本系统的异地双活并不是简单地在两个机房各自部署一套完整的系统。它的设计需要遵从以下原则:

原则一:保证基本可用性
从系统设计CAP理论延伸出了BASE理论。其中,BA是BasicallyAvailable,基本可用。可以理解为在一个平台中,假使有一部分出现了故障,这个时候系统应该在允许这些故障出现的情况下依旧保持部分功能(应该是核心功能)可以正常使用。那么本系统遵循这条基本可用性保障原则,就只是保障核心业务双活。核心业务,主要指收单。关键时刻容忍有限时间段内的数据不一致,允许在事后修复。只要做到最终数据一致性即可。

原则二:区分多活和非多活
不需要跨机房同步的业务都应被标记为非多活业务。非多活数据库与多活数据库要严格区分开来。只有多活数据库需要跨机房双向实时同步。

原则三:双写保护
一个订单尽量在一个机房内完成写操作,避免跨机房同时写。因此需要引入数据库和分布式缓存的双写保护。

原则四:业务可感
本系统暂时还无法抹去机房的差异,所以必须让终端设备感知到机房(或者分片)的存在,必须能够识别出业务归属于哪一个机房。
 
综上所述,我们用了很短的时间就做了这些事:
异地双活管理系统
——网格单元化部署
——数据库双机房双向实时同步管理
——分布式缓存双机房实时同步管理
从而实现了预期的效果,灵活地以商户、城市、省份、机房为维度秒级在网格之间切换流量,商户和用户无感知,保障整个技术团队有信心有能力达成网站 RTO(Recovery Time Objective,容许服务中断后恢复的时间长度)=1分钟的目标。


注:本文源自《禧云异地多活技术白皮书》,为禧云信息内部编著的技术交流资料。

文章转载自yangyidba,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论