面试官:跨地域场景下,如何处理分布式系统的一致性?尴尬了

作者 : 开心源码 本文共7997个字,预计阅读时间需要20分钟 发布时间: 2022-05-14 共152人阅读

导读

**阿里妹导读: 跨地域,即常说的“异地双活”、“异地多活”中的异地概念。 **在业务发展较快的情况下,我们的服务便需要跨地域部署,以满足各区域就近访问和跨地域容灾等需求,在此过程中,不可避免会涉及到跨地域下的分布式一致性问题。 由跨地域所带来的网络推迟问题,以及因为网络推迟而衍生的一系列问题,对于设计和构建一个跨地域分布式一致性系统是极大的挑战,业界有很多针对此问题的处理方案,都希望能处理跨地域场景下的一致性问题。

面试官:跨地域场景下,如何处理分布式系统的一致性?尴尬了

本文分享阿里巴巴女娲团队在跨地域场景下对分布式一致性系统的探究,从”What How Future”三个方面,详情跨地域场景下要承接的需求和挑战、业界常见系统和女娲团队对于跨地域场景权衡点的思考,以及对跨地域一致性系统未来发展的设计与思考,以发现和处理跨地域场景下更多的需求和挑战。

一、跨地域需求和挑战

面试官:跨地域场景下,如何处理分布式系统的一致性?尴尬了

1 需求

跨地域问题是在集团全球化战略下,业务快速发展带来的挑战。像是淘宝单元化业务,或者是AliExpress区域化业务,都有一个无法回避的问题——数据跨区域读写一致性。

其核心需求可以总结为以下几点:

  • 跨地域业务场景

跨地域配置同步与服务发现是两个常见的跨地域一致性协调服务的业务需求,跨地域部署可以提供就近访问能力以减小服务推迟,根据具体业务场景可分为多地域写或者简化的单地域写、强一致性读或者最终一致性读等场景。跨地域的会话管理及基于此的跨地域分布式锁也亟待提供成熟的处理方案。

  • 服务、资源的拓展问题

当一个地域内某个机房的服务能力达到上限而又无法扩容,需要一致性系统在一个地域多个机房水平拓展和能够跨地域拓展。

跨地域容灾能力

当遭遇机房或者者一个地域的灾难性故障时,需要一致性系统通过跨地域服务部署,将一个地域的业务迅速迁移到另一个地域完成灾备逃逸,实现高可用。

2 挑战

综合网络推迟和业务需求,可以归纳出跨地域一致性系统所需要化解的挑战:

  • 推迟:网络推迟达几十毫秒

多地域部署带来的核心问题便是网络推迟高,以我们线上跨地域部署的跨地域集群为例,集群中机器分属于杭州、深圳、上海、北京四个地域的机房,实际测试杭州机房到上海推迟大约6ms,到深圳和北京的推迟可以达到接近30ms。同机房或者同地域机房间的网络推迟一般在毫秒内,相比之下跨地域访问推迟上升了一个量级。

  • 水平拓展:Quorum Servers规模受限

基于Paxos理论及其变种的分布式一致性系统,在拓展节点时不可避免会遇到Replication Overhead问题,一般一个Quorum的节点数目不大于9个,故无法简单地将一致性系统节点直接部署在多个地域,系统需要能持续地水平拓展,来满足服务、资源的拓展需求。

  • 存储上限:单个 节点存储数据受限且failover恢复慢

无论是MySQL还是基于Paxos的一致性系统,其单个节点都会维护和加载全量的镜像数据,会受到单台集群容量的限制。同时在failover恢复时,若数据版本落后较多,通过拉取其余地域镜像恢复会有较长的不可用时间。

二、 我们的探究

1 业界处理方案

业界有针对跨地域的一致性系统有很多的设计,主要参考了论文[1]和少量开源的实现,下面详情常见的几种:

跨地域部署

面试官:跨地域场景下,如何处理分布式系统的一致性?尴尬了

图1 直接跨地域部署

