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

如何在并发场景下安全设置实例编号

  •  
  •   Fu4ng · 2021-07-02 10:53:55 +08:00 · 1734 次点击
    这是一个创建于 1231 天前的主题,其中的信息可能已经有所发展或是发生改变。
    遇到一个不大不小的问题,虽然目前这个方法能解决一般场景。
    但总觉得有更巧妙的解法。

    背景:
    需要保证服务实例编号唯一,
    如果是实例编号重复,则有风险产生重复的编号

    目前解决办法:

    实例初始化时,按序执行以下步骤
    1.无脑 setNX(key,0,永不过期),确保实例能取到值
    2.val := incrby(key,1)
    3.对 val 取余 1000,设为实例编号

    存在问题:
    1.如果在一台实例挂了 1000 次,则会和其他实例编号重复
    12 条回复    2021-07-02 16:49:57 +08:00
    BBCCBB
        1
    BBCCBB  
       2021-07-02 11:00:23 +08:00   ❤️ 1
    snowflake 吗?

    1. 如果在同一个局域网, 可以用 ip 来判定吧?
    2. 启动时数据库插入一条纪录. 可以参考 uid-generator
    3. zk 这种? 参考美团 leaf.
    swulling
        2
    swulling  
       2021-07-02 11:13:35 +08:00
    UUID4 就挺好的,唯一 ID 除非业务真的有需求(比如单调递增),否则建议都用 UUID 。
    Fu4ng
        3
    Fu4ng  
    OP
       2021-07-02 11:18:21 +08:00
    @BBCCBB 感谢老哥。
    1.因为跨机房所以不能用第一个方法。
    2.引入数据库有点太重了。
    3.不想引入太多依赖,在想能不能只使用 redis 解决。
    yufpga
        4
    yufpga  
       2021-07-02 11:48:40 +08:00
    我不明白为什么要取余数. 按照现有的逻辑,可以在 redis 中维护一个已使用的编号集合,先取号,然后 sadd {:key:} {:取的号:}, 如果 sadd 返回值是 1, 说明该号没有被占用,取号成功; 如果返回值是 0,说明该号已被占用,取号失败,就继续取。关键在于要处理实例下线之后,要将下线实例从集合中剔除。
    cpstar
        5
    cpstar  
       2021-07-02 11:58:07 +08:00
    实例编号,UUID 一劳永逸。
    递增的编号,除了人阅读起来好看,机器处理起来,1 和 2 这两个实例,哪台设备能知道这两个是有所谓的先后顺序,就是两个字符而已。
    err1y
        6
    err1y  
       2021-07-02 12:05:09 +08:00 via iPhone
    uuid
    Fu4ng
        7
    Fu4ng  
    OP
       2021-07-02 12:43:56 +08:00
    @yufpga 业务逻辑里生成的单号 留给实例编号的位数 的三位
    Jooooooooo
        8
    Jooooooooo  
       2021-07-02 15:14:04 +08:00
    搜一下雪花

    如果不太要求长度, 拿到当前时间(毫秒) + 设备自身编号 + 随机数 几乎不可能重复
    aitaii
        9
    aitaii  
       2021-07-02 15:18:47 +08:00
    雪花算法,分布式部署,加上机器号唯一标识,一毫秒生成 4194304 个不同 id
    链接: https://zhuanlan.zhihu.com/p/85837641
    atalia
        10
    atalia  
       2021-07-02 16:13:39 +08:00
    为什么要取余 1000,只有 3 个字符串大小的编号吗
    clf
        11
    clf  
       2021-07-02 16:29:11 +08:00
    雪花算法+1

    自定义 workerId 和 datacenterId,我一般用 datacenterId 区分服务器,workerId 区分业务;生成的 ID 呈现增长趋势,存入数据库后检索效率也不错。
    sunjiayao
        12
    sunjiayao  
       2021-07-02 16:49:57 +08:00
    取硬件 CPU 的序列号去 Redis 注册下吧。自己实现个自增序列号
    如果一台机器部署多个服务需要手动配置下服务编号(或者根据序列号 + 服务监听的端口作为硬件唯一标识)
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1027 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 22:03 · PVG 06:03 · LAX 14:03 · JFK 17:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.