当前位置: 首页 > 科技观察

淘宝的高可用远程多活架构有多好?

时间:2023-03-21 23:29:08 科技观察

远程多活,作为一种高可用的部署架构,已经成为大中型互联网公司的选择。知名的大型互联网公司,如阿里、腾讯、百度、网易、新浪等,都完成了远程多活动的技术改造。图片来自Pexels。可以说,异地多活是互联网公司业务规模扩大后必经的阶段。那么如何解决高可用和异地多活呢?有状态服务和后台服务可以分为两类,有状态的和无状态的。高可用性对于无状态应用来说相对简单。无状态应用只有通过F5或者任何代理才能很好的解决。下面的描述主要是针对有状态服务的分析。服务器的状态维护主要通过磁盘或者内存来保存,比如MySQL数据库,Redis等内存数据库。除了这两类维护方式外,还有JVM内存的状态维护,但JVM状态的生命周期通常很短。一些高可用解决方案是高可用的。从发展来看,大致经历了以下几个过程:冷备双机热备同城双活异地双活异地多活说到异地多活,我们再看看其他的解决方案,这有助于我们了解许多设计的原因。冷备是通过停止数据库对外提供服务和复制文件的能力,对数据进行快速备份和归档的一种操作方式。简而言之,冷备就是复制粘贴,在linux上用cp命令可以快速完成。它可以手动完成,也可以通过预定脚本完成。它具有以下优点:简单快速备份(与其他备份方法相比)快速恢复。只需要将备份文件复制回工作目录即可完成恢复过程(或者修改数据库的配置,直接修改备份目录为数据库工作目录)。更重要的是,使用两个mv命令可以在瞬间完成恢复。可以根据时间点恢复。比如前几天发生的拼多多优惠券漏洞被刷了一大笔钱,可以按照之前的时间点恢复,“追回损失”。以上好处是以前软件的好方法。但对于今天的很多场景来说,它并不好用,因为:需要关闭服务。N个九是绝对做不到的。那么,以前我们的停机冷备份是在凌晨没人用的时候进行的,但是现在很多互联网应用已经是全球性的,所以随时有人在用。数据丢失。如果不采取任何措施,数据恢复完成后,从备份时间点到恢复时间点的数据将会丢失。传统的方法是冷备恢复后,通过数据库日志手动恢复数据。比如通过redologs,更有什者,我曾经用业务日志手动回放请求恢复数据。恢复是一项巨大的体力活动,错误率高,恢复时间长。冷备份是完全备份。完全备份会造成磁盘空间浪费和容量不足,只能通过将备份复制到其他移动设备来解决。因此,整个备份过程耗时较长。想象一下,每天要将数TB的数据拷贝到移动硬盘,需要多少移动硬盘和多少时间。此外,无法自定义完整备份。例如,只有某些表无法备份。如何权衡冷备份的利弊,是每个企业都需要考虑的问题。与冷备份相比,双机热备份与热备份的主要区别在于不需要停机,在备份的同时提供服务。但是恢复的时候还是需要关机。由于我们讨论的是存储相关的,所以共享磁盘的方式不算双机热备。①主备模式相当于1主1从,主节点对外提供服务,从节点作为备份。通过某种方式,将数据从主节点同步到从节点,当发生故障时,从节点设置为工作节点。数据同步的方法可以是软件层面的,也可以是硬件层面的。软件层面,比如MySQL的master/slave方式,通过同步binlog的方式;sqlserver的订阅复制方式。在硬件层面,通过扇区和磁盘拦截等镜像技术将数据复制到另一个磁盘。面向硬件的方法也称为数据级容灾;面向软件的方法称为应用程序级灾难恢复。后面的文章会更多的讲到应用级的容灾。②双机互备本质上是Active/Standby,但只是互为主。双机互备对同一个业务不起作用,但是从服务器的角度来说,更好的挤压了可用资源。比如两个业务分别有库A和B,通过两台机器P和Q进行部署,那么对于A业务,P主控Q从,对于B业务,Q主控P从。从整体上看,两台机器似乎是互为主备。在这种架构下,读写分离非常好。单写多读,减少冲突,提高效率。其他的高可用方案也可以参考各种数据库的各种部署方式,比如MySQL主从、双主多从、MHA;Redismaster-slave、Sentinel、Cluster等。上面提到的同城双活的几种方案,基本都是在一个局域网中进行的。业务发展后,有打算多住同一个城市。和之前相比,不信任的粒度从机器变成了机房。该方案可以解决IDC机房整体挂掉的情况(停电、断网等)。其实同城双活和上面说的双机热备没有本质区别,只是“距离”更远,基本是一样的(专线网速在同城还是挺快的)。双机热备提供容灾能力,双机互备避免资源过度浪费。借助程序代码,部分业务还可以实现真正的双活,即同一个业务,双主,同时提供读写,只要处理好冲突即可。需要注意的是,并不是所有的企业都能做到这一点。行业更多采用两地三中心的做法。异地备份机房可以提供更强的容灾能力,更好地抵御地震、恐怖袭击等情况。双活机必须部署在同一个城市,距离较远的城市作为容灾机房。灾备机房不对外提供服务,仅作为备份,发生故障时将流量切换至灾备机房;或者它仅用作数据备份。主要原因是距离太远,网络延迟太大。图1:两地三中心如上图所示,用户流量负载均衡,服务A的流量发往IDC1,服务器集合A;服务B的流量发送到IDC2,服务器B。同时,服务器集a和b分别从A和B进行同城专线数据同步,通过异地长途专线同步到IDC3.当任何一个IDC宕机时,所有流量切换到同城另一个IDC机房,完成故障切换。当1市发生大面积故障时,比如地震导致IDC1和2同时停止工作,数据会保存在IDC3中。同时,如果负载均衡仍然有效,则可以将所有流量转发到IDC3。但是此时IDC3机房距离很远,网络延迟变得很严重,通常会严重影响用户体验。图2:两站点三中心Master-Slave模式上图是两站点三中心基于Master-Slave模式的示意图。1市2个机房作为1主1从,远程机房作为从。也可以采用同城双主+Keepalived+VIP的方式,或者MHA的方式进行failover。但是城市2不能(最好不要)被选为Master。异地双活和同城双活可以应对大部分容灾情况,但在大面积停电或自然灾害发生时,服务仍然会中断。对以上三个中心进行两地改造,前端入口节点和应用异地部署,在1城停服后将流量切换到2城,可以降级同时降低用户体验。但是,用户体验明显下降。因此,大部分互联网公司都采用了远程双活方案:图3:远程双活简单示意图上图是远程双活简单示意图。流量经过LB后分发到两个城市的服务器集群。服务器集群只连接到本地数据库集群。只有当所有本地数据库集群都无法访问时,它们才会故障转移到远程数据库集群。这样,由于远程网络问题,双向同步需要更多的时间。较长的同步时间将导致更严重的吞吐量下降或数据冲突。吞吐量和争用是两个对立的问题,您需要在它们之间做出权衡。比如解决冲突,引入分布式锁/分布式事务。为了达到更高的吞吐量,使用中间状态、错误重试等手段实现最终一致性;减少冲突,合理分片数据,尽可能在一个节点完成整个交易。对于一些不能接受最终一致性的业务,饿了么采用下图所示的方式:针对个别需要高一致性的应用,我们提供强一致性解决方案(GlobalZone)。GlobalZone是一种跨机房的读写分离机制,所有写操作都指向一个Master机房保证一致性,读操作可以在各个机房的Slave库中进行,也可以绑定Master机房room,都是基于我们的数据库访问层(DAL)完成的,业务基本无感知。《饿了么异地多活技术实现(一)总体介绍》也就是说不能在这个区域进行active-active。采用master代替双写自然就解决了冲突的问题。其实远程双活和远程多活已经很相似了。active-active的结构更简单,不需要过多考虑程序架构,只需要做限流、failover等传统操作即可。但实际上,双活只是暂时的一步,最终目的还是要转为多活。因为双活存在数据冲突的问题,无法横向扩展。远程多活示意图4:远程多活示意图根据远程多活的思路,我们可以画出远程多活示意图。每个节点的出度和入度都是4,这样的话,任何一个节点下线都不会影响业务。但是考虑到距离,一次写操作会带来更大的时间开销。除了影响用户体验,时间开销也带来了更多的数据冲突。在数据冲突严重的情况下,使用分布式锁的代价也更大。这将增加系统的复杂性并降低吞吐量。因此,不能使用上面显示的解决方案。还记得我们如何优化网状网络的拓扑结构吗?引入中间节点,把网格改成星型:图5:星型异地多活改成上图后,每个城市不下线都会影响数据。对于原请求城市的流量,会重新LoadBalanced到新的节点(最好LB到最近的城市)。为了解决数据安全问题,我们只需要和中心节点打交道即可。但这样一来,对中心城市的要求就会高于其他城市。比如恢复速度、备份完整性等,这里暂且不展开。我们首先假设集线器是完全安全的。如果我们按照上图的结构部署了远程多活业务,那么各地数据同步的问题已经基本解决了,但是还是会存在大量的冲突,可以简单的认为类似于双活性。那么有没有更好的办法呢?回顾前面提到的饿了么的GlobalZone方案,大意是“去分布式”,即将写好的业务放在一个节点(同城)机器上。阿里是这样想的:阿里理想中的异地多活结构其实我猜很多业务也是按照上面的图来实现的,比如滴滴打车业务,所有业务都是按城市划分的。用户、车主、目的地的经纬度通常在同一个城市。单个数据中心不需要与其他数据中心交互。只在生成报表的时候需要,但是报表不太注重实时性。那么在这种情况下,全国业务其实是可以很好的分片的。但是,对于电商等复杂场景和业务,上述方式的分片已经不能满足需求。由于业务线非常复杂,数据依赖关系也非常复杂,各个数据中心之间难免会同步数据。淘宝的方案有点类似于我们切分微服务的方法:淘宝的远程多活架构以单元切分,注意图中的数据同步箭头。以交易单元为例,属于交易单元的业务数据会从两个方向同步到中心单元;不属于交易单元的业务数据将从中央单元单向同步。中心单元承担最复杂的业务场景,业务单元承担相对单一的场景。对于业务单元,弹性伸缩和灾难恢复是可用的。对于中央单元,扩展能力较差,稳定性要求较高。可以看出,大部分故障都会发生在中央单元。按业务切分单元已经需要对代码和架构进行彻底的改造(也许这就是为什么阿里从双活转多活,用了3年时间)。比如业务拆分、依赖拆分、meshtostar、分布式事务、缓存失效等。除了对编码的高要求外,对测试和运维也有很大的挑战。在如此复杂的情况下,如何自动化覆盖,如何进行演练,如何改造流水线。这种级别的容灾不是一般企业敢做的,投入和产出不成正比。但是,我们还是可以把这个场景作为我们的“假想敌”来思考我们自己的业务,未来会怎样发展,我们需要什么样的灾备水平。相对而言,饿了么的多活方案可能更适合大部分企业。本文仅通过配图进行简要说明。其实异地多居需要很多非常强大的基础能力。比如数据传输、数据校验、数据操作层(简化了客户端控件编写和同步的过程)等。在思考的最后,有几个问题需要你去思考:假设你在开发Ele。me,服务多活异地部署,shardingkey按省市分片。假设买家在多个城市交汇的地方,比如路口的四个位置分别是4个城市,如何处理才能拉取更正常的数据?在你目前的业务模块中,可以做哪些业务?更主动,哪些不能更主动?是否所有企业都需要更加活跃?还是只有核心业务需要更活跃?参考资料及其他资料:《饿了么异地多活技术实现(一)总体介绍》https://zhuanlan.zhihu.com/p/32009822《饿了么框架工具部技术博客》https://zhuanlan.zhihu.com/eleme-arch《阿里异地多活与同城双活的架构演进》https://www.sohu.com/a/158859741_444159《阿里云 数据库异地多活解决方案》https://help.aliyun.com/document_detail/72721。html《异地多活没那么难》https://wely.iteye.com/blog/2313293作者:东国潮编辑:陶家龙来源:https://blog.dogchao.cn/?p=299