直接跨地域部署,读请求直接读本地域节点,速度较快,一致性、可用性由Paxos保证,没有单点问题。缺点也很显著,会遇到第一部分中讲到的水平拓展问题,即Quorum拓展时会遇到Replication Overhead问题。且随着Quorum节点数目变多,在跨地域极高的网络推迟下,每次多数派达成一致的时间会很长,写效率很低。

单地域部署+Learner角色

面试官:跨地域场景下,如何处理分布式系统的一致性?尴尬了

图2 引入Learner角色

通过引入Learner(例如zk中Observer、etcd的raft learner[2]) 角色,即只进行数据同步而不参加多数派投票的角色,将写请求转发到某一个区域(如图2中的Region A),来避免直接多节点部署的投票延时问题。此种方式可以处理水平拓展问题和延时问题,但因为参加投票的角色都部署在一个地域内,当此地域机房遇到灾难性时间时,写服务便不可用了。此种方式是Otter[3]所采用的部署方式。

多服务+Partition&单地域部署+Learner

面试官:跨地域场景下,如何处理分布式系统的一致性?尴尬了

图3 多个服务解决分Partition

将数据按规则切分为不同Partition,每个地域一个Quorum提供服务,不同地域Quorum负责不同Partition,地域之间Quorum使用Learner进行不同Partition数据同步填写请求转发,保证某区域出现问题只影响该区域Partition可用性。同时此种方案下会有正确性问题,即操作不符合顺序一致性[4]的问题(见论文[1])。

实际实现时根据业务场景有各种处理方案,会针对性地进行优化和权衡,弥补缺陷。业界较常见方案的是单地域部署+Learner角色这种方案,通过同城多活和Learner做跨地域数据同步来保证较高的可用性和较高的效率。其余方案也各有优化方案,跨地域部署可以通过减少达成决议时地域间通信,来减小延时和带宽问题,如TiDB的Follower Replication[5];多服务+Partition&单地域部署+Learner这种方案的正确性也可以通过论文[1]中所述,在读之前增加sync操作,牺牲一部分读的可用性来保证一致性。

最后的结论如下表,后面会详细阐释其中的关键项:

面试官:跨地域场景下,如何处理分布式系统的一致性?尴尬了

2 跨地域的权衡

通过第一部分总结的需求挑战和前面对业界跨地域一致性系统处理方案的调研,可以总结出基于Paxos的分布式一致性系统在跨地域场景下的核心权衡点:

  • 写操作跨地域走一致性协议达成决议太慢* 地域内多活无法提供极端情况下的可用性* 需要具有分布式系统最核心的水平拓展能力

针对这三点问题,我们设计了一种日志镜像解耦的跨地域一致性系统。

3 跨地域日志镜像解耦

面试官:跨地域场景下,如何处理分布式系统的一致性?尴尬了

图4 日志镜像解耦示用意

如图3所示,我们的系统分为后台日志同步通道和前台全量状态机——日志与镜像解耦的架构。后台跨地域全局日志同步通道,负责保证请求日志在各个区域的强一致性;前台全量状态机部署在各地域内,解决用户端请求,也负责与后台日志服务交互,对外提供全局强一致性元数据访问服务,接口可以根据业务需求快速修改状态机来实现。

在全局日志与本地镜像分离的架构下,除理解耦本身带来的系统运维和可拓展性的提升,我们还可以处理很多未解耦架构下的问题,后面几条分析是在此种架构下如何对之前思考部分几大问题的一个处理:

写操作效率

单从部署的模式上看,看起来与直接多地域多节点部署,而后各地域增加Learner角色的做法相似,是直接多节点部署和引入Learner的一个结合,综合了两种方式的优缺点。最大区别在于,我们的日志和镜像解耦了,也就是说跨地域的部分是足够轻量高效的单纯日志同步,且因为每个地域只有一个节点,能够节省跨地域带宽(相似TiDB的Follower Replication)。同时后台日志同步通道,也可以实现多Group的功能,将数据分成Partition,每个一致性Group负责不同的Partiton。

