分布式 ID 生成中的时钟漂移治理
风险根源 基于时间戳的 ID 方案在时钟回拨时可能生成重复 ID,影响去重、排序和分库分表路由。 治理策略 本地单调时钟优先,墙钟只用于校准。 发现回拨后进入保护模式:阻塞、切序列段或切机房位。 强制 NTP 漂移告警与节点摘除。 业务层补偿 关键写入加唯一约束兜底。 为 ID 冲突暴露独立错误码,支持快速定位。 小结 ID 生成器不是纯算法组件,它是时间系统的一部分。时钟治理做不好,任何高并发优化都会失效。
风险根源 基于时间戳的 ID 方案在时钟回拨时可能生成重复 ID,影响去重、排序和分库分表路由。 治理策略 本地单调时钟优先,墙钟只用于校准。 发现回拨后进入保护模式:阻塞、切序列段或切机房位。 强制 NTP 漂移告警与节点摘除。 业务层补偿 关键写入加唯一约束兜底。 为 ID 冲突暴露独立错误码,支持快速定位。 小结 ID 生成器不是纯算法组件,它是时间系统的一部分。时钟治理做不好,任何高并发优化都会失效。
先回答三个问题 新写对象是否读后可见? 覆盖写是否存在短暂旧读? 跨地域复制的延迟窗口是多少? 业务协议建议 写入时带版本号(ETag/VersionId)。 读取时声明期望版本,不满足则重试或降级。 删除采用 tombstone 而非立即硬删。 典型流程 PUT(v2) -> 返回version=v2 -> GET(if-match=v2) -> 成功 多地域策略 强一致需求走单主写入。 多主写入必须引入冲突解决策略(LWW 或 CRDT)。 对外暴露“可见性延迟”SLO,避免误判故障。 小结 对象存储的一致性不是文档注释,而是业务协议的一部分。把版本语义显式化,读写行为才可预测。
常见误解 启用 Kafka EOS 后,很多团队默认“不会重复消费”。实际上,数据库写入、HTTP 调用等外部副作用仍可能重复。 EOS 真正保证什么 Producer 端幂等写入(同一会话内去重)。 事务内“写输出 + 提交消费位点”原子性。 只在 Kafka 生态内部有效。 仍需业务补齐 下游写库使用幂等键(业务主键或事件 ID)。 外部调用提供去重令牌。 失败重试具备可重入语义。 处理流程建议 consume -> validate -> execute(idempotent) -> produce -> commit offsets 任何一步失败都可重试,且不会造成不可逆双写。 小结 EOS 不是银弹,而是基础设施层的“至少一次到一次”的收敛器。业务副作用一致性仍需你自己设计。
为什么会“越跑越慢” Raft 日志长期不压缩会拖慢重放与追赶;但压缩过于激进又会让慢 follower 频繁走全量快照,网络和磁盘双杀。 压缩策略建议 用“日志条目数 + 磁盘占用”双阈值触发快照。 快照频率按写入速率自适应,而不是固定分钟数。 仅在 commit index 安全推进后截断日志。 安装快照时的工程点 分块传输并带 offset 校验。 最后一块再原子切换状态机数据目录。 快照应用期间限制客户端写入峰值。 Go 侧接口设计 type SnapshotStore interface { Create(meta SnapshotMeta) (io.WriteCloser, error) Open(id string) (io.ReadCloser, SnapshotMeta, error) List(limit int) ([]SnapshotMeta, error) } 常见故障 截断日志早于快照持久化完成,导致节点重启后状态缺口。 快照元数据未纳入 WAL,断电恢复后索引错位。 对慢 follower 缺少限流,拖累 leader。 小结 Raft 的可用性不只来自选主,更来自“日志、快照、复制窗口”三者的节奏匹配。压缩策略设计得当,集群才能长期平稳运行。