分布式系列:True Time

本文探讨了计算机时钟为何无法保持一致,并介绍了Google Spanner如何通过“等”字诀和TrueTime技术来确保分布式系统中时间的一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  物理时钟的无奈

  大家可能都知道,计算 机的时钟过一段时间就不准了,为什么计算机的时钟不能保持统一的速度前进呢?因为计算机的时钟速度取决于它的石英振荡器,计算机上的石英振荡器一般来说精度都不是很高(因为精度高了就贵了。。。),在各种物理条件发生变化时有可能频率也发生变化(计算机全速运行一个for循环时的时钟速度和空闲时是不一样的),所以导致计算机时钟不能匀速前进。

  现在一般都采用NTP之类的技术来保持时钟同步,不过由于网络延迟,同步频率等因素,物理时钟还是很难保持精确一致。用真实的时间作为横坐标来看,理想情况下,节点上时间应该是下图那样一条斜率为1的直线,真实情况则是它在这条直线上上蹿下跳。

  

 

  对于分布式系统来说,时钟不能精确一致会有什么问题呢?假设在真实时间100的时候,一个操作X=200发生在节点A,节点记录时间为101,接着在真实时间101的时候一个操作Y=50发生在节点B,节点记录时间为98,那么从外部观测者看来,Y=50是发生在X=200前面了。

  

 

  简单粗暴的“等”

  如何处理上述情况呢,最简单的方法就是一个字——等!

  要想使用“等”字诀,就要知道节点的时钟和真实时钟的误差的最大值。假设系统中节点时钟和真正的时钟最大误差为e,意味着在真正的t时刻,节点的时钟应该在[t-e, t+e]这个范围。完成一个操作之后,不管三七二十一,先等一会儿,再执行下一个操作,这样就保证了后一个操作的时钟大于前一个。要等多久呢?万无一失的操作是,每次等2e的时间就行了。

  

 

  Google Spanner的“等”

  Google Spanner就是用“等”来解决分布式系统的时钟问题的。按照论文中的说法,Spanner是Google的“scalable, multiversion, globally distributed, and synchronously replicated database”,它实现了external

  consistency的一致性模型(按照论文中说法,就是linearizability),其方法就是利用TrueTime和“等”字诀(官方说法叫“Commit Wait”)。TrueTime有两方面的作用:

  使e变得非常小

  不用每次操作都等待e,而是最多等待e

  TrueTime的实现

  TrueTime的实现细节Google没有透露,论文里只是介绍说同时使用了GPS和原子时钟,因为GPS和原子时钟有不一样的失效模型。他们在数据中心内部署一组time master,大部分的master上有GPS接收器,剩下的master上则装备原子时钟(这些master叫做世界末日master。。。),master之间互相通信,按照特定的规则运行。在其他服务器上则有time slave,slave定期从master进行时间同步。所以服务器上的时钟误差一直在变化,刚同步完时误差最小,同步之前则误差最大。

  

图片描述

 

  如下图所示,TrueTime对外提供了三个API。

  

图片描述

 

  在一般的时间库中,时间都是以一个时间点的方式取得,而TT.now()返回的则是一个区间[earliest,latest]。TrueTime保证的是调用TT.now()的真实时间一定处于它返回的区间之内。

  

图片描述

 

  TT.after和TT.before在论文中被一笔带过——“The TT.after() and TT.before() methods are convenience wrappers around TT.now()”,按常理推断,TT.after(t)是TT.now().earliest t,而TT.before(t)是TT.now().latest t。

  但是,TT.after()和TT.before()的说明里的“definitely”有点不太严谨。

  按理说,同一时刻在不同的节点上调用TT.now(),返回的区间应该是不一样的,那么有的节点认为TT.after(t)是true,有的认为是false?也就是说,有些服务器上“t肯定已经过去了”,而有些服务器不是。

  由于时钟误差一直在变化,所以TT.now()的区间的宽度也是在变化的。那么就有可能在一台服务器上,某个时刻TT.after(t)是true,在随后的某个时刻TT.after(t)变成false了?在一台服务器上,某一时刻,它认为“t肯定已经过去了”,但是过了一会儿,它又不肯定了,总是感觉有一种出尔反尔的感觉。

  TrueTime的应用

  Spanner中有以下四种操作,这里我们以简化版的“Read-Write Transaction”为例,说明一下TrueTime的使用。

  

图片描述

 

  在“Read-Write Transaction”操作中,Spanner想要完成的一致性模型是:如果事务T2的start发生在事务T1的commit之后,那么T2的commit时间必须比T1的commit时间大。这里,我们假设某个事件e的真实时间是tabs(e),事务i的start事件是eistart,事务i的commit事件是eicommit,事务i的commit请求到达服务器的事件为eiserver,事务i的commit时间是si,那么要达到的要求就是:如果tabs(e1commit) tabs(e2start),那么s1 s2。

  Spanner的操作有两条规则:

  Start:在事务i的eiserver事件发生之后,它产生一个时间si,要求si = TT.now().latest,所以si = tabs(eiserver) ,这个时间si将作为事务Ti的commit时间。

  Commit Wait:产生si以后,它要一直等到TT.after(si)返回true之后再commit。这样si小于真实的commit时间,即si tabs(eicommit) 。

  很容易证明如果tabs(e1commit) tabs(e2start),那么s1 s2:

  由“Commit Wait”可知,s1 tabs(e1commit),所以s1 tabs(e2start)

  显然tabs(e2start) tabs(e2server)

  由“Start”可知,tabs(e2server) = s2

  所以s1 s2

  这样平均每次等待误差的平均值即可,而不是每次每次等待最大值。

  

图片描述

 

  当然如下图所示,实际上Spanner会有更复杂的步骤,这里就不深入展开了。

  

图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值