因为大部分业务场景的读操作为读本地数据,各种方式相差不大,主要进行写操作的推迟分析,下面是对于写操作(或者强一致性读)的推迟分析:

RTT(Round-Trip Time),可以简单了解为发送消息方从发送请求到得到响应所经过的时间。因为跨地域网络推迟较大,后面RTT主要指跨地域RTT。

(1)直接跨地域部署

对于一个常见的有主一致性协议,我们的请求分两种情况:

  • 访问Leader所在地域 1个RTT(暂时忽略地域内较小的推迟)
Client -> Leader ----> Follower ----> Leader -> Client
  • 访问Follower所在地域 2个RTT
Client -> Follower ----> Leader ----> Follower ----> Leader ----> Follower -> Client

(2)单地域部署+Learner同步

在地域内多活,地域间Learnner同步的方案中,我们的延时为:

  • 本地域 0个RTT
Client -> Quorum -> Client
  • 地域间 1个RTT
Client -> Learner ----> Quorum ----> Learner -> Client

(3) 多服务Partition,单地域部署+Learner同步(与B结果相似)

  • 写本地域Partition 0个RTT* 跨Partition写 1个RTT

(4) 日志镜像解耦的架构(与A结果相似)

  • 写本地域Partiton 1个RTT
Client ->Frontend -> LogChannel(local) ----> LogChannel (peer) ----> LogChannel (local) -> Frontend -> Client
  • 跨Partition写 2个RTT (Paxos两阶段提交/转发leader)
Client ->Frontend -> LogChannel (local) ----> LogChannel (peer) ----> LogChannel (local) ----> LogChannel (peer) ----> LogChannel (local) -> Frontend -> Client

经过以上的比照,可以看出只需跨地域走一致性协议进行写操作,最少也会有1个RTT的推迟,而假如将Paxos Quorum只部署在单地域,又不能保证任何极端情况下的可用性。所以我们根据业务需要,可以进行可用性和写效率的权衡,日志镜像解耦的架构可以在多地域部署场景下保证极端的可用性和正确性,当然效率上会比单地域部署+learner稍差少量,但假如采用多整体比直接多地域部署的方式要轻量高效,由于Quorum规模不会因水平拓展添加,不会影响投票效率。与多服务分Partition部署的方案则没有效率优势,但在可运维护性、正确性、可用性这些方面都有优势。

跨地域部署和单地域部署+Learner的强一致性是满足的,zookeeper和etcd都有对应的详情,在此不做赘述。多服务Partition分Partion这种方案不满足顺序一致性,主要是由于多服务不能保证每条写操作commit的顺序性,见下图:

面试官:跨地域场景下,如何处理分布式系统的一致性?尴尬了

图5 顺序一致性

可以看到,当两个Client同时对x,y进行修改时,在写操作并发程度较高的情况下,不能保证顺序一致性。

顺序一致性就可以将各个Client的操作排列出一个正确顺序,在图4的例子中:

set1(x,5) => get1(y)->0 => set2(y,3) => get2(x)->5 

或者者

set2(y,3) => get2(x)->0 => set2(y,3) => get1(y)->3 

都是符合顺序一致性的。

日志镜像解耦的架构的一致性可以简单了解为跨地域部署+Learner,写操作有sync选项,会在后台log提交成功并拉取到对应log时才会返回成功,因而肯定是可以拉取到其余Client在此操作之前的写操作对应的log,故符合顺序一致性。

  • 可用性

可用性这点与直接跨地域多节点部署的可用性相似,前台状态机可以在某个地域后台节点挂掉情况下进行请求转发,在后台全局日志服务不可用时也可以提供读的可用性,可以提供极端情况下的读写高可用保证。

同时因为镜像存储在各个地域的状态机中,当某个前台状态机挂掉时可以把用户端切换到其余前台,failover恢复时也可以直接从后台拉取数据恢复,在落后太多情况下才需要从本地域其余前台拉取镜像,不用跨地域同步镜像,由此可以使得前台的不可用时间极短。

  • 水平拓展能力

