分布式系统生成全局唯一 ID 的方式请教

2023-07-25 14:53:59 +08:00
jiobanma  jiobanma

咨询各位大佬们一个问题目前有两台服务器负载,使用 apache 的 SnowflakeShardingKeyGenerator 生成雪花算法作为 id ,业务上需要生成的 id 是递增的。 之前两台服务器的 SnowflakeShardingKeyGenerator 的 workId 都是默认的,高并发情况下,两台服务器的时间可能会有误差 就会导致生成的 id 是重复的。但是两台服务器根据不同的 workId 去生成虽然能解决重复的问题,但是会导致生成的 id 不是连续递增的。 有什么其他的方式实现吗(排过坑的[旺柴])。

9359 次点击
所在节点   Java  Java
114 条回复
my3157
my3157
2023-07-25 14:57:16 +08:00
用一个专门的服务批量生成 ID , 其他服务直接从这个服务拿
mineralsalt
mineralsalt
2023-07-25 14:57:28 +08:00
没用过 SnowflakeShardingKeyGenerator, 但是如果是我实现这样的需求, 能想到 2 种办法, 第一就是 redis 加锁, 但是会影响并发效率. 第二种就是发现 id 重复时递归生成一次,直到不重复为止
mineralsalt
mineralsalt
2023-07-25 14:59:29 +08:00
1L 这种多引入一个服务感觉太重了, 多一个服务就多一份负担和不稳定性, 不是太优雅
thevita
thevita
2023-07-25 15:25:10 +08:00
2L 提的第一个方法与 1L 本质上是一样的,都是引入一个全局一致的协调者(目前看这其实是比较现实的办法,功能简单,稳定性和性能应该能做很多优化,当然具体看你场景能否接受)
thevita
thevita
2023-07-25 15:29:04 +08:00
2L 第二种也是一个办法,相当于 用 db 作为一致性保证?,乐观冲突检测的方式来做,但是 db 的事务的貌似还是得依赖全局锁的方式来支持 insert id 有序
zhzy0077
zhzy0077
2023-07-25 15:29:11 +08:00
2 台服务器能承载的业务直接用数据库的 auto increment 不行吗
CocaCola001
CocaCola001
2023-07-25 15:31:19 +08:00
我觉得还是新建一个服务用来生成 id 比较好,后期也方便扩展
thevita
thevita
2023-07-25 15:31:30 +08:00
还不如看看你的需求只是要 “递增“ 呢,还是真的需要严格的全局有序
SenLief
SenLief
2023-07-25 15:32:42 +08:00
有没有考虑过最简单的方案,使用一个大数,一台往上递增,一台往下递增
luciankaltz
luciankaltz
2023-07-25 15:34:57 +08:00
> 两台服务器的时间可能会有误差 就会导致生成的 id 是重复的

snowflake 算法初始化的时候会填入一个 machine id ,为什么两台服务器上生成出来的 id 会重复呢(
还是说你故意设置成了一样的 machine id ,是希望所有生成出来的 id 在全局上单调递增并且唯一?

如果是的话那就必须引入一个单点的算号服务,不管是一个 app 服务还是 db 的自增
veike
veike
2023-07-25 15:35:33 +08:00
ulid 可行?
Masoud2023
Masoud2023
2023-07-25 15:36:40 +08:00
想了半天为什么这东西能重复,一仔细看帖子原来没改 workerId...

你如果非想要连续递增的 id ,那么只能考虑做个服务专门搞这种自增

是不是某些架构设计出问题了,感觉不应该有这种问题..
thevita
thevita
2023-07-25 15:36:49 +08:00
想到一个比较破的方案:

就是你在 db 里面 预先 “生成, 分配” 一批 id (假设这里你的 全局有序 id 是主键)

这样就能让服务来`抢` next id, 对 行加锁了,并发应该会好一些,

就是不能回滚,需要让签名的 id 失效
jiobanma
jiobanma
2023-07-25 15:38:27 +08:00
@mineralsalt #2
@thevita #4
@CocaCola001 #7 这个比较简单 缺点就是可能会有性能问题已经服务掉线之后的问题
@luciankaltz #10 目前都是默认的 没有传参,所以你说的 machine id 应该是个默认值,两台服务器应该是一样的值
@veike #11 uuid 缺点太多了
nekolr
nekolr
2023-07-25 15:40:06 +08:00
大致上是趋势递增的就可以了呀,或者像楼上几位说的,独立出来一个服务
dw2693734d
dw2693734d
2023-07-25 15:41:20 +08:00
@jiobanma 能讲讲 uuid 缺点吗
bugmakerxs
bugmakerxs
2023-07-25 15:41:57 +08:00
https://github.com/Meituan-Dianping/Leaf/blob/master/README_CN.md
为什么要连续?简单点引入这个就行
nekolr
2023-07-25 15:43:10 +08:00
@nekolr 没注意看楼主要求,楼主想要的是严格的单调递增是吗?如果是用雪花的话,那只能独立出来一个服务
silentsky
2023-07-25 15:43:11 +08:00
很简单的事情 搜 Redisson IdGenerator
bugmakerxs
2023-07-25 15:44:27 +08:00
另外的简单方案是 timestamp + (redis.incr(key) % 100000)
服务器时钟用 ntp 同步

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/959560

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX