一 雪花算法介绍
雪花算法是推特开源的分布式ID生成算法,用于在不同的机器上生成唯一的ID的算法。
该算法生成一个64bit的数字作为分布式ID,保证这个ID自增并且全局唯一。
1.第一位占用1bit,其值始终是0,没有实际作用。
2.时间戳占用41bit,单位为毫秒,总共可以容纳约69年的时间。当然,我们的时间毫秒计数不会真的
从1970年开始记,那样我们的系统跑到2039/9/7 23:47:35 就不能用了,所以这里的时间戳只是相对
于某个时间的增量,比如我们的系统上线是2020-07-01,那么我们完全可以把这个timestamp当作是
从2022-10-01 00:00: 00.000的偏移量。
3.工作机器id占用10bit,其中高位5bit是数据中心ID,低位5bit是 工作节点ID,最多可以容纳1024个节
点。
4.序列号占用12bit,用来记录同毫秒内产生的不同id。每个节点每毫秒0开始不断累加,最多可以累加
到4095,同一毫秒-共可以产生4096个ID。
SnowFlake算法在同- -毫秒内最多可以生成多少个全局唯- -ID呢?
同-毫秒的ID数量= 1024 X 4096 = 4194304
二 雪花算法优缺点
雪花算法有以下几个优点:
高并发分布式环境下生成不重复 id,每秒可生成百万个不重复 id。
基于时间戳,以及同一时间戳下序列号自增,基本保证 id 有序递增。
不依赖第三方库或者中间件。
算法简单,在内存中进行,效率高。
雪花算法有如下缺点:
依赖服务器时间,服务器时钟回拨时可能会生成重复 id。
三 雪花算法实现
package snow_flake import ( "github.com/golang/glog" "sync" "time" ) type Snowflake struct { sync.Mutex // 锁 timestamp int64 // 时间戳 ,毫秒 workerid int64 // 工作节点 datacenterid int64 // 数据中心机房id sequence int64 // 序列号 } const ( epoch = int64(1577808000000) // 设置起始时间(时间戳/毫秒):2020-01-01 00:00:00,有效期69年 timestampBits = uint(41) // 时间戳占用位数 datacenteridBits = uint(2) // 数据中心id所占位数 workeridBits = uint(7) // 机器id所占位数 sequenceBits = uint(12) // 序列所占的位数 timestampMax = int64(-1 ^ (-1 << timestampBits)) // 时间戳最大值 datacenteridMax = int64(-1 ^ (-1 << datacenteridBits)) // 支持的最大数据中心id数量 workeridMax = int64(-1 ^ (-1 << workeridBits)) // 支持的最大机器id数量 sequenceMask = int64(-1 ^ (-1 << sequenceBits)) // 支持的最大序列id数量 workeridShift = sequenceBits // 机器id左移位数 datacenteridShift = sequenceBits + workeridBits // 数据中心id左移位数 timestampShift = sequenceBits + workeridBits + datacenteridBits // 时间戳左移位数 ) func (s *Snowflake) NextVal() int64 { s.Lock() now := time.Now().UnixNano() / 1000000 // 转毫秒 if s.timestamp == now { // 当同一时间戳(精度:毫秒)下多次生成id会增加序列号 s.sequence = (s.sequence + 1) & sequenceMask if s.sequence == 0 { // 如果当前序列超出12bit长度,则需要等待下一毫秒 // 下一毫秒将使用sequence:0 for now <= s.timestamp { now = time.Now().UnixNano() / 1000000 } } } else { // 不同时间戳(精度:毫秒)下直接使用序列号:0 s.sequence = 0 } t := now - epoch if t > timestampMax { s.Unlock() glog.Errorf("epoch must be between 0 and %d", timestampMax-1) return 0 } s.timestamp = now r := int64((t)<<timestampShift | (s.datacenterid << datacenteridShift) | (s.workerid << workeridShift) | (s.sequence)) s.Unlock() return r }
四 最后
- 至此,go-micro微服务雪花算法开发工作就正式完成。
- 接下来就开始JWT跨域认证的代码编写了,希望大家关注博主和关注专栏,第一时间获取最新内容,每篇博客都干货满满。