snowflake.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. package tools
  2. import (
  3. "errors"
  4. "sync"
  5. "time"
  6. )
  7. /*
  8. * Snowflake
  9. *
  10. * 1 42 52 64
  11. * +-----------------------------------------------+------------+---------------+
  12. * | timestamp(ms) | workerid | sequence |
  13. * +-----------------------------------------------+------------+---------------+
  14. * | 0000000000 0000000000 0000000000 0000000000 0 | 0000000000 | 0000000000 00 |
  15. * +-----------------------------------------------+------------+---------------+
  16. *
  17. * 1. 41位时间截(毫秒级),注意这是时间截的差值(当前时间截 - 开始时间截)。可以使用约70年: (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69
  18. * 2. 10位数据机器位,可以部署在1024个节点
  19. * 3. 12位序列,毫秒内的计数,同一机器,同一时间截并发4096个序号
  20. */
  21. const (
  22. twepoch = int64(1483228800000) //开始时间截 (2017-01-01)
  23. workeridBits = uint(10) //机器id所占的位数
  24. sequenceBits = uint(12) //序列所占的位数
  25. workeridMax = int64(-1 ^ (-1 << workeridBits)) //支持的最大机器id数量
  26. sequenceMask = int64(-1 ^ (-1 << sequenceBits)) //
  27. workeridShift = sequenceBits //机器id左移位数
  28. timestampShift = sequenceBits + workeridBits //时间戳左移位数
  29. )
  30. // A Snowflake struct holds the basic information needed for a snowflake generator worker
  31. type Snowflake struct {
  32. sync.Mutex
  33. timestamp int64
  34. workerid int64
  35. sequence int64
  36. }
  37. // NewNode returns a new snowflake worker that can be used to generate snowflake IDs
  38. func NewSnowflake(workerid int64) (*Snowflake, error) {
  39. if workerid < 0 || workerid > workeridMax {
  40. return nil, errors.New("workerid must be between 0 and 1023")
  41. }
  42. return &Snowflake{
  43. timestamp: 0,
  44. workerid: workerid,
  45. sequence: 0,
  46. }, nil
  47. }
  48. // Generate creates and returns a unique snowflake ID
  49. func (s *Snowflake) Generate() int64 {
  50. s.Lock()
  51. now := time.Now().UnixNano() / 1000000
  52. if s.timestamp == now {
  53. s.sequence = (s.sequence + 1) & sequenceMask
  54. if s.sequence == 0 {
  55. for now <= s.timestamp {
  56. now = time.Now().UnixNano() / 1000000
  57. }
  58. }
  59. } else {
  60. s.sequence = 0
  61. }
  62. s.timestamp = now
  63. r := int64((now-twepoch)<<timestampShift | (s.workerid << workeridShift) | (s.sequence))
  64. s.Unlock()
  65. return r
  66. }