github.com/tursom/GoCollections@v0.3.10/util/snowflake/snowflake.go (about) 1 package snowflake 2 3 import ( 4 "github.com/tursom/GoCollections/util/time" 5 6 "github.com/tursom/GoCollections/lang" 7 "github.com/tursom/GoCollections/lang/atomic" 8 "github.com/tursom/GoCollections/util/b62" 9 ) 10 11 /** 12 * 被改造过的雪花ID 13 * |---------|------------|-----------|------------| 14 * | 空位(1) | 时间戳(43) | 自增位(7) | 机器ID(13) | 15 * |---------|------------|-----------|------------| 16 * 时间戳仅在初始化时使用, 与序列号接壤, 这样做可以避免某一时间内大量请求导致的ID爆炸 17 * 当前方案在ID溢出时, 溢出的数据会让时间戳 +1. 18 * 这样做, 只要节点不重启或者在重启前平均QPS没有超标, 重启后分配的ID仍能唯一 19 * 20 * 当前被调试为平均每毫秒可以相应 128 个消息 21 * 如果平均每个人 10 秒发一条消息, 1 秒 128 条消息大约要 1280 人, 1 毫秒 128 条消息就大约需要 128W 用户了 22 * 单点无法应付如此巨量的并发, ID生成器保证性能过剩 23 * 24 * 当前最多支持 8192 个节点同时上线, 未来如果节点数超过了 8192 个, 也可以以ID生成的最晚时间为代价提升节点最高数量 25 */ 26 27 const ( 28 incrementBase uint64 = 0x2000 29 ) 30 31 type ( 32 Snowflake interface { 33 New() uint64 34 NewStr() string 35 Close() 36 } 37 38 snowflake struct { 39 nodeId uint16 40 incrementLength int 41 seed atomic.UInt64 42 closer lang.SendChannel[struct{}] 43 } 44 ) 45 46 func New(nodeId uint16) Snowflake { 47 if uint64(nodeId) >= incrementBase { 48 panic(nodeId) 49 } 50 51 closer := make(chan struct{}) 52 53 s := &snowflake{ 54 nodeId: nodeId, 55 incrementLength: 7, 56 closer: lang.RawChannel[struct{}](closer), 57 } 58 59 s.updateTime() 60 61 go func() { 62 ticker := time.NewTicker(time.Millisecond) 63 defer ticker.Stop() 64 65 for { 66 select { 67 case <-closer: 68 return 69 case _, ok := <-ticker.C: 70 if !ok { 71 return 72 } 73 74 s.updateTime() 75 } 76 } 77 }() 78 79 return s 80 } 81 82 func (s *snowflake) Close() { 83 s.closer.TrySend(struct{}{}) 84 } 85 86 func (s *snowflake) updateTime() { 87 seed := s.newSeed() 88 old := s.seed.Load() 89 for old < seed && !s.seed.CompareAndSwap(old, seed) { 90 seed = s.newSeed() 91 old = s.seed.Load() 92 } 93 94 } 95 96 func (s *snowflake) newSeed() uint64 { 97 return uint64(s.nodeId&0x1fff) | 98 (uint64(time.Now().UnixMilli()<<(s.incrementLength+13)) & uint64(0x7f_ff_ff_ff_ff_ff_ff_ff)) 99 } 100 101 func (s *snowflake) NewStr() string { 102 return b62.Encode(s.New()) 103 } 104 105 func (s *snowflake) New() uint64 { 106 return s.seed.Add(incrementBase) 107 }