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

雪花 ID 转 int64 位数字,长度是不固定的吗?

  •  
  •   dyllen · 2023-09-20 11:45:20 +08:00 · 2251 次点击
    这是一个创建于 428 天前的主题,其中的信息可能已经有所发展或是发生改变。

    https://github.com/bwmarrin/snowflake

    https://github.com/sony/sonyflake

    用了两个库,生成的 ID 转 int64 纯数字长度都不一样,而且库的配置不同,长度也不一样。

    长度是不固定吗?

    生成是 18 个数字:

    import (
    	"time"
    
    	"github.com/sony/sonyflake"
    )
    
    var (
    	sf = sonyflake.NewSonyflake(sonyflake.Settings{
    		StartTime: time.Now().Add(-time.Hour),
    		MachineID: func() (uint16, error) {
    			return uint16(10), nil
    		},
    	})
    )
    
    func GetNextSonyflakeId() int64 {
    	flakeId, _ := sf.NextID()
    	return int64(flakeId)
    }
    

    生成的是 13 个数字:

    import (
    	"github.com/sony/sonyflake"
    )
    
    var (
    	sf = sonyflake.NewSonyflake(sonyflake.Settings{})
    )
    
    
    func GetNextSonyflakeId() int64 {
    	flakeId, _ := sf.NextID()
    	return int64(flakeId)
    }
    
    15 条回复    2023-09-21 17:56:40 +08:00
    a632079
        1
    a632079  
       2023-09-20 11:56:15 +08:00   ❤️ 1
    int64 固定占用 8 字节啊。雪花本质是利用 64bit 按自己需求划定区域(实际上符号位是不用的,大部分实现只用了 63 位),然后表示出 id 。你去纠结 int64 实际数字转成 string 后实际的 len 长度其实没有意义的。
    如果你想等长表示,应该考虑将他的 64bit 直接转成 string 。

    原理可以参考: https://pdai.tech/md/algorithm/alg-domain-id-snowflake.html
    Nazz
        2
    Nazz  
       2023-09-20 14:16:31 +08:00
    整数是不关心长度的, 你是不是转成字符串使用了
    Ericcccccccc
        3
    Ericcccccccc  
       2023-09-20 14:17:22 +08:00
    雪花是种思想, 你自己实现一个也行.
    jorneyr
        4
    jorneyr  
       2023-09-20 14:25:15 +08:00
    长度和配置+实现有关系,最大长度是 long 的最大值,应该有 19 位。
    heeeeeem
        5
    heeeeeem  
       2023-09-20 16:43:49 +08:00
    摘自自己写的文章:
    Twitter Snowflake 最初由 Scala 语言编写,Scala 为 JVM 系语言,其 long 类型的大小为 64bit ,所以 Snowflake 产生的 ID 也被设计为 64bit 大小。
    算法的核心思想是将 64bit 分段处理,64bit 的 ID 被分成了五段:
    1. 首位 1 个 bit ,首段,不使用,固定为 0 ,表示 ID 为无符号数
    2. 往后 41 个 bit ,毫秒跨度段,表示当前时间与初始设定时间相差的毫秒数,241 个毫秒数,可以使用 69 年
    3. 再后 5 个 bit ,数据中心段,表示数据中心的 ID ,可配置 25=32 个数据中心
    4. 再后 5 个 bit ,节点段,表示节点 ID ,每个数据中心可以配置 32 个节点
    5. 最后 12 个 bit ,序列号段,表示 0~4096 范围中的一个数,默认为 0 ,当在 1 毫秒内产生多个 ID 时,前面段的 bit 值是相同的,用这 12 个 bit 的值来区分,即在 1ms 内,支持产生 4096 个 ID

    当配置好数据中心 ID 和节点 ID 后,这两个段的值和首段的 0 是不会再变化了的,只有毫秒跨度段和序列号段值会发生变化。 如果 Snowflake 产生 ID 的间隔大于 1 毫秒,那么只有毫秒跨度段的值会发生变化;如果在 1 毫秒内要产生多个 ID ,则这一毫秒内只有序列号段发生变化( 0~4095 范围内递增)。最后将每次生成的 64bit 二进制数字转为 long 类型的十进制数字,得到最终的 ID 。
    fox0001
        6
    fox0001  
       2023-09-20 16:45:55 +08:00 via Android
    二进制位数,确定;十进制位数,不确定
    xausky
        7
    xausky  
       2023-09-20 17:30:53 +08:00
    StartTime: time.Now().Add(-time.Hour) 这种写法就完全错的,这样会产生重复的雪花 ID 的
    maocat
        8
    maocat  
       2023-09-20 17:34:55 +08:00
    @xausky 时间回拨问题?

    只要系统时间一直没问题应该不会有啥问题吧
    gps949
        9
    gps949  
       2023-09-20 17:52:14 +08:00
    因为 sonyflake 不是标准 snowflake 实现,而是经过了自定义。所以两者确实是不一样的。这你既然用到了 sonyflake 库,应该还是要读一读文档的。
    https://github.com/sony/sonyflake/blob/master/README.md

    另外,你不应该提问“长度是不固定的吗”,而应该提问“snowflake 和 sonyflake 包产生的 ID 长度不一样的吗”。
    再另外,因为 snowflake/sonyflake 都是基于时间戳的,所以如果你使用它们中的任一种,时间跨度超过一段时间,也会造成 ID 字符串长度不一样。
    xausky
        10
    xausky  
       2023-09-20 19:12:10 +08:00
    @maocat 重启程序就得出问题,时间位是用 now() - StartTime 填充的,以他这个写法重启程序就会从 1 小时重新计数,和之前的完全重复,正确的做法是所有地方都写一个固定时间,比如项目 2023 年开始,那就 2023-01-01 00:00:00.000 UTC ,或者直接写 0 库会用默认值也就是著名的 1970-01-01 00:00:00.000 UTC
    dyllen
        11
    dyllen  
    OP
       2023-09-21 17:06:13 +08:00
    @Nazz 是呀,想放在数据库做长度一样的 ID 的。
    dyllen
        12
    dyllen  
    OP
       2023-09-21 17:08:45 +08:00
    @xausky 这个是我测试的时候加的,测的时候改了时间看看结果,我用的时候没设置,用的库默认的。
    dyllen
        13
    dyllen  
    OP
       2023-09-21 17:15:22 +08:00
    @gps949 看过了,我看是固定 64 位的(库实际使用是 63 位),我转成十进制 int64 我以为也是固定长度的。
    gps949
        14
    gps949  
       2023-09-21 17:22:56 +08:00
    @dyllen
    😂 转成十进制什么鬼,你是说转成十进制字符串吧?是固定 int64 类型存储,怎么会等同于固定长度呢? 64 个 0 的十进制是 0,60 个 0 、4 个 1 十进制就是 15 了。。。ID 前面是时间戳,跨度还蛮大的,肯定会在一些可能的位数间变化的。。。。snowflake 和 sonyflake 的时间戳和后面部分组成不一样,自然同一个时间生成的位数也可以不一样。。。
    dyllen
        15
    dyllen  
    OP
       2023-09-21 17:56:40 +08:00
    @gps949 库返回的就是是十进制的数,类型是 uint64 。那是我理解错了,我以为 64 个位全都会有值。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1073 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 22:38 · PVG 06:38 · LAX 14:38 · JFK 17:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.