唯's Blog

笔者是一个热爱编程的 Java 程序员。

0%

分布式协调

在分布式节点处理数据,例如多主复制。存在冲突问题

解决思路

1. 避免冲突

所谓解决问题最根本的方式则是尽可能不让它发生,如果能够在应用层保证对特定数据的请求只发生在一个节点上,这样就没有所谓的“写冲突”了。继续拿上面的协同编辑文档举例,如果我们把每个人的都在填有自己姓名表格的一行里面进行编辑,这样就可以最大程度地保证每个人的修改范围不会有重叠,冲突也就迎刃而解了。

2. 收敛于一致状态

然而,对更新标题这种情况而言,冲突是没法避免的,但还是需要有方法解决。对于单主节点模式而言,如果同一个字段有多次写入,那么最后写入的一定是最新的。ZK、KafkaController、KafkaReplica都有类似Epoch的方式去屏蔽过期的写操作,由于所有的写请求都经过同一个节点,顺序是绝对的,但对于多主节点而言,由于没有绝对顺序的保证,就只能试图用一些方式来决策相对顺序,使冲突最终收敛,这里提到了几种方法:

给每个写请求分配Uniq-ID,例如一个时间戳,一个随机数,一个UUID或Hash值,最终取最高的ID作为最新的写入。如果基于时间戳,则称作最后写入者获胜(LWW),这种方式看上去非常直接且简单,并且非常流行。但很遗憾,文章一开始也提到了,分布式系统没有办法在机器间共享一套统一的系统时间,所以这个方案很有可能因为这个问题导致数据丢失(时钟漂移)。

每个副本分配一个唯一的ID,ID高的更新优先级高于地域低的,这显然也会丢失数据。

当然,我们可以用某种方式做拼接,或利用预先定义的格式保留冲突相关信息,然后由用户自行解决。

3. 用户自行处理

其实,把这个操作直接交给用户,让用户自己在读取或写入前进行冲突解决,这种例子也是屡见不鲜,Github采用就是这种方式。