【分布式系统百科】Spanner 与 TrueTime:用硬件解决分布式时间问题
内容提要
Spanner通过TrueTime API(结合GPS与原子钟)提供时间区间,实现外部一致性。事务提交时分配时间戳并执行Commit Wait(约2ε),确保时间戳与真实时间顺序一致。支持快照读、强读及跨Paxos Group事务。CockroachDB用HLC和不确定性区间近似,TiDB用集中式TSO,各有取舍。
延伸解读
TrueTime 的工程代价与收益
Spanner 通过 GPS 和原子钟构建 TrueTime,将时间误差控制在毫秒级(论文中 ε 通常 1-7ms),从而用 Commit Wait(约 2ε)实现外部一致性。这种硬件投入对 Google 是合理的,但对大多数组织而言成本过高。CockroachDB 用 HLC 和不确定性区间(默认 max-offset 500ms)近似,TiDB 用集中式 TSO 绕开时钟同步,各有取舍。理解这些方案的关键在于:时间不确定性的处理方式决定了事务路径的额外开销,而非简单的性能对比。
Commit Wait 为何是 2ε?
Commit Wait 等待时间上界为 2ε,源于 TrueTime 的误差边界。协调者选择 TT.now().latest 作为时间戳 s,但真实时间可能落在区间最早端,因此需等待直到 TT.now().earliest > s,即真实时间确定性超过 s。这个等待通常为 5-10ms,但相比跨数据中心 Paxos 复制 RTT,占比可能较小。降低 ε 能减少等待,但需结合论文 Fig. 8 的分位数评估实际收益。
读路径的优化与权衡
Spanner 的快照读无需锁,可从任意副本读取历史数据,适合分析查询;强读则需 leader 协调并等待 safe time。CockroachDB 的读操作可能因不确定性区间触发读重启,增加尾延迟;TiDB 的 TSO 虽无不确定性,但引入额外网络往返。选择哪种方案取决于应用对延迟、一致性和部署成本的综合考量。
Q&A
Spanner 的 TrueTime API 是什么?它如何解决分布式系统中的时间同步问题?
TrueTime API 是 Spanner 提供的时间服务接口,它返回一个时间区间 [earliest, latest] 而不是精确时间点,通过结合 GPS 和原子钟硬件,将时间误差控制在毫秒级(通常 1-7ms),从而为分布式事务提供可靠的时间参考。
Spanner 如何实现外部一致性?
Spanner 通过为每个事务分配一个时间戳(取 TT.now().latest),并执行 Commit Wait(等待直到 TT.after(s) 为真)来确保时间戳与真实时间顺序一致,从而保证外部一致性(即严格可串行化)。
什么是 Commit Wait?为什么需要等待 2ε?
Commit Wait 是 Spanner 在事务提交时,分配时间戳 s 后等待直到真实时间确定超过 s 的机制。等待时间通常为 2ε(ε 为 TrueTime 误差的一半),因为需要确保任何后续事务的时间戳都大于 s,从而保证外部一致性。
Spanner 支持哪些读操作?它们有什么区别?
Spanner 支持快照读和强读。快照读读取过去某个时间点的一致性快照,无需加锁,可从任意副本读取;强读读取当前最新数据,需要等待 safe time 达到指定时间戳,但无需两阶段提交。
CockroachDB 和 TiDB 如何在没有 TrueTime 的情况下近似实现类似的一致性?
CockroachDB 使用混合逻辑时钟(HLC)和不确定性区间(默认 max-offset 500ms),通过读重启处理时间不确定性;TiDB 使用集中式 TSO(时间戳预言机)提供全局单调递增的时间戳,完全避免不确定性,但引入单点瓶颈和额外网络延迟。
Spanner 的架构中,Paxos Group 和 Directory 是什么关系?
Directory 是数据放置的基本单元,每个 Directory 属于一个 Paxos Group。Paxos Group 负责复制和管理一组 Directory,使用 Paxos 协议在多个副本间达成共识。
Spanner 如何处理跨 Paxos Group 的事务?
Spanner 使用两阶段提交(2PC)处理跨 Paxos Group 事务,协调者分配全局时间戳并执行 Commit Wait,参与者通过 Paxos 复制 prepare 和 commit 记录,确保原子性和外部一致性。
Spanner 的 schema change 是如何做到非阻塞的?
Spanner 为 schema change 分配一个未来的时间戳,广播到所有 Paxos Group,当真实时间达到该时间戳时,所有节点同时应用 schema change,从而不阻塞正常读写事务。