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;
    }
}

posted @   genec  阅读(66)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示