背景

雪花算法是 twitter 高并发环境下对唯一 ID 生成的需求。

结构


主要分为 4 个部分

  • 一个 bit,无意义。
  • 41 个 bit,表示时间戳。
  • 10 个 bit,表示机房 id 和 机器 id。可任意拆分。
  • 12 个 bit 表示某个机房在这一毫秒内生成的 id 的序列号。

实现

结构定义

// SnowFlake 雪花算法 id 生成器
type SnowFlake struct {
	mutex     *sync.Mutex
	LastStamp int64 // 上次 id 的时间戳
	WorkerID  int64 // 节点 id
	Sequence  int64 // 当前毫秒已经生成的 id 序列号
}

基本常量

const (
	_workerIDBits = uint64(10) // 机器 id 长度
	_sequenceBits = uint64(12) // 序列号长度
)

const (
	_maxSequence = int64(-1) ^ (int64(-1) << int64(_sequenceBits)) // 最大序列号
)

const (
	_timeLeft   = _workerIDBits + _sequenceBits // 时间戳偏移量
	_workerLeft = _sequenceBits                 // 序列号偏移量
)

const (
	_timeStamp = int64(1607616000000) // 常量时间戳 2020-12-11-00-00
)

生成 ID

func (s SnowFlake) getMilliSeconds() int64 {
	return time.Now().UnixMilli()
}

// NextID 生成 id
func (s *SnowFlake) NextID() (uint64, error) {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	timeStamp := s.getMilliSeconds()
	if timeStamp < s.LastStamp {
		return 0, errors.New("")
	} else if timeStamp == s.LastStamp {
		s.Sequence = (s.Sequence + 1) & _maxSequence

		// 若序列号溢出,则等待下一毫秒
		if s.Sequence == 0 {
			for timeStamp <= s.LastStamp {
				timeStamp = s.getMilliSeconds()
			}
		}
	} else {
		s.Sequence = 0
	}

	s.LastStamp = timeStamp
	id := ((timeStamp - _timeStamp) << int64(_timeLeft)) |
		(s.WorkerID << int64(_workerLeft)) |
		s.Sequence

	return uint64(id), nil
}