Snowflake算法生成分布式ID实现Go、C++
Snowflake 算法是一种用于生成全局唯一 ID 的分布式算法。它在分布式系统中被广泛应用,用于解决多节点同时生成 ID 的冲突问题。
Snowflake 算法的核心思想是将一个64位的长整数(Long)分解成多个部分,每个部分代表不同的信息,例如时间戳、节点ID和序列号。通过这种方式,Snowflake 算法可以在分布式环境下保证生成的 ID 具有唯一性。
Snowflake 算法将64位的整数划分如下:
- 第一位为符号位,一般不使用;
- 接下来的41位为时间戳,记录生成 ID 的时间,精确到毫秒级;
- 接下来的10位为节点ID,用于标识不同的节点;
- 最后的12位为序列号,用于记录同一节点在同一毫秒内生成的 ID 的顺序。
Snowflake 算法的优点包括:
- 生成的 ID 具有唯一性,几乎不会出现重复的情况;
- 生成的 ID 有序增长,可以按照时间先后进行排序;
- 算法简单、高效,并且对系统的依赖较低;
- 可以根据需求调整节点ID和序列号的位数,适应不同规模的分布式系统。
然而,Snowflake 算法也存在一些限制:
- 依赖于系统的时钟,如果时钟回拨或者不稳定,可能会导致生成的 ID 重复或无序;
- 节点ID的数量有限,最多支持1024个节点;
- 在极高并发的情况下,同一节点在同一毫秒内生成的 ID 可能会发生冲突。
总体而言,Snowflake 算法是一种简单、高效且具有较低复杂性的分布式ID生成算法,非常适合大多数分布式系统中生成唯一ID的需求。
Go实现
package main
import (
"fmt"
"sync"
"time"
)
// Snowflake 结构体
type Snowflake struct {
mutex sync.Mutex // 互斥锁
epoch int64 // 起始时间戳(毫秒)
nodeIDBits uint // 节点ID所占的位数
sequenceBits uint // 序列号所占的位数
nodeIDShift uint // 节点左移位数
timestampShift uint // 时间左移位数
sequenceMask int64 // 序列号有效位
nodeID int64 // 节点ID
lastTimestamp int64 // 上一次生成ID的时间戳
sequence int64 // 序列号
}
// NewSnowflake 函数用于创建一个Snowflake实例
func NewSnowflake(nodeID int64) *Snowflake {
s := new(Snowflake)
s.epoch = 1697354687979
s.nodeIDBits = 10
s.sequenceBits = 12
s.nodeIDShift = s.sequenceBits
s.timestampShift = s.nodeIDBits + s.nodeIDShift
s.sequenceMask = -1 ^ (-1 << s.sequenceBits)
s.nodeID = nodeID
s.lastTimestamp = -1
s.sequence = 0
s.mutex = sync.Mutex{}
return s
}
// GenerateID 方法用于生成一个全局唯一的ID
func (s *Snowflake) GenerateID() int64 {
s.mutex.Lock()
defer s.mutex.Unlock()
currentTimestamp := time.Now().UnixNano() / 1000000
if s.lastTimestamp == currentTimestamp {
s.sequence = (s.sequence + 1) & s.sequenceMask
if s.sequence == 0 {
for currentTimestamp <= s.lastTimestamp {
currentTimestamp = time.Now().UnixNano() / 1000000
}
}
} else {
s.sequence = 0
}
s.lastTimestamp = currentTimestamp
id := (currentTimestamp-s.epoch)<<s.timestampShift | (s.nodeID << s.nodeIDShift) | s.sequence
return id
}
func main() {
// 创建两个Snowflake实例,对应两个不同的节点
s1 := NewSnowflake(1)
s2 := NewSnowflake(2)
// 生成10个ID,并输出
for i := 0; i < 10; i++ {
id1 := s1.GenerateID()
id2 := s2.GenerateID()
fmt.Println("Node 1 ID:", id1)
fmt.Println("Node 2 ID:", id2)
fmt.Println()
}
}
C++实现
#include <iostream>
#include <chrono>
#include <mutex>
class Snowflake {
public:
Snowflake(int64_t nodeId);
~Snowflake(){}
int64_t generateId();
private:
static uint64_t getTimestamp() {
auto now = std::chrono::system_clock::now().time_since_epoch();
return std::chrono::duration_cast<std::chrono::milliseconds>(now).count();
}
private:
std::mutex mutex_;
uint64_t epoch_; // 起始时间戳
uint32_t nodeIdBits_; // 节点ID所占位数
uint32_t sequenceBits_; // 序列号所占位数
uint16_t nodeIdShift_; // 节点左移位数
uint16_t timestampShift_; // 时间左移位数
int64_t sequenceMask_; // 序列号有效位
int64_t nodeID_; // 节点ID
uint64_t lastTimestamp_; // 上一次生成ID得时间戳
int64_t sequence_; // 序列号
};
Snowflake::Snowflake(int64_t nodeId) {
this->epoch_ = 1697354687979;
this->nodeIdBits_ = 10;
this->sequenceBits_ = 12;
this->nodeIdShift_ = this->sequenceBits_;
this->timestampShift_ = this->nodeIdBits_ + this->nodeIdShift_;
this->sequenceMask_ = -1 ^ (-1 << this->sequenceBits_);
this->nodeID_ = nodeId;
this->lastTimestamp_ -1;
this->sequence_ = 0;
}
int64_t Snowflake::generateId() {
std::lock_guard<std::mutex> guard(this->mutex_);
uint64_t currentTimestamp = Snowflake::getTimestamp();
if (this->lastTimestamp_ == currentTimestamp) {
this->sequence_ = (this->sequence_ + 1) & this->sequenceMask_;
if (this->sequence_ == 0) {
while (currentTimestamp < this->lastTimestamp_) {
currentTimestamp = Snowflake::getTimestamp();
}
}
} else {
this->sequence_ = 0;
}
this->lastTimestamp_ = currentTimestamp;
int64_t id = static_cast<int64_t>(currentTimestamp - this->epoch_) << this->timestampShift_ |
(this->nodeID_ << this->nodeIdShift_) |
this->sequence_;
return id;
}
int main() {
Snowflake s1(1);
Snowflake s2(2);
for (int i = 0; i < 10; ++i) {
int64_t id1 = s1.generateId();
int64_t id2 = s2.generateId();
std::cout << "Node 1 ID: " << id1 << std::endl;
std::cout << "Node 2 ID: " << id2 << std::endl;
std::cout << std::endl;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~