Tagged: multiple leader

1

多leader replication的实现及常见问题介绍

我们在前面的文章中介绍的都是单leader的实现。也就是说所有的写操作都会通过这个leader来实现。虽然说这是一种比较常见的实现方法,但是它也尤其局限性,比如说leader可能会有问题,比如网络问题等,这个时候就会有一段时间没法进行写操作。或者说当写操作很重的时候,所有的写的load都需要到leader这边,无形中就加重了leader的traffic。本文就来介绍一种多leader的实现方案。 顾名思义,多leader实现方案就是可以同时有多个节点成为leader,所有的写操作可以同时通过这些节点来进行。当其中一个leader在写的时候,另外的leader就和follower一样,也需要从它这边进行replication。 多leader的使用场景 多leader其实并不是一个比较常见的方案。那么一般在什么情况下,我们会考虑多leader的方案呢? 多数据中心的操作 假如我们的数据库是在多个数据中心的时候(实际上为了防止但数据中心出问题,一般的数据库都会分布在不同的数据中心),假如使用单leader的实现,那么leader就会在一个数据中心,从而使得所有的写都得通过那个数据中心。 而假如是多leader的实现,我们就可以在每一个数据中心放一个leader,这样在每一个数据中心中,还是单leader的情况,但是这个数据库则是多leader的情况。具体的架构如下图所示: 下面我们来看看这样的实现有什么好处: 性能 单leader的情况下,所有的写都需要到leader那边,显然跨数据中心的访问性能不会很好。而多leader的情况下,所有的读操作可以直接访问本地的数据中心,虽然需要在数据中心进行数据replication,但是数据中心之间的延迟其实对用户来说是黑盒,所以对用户来说性能是有提升的。 数据中心宕机的容忍性 单leader的情况下,如果有数据中心宕机,那么需要通过failover来找到新的leader,然后可以继续服务。多leader的情况下,单个数据中心的宕机不影响整体的写操作,无需做额外的failover也可以继续进行写操作。 网络问题的容忍性 同样的,但leader其实受leader所在数据中心的网络情况所影响,而相对来说多leader则可以更好的容忍单个数据中心网络的问题。 虽然看起来多leader的实现有很多好处,但其实它也有其问题,那就是冲突写,比如两个写同时发生在两个不同的leader上,并且彼此冲突,该如何进行处理,这个问题我们后面会详细介绍一些处理的方案。 Offline操作的应用 另外一个多leader replication常见的场景就是offline操作,比如你有一个应用哪怕没有网络也希望能够持续工作。 比如说你手机中的日历程序,你希望安排你的日程,比如添加事项,看看后面哪天有哪些安排。这些操作哪怕是在没有网络的时候也希望能够正常工作。只要当这个设备能够再次访问网络的时候我们能够成功同步这些就可以了。其实这就是一个多leader的场景,你可以把你的设备想象成一个数据中心,有网络的时候,就是正常的多leader同步。没有网络的时候,本地的leader也支持读、写操作。当再次有网络的时候能够做跨数据中心(设备)的replication。 协同写操作的应用 另外一个常见的使用场景就是会有多人同时写一个文档。比如说Google Doc,它支持同时有多个人来编辑。这种常见就和上面的比较类似,我们不希望一个人的写去影响另外一个人的写,所以这里通常就会写入本地leader,然后进行多节点的同步。 处理写冲突 我们上面提到多leader最大的问题就是写冲突,毕竟两个leader完全有可能同时修改同样的内容,如下图所示: 这里User1通过Leader1修改了title到B,但是User2又通过leader2修改了title到C,这个时候在他们进行replication的时候就会出现了冲突的问题,究竟是该改成B还是改成C呢? 避免冲突 假如我们现在能够想到一个简单的方法来避免冲突,那么这个问题就自然而然解决了。比如所有修改title的请求全部要到同一个leader来处理,这就可以规避掉上文提到的写冲突。这个方案还是蛮常见的,比如说用户的资料只能他自己能修改,而所有这个用户修改自己资料的请求我们全部指向同一个leader,这样就可以实现冲突的避免。 但是世事显然不会总是这么一帆风顺,比如说有时候某一个数据中心突然就出问题了,那么无可避免的,你就只能把所有的写操作都指向另外数据中心,这样就还是会出现写冲突。 收敛到一致状态 多leader其实很难说谁是最后写的,所以最终应该是什么样的内容有时很难讲,就像上面的例子一样,你说最终title应该是B还是C呢?这个时候就需要一些额外手段来辅助判断: 给每一个写一个独有的ID(比如使用timestamp,UUID等等),然后比较他们的大小。大得获胜。当这个ID使用的时间,那我们称这种方法为最后写的获胜(Last write wins LWW)。这个方法听起来不错,但也有其问题,我们在后面的文章中再具体讨论。...