Hinted Handoff
分布式系统的节点不是铁打的。网络抖动、机器宕机、磁盘故障——各种问题都会导致节点暂时不可用。在无主复制系统中,当某个节点故障时,写入请求去哪了?数据会不会丢失?
Hinted Handoff(临时转交)就是解决这个问题的一种机制:故障期间,其他节点代为处理本该写入故障节点的请求,并记录一个「提示」(Hint),等故障节点恢复后再归还数据。这是一种优雅的「先欠着,后面还」策略。
问题的核心
在无主复制中(如 Dynamo、Cassandra),数据按照一致性哈希分布在 N 个节点上:
当节点 2 故障时:
- 本该写入节点 2 的数据(key=B)应该去哪?
- 如果直接丢弃,节点 2 恢复后数据就丢失了
- 如果等待节点 2 恢复,系统写入吞吐下降
Hinted Handoff 的原理
核心思想
当协调节点发现目标节点不可用时:
- 选择一个备用节点代为写入
- 记录 Hint:包含目标节点 ID、原始数据、写入时间
- 写入成功后返回客户端:写入没有失败,用户无感知
- 故障节点恢复后:从 Hint 中读取数据,归还到正确的节点
Hint 的数据结构
Cassandra 中的 Hinted Handoff
Cassandra 是 Hinted Handoff 应用最广泛的系统之一。让我看看它的具体实现。
配置参数
写入 Hint 的流程
Hint 归还(Hint Replay)
禁用特定表的 Hinted Handoff
Cassandra 允许对特定表禁用 Hinted Handoff:
禁用 Hinted Handoff 后,如果目标节点在写入期间不可用,该数据可能永久丢失。如果业务对数据持久性要求高,需要使用 CONSISTENCY ALL 或应用层重试策略。
Hint 过期与数据修复
Hint 的生命周期
Hint 过期后的数据修复
当 Hint 过期被丢弃后,故障节点恢复时数据可能不完整。这时依赖 Anti-Entropy(反熵)和 Read Repair(读修复)来恢复数据:
- Read Repair:下次读取时发现不一致,主动修复
- Anti-Entropy:后台定期检查并修复不一致
这些机制在下一章会详细讲解。
真实案例:节点重启后的数据恢复
某社交平台 Cassandra 集群的 Hinted Handoff 实践
场景:凌晨 3 点,3 节点 Cassandra 集群的节点 2 因内存故障重启。
处理过程:
故障检测(T+0s):节点 2 无响应,Gossip 协议在 10 秒内检测到
写入接管(T+0s ~ T+30min):
- 期间写入节点 2 的数据全部写入节点 3,并生成 Hint
- Hint 存储在
/var/lib/cassandra/hints/目录- Hint 总数:约 50,000 条
节点恢复(T+30min):
- 节点 2 重启上线
- Hinted Handoff 服务自动扫描 Hint 目录
数据归还(T+30min ~ T+45min):
- 节点 3 逐条将 Hint 数据发送给节点 2
- 节点 2 接收并写入 MemTable
完成验证(T+60min):
nodetool repair执行全量一致性校验- 所有数据恢复一致
Hinted Handoff 与 Quorum 的配合
写入流程整合
失效后降级处理
当 Hinted Handoff 也无法满足时,系统需要降级处理:
权衡矩阵
Hinted Handoff 的局限性
1. 无法处理永久故障
Hint 是临时的,如果节点永久离开集群:
- Hint 过期被丢弃
- 数据永久丢失
- 需要其他副本恢复(如 Anti-Entropy)
2. Hint 丢失
Hint 存储在磁盘上,如果备用节点也故障:
- Hint 可能丢失
- 数据需要从其他途径恢复
3. Hint 重放顺序
Hint 重放可能不按原始顺序进行,对有依赖关系的数据可能有问题:
4. 跨数据中心延迟
跨数据中心 Hinted Handoff 延迟高,Hint 传输可能失败:
术语表
总结
Hinted Handoff 是无主复制系统中保证数据持久性的重要机制。它的核心思想是「临时接管、后面归还」:
- 故障期间:备用节点代写 + 记录 Hint
- 节点恢复:从 Hint 中恢复数据到目标节点
- Hint 过期:依赖 Read Repair 和 Anti-Entropy 兜底
但 Hinted Handoff 不是万能的:
- 无法处理永久故障
- Hint 本身可能丢失
- Hint 重放顺序可能有问题
下一章我们将讲解 Anti-Entropy(反熵),看看系统如何主动检测和修复副本间的数据不一致。