水平拓展能力是分布式服务的核心能力,在前述的多种方案中,直接跨地域部署水平拓展能力极差,其余依赖Learner的方式,也处理了水平拓展的问题,只是解耦没有日志镜像解耦的设计干净。

将以上几个关键问题总结比照:

面试官:跨地域场景下,如何处理分布式系统的一致性?尴尬了

三、跨地域更多可能性

后台日志和前台镜像解耦的状态下,我们对跨地域场景的探究分为两部分—— 后台日志同步轻量高效和 前台状态机灵活丰富。

  • 轻量,表现在架构,后台只同步日志带来的后台存储压力极小,只用同步轻量的增量日志。* 高效,表现在后台的一致性协议,因为轻量,所以只要要考虑投票和选举的逻辑,只用注重日志同步效率的提升,后台资源不用消耗在其余业务逻辑上。* 灵活,表现在架构,前台可以自己设置上传日志,CAS、事务等都可以包装成日志由前台解析和解决。* 丰富,主要是表现在前台的状态机,因为日志的灵活留给我们探究和构建的空间极大,可以根据需求包装出解决各种复杂事务的状态机。

新的架构下有新的问题,这一部分主要探索如何吸取已有系统的优点,利用日志镜像解耦下的轻量、灵活,来实现跨地域场景下一致性协议和状态机的高效、丰富,也会对跨地域一致性系统后继如何发展有一个思考和规划。总体目标是后台一致性协议做精做深,前台状态机做大做强。

1 高效的后台一致性协议

基于我们前面对写操作效率的探讨,在多地域写同一数据场景下,推迟只能控制在2RTT。由于跨地域场景下,推迟占比主要在跨地域网络通信,无论是有主的转发还是无主的Paxos两阶段提交,推迟都有2RTT。但假如使用无主的协议,如Paxos的变种EPaxos[6],则可以尽可能提高跨地域场景下写的效率,其推迟分Fast Path和Slow Path两种情况,在Fast Path下推迟为1RTT, Slow Path下推迟为2RTT。

引用详情EPaxos文章中的一句话:

若并发提议的日志之间没有冲突,EPaxos只要要运行PreAccept阶段就可提交(Fast Path),否则需要运行Accept阶段才能提交(Slow Path)。

相比于分Partition操作,假如将后台一致性协议选为EPaxos,则可以保证极端情况下的可用性和大多数情况下推迟为1RTT,这是无主一致性协议在跨地域场景下的优势,主要是由于省去了一次转发Leader操作的RTT。目前我们系统中使用的是最基础的Paxos的实现,在多地写场景下推迟理论上与有主的协议相差不大,后继发展期望利用EPaxos来加快跨地域场景下写操作的效率。

因为不需要实现各种业务逻辑,高效便是后台一致性协议的最大诉求,当然其正确性、稳固性也是必不可少的,而对于前台的状态机,则有着丰富的场景来设计和发挥。

CAS操作

CAS操作在此种架构下的实现是很自然的,因为后台只有一致性log,所以我们每一次CAS请求,自然而然会有Commit的先后顺序,举一个例子。

两个用户端同时写同一个Key的值:

面试官:跨地域场景下,如何处理分布式系统的一致性?尴尬了

图 6 CAS操作示用意

开始时key的值为0,此时Client 1和Client 2并发对key进行CAS操作,分别为CAS(key, 0, 1)和CAS(key, 0, 2),当这两个操作同时提交并Commit后,因为后台Quorum达成决议的先后,Replication Log肯定会有先后顺序,因而自然而然这两个并发的CAS操作转换为顺序执行。当Frontend同步到这两个操作的log时,会依次apply这两个操作到本地状态机,自然CAS(key, 0, 1)成功,升级key值为1,而CAS(key, 0, 2)升级失败,这时前台会返回给对应请求的Client其CAS请求能否成功或者失败的结果。

