TrueTime和原子钟

2021-02-10
分布式系统 TiDB

如果你关注分布式数据库,相信多少听说过Google的分布式数据库Spanner,以及Spanner使用原子钟搞了一套TrueTime来实现跨数据中心的分布式事务。

而Spanner的后继者们,却都采用了不使用原子钟替代方案,比如TiDB的TSO,CockroachDB的HLC。对此很多人的印象就是Google财大气粗,所以有能力搞原子钟这种精密高端设备。这个说法不能说全错,但至少不是完全准确的。

网络时钟同步

上面提到的3种取时间戳的方式的底层逻辑是迥然不同的。TiDB的TSO是中心授时,每一个时间戳都要从中心服务器获取;CockroachDB的HLC本质上是逻辑时钟,依赖于消息交换时去推进时钟计数器;Spanner的TrueTime是时钟同步,通过定期交换消息,把本地时钟与源时钟进行同步。

时钟同步的模式跟我们日常用手表的方法是类似的,我们隔一段时间把手表跟新闻联播同步一下,期间的时间直接从手表上读出来。

计算机里面最常见的时钟同步就是NTP了,通过网络同步时钟有个问题就是延迟导致的误差。

网络同步时钟

比如客户端在12:00:00发起查询请求,2秒钟后收到服务器的消息,返回的时间也是12:00:00。这时并不意味着本地时钟是准确的,因为消息发到服务器要花费时间,本地时钟实际上是快了一点。但是具体快了多少是没法知道的,我们只知道消息一来一回花了2秒,却不知道来回分别花了多长时间。因此只能大概估摸着取个中间值,把时间往回拨1秒,这时误差范围就是±1秒了。

Marzullo算法

只从单一时间源同步时间是不够靠谱的。除了有可能发生故障或者网络中断,更可怕的是时间源本身就出了问题。Marzullo算法就是用来从多个时间源来估算准确时间的算法。

Marzullo算法

如图,我们通过向ABCD四个时间源查询时间分别得到时钟偏差及误差范围,算法的大体思路就是选被尽可能多时间源所覆盖的区间(缩小误差范围),并排除掉有问题的区间(如A)。

不过,在对时序有严格要求的场景(比如分布式事务),Marzullo算法还要进行一些改良。例如比较明显的缺陷是,当有问题的时间源offset区间与正常的区间有交叠时,可能导致误差范围被估算得过小。如果想了解相关细节,可以去研究下相关资料,这里不展开了。

时钟漂移

跟服务器对上时间了还没完,通常对时的过程都要周期性地触发。正如我们的手表用着用着就不准了,CPU的晶振周期也不是完全精确的,会受温度和电压的影响,时间一长也会“跑偏”。

Spanner假设他家服务器的误差不超过每秒钟200μs。按最大值去计算,30秒不同步,误差最多会累计到6ms,如果1天不同步,最大误差达到约为17s。要注意这里的误差范围是非常非常保守的,实际情况CPU远不可能这么糟糕,举个例子对比一下,我国石英电子表的行业标准是,一类月差10-15秒,二类月差20-30秒。

原子钟

原子钟,是一种利用原子、分子能级差为基准信号来校准晶体振荡器或激光器频率,以使其输出标准频率信号的一种装置。它的工作原理是:利用原子吸收或释放能量时发出的电磁波来计时的。由于这种电磁波非常稳定,再加上利用一系列精密的仪器进行控制,原子钟的计时就可以非常准确了,可以达到千万年仅差一秒或者更好的水平。

—— 时间频率:5G 叠加自主可控, 被忽视的高精尖领域

看上去确实很高端,那么假如想买这样一个原子钟要多少钱呢?实际情况是原子钟比听上去亲民的多,我们直接在东哥的网站上就能搜到

京东商城售卖的原子钟

售价大约是几万到十几万不等,并非承受不起的昂贵,和一台高端点的服务器是差不多的价位,如果降低精度的要求还能更便宜。

说白了原子钟和计算机上面随处可见的晶振就是同一类东西,只不过精度高了好几个数量级。

不同硬件的计时精确度

