从github超24小时的故障看异地多活全局设计的重要性

咱们先来回顾一下github此次事故: 2018年10月21日,github 在更换网络设备时,引起了美国东海岸网络中心和东海岸数据中心的网络连接发生了40秒的中断,最终致使多个mysql的主集群由Orchestrator 自动选举切换到了美国西海岸数据中心对应的集群,由此引起了数据不一致,直接致使了超过24小时的服务降级,最后仍然还有少许数据需人工排查修复的悲剧。前端

事件的整个过程参考blog.github.com/2018-10-30-… 这篇文章,在这里不详细说明,咱们来直接看致使事件的根本缘由。mysql

根本缘由:缺失异地数据中心之间数据一致性的保障机制

github数据库作的是本地主备+跨区域数据中心的容灾方案,主数据库集群和其余数据中心的集群是异步同步的,当物理网络发生中断后,对于github这样全球性的,大量用户访问的系统,时时刻刻都有数据变动,刚刚提交的数据尚未来得急同步过去,这时按照Orchestrator的机制,必然会从新选举出新的数据库写入主节点。在没有肯定数据全局一致性的状况,就这么一切,两边数据就无法一致同步了,更悲剧的是等网络40s后恢复后,在Orchestrator没有将原有的数据库主节点置为从节点以前,东海岸本地的应用还在往本地数据库集群写数据,加重了数据的不一致,发生了脑裂现象。除了数据不一致的问题外,还有个比较严重的后果,github 除了数据库主节点负责单点写外,其余区域数据中心的数据库节点负责读,把东海岸的应用数据库切都西海岸,会有60ms的网络消耗,就这点耗时,致使不少应用出现了服务超时不可用,对于不少web应用,一个前端请求会触发后端系统几十次的请求很是正常。由此能够看出,github在处理跨数据中心的高可用方案上是有较大漏洞,没有真正考虑一个数据中心不可用,和数据中心之间的网络故障时的两个重要场景。git

没有引发重视的缘由分析

对于这么重要的场景,为啥github这么牛的公司没有实施了?我的猜想的几个缘由(仅我的观点):github

1.github 发展太快也太顺利了,以前应当是没有出过什么严重问题,精力都聚焦到能带来效益的事情了,这样的事情没有引发足够的重视,技术战略上没有特别重视。web

2.异地多活的方案很是复杂,不只是数据库的跨地域数据中心同步这么简单,须要结合公司的实际业务进行全局总体性的方案设计。redis

3.投入大,成本高,就拿异地机房之间的网络线路来讲,至少须要保障两个物理上独立的线路,而这些线路对数据中心来讲,至少须要100G 光纤专线。此外其应用系统为了适应异地多活带来也须要进行架构升级,灰度测试等等。sql

实际来看这是不少公司都面临的广泛问题,在业务高速发展和系统可靠性建设上如何找到平衡点的问题。对于不少业务导向的公司,系统出现过严重问题,才会重视起来。数据库

异地多活方案如何来作?

计算机的分层思想很是有利于分析一个复杂系统,异地多活涉及到数据,应用系统,基础软件,网络,运维系统等等,很是复杂。采用分层思想能极大的简化问题,解耦各层,而后全局看。下面是一个典型分布式是数据中心的分层结构:后端



让咱们来看每一个分层的异地多活方案如何作:缓存

DNS层:自己就是一个全球性的分布式系统,自然就是异地多活的,在这一层作本身的异地多活,更可能是依赖DNS机制,系统化的动态切换域名和服务器的映射。因其DNS变动生效须要几分钟到几十分钟,对实时性要求高的容灾,不能依赖这块。

CDN层:严格来讲,和DNS 同样,也是自然异地多活的,由于CDN更多的是对静态资源访问的加速,需提早将静态资源分发到离消费者更近的节点,挂掉一个节点不会影响数据的不一致,会下降访问速度,影响用户体验。

