三座山头,三座钟楼,彼此隔着山谷。每座钟楼里都有一位守钟人,负责给往来的契约盖上”这是什么时辰”的印记。麻烦在于:没有一只钟是准的。守钟人怀里的怀表会走快走慢,山谷的风也会骗人。

老守钟人却从不说”现在是正午”。他只会说”现在,落在午时初刻到午时二刻之间”——他给出的从来是一段区间,而不是一个点。为了压窄这段区间,他每天正午对着院里的日晷校准(太阳骗不了人),又靠塔里那座昼夜不停的大摆钟兜底。日晷给方向,摆钟给稳当,两者一夹,那段”说不准的窗口”就被压得很窄——窄到只剩几口气的工夫。

真正的讲究在盖印那一刻。当一份契约要封蜡时,守钟人取区间里最靠后的那个时辰,写上去。写完他并不立刻敲钟,而是掐着指头等——一直等到连他最悲观的估计都已经追过那个时辰,确认”此刻真的已经越过我盖的那个数了”,才敲响”此约已成”的铜钟。

这一等,看似多余,却是全部的关键。因为这么一来,山那头另一座钟楼、下一刻要封的任何一份契约,无论那位守钟人的怀表快慢,他取的时辰都必然比这一份更靠后。三座山头从不需要一只公用的钟,也没人能把两份契约的先后颠倒——谁先封的,印上的数就一定更小。

——到这儿你大概已经认出来了:这就是 Google Spanner 的 TrueTimecommit-wait

TrueTime 不像普通时钟返回一个时间点,而是返回一段区间 [earliest, latest],并保证真实时间一定落在其中——它把时钟的不确定度 ε 明明白白地暴露出来。这段区间靠每个机房里的 GPS 接收器和原子钟共同压窄。事务提交时,协调者选定一个 commit 时间戳 s,然后刻意等待,直到 TT.after(s) 为真(即区间下界都已越过 s)才释放锁、真正提交。这个”等一等”就是 commit-wait,它换来了 external consistency(线性一致):任何在此之后开始的事务,拿到的时间戳一定严格更大,于是全球分布的机房无需一只公用时钟,也能对所有事务定出一致的先后顺序。区间宽度(约 2ε,通常几毫秒)直接决定了这段等待要花多久——这也是为什么 Google 要花大力气把时钟误差压到极小。

隐喻对应:

  • 三座山头的钟楼 → 全球分布的多个 datacenter
  • 守钟人怀里走不准的怀表 → 单机会漂移的本地时钟
  • 院里的日晷 + 塔中不停的大摆钟 → GPS 接收器 + 原子钟
  • 从不说”正午”,只说”午时初到二刻之间” → TT.now() 返回区间 [earliest, latest],暴露不确定度 ε
  • 被夹得很窄的”说不准的窗口” → 不确定度 2ε
  • 取区间里最靠后的时辰盖印 → 选定 commit 时间戳 s
  • 敲钟前掐指头多等的那一小会儿 → commit-wait,等到 TT.after(s) 为真
  • 后封的契约印上的数必然更大 → external consistency / 线性一致

Three hilltops, three bell towers, each cut off from the others by a valley. In every tower lives a keeper whose job is to stamp passing contracts with the hour they were sealed. The trouble: no clock is true. The keeper’s pocket watch runs fast one day and slow the next, and the valley wind tells its own lies.

Yet the old keeper never says “it is noon.” He only ever says “it is somewhere between the first and the second stroke of noon” — always a range, never a point. To keep that range narrow he calibrates every noon against the sundial in the yard (the sun cannot be bribed), and leans on the great pendulum that swings in the tower day and night to hold him steady between calibrations. The sundial gives direction, the pendulum gives constancy; squeezed between the two, his window of doubt shrinks to no more than a few held breaths.

The real craft is in the stamping. When a contract is ready for the wax, the keeper takes the latest hour in his range and writes that down. But he does not ring at once. He counts on his fingers and waits — until even his most pessimistic guess has run past the hour he wrote, until he is certain “this very moment has truly passed the number I stamped.” Only then does he strike the bronze bell that means “this contract is sealed.”

That pause looks like wasted time, and it is the whole point. Because of it, the very next contract sealed on any hilltop — no matter how fast or slow that keeper’s watch — must carry an hour later than this one. The three hills never need a shared clock, and no one can ever swap two contracts’ order: whoever sealed first carries the smaller number, always.

— By now you have probably recognized it: this is Google Spanner’s TrueTime and commit-wait.

TrueTime does not return an instant like an ordinary clock; it returns an interval [earliest, latest] and guarantees the true time lies within it — it makes the clock’s uncertainty ε explicit. That interval is kept narrow by GPS receivers and atomic clocks in every datacenter. To commit a transaction, the coordinator picks a commit timestamp s, then deliberately waits until TT.after(s) is true (until even the interval’s lower bound has passed s) before releasing locks and committing. That deliberate wait is commit-wait, and it buys external consistency (linearizability): any transaction that begins afterward is guaranteed a strictly greater timestamp, so datacenters spread across the globe can agree on one consistent ordering of all transactions without ever sharing a clock. The width of the interval (about 2ε, usually a few milliseconds) sets how long that wait must be — which is why Google spends so much effort driving the clock error down.

Metaphor mapping:

  • The three hilltop bell towers → datacenters spread across the globe
  • The keeper’s unreliable pocket watch → the local machine clock that drifts
  • The sundial in the yard + the ever-swinging pendulum → GPS receivers + atomic clocks
  • Never saying “noon,” only “between the first and second stroke” → TT.now() returning an interval [earliest, latest], exposing uncertainty ε
  • The narrowed window of doubt → the uncertainty 2ε
  • Stamping with the latest hour in the range → choosing the commit timestamp s
  • The extra beat counted out before ringing → commit-wait, waiting until TT.after(s) is true
  • A later-sealed contract always carrying a larger number → external consistency / linearizability