Skip to main content

04 Consistency

一致性

一致性模型

只有一个服务器。发送消息时发送到服务器上;读取时也从服务器读取。不会出现操作重排。

问题为

  • 响应时间长
  • 读取慢
  • 不支持离线
  • 无法处理故障

现实的系统会复制数据,用户、用户设备和服务器都会存储副本。在这种情况下,发送消息会带来不一致。

一般的设计是,读取时只读取本地副本,并定期同步;只同步部分服务器,同步操作而不是数据,使用过滤+追加方式更新。

但这种设计可以导致客户端重排。

最终一致性

所有服务器最终都会获得所有更新,且持有相同更新的服务器有相同的数据内容。对具体的读写方式没有限制。

具体实现为

  • 读:直接从本地副本读取
  • 写:写入到本地副本并写回。同步时传播到所有服务器

同步时,需要交换不同服务器的数据内容,需要对不同的内容进行排序。不同服务器都需要将操作记录在log中,然后在log中排序。排序后,可能需要重写内容。

考虑到时钟,需要引入nodeid(服务器id)作为额外的排序手段。

  • (time, id):全局一致性更好,但可能因为时钟偏差短暂违背因果顺序,用户体验差
  • (id, time):全局一致性较差,但每个节点严格有序,用户体验较好

实际设计需要权衡。

强一致性

从开发者角度,强一致性代表只有一个副本,一切都串行执行。

严格一致性

按发出时间排序,实际无法实现。

线性一致性

线性一致性是实际可以实现的最强一致性模型。这种方式需要单写入者原则,只允许一个线程读写,将写入顺序传播到其它进程。这种设计需要主服务器使用序列号。

这种设计比最集中实现可能更低效,还会有可靠性问题。

时钟

这里的时钟都只用于实现最终一致性。

Lamport时钟

这是一种逻辑性的时钟。在同一个节点上,lamport给出的结果遵循时间顺序;此外,结果遵循因果关系。

实现:

  • 每个服务器包含时钟T
  • 随真实时间流逝递增,或在事件发生时递增
  • 如果获取另一个服务器的时间t,则T=max(t+1, T)

可能出现不一致,但是后续会回滚。

向量时钟

向量时钟是对lamport时钟的增强。

每个服务器维护一个向量时钟,维度等于服务器数。本地时间发生时,递增自己的向量分量。进程发送消息时,先递增自己,然后发送整个向量。接受时,将每个分量和收到的对比取最大值,并递增自己的分量。如果所有v分量都(相对的)小于w分量,则v小于w。