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  }