其原理是将一个并发操作变成了一个顺序执行的串行过程,由此避免了在跨地域场景下对加锁的操作,可以想象假如是后台维护了一个kv结构数据,则还需要添加一个跨地域分布式锁来完成此操作,相对更加繁琐,效率也没有保证。通过只同步日志把复杂计算转移到Frontend,可以灵活地构建前台状态机,更好地实现CAS或者更复杂的事务功能(此种架构可参考pravega的StateSynchronizer[7])。

Global ID

Global ID是一个常见的需求,分布式系统生成一个唯一ID,常见的有使用UUID、snow flake算法,或者者基于数据库、redis、zookeeper的方案。

相似使用zookeeper的znode数据版本进行Global ID的生成,在此种日志镜像分离架构中,可以使用CAS接口调用,生成一个key作为Global ID,每次对Global ID进行原子操作。基于上述的CAS设计,跨地域并发场景下不需要加锁,在使用方式上相似redis对key进行原子操作。

2 Watch操作

订阅功能是分布式协调服务的不可或者缺的,是业务最常见的一种需求,下面是对zk和etcd的调研结果:

目前业界比较成熟的实现了订阅通知的分布式协调系统包括ETCD和ZooKeeper,我们分别以这两个系统为例讲解各自的处理方案。

ETCD会保存数据的多个历史版本(MVCC),通过单调递增的版本号来表明版本的新旧,用户端只需传入自己关心的历史版本,服务端即可以将后续的所有事件推送给用户端。

Zookeeper并不会保存数据的多个历史版本,只有当前的数据状态,用户端并不能订阅数据的历史版本,用户端只能订阅当前状态之后的改变事件,所以订阅伴随着读,服务端把当前的数据发送给用户端,而后推送后续的事件,同时为了防止在failover等异常场景订阅到老的数据和事件,用户端会拒绝连接数据比较老的服务端(这依赖于服务端会在每个请求会返回当前的服务端全局的XID)。

面试官:跨地域场景下,如何处理分布式系统的一致性?尴尬了

上述的调研结果中ETCD较为符合我们的接口设计,目前ETCDv3 使用了HTTP/2的TCP链接多路复用,watch性能有提升。因为同为日志加状态机结构,设计功能时主要参考了ETCD v3,借鉴其如何订阅多个key以及返回一律历史事件这两个特性。若要达到etcd订阅的功能,我们在前台状态机同步并解析日志时,假如出现写日志,则将kv结构的状态机Store和 专门提供给watch接口的状态机watchableStore同时升级,具体实现可以完全参考etcd,而后按日志版本号将订阅时版本后的历史事件一律返回给用户端。而订阅多个key则同样使用线段树作为watcher的range keys存储结构,可以实现watch范围keys的watcher通知。

3 Lease机制

在无主的系统中实现高效的Lease机制是一大挑战,无主的系统中没有Leader,任意节点均可维护Lease,Lease分布在各个节点上,当有节点不可用时,需要平滑切换到其它节点。无主的系统中实现高效的Lease机制的难点在于随着Lease数量的添加,如何避免后台的一致性协议中出现大量的Lease维持消息,影响系统性能,最好让Lease维持消息能够直接在前台本地解决,而不经过后台。所以我们的思路是将用户端与前台的Lease聚合到前台与后台的Lease,使得Lease维持消息能够直接在前台本地解决。

四、结语

随着全球化战略的推进,跨地域方面的需求肯定会越来越迫切,跨地域场景的真正痛点也会越来越清晰,希望我们在跨地域方面的调研和探究可以给大家一个思路和参考,我们也会继续探究跨地域日志镜像分离的架构下更多的可能性。

希望可以对大家学习分布式系统有肯定的帮忙,喜欢的小伙伴可以帮LZ进行转发+关注,感谢大家!(LZ也会尽力给大家分享有学习价值的资料!)

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 面试官:跨地域场景下,如何处理分布式系统的一致性?尴尬了

发表回复