一个ID引起的血案
一个少见的丢单问题
最近遇到一个少见的丢单问题:
2个订单在同一秒下单,产生的订单ID居然是一样的!
经过一番查找,问题的原因在生产ID的工具类实现算法有漏洞,关键方法源码如下:
1 | public class LongId { |
这个方法是参考Twitter Snowflake(一个来自Twitter的分布式ID算法)的java实现.
确定问题的方法是重现问题,幸好这个工具类是孤独的,:) ,所以写个单元测试还是比较简单的.
测试代码如下,简单来说就是模拟同一时间有多少生产ID的并发请求,当出现重复ID的时候测试失败.
1 | public class LongIdTest { |
测试结果,当并发次数为1000次的时候,很容易重现问题.
虽然源码通过 shiftedTimestamp | random 来保证每次产生的ID是不一样的,但是实验结果表面尽管shiftedTimestamp和random每次都是不一样的,
但是与运算的结果却可能是一样的,知道问题原因就好处理了.
重新写了一个新的ID生产算法工具类如下,在规定的时间内缓存生产的ID,如果出现重复就重新生成.
1 |
|
同样用相同的测试代码来测试,测试1000,10000次都通过测试,Issue Fixed !
1 |
|