这是我参与「第三届青训营 -后端场」笔记创作活动的第1篇笔记
雪花算法介绍
它是Twitter开源的分布式ID生成算法,其可以在分布式系统中生成全局唯一ID,而且相较于利用数据库主键自增特性,不同节点直接使用自增的ID有很多优势。
雪花算法优点
1、生成时不依赖数据库,完全在内存中生成 2、生成效率高,能达到每秒数百万全局唯一自增ID
雪花算法生成ID组成
生成ID为默认64bit的整数(可以按场景自行配置长度,如增加时间戳的位数,为了支持更多机器节点,可以增加标识位的长度),且按照时间递增,由符号位,时间戳,机器码,序列号组成。
如图:
1、首位为符号位,因为ID都是为正整数,第一位默认为0
2、时间戳:占41bit,毫秒级时间戳
3、标识符:占10bit,通常由5bit的数据中心ID和5bit的工作机器ID组成
雪花算法golang实现
const (
//机器ID
workerIDBits = uint64(5)
//数据中心ID
dataCenterIDBits = uint64(5)
//序列号
sequenceBits = uint64(12)
//最大机器ID 以8位的有符号整数为例,-1的二进制11111111 其右移workerIDBits(5)位 结果为11100000 ,
//与11111111异或得00011111 即2^5-1 为最大机器ID
maxWorkerID = int64(-1) ^ (int64(-1) << workerIDBits)
maxDataCenterID = int64(-1) ^ (int64(-1) << dataCenterIDBits)
maxSequence = int64(-1) ^ (int64(-1) << sequenceBits)
//分别代表偏移量,以时间戳为例,它离最低位差22位,在分别生成序列号、机器id,时间撮之后需要进行右移,在进行
//或运算即可得到ID
timeLeft = uint8(22)
dataLeft = uint8(17)
workLeft = uint8(12)
twepoch = int64(1589923200000)
)
type Worker struct {
mu sync.Mutex //锁
LastStamp int64 //上一个时间戳
WorkerID int64 //机器ID
DataCenterId int64 //数据中心ID
Sequence int64 //序列号
}
func NewWorker(WorkerID, dataCenterID int64) *Worker {
return &Worker{
WorkerID: WorkerID,
LastStamp: 0,
Sequence: 0,
DataCenterId: dataCenterID,
}
}
func (w *Worker) getMilliSeconds() int64 {
return time.Now().Unix() / 1e6
}
func (w *Worker) NextID() (uint64, error) {
w.mu.Lock()
defer w.mu.Unlock()
return w.nextID()
}
func (w *Worker) nextID() (uint64, error) {
timeStamp := w.getMilliSeconds()
if timeStamp < w.LastStamp {
return 0, errors.New("time is moving backwards,waiting until")
}
if w.LastStamp == timeStamp {
w.Sequence = (w.Sequence + 1) & maxSequence
if w.Sequence == 0 {
//保证时间戳递增
for timeStamp <= w.LastStamp {
timeStamp = w.getMilliSeconds()
}
}
} else {
w.Sequence = 0
}
w.LastStamp = timeStamp
id := ((timeStamp - twepoch) << timeLeft) |
(w.DataCenterId << dataLeft) |
(w.WorkerID << workLeft) |
w.Sequence
return uint64(id), nil
}
总结
雪花算法是一个优秀的全局生成唯一ID的算法,适用于大多数的场景,但也不是万能的,因为工作机器id只有10bit,意味着最多支持1024机器节点,一旦多于其就不能保证全局id唯一了,可以通过扩展工作id位数解决。此外它还依赖于当前机器时钟,出现时钟回拨,可能就会有主键重复的问题。