snowflake.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. package util
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. "github.com/pkg/errors"
  7. )
  8. const (
  9. twepoch = int64(1417937700000) // 默认起始的时间戳 1449473700000 。计算时,减去这个值
  10. DistrictIdBits = uint(5) //区域 所占用位置
  11. NodeIdBits = uint(9) //节点 所占位置
  12. sequenceBits = uint(10) //自增ID 所占用位置
  13. /*
  14. * 1 符号位 | 39 时间戳 | 5 区域 | 9 节点 | 10 (毫秒内)自增ID
  15. * 0 | 0000000 00000000 00000000 00000000 00000000 | 00000 | 000000 000 | 000000 0000
  16. *
  17. */
  18. maxNodeId = -1 ^ (-1 << NodeIdBits) //节点 ID 最大范围
  19. maxDistrictId = -1 ^ (-1 << DistrictIdBits) //最大区域范围
  20. nodeIdShift = sequenceBits //左移次数
  21. DistrictIdShift = sequenceBits + NodeIdBits
  22. timestampLeftShift = sequenceBits + NodeIdBits + DistrictIdBits
  23. sequenceMask = -1 ^ (-1 << sequenceBits)
  24. maxNextIdsNum = 100 //单次获取ID的最大数量
  25. )
  26. type IdWorker struct {
  27. sequence int64 //序号
  28. lastTimestamp int64 //最后时间戳
  29. nodeId int64 //节点ID
  30. twepoch int64
  31. districtId int64
  32. mutex sync.Mutex
  33. }
  34. // NewIdWorker new a snowflake id generator object.
  35. func NewIdWorker(NodeId int64) (*IdWorker, error) {
  36. var districtId int64
  37. districtId = 1 //暂时默认给1 ,方便以后扩展
  38. idWorker := &IdWorker{}
  39. if NodeId > maxNodeId || NodeId < 0 {
  40. // fmt.Sprintf("NodeId Id can't be greater than %d or less than 0", maxNodeId)
  41. return nil, errors.New(fmt.Sprintf("NodeId Id: %d error", NodeId))
  42. }
  43. if districtId > maxDistrictId || districtId < 0 {
  44. // fmt.Sprintf("District Id can't be greater than %d or less than 0", maxDistrictId)
  45. return nil, errors.New(fmt.Sprintf("District Id: %d error", districtId))
  46. }
  47. idWorker.nodeId = NodeId
  48. idWorker.districtId = districtId
  49. idWorker.lastTimestamp = -1
  50. idWorker.sequence = 0
  51. idWorker.twepoch = twepoch
  52. idWorker.mutex = sync.Mutex{}
  53. // fmt.Sprintf("worker starting. timestamp left shift %d, District id bits %d, worker id bits %d, sequence bits %d, workerid %d", timestampLeftShift, DistrictIdBits, NodeIdBits, sequenceBits, NodeId)
  54. return idWorker, nil
  55. }
  56. // timeGen generate a unix millisecond.
  57. func timeGen() int64 {
  58. return time.Now().UnixNano() / int64(time.Millisecond)
  59. }
  60. // tilNextMillis spin wait till next millisecond.
  61. func tilNextMillis(lastTimestamp int64) int64 {
  62. timestamp := timeGen()
  63. for timestamp <= lastTimestamp {
  64. timestamp = timeGen()
  65. }
  66. return timestamp
  67. }
  68. // NextId get a snowflake id.
  69. func (id *IdWorker) NextId() (int64, error) {
  70. id.mutex.Lock()
  71. defer id.mutex.Unlock()
  72. return id.nextid()
  73. }
  74. // NextIds get snowflake ids.
  75. func (id *IdWorker) NextIds(num int) ([]int64, error) {
  76. if num > maxNextIdsNum || num < 0 {
  77. // fmt.Sprintf("NextIds num can't be greater than %d or less than 0", maxNextIdsNum)
  78. return nil, errors.New(fmt.Sprintf("NextIds num: %d error", num))
  79. }
  80. ids := make([]int64, num)
  81. id.mutex.Lock()
  82. defer id.mutex.Unlock()
  83. for i := 0; i < num; i++ {
  84. ids[i], _ = id.nextid()
  85. }
  86. return ids, nil
  87. }
  88. func (id *IdWorker) nextid() (int64, error) {
  89. timestamp := timeGen()
  90. if timestamp < id.lastTimestamp {
  91. // fmt.Sprintf("clock is moving backwards. Rejecting requests until %d.", id.lastTimestamp)
  92. return 0, errors.New(fmt.Sprintf("Clock moved backwards. Refusing to generate id for %d milliseconds", id.lastTimestamp-timestamp))
  93. }
  94. if id.lastTimestamp == timestamp {
  95. id.sequence = (id.sequence + 1) & sequenceMask
  96. if id.sequence == 0 {
  97. timestamp = tilNextMillis(id.lastTimestamp)
  98. }
  99. } else {
  100. id.sequence = 0
  101. }
  102. id.lastTimestamp = timestamp
  103. return ((timestamp - id.twepoch) << timestampLeftShift) | (id.districtId << DistrictIdShift) | (id.nodeId << nodeIdShift) | id.sequence, nil
  104. }