分享一个 id 自增生成器,依赖于 redis,求大佬帮忙挑挑毛病 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
flycloud
V2EX    程序员

分享一个 id 自增生成器,依赖于 redis,求大佬帮忙挑挑毛病

  •  
  •   flycloud 2021-09-17 10:08:03 +08:00 6703 次点击
    这是一个创建于 1534 天前的主题,其中的信息可能已经有所发展或是发生改变。

    看了雪花算法,服务需要配置标识位(数据中心 ID 、机器 ID ),多一项配置就多一份出错的风险,同时在不依赖其他基础服务的情况下也不太好解决时间回调的问题。然后自己实现了一个简化版的,依赖于 redis 。大佬们帮忙看看有啥问题没有,感谢。

    func GlobalIncrId() (int64, error) { script := redis.NewScript(` local key = KEYS[1] local stamp = ARGV[1] local newValue = redis.call("incr", key) if newValue then if newValue > tonumber(stamp) then return newValue else local flag = redis.call("set", key, stamp) if flag then return stamp end end end return nil `) stamp := (time.Now().Unix() - 50 * 365 * 86400) << 22 ret, err := script.Run(RedisIns, []string{sredis.KEY_GLOBAL_INCR_ID}, stamp).Int64() return ret, err } 

    自增 id 带上 stamp 信息, 是为了防止 redis 的 key 丢失, 或者值被清除。stamp 的计算回拨了 50 年, 因为 32bit 的时间戳到 2038 年就溢出了。只要机器的系统时间回调以及 key 失效这两件事不同时发生, 就能保持自增性。

    低 22 位用于 redis incr 自增,高位是时间信息,即 1s 内最多支持 4194304 个 id,超出了也没关系,只是会提前占用高位的时间。

    用 22 位来自增是因为某些业务可能会将 id 用在 zadd 中,zadd 的 score 范围是:-(2^53) 至 +(2^53), 即时间信息可以占用 31 位, 保证 score 不会溢出。

    33 条回复    2021-12-13 22:02:09 +08:00
    GM
        1
    GM  
       2021-09-17 10:18:40 +08:00   23
    看到那么多发明 id 生成器的,我来分享一个我喜欢用的吧:

    select uuid_short() as id;


    优点:
    纯数字单调递增 id
    性能足够好,每秒几万 ID 毫无压力
    分布式,多台服务器生成的 id 不会重复
    依赖少,只要你用 MySql 就够了。
    不怕 id 生成系统失效,只要数据库还活着就能用。如果数据库都挂了,id 生成器活着也没用。
    zhaokun
        2
    zhaokun  
       2021-09-17 10:21:27 +08:00   1
    依赖的服务要稳住
    雪花可以拿机器 ip 作为机器 id,不需要配置
    flycloud
        3
    flycloud  
    OP
       2021-09-17 10:29:30 +08:00
    @GM 我们业务没有用 mysql,
    flycloud
        4
    flycloud  
    OP
       2021-09-17 10:29:43 +08:00
    @zhaokun 有道理
    Ariver
        5
    Ariver  
       2021-09-17 10:39:35 +08:00 via iPhone
    redis 集群的话考虑了吗
    flycloud
        6
    flycloud  
    OP
       2021-09-17 10:41:26 +08:00
    @Ariver 集群或者单实例都支持呀,反正只用到了一个 key 。主要是可以规避时间回调问题。
    lysS
        7
    lysS  
       2021-09-17 10:45:24 +08:00
    @flycloud 这跟 mysql 有啥关系?
    不考虑持久化,直接 uint64 自增;根本不会出现碰撞的可能
    flycloud
        8
    flycloud  
    OP
       2021-09-17 10:51:29 +08:00
    @lysS 没懂你的意思。

    我们业务目前没有使用 mysql,不想因为一个 id 生成新增加一个组件。

    “不考虑持久化,直接 uint64 自增” 这个分布式环境你咋个自增
    bthulu
        9
    bthulu  
       2021-09-17 12:07:00 +08:00
    @zhaokun ip 重复了咋办,我司机器是分布式部署的,直接部署在门店里,门店用的都是家用路由器,ip 都是 192.168.x.xxx ,很容易重复的
    enan01
        10
    enan01  
       2021-09-17 12:27:53 +08:00 via iPhone
    redis 如果使用主从,从节点同步延迟,也会导致 ID 重复吧
    KagurazakaNyaa
        11
    KagurazakaNyaa  
       2021-09-17 12:32:34 +08:00
    @bthulu 那就用 mac
    skies457
        12
    skies457  
       2021-09-17 12:59:53 +08:00
    return ++i;
    draymonder
        13
    draymonder  
       2021-09-17 13:16:20 +08:00
    1. 用脚本,会拖慢 redis 性能,主从之间复制也可能会出问题
    2. 另外,请求 redis 失败了呢,多一个依赖,就会降低整体系统稳定性
    billly
        14
    billly  
       2021-09-17 13:44:05 +08:00
    redis 出问题的几率肯定比我加两个配置出问题的几率大
    Kinnice
        15
    Kinnice  
       2021-09-17 16:26:40 +08:00
    @bthulu ip+mac+hostname+deviceid
    flycloud
        16
    flycloud  
    OP
       2021-09-17 17:52:20 +08:00
    @draymonder #13

    第一个问题确实存在。
    因为本来就会大量用到 redis,所以并没有增加依赖。
    flycloud
        17
    flycloud  
    OP
       2021-09-17 17:55:50 +08:00
    @enan01 #10 没有这个问题,因为只会在主节点写 redis
    enan01
        18
    enan01  
       2021-09-17 20:14:12 +08:00
    @flycloud 主节点挂掉,切换到从节点,从节点异步复制,没办法保证数据强一致,如果从节点 key 存在,但是 value 没有完成复制,从节点继续 incr,会存在重复的可能
    workingonescape
        19
    workingonescape  
       2021-09-17 20:34:43 +08:00
    @GM 你这个有链接么,想学习一下
    GM
        20
    GM  
       2021-09-17 20:43:53 +08:00
    @workingonescape

    没什么要学的,就是 mysql 自带的,直接 select uuid_short() 就 完事了。
    JakeZou
        21
    JakeZou  
       2021-09-17 21:59:15 +08:00
    @GM 确实不错
    seakingii
        22
    seakingii  
       2021-09-17 22:15:13 +08:00
    最大的问题是用 REDIS
    xingzhi
        23
    xingzhi  
       2021-09-18 01:21:21 +08:00
    @GM 这方法确实不错

    本质上感觉跟雪花算法差不多,机器 ID+时间戳+自增序列
    区别在于雪花算法用了 ZK 来管理机器 ID 了
    wangritian
        24
    wangritian  
       2021-09-18 02:51:18 +08:00
    数据中心 ID 配置不麻烦吧,机器 ID 可以用 redis incr 搞定啊,生成就不要依赖网络了,也可以用 k8s-statefulset 的 hostname 最后数字作为机器 ID
    Rocketer
        25
    Rocketer  
       2021-09-18 03:23:59 +08:00
    uuid 的问题在于多台机器之间无法实现递增关系,雪花算法主要就是为了解决这个问题的,后生成的 id 一定大于之前生成的 id 。

    如果对雪花的性能不满意,可以考虑做个 id 微服务,闲余时提前生好,存在内存里,需要时取第一个发下去就行了,这样不会重复,也保证了递增关系。关键是算法可以很简单(比如就是数字递增),从而保证这个微服务有极强的承载能力。
    hanxiV2EX
        26
    hanxiV2EX  
       2021-09-18 06:22:42 +08:00 via Android
    https://github.com/hanxi/skynet-demo/commit/b4ef9dd1b8e835318da8f17bec885bb4b58d5b73

    我也实现了一个雪花算法,分布式不依赖数据库。用本地定时存文件的方式解决时间回调问题。
    hanxiV2EX
        27
    hanxiV2EX  
       2021-09-18 06:34:29 +08:00 via Android
    既然用 redis 了,还不如直接用 lua 实现集成在 redis 里,用 EVALSHA 获取 id
    fpure
        28
    fpure  
       2021-09-18 08:15:08 +08:00
    @GM 学到了
    JamesChen
        29
    JamesChen  
       2021-09-18 08:36:09 +08:00
    路过提一嘴,“if newValue then”和“if flag then”永远都是 True 。lua 不是 js,别写混了
    yemoluo
        30
    yemoluo  
       2021-09-18 09:25:06 +08:00
    @GM
    flycloud
        31
    flycloud  
    OP
       2021-09-18 10:10:28 +08:00
    @JamesChen #29 谢谢,看了文档,确实啊。如果 redis.call 命令有错误会直接抛出异常了,如果执行成功,返回值一定是 True
    egfegdfr
        32
    egfegdfr  
       2021-09-18 18:30:45 +08:00
    mybatis-plus 自带的 ID_WORKER 及挺好用的,不需要太多配置,直接注解就行,生产的是 有序但是不连续的 id,还可防止被人恶意爆破的问题
    cp19890714
        33
    cp19890714  
       2021-12-13 22:02:09 +08:00
    1. 中心化代替分布式
    雪花算法三要素:1 时间戳 2 自增序列 3 全局唯一标识
    “全局唯一标识” 实现了分布式能力, 而你的算法删掉了这个要素,用中心化的 redis 替代了。

    2.多依赖代替单依赖
    雪花算法依赖 服务器时间的同步性。
    你的算法依赖 网络和 redis 。
    雪花算法仅在启动的时候 workId 依赖 Redis, 而你的是时刻都依赖 redis 。

    总结:删掉对服务器时间的依赖,却大大降低了高可用性。性能也肯定降了一大截。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2550 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 15:07 PVG 23:07 LAX 07:07 JFK 10:07
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86