负载均衡层:经过故障转移策略,能够迅速的将挂掉的服务器流量切到同城或者异地的数据中心,很是便捷高效,但这个地方必定要确保底层的数据已经同步过去以后,才能切,不然会出现数据不一致的状况。

应用层:须要跨数据中心弹性集群部署,就单个应用自己而言,没有什么难度,难度主要集中在依赖应用上,对于不少业务系统,特别是微服务架构成为主流后,一个业务系统至少会依赖调用好几个其余应用,对于复杂的电商系统来讲,一个系统依赖几十个其余系统的服务很正常。应用层的异地双活,就不是简单的单应用的跨数据中心部署,而是须要按照业务单元总体性考虑,单元化的思想是阿里异地双活的基础。这块须要重点考虑的是,业务单元内的系统之间相互调用要本地化调用,避免跨单元,但对于一些无法单元化的业务,须要有中心单元化来统一支撑。此外应用系统自己的架构也须要考虑异地多活,特别是要考虑跨地域访问带来的时延影响,数据重复消费等问题。

中间件,缓存层:须要中间件自己要支持异地多活,就拿分布式缓存redis来讲,put 数据,须要支持在本地数据中心,和异地数据中心同时生效,失效也是同样。这就须要对redis 进行修改。消息中间件,以及其余中间件也是相似,对于不支持异地数据中心的版本,都需自行修改源码进行支持,对于通常的小公司来讲,这个难度很是大。只有top的公司才具有这样的技术和环境去作这个事情。

数据库/存储:数据库每一个厂商对异地数据中心的支持方案有差别,就mysql来讲,mysql 目前的版本还不支持异地同步的方案,只支持本地同步副本,对于mysql的同步,只能是利用实时的数据同步工具drc 来作,由于不是异步同步,仍然存在几ms-几百ms的延迟。将流量从故障的数据中心切换到其余数据中心时,必定要先将故障集群的数据库设置成只读集群,其次肯定数据库已经彻底同步数据到对应异地数据中心的数据库。最后将异地数据库集群设置为写集群。



而整个过程会有几分钟的中断,服务不可用,赶上罕见的这种故障,几分钟的故障恢复时间是能够接受的,支付宝的异地多活也是分钟级别的。这个地方最怕的就是物理线路故障,如挖掘机挖断光纤的事情,对于大型金融级的数据中心,物理上有两条独立的光纤线路是必须的。赶上物理线路故障,确定会存在少许数据没有同步完的状况,这时候,本来到故障dc的写流量是不能贸然转移到其余dc的,这时必然要牺牲部分服务的可用性;除非你能接受数据不一致的状况。

看完每层的状况,再来看全局,当一个DC发生故障时,如何在保证数据完整的状况下,故障转移了。发生故障不可怕,怕的是丢数据,数据错乱。全部的策略都是围绕数据的完整和正确性。全局设计也是同样,所以我认为较为合理故障处理策略应当按照下面的步骤来:



咱们的原则就是将一切形成数据混乱的可能性降到最低,必然就是先关闭数据库的写,这会形成应用层写数据库等异常,但这也是咱们指望的。

发生整个DC出现大面积故障的事件是比较少的,最多见的故障仍是好比某个核心系统库,部分网络故障. 而这些故障会根据异地多活的方案有不一样的一些恢复策略,以数据库发生异常为例,一般的恢复策略为:

1.切换本地备库为主库;从已有备份从新还原作备库.

2.切换数据库的代理到异地/同城的对应的数据库集群,必定要确保数据是彻底同步过去以后才能切,若是用Orchestrator之类的故障自动转移,须要作对应的数据检查机制。

总结

对于异地多活,没有一刀切彻底通用的方案,须要根据本身的业务特色,在成本,服务可用性和数据完整性,技术复杂度之间作平衡,找到最适合本身公司的方案;可是最重要的原则就是无论那种方案,确保数据的完整性和一致性是首要考虑的。

更多文章欢迎访问 http://www.apexyun.com/

联系邮箱:public@space-explore.com

(未经赞成,请勿转载)

相关文章
相关标签/搜索