聊聊高可用架构——异地多活
本文转载自 微信公众号 chiukong_diary
很久没写了,要长草了。
今天咱们来聊聊高可用系统架构的热点——异地多活。
现在比较吊的多活方式是异地三节点,有多少公司真正实现了就不得而知了。为什么要做异地多活,主要是为了提升系统的容灾能力,比如单机房的网络故障、地震火灾等不可抗因素,都有可能造成整个机房瘫痪。
在上一家公司负责支付系统开发的时候,由于我们在天津机房的硬件设施太过老旧,经常时不时地网络故障,进而逼我们搭建了一个异地多活的架构。我们先来看看我们当时的做法。整个部署结构如下图:
通过域名做负载均衡,将请求路由到最近的可用服务的机房
服务全部机房内自治,不进行跨机房访问
DB(mysql)仅有一个,机房2跨机房访问机房1的DB进行读写
整个架构看起来是可行的,并且当时也是有在生产环境使用。但是不难看出,机房2的服务,在响应时间上肯定要比机房1更慢。因为跨机房访问数据库带来了一定的网络延时,在最正常的情况下,通过当时购买的专线,可以控制在数十ms以内。
当机房1故障时,通过dns切换(据说可以智能切换,不过我们当时并没有实施)关闭机房1的请求,然后将机房2的数据库从slave升级为master,就可以完成整个容灾过程。看起来并不是全自动的,但至少比服务长时间瘫痪等待机房修复要好。而且,dns切换以及db切换,都可以通过自动的方式来实现。
上面的方案实现简单,对于一般的业务也够用了。但是,存在以下几个问题。而这几个问题,也是异地容灾跨不过的坎。
机房间延时。不管是机房2访问机房1的DB,还是DB之间的主从同步,都进行了跨机房的网络请求,其延时是难以避免的。
专线网络需要花钱,而且不便宜。严格来讲,你拉一条专线网络,这也是一个单点服务。如果要做到专线网络容灾,价格应该至少要翻番吧。
数据同步。对于实时性要求不高的业务,比如微信发朋友圈,可以允许延时。但对于支付(账号余额)这种数据来讲,必须是强一致性的。如果机房1挂了,机房2备份库的数据还是一份脏数据,那必然会带来重大的损失。所以,这种数据同步方案,对于强一致性要求的数据,是不可接受的。对于强一致性的数据,只有通过人为修复确保都更新到位后,才能恢复服务。也就是在此期间,其实服务也处于不可用状态。
通过以上分析,我们不难看出,1.2两个缺点,可以勉强花钱解决,但是对于3,花钱也解决不了。那么,对于强一致性要求的数据,我们如何来做容灾呢?
机房1、机房2实现双主(Master-Master)的数据库架构。两个数据库分别置于机房1和机房2,实现读写。master之间通过mysql的内部实现,进行数据同步。这个方案其实跟之前的方案区别不大,只是减少了服务去访问数据库的网络延时,属于一个伪数据强一致性方案。而且双主很依赖网络延时进行数据同步,同时容易出现脑裂现象,个人不推荐使用。
通过业务层来实现分布式事务,以此来确保两个机房数据的强一致性。两个数据库分别置于两个机房中,通过业务程序来实现分布式事务,也就是通过业务层来确保数据库1和数据库2都更新成功,才视为更新成功。这样确实可以保证数据库1和数据库2的数据强一致性。但是增加了系统的实现复杂度,也增强了对开发人员能力的要求。另外,分布式事务会增加业务处理时长以及失败率,如果单机房故障一年都仅有几个小时,这种分布式的代价是否值得呢?
将服务状态化。对用户进行分区,将用户请求固定路由到机房1或机房2。如此一来,两个机房不会对同一份数据进行更新,也就避免了数据强一致性的要求。同时,这两个数据库之间,仍然通过主备进行数据备份。当其中一个机房故障时,通过人为修复该机房同步到另外一个机房的数据后,再恢复机房1中的服务。对比在上家公司已实现的方案,这种方案有两个优点:减小了跨机房访问数据库的延时;减小了受灾用户群体。个人觉得该方案不错,但是如何在dns解析域名时进行状态化呢?如果又引入中间件,那不是又单点了吗?
好吧,如果细读了CAP理论,就会发现这个问题是没有十全十美的解决方案的。在这个问题上,我更加倾向于的解决方案是:使用阿里云服务,增加可用性。你有更好的方案吗,欢迎给我留言。
更多深度技术内容,请关注云栖社区微信公众号:yunqiinsight。