HLC
HLC是Hybrid Logical Clock的缩写,混合逻辑时钟。时钟分为物理时钟和逻辑时钟。
物理时钟
: 电子设备,计算有固定频率晶体的震荡次数,存在时钟偏移和时钟漂移,会导致时钟不连续的变化,比如时间回退等, 以及长时间使用导致时钟存在偏差,普通石英晶体时钟漂移率在(10)-6s/s, 即每1 000 000s会导致1s的偏差。 原子钟的偏倚率在(10)-13.
逻辑时钟
: 时间发生的逻辑顺序,可以是顺序的序号,和物理时间相对。
HLC同时使用了物理时钟和逻辑时钟,能够保证单点的时间发生器是单调递增的,同时能够尽量控制不同节点之间的时钟偏差在规定的误差范围内。主要用于分布式系统中。
HLC实现
pkg/util/hlc/hlc.go
结构体
|
|
分为两部分,WallTime表示物理时钟,单位是纳秒,Logical表示逻辑时钟,用于在WallTime相同的时候,进行递增。 Timestamp是绝对单调递增的,单点内不存在相同的Timestamp,不存在时钟的回退。
物理时钟的获取
|
|
其中c.physicalClock()即调用函数UnixNano(), 直接获取当前操作系统的时间。
逻辑时钟的获取逻辑
|
|
如果获取的物理时钟小于之前的WallTime,则只进行逻辑时钟的递增。否则,重置WallTime为最新的physicalClock。
不同节点间时钟同步
分布式系统中,每个节点的时间是不精确的,各个节点的HLC也无法准确判断先后顺序,故分布式系统时间处理上出现了两种方式:
Timestamp oracle
: 专门的一台机器用于生成时间戳。优点是时间全局排序唯一,缺点是TO存在单点问题, 跨机房问题,以及性能瓶颈问题。Spanner
: 通过高精度物理时钟,如原子钟、GPS,保证节点间的时钟误差在合理范围,比如Spanner能保证节点间时间误差在10ms以内。优点是完全分布式,无单点,缺点是无全局排序唯一的时间生成。
crdb使用类似snapper的方式,但是没有使用专用硬件,需要通过节点间通信来控制节点间的时钟误差。
所有节点间的gRPC消息都会把时间戳带入到消息中,接收到消息的节点会通过消息中的时间戳更新自己的时间, 从而达到节点间时间同步的效果。
|
|
rt表示rpc中消息的时间戳, 更新逻辑如下:
-
获取本地物理时间pt
-
如果pt大于之前的
c.mu.timestamp.WallTime
本地时间,且pt大于rt,则使用pt时间 -
如果rt时间大于
c.mu.timestamp.WallTime
12c.mu.timestamp.WallTime = rt.WallTimec.mu.timestamp.Logical = rt.Logical + 1 -
如果rt时间小于
c.mu.timestamp.WallTime
1c.mu.timestamp.Logical = rt.Logical + 1 -
如果rt时间等于
c.mu.timestamp.WallTime
1234if rt.Logical > c.mu.timestamp.Logical {c.mu.timestamp.Logical = rt.Logical}c.mu.timestamp.Logical++
总之就是比较pt,rt, c.mu.timestamp
,取其最大者作为最新时间。