https://www.cnblogs.com/king0101/p/11908305.html
上文中所描述的微信朋友圈评论同步问题,可看作多主复制数据库中的因果一致性问题。
对于数据库中的某一条朋友圈(由唯一key标识),其value对应多条评论。朋友圈由多主复制数据库进行存储,四个数据中心中均存在朋友圈的主库,均提供写入功能。
问题:
- 假设用户A在数据中心1进行对朋友圈进行评论a,数据中心1将此条评论异步复制到数据中心2和数据中心3。
- 当数据中心2接收到此评论后,用户B查看到评论a进行回复评论b,数据中心2将评论b复制到数据中心1和3.
- 数据中心先接收到评论b,在接收到评论a,因果倒置。
解决方法:
- 每条评论都赋值一个唯一ID,相邻唯一ID的间隔为数据中心的数量,唯一ID的起点为数据中心的编号。这样保证每个数据中心生成的唯一ID不重复。
- 每条新评论的ID都必须比本地已经见过的全局最大的ID大,确保因果关系
- 广播本地看到的所有评论和新评论到其它数据中心;相同ID的评论合并排重
个人理解:
这是逻辑时钟的应用。
为什么使用逻辑时钟而不是向量时钟?
向量时钟需要在每个数据中心记录各自的版本号,而逻辑时钟只需要记录一个版本号。逻辑时钟更省空间。更重要的是向量时钟的主要作用是用来检测是否出现并发写入冲突,而逻辑时钟虽然不能检测并发冲突,但是可以保证不会出现因果倒置。所以使用具有最大版本号的记录,一定是最新的记录,且保证了因果一致性。
朋友圈的使用场景下,是不需要检测并发写入冲突的,因为朋友圈是可以接受并发写入的(两个人同时评论同一条朋友圈是正常行为),而且使用了唯一ID可以非常容易的合并并发写入。所以使用逻辑时钟保证因果一致性即可。
为什么每个数据中心的唯一ID要不重复?
这是为了更容易的合并并发写入的冲突。
假设每个数据中心生成的唯一ID均是从1-N,那么当一个数据中心接收到两条ID相同的复制记录时,无法判别是重复复制还是两条记录并发的写入。而且这样会导致并不能为每一条评论生成唯一ID。
比如:
- 数据中心1和数据中心3同时写入评论a和c,则评论a和c的ID都为1。
情况一:
- 数据中心1的评论a复制到数据中心2,数据中心2写入评论b,ID为2。
- 数据中心2的评论a和b复制到数据中心3,那么数据中心3的评论a和c的ID均为1,但是是并发写入的。
情况二:
- 数据中心3的评论c复制到数据中心2,数据中心2写入评论b,ID为2。
- 数据中心2的评论c和b复制到数据中心3,那么数据中心3的评论c和c的ID均为1,但是是重复的。
由于网络延迟,上述两种情况均可能发生,这为合并并发写入带来了困难。
但是当按照上述方法生成唯一ID,则并发写入的评论具有不同ID,直接合并即可。具有相同ID的评论一定是重复的。