import (
"errors"
"fmt"
"time"
)
/**
* Snowflake<br>
* SnowFlake的结构如下(每部分用-分开):<br>
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 0000000 - 0000 - 00000000000 <br>
* 1位标识,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br>
* 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)
* 得到的值),这里的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序StartSecs)。
41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年
* 11位的数据机器位,可以部署在2048个节点,包括7位RegionId和4位GroupId<br>
* 11位序列,毫秒内的计数,11位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生2048个ID序号<br>
* 加起来刚好64位,为一个Long型。<br>
* SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。
*/
const(
//开始时间戳 2020-05-19
StartSecs int64 = 1589817600000
// 大区ID所占的位数
RegionIdBits int64 = 7
// 机房ID所占的位数
GroupIdBits int64 = 4
// 支持的最大大区id,结果是31
MaxRegionId int64 = -1 ^ (-1 << RegionIdBits)
// 支持的最大机房ID,结果是15
MaxGroupId int64 = -1 ^ (-1 << GroupIdBits)
// 序列在id中占的位数
SequenceBits int64 = 11
// 机房ID向左移11位
GroupIdShift int64 = SequenceBits
// 大区ID向左移15位(11+4)
RegionIdShift int64 = SequenceBits + GroupIdBits
// 时间截向左移22位(11+4+7)
TimestampLeftShift = SequenceBits + GroupIdBits + RegionIdBits
// 生成序列的掩码,这里为2047 (0b11111111111=0x7ff=2047)
SequenceMask = -1 ^ (-1 << SequenceBits)
)
type SnowflakeIdWorker struct {
RegionId int64 //大区id
GroupId int64 //机房id
LastTimestamp int64
Sequence int64 // 毫秒内序列(0~2047)
}
//==============================Constructors=====================================
/**
* 构造函数
* @param RegionId 大区ID (0~15)
* @param GroupId 机房序号 (0~127)
*/
func NewSnowflakeIdWorker(RegionId, GroupId int64)(idWork *SnowflakeIdWorker, err error) {
if RegionId > MaxRegionId || RegionId < 0 {
return nil, errors.New("err RegionId")
}
if GroupId > MaxGroupId || GroupId < 0 {
return nil, errors.New("err GroupId")
}
idWork = &SnowflakeIdWorker{
GroupId: GroupId,
RegionId: RegionId,
LastTimestamp: -1,
Sequence: 0,
}
return
}
/**
* 获得下一个ID
*/
func (idWork *SnowflakeIdWorker) NextId()(id int64, err error) {
timestamp := timeGen()
//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
if timestamp < idWork.LastTimestamp {
return 0, errors.New("err time")
}
//如果是同一时间生成的,则进行毫秒内序列
if idWork.LastTimestamp == timestamp {
idWork.Sequence = (idWork.Sequence + 1) & SequenceMask
//毫秒内序列溢出
if idWork.Sequence == 0 {
//阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(idWork.LastTimestamp)
}
} else {
//时间戳改变,毫秒内序列重置
idWork.Sequence = 0
}
//上次生成ID的时间截
idWork.LastTimestamp = timestamp
//移位并通过或运算拼到一起组成64位的ID
id = (timestamp - StartSecs) << TimestampLeftShift | (idWork.RegionId << RegionIdShift)| (idWork.GroupId << GroupIdShift) | idWork.Sequence
return
}
/**
* 阻塞到下一个毫秒,直到获得新的时间戳
* @param lastTimestamp 上次生成ID的时间截
* @return 当前时间戳
*/
func tilNextMillis(lastTimestamp int64)(timestamp int64) {
timestamp = timeGen()
for {
if timestamp > lastTimestamp {
break
}
timestamp = timeGen()
}
return timestamp
}
/**
* 返回以毫秒为单位的当前时间
*/
func timeGen()int64{
return time.Now().UnixNano() / int64(time.Millisecond)
}
//==============================Test=============================================
/** 测试 */
func TestGetId() {
idWorker, _ := NewSnowflakeIdWorker(10, 2)
for i :=0;i<1000;i++ {
id, err := idWorker.NextId()
if err != nil{
fmt.Println(err)
continue
}
fmt.Println(id)
}
}
0条评论