唯一ID算法Snowflake
相信大家都不墨生,他是Twitter公司提出来的算法。非常广泛的应用在各种业务系统里。也因为Snowflake
的灵活性和缺点,对他的改造层出不穷,比百度的UidGenerator、美团的Leaf、索尼的Sonyflake等等。这篇帖子主要是讲一下原生的Snowflake
算法、缺点及改造方案,并分析索尼的Sonyflake源码对原生Snowflake
的改造,
原生Snowflake
算法使用一个64 bit
的整型数据,根据当前的时间来生成ID。
原生Snowflake
结构如下:
原生的Snowflake
算法是完全依赖于时间的,如果有时钟回拨的情况发生,会生成重复的ID,市场上的解决方案也是非常多的:
5
毫秒,就等待,然后再生成。或者就直接报错,交给业务层去处理。个人比较推荐的是最后一个方案
找2bit位作为时钟回拨位,发现有时钟回拨就将回拨位加1,达到最大位后再从0开始进行循环。
比如下图这样,从机器位上,均出来2位做回拨位:
Snowflake
算法是相当灵活的,我们可以根据自己的业务需要,对63 bit的的各个部分进行增减。索尼公司的Sonyflake对原生的Snowflake
进行改进,重新分配了各部分的bit位:
Snowflake
不同的地方是,Sonyflake
是以10毫秒为单位来保存时间的。这样的话,可以使用的年限为 174年
比Snowflake
长太多了。const sonyflakeTimeUnit = 1e7 // nsec, i.e. 10 msec
func toSonyflakeTime(t time.Time) int64 {
return t.UTC().UnixNano() / sonyflakeTimeUnit
}
func currentElapsedTime(startTime int64) int64 {
return toSonyflakeTime(time.Now()) - startTime
}Snowflake
少好多,如果感觉不够用,目前的解决方案是跑多个实例生成同一业务的ID来弥补。sf.machineID, err = lower16BitPrivateIP()
func lower16BitPrivateIP() (uint16, error) {
ip, err := privateIPv4()
if err != nil {
return 0, err
}
return uint16(ip[2])<<8 + uint16(ip[3]), nil
}
对于时间回拨的问题Sonyflake
简单暴力,就是直接等待 :
func (sf *Sonyflake) NextID() (uint64, error) {
const maskSequence = uint16(1<<BitLenSequence - 1)
sf.mutex.Lock()
defer sf.mutex.Unlock()
current := currentElapsedTime(sf.startTime)
if sf.elapsedTime < current {
sf.elapsedTime = current
sf.sequence = 0
} else { // sf.elapsedTime >= current
sf.sequence = (sf.sequence + 1) & maskSequence
if sf.sequence == 0 {
sf.elapsedTime++
overtime := sf.elapsedTime - current
time.Sleep(sleepTime((overtime)))
}
}
return sf.toID()
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。