咨询各位大佬们一个问题目前有两台服务器负载,使用 apache 的 SnowflakeShardingKeyGenerator 生成雪花算法作为 id ,业务上需要生成的 id 是递增的。 之前两台服务器的 SnowflakeShardingKeyGenerator 的 workId 都是默认的,高并发情况下,两台服务器的时间可能会有误差 就会导致生成的 id 是重复的。但是两台服务器根据不同的 workId 去生成虽然能解决重复的问题,但是会导致生成的 id 不是连续递增的。 有什么其他的方式实现吗(排过坑的[旺柴])。
101
daye 2023-07-26 11:24:42 +08:00
哈哈,改算法把 workId 放到 id 尾部的方式是不符合 OP 要求的递增,我的方案对项目改动最小
|
102
aragakiyuii 2023-07-26 11:25:41 +08:00 via iPhone
uuid version1
|
103
sillydaddy 2023-07-26 11:25:54 +08:00
「代码中存在大量的根据雪花算法生成的 id 排序比大小的操作」。
问题是,你把 workerID 改了,也不影响这种排序比较啊!!因为对于分布式应用来说,数据的产生本来就没有绝对的先后顺序。无论你怎么设置新生的数据的顺序,都是合理的啊! 你们公司的应用,对 2 台机器产生的新数据的排序标准是啥? 你们公司的应用,需要按照绝对时间来排序吗? 你们公司的应用,是抢票程序吗? 你确定,绝对时间存在吗? |
105
vevlins 2023-07-26 11:35:23 +08:00
严格递增,提前生成一批放在 redis 里面,每次 pop 出来一个呢
|
107
leonshaw 2023-07-26 11:43:53 +08:00
@zhh0000zhh #94 严格来说问题本身就是不准确的,两个类空间隔的事件在不同参考系看来可能有不同的顺序(两台相对静止的服务器所处引力场不同,参考系也会不同),所以分配 ID 应该以哪个参考系观测到的顺序为准?回答了这个问题就等于引入了一个参考系作为仲裁。
|
108
sillydaddy 2023-07-26 11:45:53 +08:00
我能想像到,这个困境的大概来源了:
OP 公司的代码逻辑很可能是,用 id 的大小比较,去作为事件发生先后(时序)的依据。 这种代码逻辑,当然可以用全局递增的 id 这种方案来解决。不过也可以用其他方案来解决啊,比如保证后续任务的 id 比前置任务的 id 要大,即使分配到了不同的负载。例如可以在一台机器上提前生成任务的 id ,把 id 传递给其他负载。 用全局递增 id 的方案来解决,相比之下就是傻大黑粗! |
109
zpfhbyx 2023-07-26 12:12:48 +08:00
自己写个 list 啊. 然后线性生成 id 扔到 list 里面. 都从这个取就行了.无非就是维护一个池子..
|
110
ashuai 2023-07-26 13:19:48 +08:00
给服务器 id ,强性伸缩的话用自发现服务分配 id ,一个 byte 循环用就行,所谓的全局唯一 id 用服务器 id 加时间戳就行
|
111
yaodong0126 2023-07-26 15:22:54 +08:00
@mineralsalt 多运行一个服务和使用 redis 加锁有本质区别,之所以使用 ID 生成服务,那就说明业务使用 redis 已经无法满足当前需求,你觉得没区别是因为你的业务量级并没有达到需要一个 ID 生成服务的程度
另外,你说的几个缺点,如果一个公司的业务到达这个规模,还在纠结几百兆内存的话,那还是倒闭算了,而且谁也没有规定这个服务必须使用 java ,你觉得 java 消耗内存,那选择其他的就是了 你最后提到的一点,“但是一个小项目”,显然和题主的需求严重冲突,没必要强行回答,甚至于说一个小项目我连 redis 都不需要就可以实现一个唯一 ID 生成的功能 |
112
qingshengwen 2023-07-26 16:52:44 +08:00
@jiobanma #49 并不能理解,我的意思跟 @lovelylain 一样,时间戳是在最高位的,一定能做到大致自增。所以得看你雪花算法的具体实现
|
113
bisyao 2023-07-26 20:51:23 +08:00
用 zookeeper 。它就是为了解决此类问题(全局序 total order) 而生的。
|
114
bisyao 2023-07-26 20:53:40 +08:00
如果不要求全局序,可以考虑使用 lamport timestamp ,保证因果顺序。
|