第五章 分布式系统一致性(下)

10803273-3b3109d3557feb5b.png
image.png

10803273-ae58fc06acd1cc32.png
image.png

上面2个一致性最大的问题就是慢,对每个必要的操作都需要发送网络请求去询问。而且依赖于高可靠的网络连接。
当出现下面的一些情况就不太适用:
如 断掉的CLIENT,如自己的手机笔记本,会有断网的时候
还有购物车,对一致性要求不这么高的应用。用户可以自己把需要的东西加回来。

那么为了支持上述情况,也就是支持断线的(本地的)操作。还有一些对一致性不敏感希望性能更好的应用。
出现了最终一致性的模型。
最终一致性是乐观的,认为冲突的写不怎么发生,如果发生了,只要担心最终会不会一致就可以。


10803273-165dc019ee4a46f8.png
image.png

最终一致性可以接受一个写不马上去和别的机器同步,同时也能容忍读到一个旧的数据。这些的牺牲都是为了更好的性能。

举一个相册APP的例子。


10803273-850d66a56b7343e4.png
image.png

传统的解决方案是用一个SERVER一次处理一个请求,然后保持所有操作有序。


10803273-2f42032e842d3d62.png
image.png

如果是在分布式的SERVER上,就可以均摊负载。但是会有下面的问题


10803273-ab2d82ff87426467.png
image.png

当遇到了写写冲突该怎么解决呢?
解决方案 是用UPDATE FUNCTIONS,也就是2 台机器把自己的更新操作 都发送给别的机器,让他们也去做。但是不用等他们回复,就可以直接返回给CLIENT。
这样的同步可能就无法保证顺序。如下图


10803273-85ed50a5b73fe83d.png
image.png

那么我们必须对每一个UPDATE FUNCTION 的log 进行排序。


10803273-75200bc5aed569b0.png
image.png

如果时间一样,ID小的机器 的LOG放在前面。
再看这个例子


10803273-8145c8e5fbb3b6ff.png
image.png

当发现顺序不一致的时候,就需要对不一致的那方ROLL BACK and replay
10803273-ea4bfbe5d20b5cc0.png
image.png

这个方案看似能保证2边一致,但是有些操作包含了因果关系。比如你发了条朋友圈,人家对你的朋友圈做评论。如果人家的手机时间是早5分钟的(相比你的手机时间)经过上述算法进行重排。反而会得到,人家先评论了你的朋友圈,你再把朋友圈发出来的奇怪事情。

下面的这个例子也是讲了这个问题。

扫描二维码关注公众号,回复: 5226314 查看本文章
10803273-90fd498ee46d0265.png
image.png
10803273-f69d51df69397fe6.png
image.png
10803273-17b6ee8d83cf8181.png
image.png

10803273-d2058294fc5ac8ff.png
image.png

就会先删除,后ADD。造成没有删除成功。

解决方案是不能用直接时间,而是逻辑时间。


10803273-faec9ff50e1d2da0.png
image.png

上一节的LAMPORT时间戳就可以用了。


10803273-4135255addf8bfac.png
image.png

上述方案的一个问题是:我们可能永远不知道有一个其他SERVER的照片你还没有SYNC到。这样如果你很久才去把那张照片SYNC过来,你会RERUN 大量的UPDATE FUNCTION。
所以更好的做法是我们可以知道哪些UPDATE 是STABLE了。那么这之前的UPDATE FUNCTION就可以扔掉了。因为不再需要RERUN这些FUNCTION了。

第一种解决思路是分布式的。


10803273-4427a289e142d86c.png
image.png

如果有一个节点SYNC到某条LOG的时候发现,所有的SERVER 的TS 都 >N,那么这个N就是个STABLE的点。之前的UPDATE FUNCTION 都可以丢了。
这个有个问题,就是一旦有一个NODE OFFLINE了。所有的节点的STABLE 位置都不再变化了。

那么集中式的可以解决这个问题吗?


10803273-1b9d630354d85d87.png
image.png

集中式的SERVER会为每一个COMMIT 都分配一个CSN,所有的写带一个CSN的都是STABLE的。

比如一个SERVER本地写了10,SERVER2本地写了20.然后去和PRIMARY SYNC。一旦SYNC到PRIMARY了,就可丢UPDATE FUNCTION了。

这个时候如果有一个OFFLINE 的节点会如何?那么当挂掉的节点连上来后,会把自己的UPDATE FUNCTION去和PRIMARY SYNC。 那么这个CSN 肯定比他在挂掉时的那些CSN要大了。所以其他SERVER 在SYNC他的这个U F的时候,丢掉比这个CSN 小的UF 也没关系了。

但是会遇到PRIMARY 的顺序 和 本地的顺序不一致的CASE。如下图,最右边的SERVER 和最左边的SERVER 同时朝PRIMARY 和中间的SERVER SYNC,
中间的收到的顺序是SRV 1, SRV2 ; PRIMARY 收到的是SRV2 SRV1。
此时PRIMARY 要去SYNC中间的SERVER的时候,就会不一致。所以还是需要ROLL BACK 并且REPLAY。


10803273-f60b715c3c1a81da.png
image.png

最后做个总结。
最终一致性:
使用UPDATE FUNCTION ,然后过度到用排序的UPDATE LOG,基于ROLL BACK and REPLAY。同时排序是根据逻辑时间。

猜你喜欢

转载自blog.csdn.net/weixin_34004576/article/details/86892190