雪花算法(Snowflake Algorithm)C# 实现版本
雪花算法(Snowflake Algorithm)是一种分布式唯一ID生成算法,由Twitter开发,用于生成唯一的、递增的、时间戳相关的ID。下面是使用C#实现雪花算法的示例代码:
public class Snowflake
{
private const long Twepoch = 1288834974657L; // 自定义的起始时间戳
private const int WorkerIdBits = 5; // 工作节点ID的位数
private const int DatacenterIdBits = 5; // 数据中心ID的位数
private const int SequenceBits = 12; // 序列号的位数
private const int WorkerIdShift = SequenceBits;
private const int DatacenterIdShift = SequenceBits + WorkerIdBits;
private const int TimestampShift = DatacenterIdShift + DatacenterIdBits;
private const long WorkerIdMask = ~(-1L << WorkerIdBits);
private const long DatacenterIdMask = ~(-1L << DatacenterIdBits);
private const long SequenceMask = ~(-1L << SequenceBits);
private long workerId; // 工作节点ID
private long datacenterId; // 数据中心ID
private long sequence = 0L; // 序列号
private long lastTimestamp = -1L; // 上一个时间戳
public Snowflake(long workerId, long datacenterId)
{
this.workerId = workerId;
this.datacenterId = datacenterId;
}
public long GetId()
{
lock (this)
{
long timestamp = GetTimestamp();
if (timestamp < lastTimestamp)
{
throw new Exception("Clock is moving backwards. Rejecting requests until " + lastTimestamp);
}
if (lastTimestamp == timestamp)
{
sequence = (sequence + 1) & SequenceMask;
if (sequence == 0)
{
timestamp = TilNextMillis(lastTimestamp);
}
}
else
{
sequence = 0L;
}
lastTimestamp = timestamp;
long id = ((timestamp - Twepoch) << TimestampShift)
| (datacenterId << DatacenterIdShift)
| (workerId << WorkerIdShift)
| sequence;
return id;
}
}
private long GetTimestamp()
{
return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
}
private long TilNextMillis(long lastTimestamp)
{
long timestamp = GetTimestamp();
while (timestamp <= lastTimestamp)
{
timestamp = GetTimestamp();
}
return timestamp;
}
}
调用的时候你只要:
Snowflake snowflake = new Snowflake(1, 1); // workerId=1, datacenterId=1
long id = snowflake.GetId(); // 生成唯一的ID
雪花算法(Snowflake Algorithm)是一种分布式唯一ID生成算法,由Twitter开发,用于生成唯一的、递增的、时间戳相关的ID。下面是雪花算法的原理详解:
雪花算法的结构
雪花算法生成的ID是一个64位的Long型数字,结构如下:
- 高32位:时间戳(timestamp)
- 中间10位:数据中心ID(datacenterId)和工作节点ID(workerId)
- 低12位:序列号(sequence)
时间戳(timestamp)
时间戳是雪花算法的核心部分,用于记录生成ID的时间。时间戳是一个41位的数字,精度为毫秒级别。它的计算方式是:
timestamp = (当前时间 - 起始时间)
其中,起始时间是一个固定的时
间戳,通常设置为2014年11月4日00:00:00 GMT(1288834974657L)。
数据中心ID(datacenterId)和工作节点ID(workerId)
数据中心ID和工作节点ID用于标识生成ID的来源。数据中心ID和工作节点ID分别占用5位和5位,总共10位。它们的计算方式是:
datacenterId = 数据中心的唯一ID
workerId = 工作节点的唯一ID
序列号(sequence)
序列号是一个12位的数字,用于记录同一个毫秒内生成的ID的序号。序列号的计算方式是:
sequence = (sequence + 1) % 4096
其中,4096是2^12,表示序列号的最大值。
雪花算法的工作流程
- 获取当前时间戳(timestamp)
- 如果当前时间戳小于上一个时间戳,抛出异常,因为时间戳不能倒退。
- 如果当前时间戳等于上一个时间戳,增加序列号(sequence),如果序列号达到最大值,等待下一个毫秒。
- 如果当前时间戳大于上一个时间戳,重置序列号(sequence)为0。
- 将时间戳、数据中心ID、工作节点ID和序列号组合成一个64位的Long型数字,即生成的ID。
雪花算法的优点
- 唯一性:雪花算法生成的ID是唯一的,因为它基于时间戳和序列号。
- 递增性:雪花算法生成的ID是递增的,因为时间戳是递增的。
- 高性能:雪花算法可以生成大量的ID,适合高并发的应用场景。
雪花算法的缺点
- 依赖时间戳:雪花算法依赖时间戳,需要确保时间戳的准确性和一致性。
- 序列号溢出:如果序列号溢出,需要等待下一个毫秒,可能会导致性能下降。
总的来说,雪花算法是一种高效、唯一、递增的ID生成算法,适合分布式系统和高并发应用场景。
那么使用这种算法如何统计所有中心所有节点的数据总量值呢?
使用雪花算法生成的ID,可以通过解析ID的结构来统计所有中心所有节点的数据总量值。下面是一个可能的解决方案:
- 将所有中心所有节点的ID收集到一个数据库或缓存中。
- 对每个ID,提取高32位的时间戳、中间10位的数据中心ID和工作节点ID、低12位的序列号。
- 根据数据中心ID和工作节点ID,统计每个中心每个节点的数据量。
- 对所有中心所有节点的数据量进行汇总,得到总的数据总量值。
具体实现可以通过以下步骤:
- 创建一个数据库表或缓存,用于存储所有中心所有节点的ID。
- 创建一个统计函数或脚本,用于解析ID的结构和统计数据量。
- 在统计函数或脚本中,使用以下步骤:
- 提取高32位的时间戳,用于过滤掉旧的数据。
- 提取中间10位的数据中心ID和工作节点ID,用于确定数据来自哪个中心哪个节点。
- 提取低12位的序列号,用于统计每个中心每个节点的数据量。
- 使用数据中心ID和工作节点ID作为键,统计每个中心每个节点的数据量。
- 对所有中心所有节点的数据量进行汇总,得到总的数据总量值。
例如,在MySQL数据库中,可以使用以下SQL语句来统计所有中心所有节点的数据总量值:
CREATE TABLE ids (
id BIGINT PRIMARY KEY
);
CREATE INDEX idx_id ON ids (id);
DELIMITER //
CREATE FUNCTION get_data_center_id(id BIGINT) RETURNS INT
BEGIN
RETURN (id >> 22) & 0x3FF;
END//
CREATE FUNCTION get_worker_id(id BIGINT) RETURNS INT
BEGIN
RETURN (id >> 12) & 0x3FF;
END//
CREATE FUNCTION get_sequence(id BIGINT) RETURNS INT
BEGIN
RETURN id & 0xFFF;
END//
DELIMITER ;
SELECT
data_center_id,
worker_id,
COUNT(*) AS data_count
FROM
ids
GROUP BY
data_center_id,
worker_id;
SELECT
SUM(data_count) AS total_data_count
FROM
(
SELECT
data_center_id,
worker_id,
COUNT(*) AS data_count
FROM
ids
GROUP BY
data_center_id,
worker_id
) AS subquery;
在上面的示例中,我们首先创建了一个ids表,用于存储所有中心所有节点的ID。然后,我们创建了三个函数,用于提取数据中心ID、工作节点ID和序列号。最后,我们使用这些函数来统计每个中心每个节点的数据量,并对所有中心所有节点的数据量进行汇总。