V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
owenliang
V2EX  ›  Go 编程语言

昨晚用 Golang 写了个 ID 生成服务,分享给大家

  •  
  •   owenliang ·
    owenliang · 2017-11-19 11:11:33 +08:00 · 4698 次点击
    这是一个创建于 2596 天前的主题,其中的信息可能已经有所发展或是发生改变。

    go-id-alloc

    Golang+Mysql 实现的分布式 ID 生成服务

    特性

    • 高性能:分配 ID 只访问内存
    • 分布式:横向扩展,理论无上限
    • 高可靠:Mysql 持久化,故障恢复快
    • 唯一性:生成 64 位整形,整体递增,永不重复
    • 易用性:可自定义 ID 起始位置,对外 HTTP 服务
    • 可运维性:提供健康检查接口,通过负载均衡自动摘除故障节点

    地址: https://github.com/owenliang/go-id-alloc

    第 1 条附言  ·  2017-11-21 13:28:35 +08:00
    整理成博客,供大家理解: https://yuerblog.cc/2017/11/21/golang-id-alloc/
    36 条回复    2018-01-02 19:29:48 +08:00
    GjriFeu
        1
    GjriFeu  
       2017-11-19 11:31:44 +08:00
    唯一性:生成 64 位整形,整体递增,永不重复 太长
    owenliang
        2
    owenliang  
    OP
       2017-11-19 11:33:50 +08:00 via Android
    @GjriFeu
    twm
        3
    twm  
       2017-11-19 11:58:48 +08:00 via iPhone
    实际情况中来讲不递增 id 会好一些
    owenliang
        4
    owenliang  
    OP
       2017-11-19 12:11:05 +08:00 via Android
    @twm 按业务规则生成会好一些
    winglight2016
        5
    winglight2016  
       2017-11-19 12:47:03 +08:00
    @owenliang id 最好不要带业务规则,这是 DB schema 的设计原则之一
    owenliang
        6
    owenliang  
    OP
       2017-11-19 12:49:27 +08:00 via Android
    @winglight2016 谁的原则
    rockuw
        7
    rockuw  
       2017-11-19 13:09:53 +08:00 via iPhone
    > 高性能:分配 ID 只访问内存

    多个服务器怎么保证递增?
    owenliang
        8
    owenliang  
    OP
       2017-11-19 13:25:06 +08:00 via Android
    @rockuw 看代码喽
    rockuw
        9
    rockuw  
       2017-11-19 13:44:19 +08:00 via iPhone
    分布式,只访问内存,还能保证严格递增,图灵奖级别的成就啊。
    owenliang
        10
    owenliang  
    OP
       2017-11-19 13:47:28 +08:00 via Android
    @rockuw 不是严格。。我的措辞是整体递增,哈哈
    hilow
        11
    hilow  
       2017-11-19 14:26:46 +08:00 via Android
    用 redis 的 increment 生成 id 比这个 mysql 方便吧?
    pynix
        12
    pynix  
       2017-11-19 14:31:37 +08:00 via iPhone
    直接用 uuid,自增 id 最麻烦的就是可猜测。。。。
    notreami
        13
    notreami  
       2017-11-19 15:21:26 +08:00
    SnowFlake
    notreami
        14
    notreami  
       2017-11-19 15:23:58 +08:00
    理论无上限,永不重复
    就这两条,我能喷死你。。。
    troywinter
        15
    troywinter  
       2017-11-19 15:34:03 +08:00
    楼上正解,现阶段 twitter snowflake 算法算是最为可用的方案。。。
    owenliang
        16
    owenliang  
    OP
       2017-11-19 15:58:42 +08:00
    @notreami 我就很好奇你能喷出啥。。
    owenliang
        17
    owenliang  
    OP
       2017-11-19 15:58:58 +08:00
    @troywinter snowflake 还需要分享给大家么?
    geelaw
        18
    geelaw  
       2017-11-19 16:32:07 +08:00
    @owenliang 编码长度是有限的,只要执行足够多次就会出现重复或者程序不正常。

    用带有硬件信息的 GUID 算法就好了啊,这样不同电脑生成的就会不同了。
    owenliang
        19
    owenliang  
    OP
       2017-11-19 16:41:30 +08:00 via Android   ❤️ 1
    鉴于不同意见较多,不再一一回复大家,关于分布式 ID 方案优劣势参考: https://tech.meituan.com/MT_Leaf.html。
    genesislive
        20
    genesislive  
       2017-11-19 17:43:05 +08:00
    @owenliang 链接多了个“。”
    myself659410
        21
    myself659410  
       2017-11-19 21:05:47 +08:00
    肯定楼主的动手出代码
    都用 golang 还再加上 mysql 就为了分布式 uuid 实现起来觉得有点重了 依赖了 mysql,考虑到就帮,那 mysql 高可用也需要保证了吧
    Chingim
        22
    Chingim  
       2017-11-19 21:38:21 +08:00 via Android
    只能有 2^64 个 id 吧,永不重复有点过了
    owenliang
        23
    owenliang  
    OP
       2017-11-19 21:48:00 +08:00 via Android
    @Chingim 很有道理
    owenliang
        24
    owenliang  
    OP
       2017-11-19 21:52:36 +08:00 via Android
    @myself659410 对 云或者公司都有能力提供高可用 mysql
    ihuotui
        25
    ihuotui  
       2017-11-20 00:31:12 +08:00 via iPhone
    有序 id 还是有用的
    swulling
        26
    swulling  
       2017-11-20 00:49:11 +08:00 via iPhone
    snowflake 加原子钟,直接硬件解决时间问题

    便宜的原子钟才几百块
    wowowo1
        27
    wowowo1  
       2017-11-20 02:49:50 +08:00
    看了下代码,仿佛核心是先分区( segments ),仿佛也可称为分片,然后根据每个分片根据自己的分区信息自己内部进行 ID 递增。


    ```
    func (alloc *Alloc)NextId() (int64, error) {
    alloc.mutex.Lock()
    defer alloc.mutex.Unlock()

    if len(alloc.segments) > 0 {
    id := alloc.segments[0].left + alloc.segments[0].offset
    alloc.segments[0].offset++
    if id + 1 >= alloc.segments[0].right {
    alloc.segments = append(alloc.segments[:0], alloc.segments[1:]...)
    }
    return id, nil
    } else {
    return 0, errors.New("no more id")
    }
    }
    ```

    套用日本中二片里面自吹的话,最简单是 ID 生成器,最难也是 ID 生成器。

    如果我理解没错的话,
    你这套代码只能保证某个分区内递增,不能保证所有分区一起递增。
    每次请求不能落盘,不能记录已分配的 ID,或许可以采用异步解决,但是遇到灾难性故障基本会出现重复的情况。
    64 位整形仍然不能保证不重复。

    目前来看,UUID 中 snowflake 才是终极方案,自增 ID 仍然数 TIDB 那套比较靠谱,虽然他不能保证连续,但是至少自增。
    wowowo1
        28
    wowowo1  
       2017-11-20 02:52:23 +08:00
    而且,mutex.lock 和 unlock 中间代码行数比较多,单个分片可能有性能问题。go 语言是否可以用 atomic.incr 那一套逻辑解决。

    我只是稍微看了点代码,如有理解错误请提。
    owenliang
        29
    owenliang  
    OP
       2017-11-20 14:22:45 +08:00
    @wowowo1 你理解错了,再看看代码吧。
    ztao8607
        30
    ztao8607  
       2017-11-20 16:30:05 +08:00
    @owenliang 问个问题,都记录在内存中,有容灾处理么?分布式节点中,多个节点 down 后,如何解决脑裂问题呢?
    zkeeper
        31
    zkeeper  
       2017-12-03 07:24:54 +08:00 via iPhone
    @owenliang 人家仔细看了代码,而且贴出来了自己的分析,即使你觉得错,多写两句告诉别人具体哪里你觉得有问题才是讨论的态度吧?什么都不说直接让人再看代码?别人估计不会再看了
    owenliang
        32
    owenliang  
    OP
       2017-12-03 11:47:26 +08:00 via Android
    @zkeeper 看不看与我何干?感兴趣自己看,还有管闲事的,真是笑尿了
    zkeeper
        33
    zkeeper  
       2017-12-03 21:06:51 +08:00 via iPhone
    @owenliang 就你这个态度,真没必要把你的什么项目贴出来,指望别人不由分说就一脸膜拜交口称赞?你自嗨去吧
    zkeeper
        34
    zkeeper  
       2017-12-03 21:07:35 +08:00 via iPhone
    @zkeeper 拉黑
    wowowo1
        35
    wowowo1  
       2017-12-14 18:02:49 +08:00
    @zkeeper 蛤蛤蛤,没必要的。

    至于态度,也还好吧。

    但是第二天 astaxie 发了每日链接,有他这个 ID 生成器的设计的文章,感觉还好。

    他自己也贴在一楼了。

    毕竟有产出,有益于社会。

    不用苛求太多。

    我要是好不容易写个东西然后被楼上这么喷,我估计我也会毛的。
    iceheart
        36
    iceheart  
       2018-01-02 19:29:48 +08:00 via Android
    1024
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   907 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 22:18 · PVG 06:18 · LAX 14:18 · JFK 17:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.