背景
在一次Uat 环境测试中,出现主键冲突异常,明明昨天测试都是正常的。多试了几笔发现生成的主键 ID 确实已经重复了,且该 ID 是在今天上午十点生成的,很奇怪。
排查过程
该分布式 ID 生成器是借助 Zookeeper 来实现的,发现Uat 环境 ZK 配置的 Host 与 Prod 环境不同。而Uat 与 Prod 又是共连相同的库表。那这出现主键冲突是几乎不可避免的。
但是为什么之前一直没冲突呢?
查阅该分布式 ID 源码分析其生成原理可得,如下
由上面逻辑分析,在项目第一次上线后是肯定会出现主键冲突问题。
假设 UAT 服务分配 ID 为:20240807000000001001 开始自增
PROD POD1:20240807000000001001
PROD POD2:20240807000000002001
PROD POD3:20240807000000003001
PROD POD4:20240807000000004001
其中 UAT 与PROD POD1之间生成的主键 ID 是肯定会出现冲突的。那为什么使用过一段时间后就不会冲突呢?因为在随着项目的重新发布次数再加上 PROD 环境主键迅速自增,其自增值会远远大于 UAT 维护的自增值,从而极大的避开了冲突的发生。
那好,按照上面的理论发生主键冲突理论上应该也就是处于项目第一次上线的初期才可能发生,那随着后期 PROD 将自增值拉大理论上就不可能出现冲突了,但是又为什么还是发生了呢?
该问题是因为我司一次故障排查过程中,运维将生产 ZK 的缓存清理了一次,导致生产生成的自增序列又被重置了然后慢慢的PROD 的自增序列很快又追上了 UAT 的自增序列因此引发了上面问题
总结
在设计分布式 ID 生成算法时还是应为多加入唯一元素,参考雪花算法,加入更长的时间戳、机器码、序列号来最大程度保证唯一性