Snowflakes ID
“雪花ID”(Snowflake ID),那么它是一种分布式系统中的唯一性标识符,可以保证在分布式环境下生成全局唯一的ID。它是由Twitter公司创造并开源的。
雪花ID由64位构成,以时间戳为高位,后面的位数分别代表数据中心信息、机器标识和序列号等元素,最终通过位运算组合而成。这样生成的ID具有全局唯一性,且在生成过程中天然自带排序能力。
雪花ID广泛应用于分布式系统中。比如,在微服务架构中,每个服务实例都需要一个唯一的ID,用于追踪相关业务操作的日志和流转情况;在分布式消息队列中,消息需要设置唯一ID,避免重复消费或者消息顺序混乱等问题。
总之,雪花ID是分布式系统中非常实用的工具之一,可以很好地解决全局唯一性的问题,进而帮助分布式系统更好地运转和管理。
雪花ID的结构
雪花ID 包含五个部分:
- 符号位:1 位,固定为 0。
- 时间戳:41 位,记录毫秒级的时间戳。这里需要注意的是,时间戳不是当前时刻的时间戳,而是指距离某个特定时间点(如某一年月日)的时间差值,因此它可以支持未来数十年甚至几百年的使用。
- 机器 ID:10 位,用于区分同一数据中心内不同的机器。与数据中心 ID 类似,机器 ID 也需要手动设置,并确保全局唯一。
- 序列号:12 位,表示同一毫秒时间戳内生成的不同 ID 序号。如果在同一毫秒内生成的 ID 数量超过了 4096 个,那么序列号会从 0 开始重新计数。
时钟回拨问题
在雪花ID算法中,系统时钟回拨可能会导致生成的ID不唯一或者无效,因此需要进行处理。
具体地,在每次生成ID时,都需要获取当前的系统时间戳,并与上一次生成ID时使用的时间戳进行比较。如果发现当前的时间戳小于等于上一次的时间戳,则说明系统时钟发生了回拨,此时可以抛出异常或者阻塞等待,直到系统时钟追上之前的时间戳。
下面是一个示例代码片段以便更好地理解,展示了一个基本的时钟回拨处理过程:
function nextSnowflakeId() {
// ...
var timestamp = getUnixTimestamp();
if (timestamp < lastTimestamp) { // 发生时钟回拨
var offset = lastTimestamp - timestamp;
if (offset <= 5) { // 小于等于5毫秒,可以等待追赶
delay(offset);
timestamp = getUnixTimestamp();
} else { // 大于5毫秒,抛出异常
throw new Exception("Clock moved backwards");
}
}
// ...
}
function delay(offset) {
try {
Thread.sleep(offset);
} catch (InterruptedException e) {
// ignore
}
}
function getUnixTimestamp() {
return new Date().getTime();
}
iml6yu.Fingerprint
一个对雪花算法封装的类库
引入nuget包(预览版)
初始化
第一个参数是机器号 1 ~ 255
第二个参数是机器组号 1~3
Fingerprint.UseFingerprint(1, 3);
测试用法
[TestMethod()]
public void GetIdTest()
{
Fingerprint.UseFingerprint(1, 3);
var ids = new ConcurrentBag<long>();
Parallel.For(0, 100, index =>
{
var id = Fingerprint.GetId();
Console.WriteLine(id);
ids.Add(id);
});
Assert.AreEqual(100, ids.Count);
}