需要注意有些同学误认为TrueTime需要每台机器都要给配一个原子钟,其实不用,一个数据中心有几个就完全足够了,具体先按下不表后面再说。

GPS授时

GPS不仅提供定位服务,还可以授时。每个GPS卫星都携带了数个高精度原子钟,并不断广播星历(运行轨迹)和时间。地面装置从至少4颗卫星接收到信号后,解开以三维空间+一维时间为变量的四元方程组,就能同时拿到时间空间信息了。

GPS的精度非常之高,可以把误差控制在数纳秒以内。这是因为电磁波信号基本上是直线传播,路径上受到的干扰很小,根据距离可以很准确地计算出信号传递延时。而网络消息会受中继和多层网络层层封包的影响,而且即便在光纤中,信号也不是沿直线传播的。

TrueTime

背景知识介绍完毕,下面我们就来看看TrueTime到底是怎么做的。

机房内的TrueTime组件部署

TrueTime组件按角色分成 time master 和 time daemon。time master 可以认为是 TrueTime 的服务端,部署在一些独立的机器上,time daemon 是客户端,以进程的形式部署在每个实际运行业务的主机上。

time master 又分成两类。一类安装 GPS 模块,分散在机房的不同位置,每个GPS节点都使用独立的天线,避免因为信号干扰的原因一起失效了。另一类安装的是原子钟,原子钟也是多台来防止故障产生不可用。

各种 time master 周期性地使用Marzullo算法相互对时,每个 time daemon 也会以 30 秒为周期跟多个 time master 进行对时(同样使用Marzullo算法)。

之前介绍过,GPS 的精度是纳秒级别的,这个误差跟机房内的网络延迟比起来都可以忽略不计了,直接计作0ms。这样time daemon进行时钟同步之后的误差就仅仅取决于网络延迟了,一般机房内不超过1ms。

我们还要考虑到完成时钟同步之后,到下一次同步期间time daemon的时钟漂移,也就是前面计算过的,30秒内最大误差可能累计到6ms。于是,time daemon上的时钟误差范围就在1ms到7ms之间不断涨落,画出来是这样的锯齿状:

time daemon误差范围变化示意

那么问题来了,原子钟是干啥用的?

简而言之,原子钟是GPS的备胎。GPS授时容易受天气和电磁信号的干扰,极端情况下还有可能整个GPS系统故障了,或者由于战争等原因被关掉服务(须知GPS是军用设施),这时原子钟才会派上用场。

论文里没细写,不过推测一下,原子钟跟GPS节点同步逻辑应该是跟time daemon类似的,即效果也是周期性地回落至1ms附近。区别在于,当GPS失效之后,原子钟的误差增长速度要远远小于普通机器,因此可以取而代之,作为数据中心的数据源离线提供时钟同步服务。

总结

回到最初的问题:为什么只有Spanner使用了TrueTime的设计?这并不是因为原子钟有多么的遥不可及。TrueTime是一整套精巧复杂的设施,原子钟只是其中一个有些关键的组成部分。

拿TiDB来说,我们没有资源和机会去从零设计搭建完整的机房来支撑这一套系统,只能选择替代方案。但是TrueTime的设计理念和思想是值得我们去学习和吸收的!

TrueTime最大的贡献在于,把时间误差范围作为API提供给上层,配合事务层面的精心设计来达成苛刻的事务一致性。我们既不能从根本上消除误差,也无法确切地计算误差范围,但是巧妙地以确定的误差上界为突破点,优雅地解决问题!

分布式系统最动人的美妙之处就在这里:我们面对的是令人近乎绝望的不确定性,然而凭着信念,理性,智慧,我们又能在如此脆弱的基础之上搭建出高度可靠的,不容置疑的系统。

收工!


参考资料


欢迎加入技术讨论 QQ 群: 745157974

给TiDB(MySQL)写一个代理网关

引入数据库网关来优化TiDB Cloud服务运营成本的故事,以及处理MySQL协议的糟心细节
TiDB MySQL serverless

双中心主从模式

2021-09-11
分布式系统

价值6万元的TiDB Hackathon创意

2020-12-17
TiDB