V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
jiobanma
V2EX  ›  Java

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

  •  
  •   jiobanma ·
    banmajio · 2023-07-25 14:53:59 +08:00 · 9056 次点击
    这是一个创建于 487 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    第 1 条附言  ·  2023-07-26 09:09:07 +08:00
    解释一下为什么要求递增,已经目前的现状
    1. 历史原因,开发初期的同事没有考虑到负载已经后续并发的问题。项目最初的时候是单节点的所以还不会出现什么明显的问题。加上代码中存在大量的根据雪花算法生成的 id 排序比大小的操作。而目前换成了负载,两个节点轮训分担压力。就会导致两个节点生成的 id 会有碰撞的可能。别问为啥一定要求递增,问就是不想改动别人的之前写的逻辑,给自己挖坑。
    2. 出现重复的原因,a 用户的请求分发到了 A 节点,此时 b 用户的请求分发到了 B 节点,两个节点同时生成的 id 就出现碰撞的问题。

    3. 还有说使用有问题的各位,op 确实对雪花算法不太熟悉,没那么深入的了解,所以才发这个问题请教,抱着学习的太多。麻烦各位嘴下留情!
    114 条回复    2023-07-26 20:53:40 +08:00
    1  2  
    daye
        101
    daye  
       2023-07-26 11:24:42 +08:00
    哈哈,改算法把 workId 放到 id 尾部的方式是不符合 OP 要求的递增,我的方案对项目改动最小
    aragakiyuii
        102
    aragakiyuii  
       2023-07-26 11:25:41 +08:00 via iPhone
    uuid version1
    sillydaddy
        103
    sillydaddy  
       2023-07-26 11:25:54 +08:00
    「代码中存在大量的根据雪花算法生成的 id 排序比大小的操作」。
    问题是,你把 workerID 改了,也不影响这种排序比较啊!!因为对于分布式应用来说,数据的产生本来就没有绝对的先后顺序。无论你怎么设置新生的数据的顺序,都是合理的啊!

    你们公司的应用,对 2 台机器产生的新数据的排序标准是啥?
    你们公司的应用,需要按照绝对时间来排序吗?
    你们公司的应用,是抢票程序吗?
    你确定,绝对时间存在吗?
    daye
        104
    daye  
       2023-07-26 11:26:12 +08:00
    @Aresxue 哈哈,改算法把 workId 放到 id 尾部的方式是不符合 OP 要求的递增,我的方案对项目改动最小
    vevlins
        105
    vevlins  
       2023-07-26 11:35:23 +08:00
    严格递增,提前生成一批放在 redis 里面,每次 pop 出来一个呢
    pkwenda
        106
    pkwenda  
       2023-07-26 11:41:25 +08:00
    @trzzzz 因为分表了
    leonshaw
        107
    leonshaw  
       2023-07-26 11:43:53 +08:00
    @zhh0000zhh #94 严格来说问题本身就是不准确的,两个类空间隔的事件在不同参考系看来可能有不同的顺序(两台相对静止的服务器所处引力场不同,参考系也会不同),所以分配 ID 应该以哪个参考系观测到的顺序为准?回答了这个问题就等于引入了一个参考系作为仲裁。
    sillydaddy
        108
    sillydaddy  
       2023-07-26 11:45:53 +08:00
    我能想像到,这个困境的大概来源了:

    OP 公司的代码逻辑很可能是,用 id 的大小比较,去作为事件发生先后(时序)的依据。

    这种代码逻辑,当然可以用全局递增的 id 这种方案来解决。不过也可以用其他方案来解决啊,比如保证后续任务的 id 比前置任务的 id 要大,即使分配到了不同的负载。例如可以在一台机器上提前生成任务的 id ,把 id 传递给其他负载。

    用全局递增 id 的方案来解决,相比之下就是傻大黑粗!
    zpfhbyx
        109
    zpfhbyx  
       2023-07-26 12:12:48 +08:00
    自己写个 list 啊. 然后线性生成 id 扔到 list 里面. 都从这个取就行了.无非就是维护一个池子..
    ashuai
        110
    ashuai  
       2023-07-26 13:19:48 +08:00
    给服务器 id ,强性伸缩的话用自发现服务分配 id ,一个 byte 循环用就行,所谓的全局唯一 id 用服务器 id 加时间戳就行
    yaodong0126
        111
    yaodong0126  
       2023-07-26 15:22:54 +08:00
    @mineralsalt 多运行一个服务和使用 redis 加锁有本质区别,之所以使用 ID 生成服务,那就说明业务使用 redis 已经无法满足当前需求,你觉得没区别是因为你的业务量级并没有达到需要一个 ID 生成服务的程度

    另外,你说的几个缺点,如果一个公司的业务到达这个规模,还在纠结几百兆内存的话,那还是倒闭算了,而且谁也没有规定这个服务必须使用 java ,你觉得 java 消耗内存,那选择其他的就是了

    你最后提到的一点,“但是一个小项目”,显然和题主的需求严重冲突,没必要强行回答,甚至于说一个小项目我连 redis 都不需要就可以实现一个唯一 ID 生成的功能
    qingshengwen
        112
    qingshengwen  
       2023-07-26 16:52:44 +08:00
    @jiobanma #49 并不能理解,我的意思跟 @lovelylain 一样,时间戳是在最高位的,一定能做到大致自增。所以得看你雪花算法的具体实现
    bisyao
        113
    bisyao  
       2023-07-26 20:51:23 +08:00
    用 zookeeper 。它就是为了解决此类问题(全局序 total order) 而生的。
    bisyao
        114
    bisyao  
       2023-07-26 20:53:40 +08:00
    如果不要求全局序,可以考虑使用 lamport timestamp ,保证因果顺序。
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1004 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 23:09 · PVG 07:09 · LAX 15:09 · JFK 18:09
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.