当前位置: 首页 > news >正文

Snowflake 算法的实现

snowflake(雪花算法)是一个开源的分布式 ID 生成算法,结果是一个 long 型的 ID。snowflake 算法将 64bit 划分为多段,分开来标识机器、时间等信息,具体组成结构如下图所示:
在这里插入图片描述
snowflake 算法的核心思想是使用 41bit 作为毫秒数,10bit 作为机器的 ID(比如其中 5 个 bit 可作为数据中心,5 个 bit 作为机器 ID),12bit 作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是 0。snowflake 算法可以根据自身业务的需求进行一定的调整。比如估算未来的数据中心个数,每个数据中心内的机器数,以及统一毫秒内的并发数来调整在算法中所需要的 bit 数。snowflake 算法的优势是稳定性高,不依赖于数据库等第三方系统;使用灵活方便,可以根据业务需求的特性来调整算法中的 bit 位;单机上 ID 单调自增,毫秒数在高位,自增序列在低位,整个 ID 是趋势递增的。而其也存在一定的缺陷,包括强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务处于不可用状态;ID 可能不是全局递增,虽然 ID 在单机上是递增的,但是由于涉及到分布式环境下的每个机器节点上的时钟,可能会出现不是全局递增的场景。

#pragma once

#include <chrono>
#include <mutex>
#include <stdexcept>

class Snowflake
{
   public:
    Snowflake(uint64_t datacenter_id, uint64_t machine_id) : datacenter_id_(datacenter_id), machine_id_(machine_id)
    {
        if (datacenter_id > kMaxDatacenterId || machine_id > kMaxMachineId)
        {
            throw std::invalid_argument("Datacenter ID or Machine ID exceeds maximum value");
        }
    }

    uint64_t Generate()
    {
        std::lock_guard<std::mutex> lock(mutex_);
        uint64_t current_timestamp = GetCurrentTimestamp();

        if (current_timestamp < last_timestamp_)
        {
            throw std::runtime_error("Clock moved backwards. Refusing to generate ID.");
        }

        if (current_timestamp == last_timestamp_)
        {
            sequence_ = (sequence_ + 1) & kMaxSequence;
            if (sequence_ == 0)
            {
                current_timestamp = WaitNextMillis(current_timestamp);
            }
        }
        else
        {
            sequence_ = 0;
        }

        last_timestamp_ = current_timestamp;

        return ((current_timestamp - kEpoch) << kTimestampShift) | (datacenter_id_ << kDatacenterIdShift) |
               (machine_id_ << kMachineIdShift) | sequence_;
    }

   private:
    uint64_t GetCurrentTimestamp() const
    {
        return std::chrono::duration_cast<std::chrono::milliseconds>(
                   std::chrono::system_clock::now().time_since_epoch())
            .count();
    }

    uint64_t WaitNextMillis(uint64_t last_timestamp) const
    {
        uint64_t timestamp = GetCurrentTimestamp();
        while (timestamp <= last_timestamp)
        {
            timestamp = GetCurrentTimestamp();
        }
        return timestamp;
    }

   private:
    uint64_t datacenter_id_;       // 数据中心ID
    uint64_t machine_id_;          // 机器ID
    uint64_t sequence_ = 0;        // 序列号
    uint64_t last_timestamp_ = 0;  // 上次生成ID的时间戳

    // 配置参数
    static constexpr uint64_t kSequenceBits = 12;     // 序列号占用位数
    static constexpr uint64_t kMachineIdBits = 5;     // 机器ID占用位数
    static constexpr uint64_t kDatacenterIdBits = 5;  // 数据中心ID占用位数

    // 最大值计算
    static constexpr uint64_t kMaxSequence = (1ULL << kSequenceBits) - 1;
    static constexpr uint64_t kMaxMachineId = (1ULL << kMachineIdBits) - 1;
    static constexpr uint64_t kMaxDatacenterId = (1ULL << kDatacenterIdBits) - 1;

    // 位移量
    static constexpr uint64_t kMachineIdShift = kSequenceBits;                      // 机器ID左移位数
    static constexpr uint64_t kDatacenterIdShift = kSequenceBits + kMachineIdBits;  // 数据中心ID左移位数
    static constexpr uint64_t kTimestampShift = kSequenceBits + kMachineIdBits + kDatacenterIdBits;  // 时间戳左移位数

    // 起始时间(2020-01-01 00:00:0 UTC)
    static constexpr uint64_t kEpoch = 1577836800000ULL;

    std::mutex mutex_;
};

使用示例:

#include <iostream>

#include "Snowflake.h"

int main()
{
    try
    {
        Snowflake snowflake(1, 1);  // 数据中心ID=1,机器ID=1

        for (int i = 0; i < 10; ++i)
        {
            std::cout << snowflake.Generate() << std::endl;
        }
    }
    catch (const std::exception& e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
    }
    return 0;
}

相关文章:

  • PHP开发:小区物业管理缴费小程序uniapp在线报修系统、活动报名、在线商城
  • 开源CDN产品-GoEdge
  • 靶场(十七)---小白心得思路分析---Hutch
  • 笔记本+移动端维修全套教程
  • Another Redis Desktop Manager下载安装使用
  • OpenCV三维解算常用方法C++
  • GraalVM原生镜像支持:Spring Cloud应用启动速度提升90%
  • 双指针---《移动零》
  • 基于LabVIEW 的虚拟功率分析仪设计(自动化院仪器专业)
  • mac命令行快捷键
  • HarmonyOS:基于axios实现文件的下载以及下载进度的监听
  • Android14 原生PackageInstaller安装某些apk报错问题
  • 【初探数据结构】快速排序的四种实现方式(Hoare,挖坑,前后指针,非递归)
  • 深入解析 C++20 中的 std::bind_front:高效函数绑定与参数前置
  • Java高频面试之集合-18
  • 基于SSM框架的线上甜品销售系统(源码+lw+部署文档+讲解),源码可白嫖!
  • Java并发编程 什么是分布式锁 跟其他的锁有什么区别 底层原理 实战讲解
  • 加快推进智慧水务发展,实现水务系统安全、高效运行
  • 2024年3月全国计算机等级考试真题(二级C语言)
  • 树莓派ollama docker报错尝试网上方法
  • 如何判断网站有cdn加速/搜索引擎营销案例有哪些
  • 山东临沂网站建设/怎么进行网络营销
  • wordpress 位置/seo网站分析报告
  • 上海网站建设,分类广告/西安seo站内优化
  • 做视频网站犯法么/百度seo营销公司
  • 自定义网站建设/关键词热度