因为时间误差存在,2-C 时间点附近会形成一个不确定时间窗口,也称为置信区间或可信区间。同样,T6-S 也只是一个时间窗口。时间误差不能消除,但可以通过工程方式控制在一定范围内,例如在 Spanner 中这个不确定时间窗口(记为ɛ)最大不超过 7 毫秒,平均是 4 毫秒。
解决方法有两种方式可供选择,分别是写等待和读等待。
写等待
Spanner 选择了写等待方式,更准确地说是用提交等待(commit-wait)来消除不确定性。
对于一个绝对时间点 S,什么时候 TT.after(S) 为真呢?至少需要等到 S + ɛ时刻才可以,这个ɛ就是我们前面说的不确定时间窗口的宽度。其中 TT.after() 用于判断当前时间是否晚于指定时间。
Ta 在 S 时刻写盘,保存的时间戳也是 S。事务 Tb 在 Ta 结束后的 S+X 时刻启动,获得时间区间的最小值是 TT1.earliest。如果 X 小于时间区间ɛ,则 TT1.earliest 就会小于 S,那么 Tb 就无法读取到 Ta 写入的数据。Tb 在 Ta 提交后启动却读取不到 Ta 写入的数据,这显然不符合线性一致性的要求。
事务 Ta 在获得“提交时间戳”S 后,再等待ɛ时间后才写盘并提交事务。真正的提交时间是晚于“提交时间戳”的,中间这段时间就是等待。这样 Tb 事务启动后,能够得到的最早时间 TT2.earliet 肯定不会早于 S 时刻,所以 Tb 就一定能够读取到 Ta。这样就符合线性一致性的要求了。
适用误差很小的系统,Spanner 能够将时间误差控制在 7 毫秒以内。
读等待:CockroachDB
读等待只在特殊条件下才被触发,影响的范围要小得多。
遇到有关联事务时,存在不确定的时间窗口,读操作的事务通过重启得到新的时间戳,以超过不确定时间窗口。
在这个过程中,可以看到读等待的两个特点:一是偶发,只有当读操作与已提交事务间隔小于设置的时间误差时才会发生;二是等待时间的更长,因为事务在重启后可能落入下一个不确定时间窗口,所以也许需要经过多次重启。
读等待适用于误差更大的系统,CockroachDB 对误差的预期达到 250 毫秒。
此文章为6月Day13学习笔记,内容来源于极客时间《分布式数据库30讲》