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

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

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

9642 次点击
所在节点    Java
114 条回复
dddd1919
2023-07-25 16:39:43 +08:00
所有服务连同一个 redis ,使用同一个 key 的 incr 生成 id ,既能自增又分布式
mineralsalt
2023-07-25 16:51:20 +08:00
@yaodong0126 #39 多运行一个服务和使用 redis 加锁没有本质区别, 一般后端项目都会引入 redis, 所以几乎是没有额外成本的. 另外我简单说一下多运行一个服务的缺点.
1. 浪费内存, java 后端项目启动就几百兆
2. 稳定性降低, 本来他是分布式部署的项目强行被这个单点服务拖累了, 一旦这个服务挂掉, 其他服务都 GG
3. 开发任务多了, 多维护一个模块, 也要多上线一个实例

当然这是一个好的解决方案, 但是一个小项目, 我还是秉承着资源最小化的理念, 不要过多的引入服务和模块
wendellup2018
2023-07-25 17:03:25 +08:00
@mineralsalt 还是有区别的, 每个项目都引入 redis, 连接数要爆掉了。引入项目可以增加网关控制调用。
quantal
2023-07-25 17:04:14 +08:00
直接用 ULID 吧,生成的 id 带时间戳精确到毫秒,毫秒级有序
luciankaltz
2023-07-25 17:06:21 +08:00
@dddd1919 热点 key 警告(
IDAEngine
2023-07-25 17:48:08 +08:00
@jiobanma 那直接用比特币钱包地址生成算法
jiobanma
2023-07-25 17:49:46 +08:00
@luciankaltz #45 了解的有点少,想问下热点 key 可能会导致哪些问题
jiobanma
2023-07-25 18:02:38 +08:00
@tabris17 #21 “自增” 和 “ 递增” 是有区别的,注意看
jiobanma
2023-07-25 18:07:05 +08:00
@qingshengwen #30
public static Comparable<?> geneSnowFlakeIDByWorkId(String workId) {
shardingKeyGenerator.getProperties().setProperty("worker.id", workId);
return shardingKeyGenerator.generateKey();
}


public static void main(String[] args) {
System.out.println(geneSnowFlakeIDByWorkId("100")); // 890660284086501376
System.out.println(geneSnowFlakeIDByWorkId("200")); // 890660284095299585
System.out.println(geneSnowFlakeIDByWorkId("100")); // 890660284094889986
System.out.println(geneSnowFlakeIDByWorkId("200")); // 890660284095299587
}

这样是不就理解了
wangxiaoaer
2023-07-25 18:07:51 +08:00
也没有大佬解释下 1 楼的方案?目前两台雪花算法在高并发下会重复,说明业务并发还是不低的,再加一个专门生成 id 的服务,是不是还是调用雪花服务器?如果这样的话这个服务就会面临瓶颈,服务如果再通过集群搞成分布式,感觉会面临同样的问题啊。
joesonw
2023-07-25 18:23:24 +08:00
通过一个中心服务器拿自增号码段

https://cloud.tencent.com/developer/article/1352896
lovelylain
2023-07-25 18:23:26 +08:00
@jiobanma 自己实现,时间戳放最高位,自增数放中间,workid 放最低位
hsymlg
2023-07-25 18:42:09 +08:00
单调递增和趋势递增是 2 个概念,1L 其实就是解决方案,再起一个服务专门做 id 生成,另外其他楼说的美团的 leaf ,那个玩意儿的基于号段的和雪花的也是 2 种不同场景,要注意甄别
IDAEngine
2023-07-25 18:49:25 +08:00
@wangxiaoaer 他这个两台服务器的 machine id 用的同一个,当然有重复的可能性。
luciankaltz
2023-07-25 19:04:01 +08:00
@jiobanma 想象一下你对一张表的数据行做 10 次 update 。如果是 10 条记录,那么这些操作之间不会有并发锁问题;如果 10 次更新的是一条记录,那么 10 次操作会退化成串行执行

热点问题会直接导致各种分片或者分布策略失效,大多数情况下直接退化到单机性能(甚至可能影响到其他的操作
xiangyuecn
2023-07-25 19:28:58 +08:00
一言难尽
说不懂吧,又用上了雪花 id 算法
说懂吧,又不给服务器分配唯一编号🐶
leonshaw
2023-07-25 19:37:32 +08:00
不知道你业务顺序是怎么定义的?
两个不相关的客户端几乎同时发送的请求本身就是没有顺序的,网络随便抖一下到服务器的顺序就变了,更不要说还有相对论了。技术上讲,事件先后只有在同一个点比较才有意义,你分 ID 的时候就是要保证和这个顺序一致。比如来自同一个连接的请求在同一个线程处理。
sampeng
2023-07-25 19:54:17 +08:00
lz 始终没解释为啥一定要递增。
产品需求?只有疯了的产品才关注这个。leader 的需求?那是技术不太行…
dayudayupao
2023-07-25 19:57:58 +08:00
@veike 万万不可,会降低 b 树的效率,降低 pagecache 的利用率
chenluo0429
2023-07-25 20:21:18 +08:00
1. 给定正确的 workerId ,
2. 雪花算法中将代表时间的段放在高位

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

https://yangjunhui.monster/t/959560

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

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

© 2021 V2EX