Spanner TrueTime #
一、TrueTime概述 #
1.1 什么是TrueTime #
TrueTime是Spanner的核心创新,提供了全局统一的时间戳服务,是Spanner实现外部一致性的关键。
text
TrueTime特点:
├── 全局统一时间
├── 有界误差
├── 高精度(1-10ms)
├── 基于GPS和原子钟
└── 外部一致性保证
1.2 时间误差 #
text
TrueTime返回时间区间 [earliest, latest]
├── 真实时间一定在区间内
├── 区间大小 = 2 × ε
├── ε 通常为 1-10ms
└── 通过多时钟源保证精度
二、TrueTime架构 #
2.1 时钟源 #
text
TrueTime时钟源:
├── GPS接收器
│ ├── 接收卫星时间信号
│ ├── 提供绝对时间
│ └── 多个GPS源冗余
│
├── 原子钟
│ ├── 铯原子钟或铷原子钟
│ ├── 高精度本地时间
│ └── GPS故障时备用
│
└── 交叉校验
├── GPS与原子钟互相验证
├── 检测异常时钟
└── 排除故障源
2.2 时间同步架构 #
text
┌─────────────────────────────────────────────────────────────┐
│ TrueTime Master │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ GPS时钟 │ │ 原子钟 │ │ 交叉校验 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Time Slave Daemon │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 时钟同步 │ │ 误差计算 │ │ 本地时钟 │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Spanserver │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ TrueTime API│ │ 事务管理 │ │ 时间戳分配 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
2.3 误差来源 #
text
时间误差来源:
├── 网络延迟: Master到Slave的通信延迟
├── 时钟漂移: 本地时钟的漂移率
├── 同步间隔: 两次同步之间的时间
└── 温度变化: 影响晶振频率
三、TrueTime API #
3.1 API接口 #
python
# TrueTime API概念
class TrueTime:
def now(self) -> Interval:
"""
返回当前时间区间 [earliest, latest]
真实时间一定在此区间内
"""
pass
def after(self, timestamp) -> bool:
"""
判断时间戳是否确定已过去
即: earliest > timestamp
"""
return self.now().earliest > timestamp
def before(self, timestamp) -> bool:
"""
判断时间戳是否确定还未到来
即: latest < timestamp
"""
return self.now().latest < timestamp
3.2 时间区间 #
text
TrueTime.now() 返回 [earliest, latest]
示例:
├── 当前时间: 2024-03-27 10:00:00.000
├── 误差 ε: 5ms
├── earliest: 2024-03-27 09:59:59.995
├── latest: 2024-03-27 10:00:00.005
└── 真实时间一定在 [earliest, latest] 内
3.3 提交等待 #
python
# 事务提交流程
def commit_transaction():
# 1. 获取提交时间戳
s = max(commit_ts, TrueTime.now().latest)
# 2. 等待时间戳确定已过去
while not TrueTime.after(s):
wait()
# 3. 返回提交结果
return s
四、外部一致性 #
4.1 外部一致性定义 #
text
外部一致性保证:
├── 事务T1在事务T2之前提交
├── T1的提交时间戳 < T2的提交时间戳
├── 所有观察者看到相同的事务顺序
└── 跨区域全局一致
4.2 实现原理 #
text
外部一致性实现:
1. 事务T1获取提交时间戳 s1
2. 等待 TrueTime.after(s1) 为真
3. 返回T1提交结果
4. 事务T2开始,获取时间戳 s2 > s1
这保证了:
├── T1的提交时间戳确定已过去
├── T2的时间戳一定大于T1
└── 所有观察者看到相同顺序
4.3 与其他一致性对比 #
| 一致性级别 | 说明 |
|---|---|
| 线性一致性 | 单操作原子性 |
| 顺序一致性 | 单节点顺序 |
| 因果一致性 | 有因果关系的顺序 |
| 外部一致性 | 全局实时顺序 |
五、时间戳类型 #
5.1 提交时间戳 #
sql
-- 创建表时启用提交时间戳
CREATE TABLE logs (
log_id INT64 NOT NULL,
message STRING(MAX),
commit_ts TIMESTAMP OPTIONS (allow_commit_timestamp = true)
) PRIMARY KEY (log_id);
-- 插入时使用提交时间戳
INSERT INTO logs (log_id, message, commit_ts)
VALUES (1, 'Test message', PENDING_COMMIT_TIMESTAMP());
5.2 读取时间戳 #
java
// Java读取时间戳
import com.google.cloud.spanner.TimestampBound;
// 强读(最新时间戳)
client.singleUse().executeQuery(...);
// 指定时间戳读取
Timestamp timestamp = Timestamp.ofTimeMicroseconds(1234567890);
client.singleUse(TimestampBound.ofReadTimestamp(timestamp))
.executeQuery(...);
5.3 时间戳边界 #
java
// 最小过期读
TimestampBound.ofMinReadTimestamp(timestamp);
// 最大过期读
TimestampBound.ofMaxStaleness(10, TimeUnit.SECONDS);
// 精确过期读
TimestampBound.ofExactStaleness(10, TimeUnit.SECONDS);
六、应用场景 #
6.1 金融交易 #
java
// 金融交易需要严格的时间顺序
public void processTransaction(DatabaseClient client,
String fromAccount,
String toAccount,
double amount) {
client.readWriteTransaction().run(transaction -> {
// 转账操作
// TrueTime保证事务顺序
// 确保资金一致性
return null;
});
}
6.2 审计日志 #
sql
-- 使用提交时间戳记录操作时间
CREATE TABLE audit_logs (
log_id INT64 NOT NULL,
user_id INT64,
action STRING(100),
commit_ts TIMESTAMP OPTIONS (allow_commit_timestamp = true)
) PRIMARY KEY (log_id);
-- 插入审计日志
INSERT INTO audit_logs (log_id, user_id, action, commit_ts)
VALUES (1, 100, 'LOGIN', PENDING_COMMIT_TIMESTAMP());
6.3 时间点查询 #
sql
-- 查询特定时间点的数据
SELECT * FROM accounts
FOR SYSTEM_TIME AS OF TIMESTAMP '2024-03-27T10:00:00Z';
-- 查询时间范围内的数据
SELECT * FROM accounts
FOR SYSTEM_TIME BETWEEN
TIMESTAMP '2024-03-27T09:00:00Z' AND
TIMESTAMP '2024-03-27T10:00:00Z';
七、TrueTime监控 #
7.1 关键指标 #
text
TrueTime监控指标:
├── clock_skew: 时钟偏差
├── time_error: 时间误差
├── commit_wait_time: 提交等待时间
└── timestamp_bound: 时间戳边界
7.2 查看时间误差 #
sql
-- 通过系统表查看
SELECT * FROM INFORMATION_SCHEMA.INSTANCES;
7.3 监控建议 #
text
监控建议:
├── 监控时钟偏差
├── 监控提交等待时间
├── 设置告警阈值
└── 定期检查时钟同步状态
八、TrueTime限制 #
8.1 误差影响 #
text
误差影响:
├── 提交等待时间: 等待时间戳确定已过去
├── 事务延迟: 增加事务提交延迟
├── 跨区域延迟: 更大的时间误差
└── 需要合理规划部署
8.2 最佳实践 #
text
TrueTime最佳实践:
├── 减少跨区域事务
├── 批量操作减少事务次数
├── 使用只读事务
├── 合理设置时间戳边界
└── 监控时钟同步状态
九、总结 #
TrueTime核心要点:
| 要点 | 说明 |
|---|---|
| 时间区间 | [earliest, latest] |
| 误差 | 通常1-10ms |
| 外部一致性 | 全局实时顺序 |
| 提交等待 | 确保时间戳已过去 |
最佳实践:
text
1. 理解时间误差
└── 真实时间在区间内
2. 使用提交时间戳
└── 记录精确操作时间
3. 监控时钟状态
└── 确保时钟同步
4. 优化事务设计
└── 减少提交等待影响
5. 利用时间点查询
└── 历史数据访问
下一步,让我们学习索引!
最后更新:2026-03-27