1.前言
前面讲了单leader模型,本节讲解多leader备份
2.多leader备份
之前讲的单leader有一个大的缺陷:
由于只有一个leader,client和leader连不上,就不能写了
那么一个拓展就是单leader变成多leader,每个leader都允许写,备份过程基本不变,如下:
接收写请求的节点把数据发送给其他所有节点。
此时,每个leader都会作为其他leader的follower角色
2.1 何时用多leader模型
根据数据中心的个数决定
如果只有一个,那么就是单leader(此时多leader太复杂了且无必要)
如果有多个,就用多leader
多leader模式下,每个数据中心都能有一个leader
在每个数据中心内部,就是常规的单leader模型
在数据中心之间,则是每个leader和其他leader互相备份。
如下图
注意数据中心之间,leader间进行冲突解决以及备份
在多数据中心的情况下比较单leader和多leader:
1.单leader配置接收所有写,延迟高,违背了单多数据中心的意愿。而多leader则能在最近的leader进行写,并且异步备份。
2.单leader挂了重选的leader可能在另外一个数据中心。而多leader模型中每个数据中心能够相对独立工作(只有leader间互相备份)
3.单leader对网络问题更敏感,多leader不会
但是多leader有一个缺点:
一个数据同时在两个不同的数据中心修改,需要解决冲突
这个问题很复杂但又很常见,比如
同一个app在不同客户端上离线设置,重新联网后需要同步数据
2.2 处理写冲突
上面讲解的冲突触发的场景可以如下图所示
2.2.1 冲突检测:同步还是异步
同步异步冲突检测都有各自问题
同步检测的话,损失了多leader允许同时写的优势。好处是能让用户知道发生了冲突及时修改
异步检测的话,会有延迟,也不能再让用户改。好处是快。
2.2.2 避免冲突
最简单的办法是避免冲突:对每个特定的记录写的请求会通通给同一个leader
比如把每个user分配到特定的 home数据中心。
当然,还得考虑这个数据中心leader挂掉的情况
2.2.3 收敛到一致性状态
单leader能够使得所有写按顺序执行
但是在多leader的配置中,不保证这个顺序,但是要保证最后一个最终的结果应用到所有的备份中去,有以下方法:
1.给写请求分配ID,谁大以谁为准
2.给节点分配ID,谁大以谁为准
3.把结果合并起来如B/C
4.记录结果,后面写业务代码去解决
2.2.4 冲突解决的策略
很多多leader的工具允许自己写冲突解决的方案,包括写的执行以及读的执行两个方面
写时
检测到冲突了之后,调用conflict handler,能执行自己写的PERL脚本
读时
检测到冲突后,所有冲突的数据都会被记录。下次这个数据被读取时,多个版本的数据都会返回给应用,应用自己决定如何处理
2.2.5 什么是冲突
有些冲突明显,修改同一条记录同一个字段。
有些则不明显,比如一个预订系统,两人同时预定一个位置。
(这里不是很理解这一节是干吗的,这个例子只是db换一个方式冲突,而且也能用2.2.4的方案解决啊)
2.3 多leader备份的拓扑关系
需要一个拓扑关系来表识写请求在节点之间的传递,有下面几种
最常见的是all-to-all这种,所有leader之间互相通信。
MySQL则默认用circular模型。是一个环状结构。
另外星形结构可以看做是树形结构,由一个root节点向所有其他节点通信。
在环形和星形中间,一个写可能要经过多次传输到达其他节点(星形的话可能是叶子-根-叶子这样传输)
为了避免传递时出现死循环,每个节点都会有一个唯一id。每个传递的消息会记录传递路径的节点的id。
环形和星形的问题是如果一个节点挂了,整个通信结构都可能受到影响,往往需要人为的修复。
另一方面,all-to-all的结构,受到网络通信的影响,可能造成备份的数据会出现 改动顺序颠倒的情况(之前提到的前缀一致性问题),如下图
为了保证顺序性,称为“version vectors”的技术被提出,后面再讲。
3.思考
星形网络
换一个角度看就是一棵树
多leader的主要问题
就是写会有冲突,要尽量避免冲突,收束到一致性,再检测冲突,解决冲突
但是感觉解决冲突的成就还是比较poor的。
4.问题
解决冲突造成的倾向性问题
2.2.3里面说比如给节点分配ID,谁大以谁为准,这也是有倾向性的
而2.2.5中提出的 “什么是冲突”感觉完全可以解决掉,不知道书中这样编排的目的是啥
5.总结
这部分主要讲解:
多leader适用的场景
然后面对的主要问题是写冲突,如何检测,避免,解决冲突
最后讲解了多leader中,各个leader互相备份的三种模型