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

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

  •  
  •   jiobanma ·
    banmajio · 289 天前 · 8303 次点击
    这是一个创建于 289 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    第 1 条附言  ·  288 天前
    解释一下为什么要求递增,已经目前的现状
    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  
       288 天前
    哈哈,改算法把 workId 放到 id 尾部的方式是不符合 OP 要求的递增,我的方案对项目改动最小
    aragakiyuii
        102
    aragakiyuii  
       288 天前 via iPhone
    uuid version1
    sillydaddy
        103
    sillydaddy  
       288 天前
    「代码中存在大量的根据雪花算法生成的 id 排序比大小的操作」。
    问题是,你把 workerID 改了,也不影响这种排序比较啊!!因为对于分布式应用来说,数据的产生本来就没有绝对的先后顺序。无论你怎么设置新生的数据的顺序,都是合理的啊!

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

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

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

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

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

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