CRDT 使用 Math 在分布式集群中强制执行一致性,而不必担心共识和相关的延迟/不可用性。
CRDT 可以随时取值的集合属于半格(特别是连接半格)的类别,它是具有最小上界函数 (LUB) 的 POSET(部分有序集) )。
简单来说,一个 POSET 是一组项目,其中并非所有项目都具有可比性。例如。在一组对中:{(2,4), (4, 5), (2, 1), (6, 3)}、(2,4) 是 (4,5),但不能与 (6,3) 进行比较(因为一个元素较大而另一个较小)。现在,半格是一个 POSET,其中给定 2 对,即使您无法比较两者,也可以找到一个大于两者的元素(LUB)。
另一个条件是需要增加对该数据类型的更新,CRDT 具有单调递增的状态,客户端永远不会观察到状态回滚。
这个excellent article 以我上面使用的数组为例。对于维护这些值的 CRDT,如果 2 个副本试图在 (4,5) 和 (6,3) 之间达成共识,他们可以选择 LUB = (6,5) 作为共识并将两个副本分配给它。由于价值观
正在增加,这是一个很好的选择。
CRDT 有 2 种方法可以在副本之间保持同步,它们可以定期传输状态(收敛复制数据类型),或者可以在获取更新时传输更新(增量)(交换复制数据类型) .前者占用更多带宽。
SoundCloud 的Roshi 是一个很好的例子(尽管它似乎不再处于开发阶段),它们存储与时间戳相关的数据,其中时间戳显然是递增的。任何时间戳小于或等于存储的时间戳的更新都将被丢弃,这确保了幂等性(重复写入可以)和交换性(无序写入可以。交换性为a=b means b=a,在这种情况下意味着 update1 后跟update2 与 update2 相同,后跟 update1)
写入被发送到所有集群,如果某些节点由于速度慢或分区等问题而无法响应,它们预计稍后会通过read-repair 赶上,这可确保值收敛。收敛可以通过我上面提到的 2 个协议来实现,将状态或更新传播到其他副本。我相信罗希是前者。作为read-repair 的一部分,副本交换状态,并且由于数据遵循半格属性,它们会收敛。
PS。使用 CRDT 的系统最终是一致的,即它们在 CAP theorem 中采用 AP(高可用和分区容错)。
Another excellent read on the subject.