一、C++实现
snowflake.h
#pragma once
#include <stdint.h>
namespace algorithm
{
/**
* @brief snowflake序列号生成器
*/
class Snowflake
{
public:
/**
* @brief 构造函数
* @param datacenterId 数据中心ID(5位), 例如: 0~99999
* @param workerId 工作机器ID(5位), 例如: 0~99999
*/
Snowflake(uint64_t datacenterId = 0, uint64_t workerId = 0);
/**
* @brief 生成序列ID
* @return 序列ID, 例如: 6814090057511600129
*/
uint64_t generate(void);
/**
* @brief 生成序列ID(自动构造对象)
* @return 序列ID, 例如: 6814090057511600129
*/
static uint64_t easyGenerate();
private:
uint64_t m_flag; /* 符号位(1位),为0,通常不用 */
uint64_t m_timestamp; /* 时间戳(41位),精确到毫秒,支持2^41/365/24/60/60/1000=69.7年 */
/* 整个分布式系统内不会产生ID碰撞(由datacenterId和workerId作区分),支持1024个进程 */
uint64_t m_datacenterId; /* 数据中心ID(5位) */
uint64_t m_workerId; /* 工作机器ID(5位) */
uint64_t m_sequence; /* 序列号(12位),每毫秒从0开始自增,支持4096个编号 */
};
} // namespace algorithm
snowflake.cpp
#include "snowflake.h"
#include <atomic>
#include <chrono>
#include <random>
namespace algorithm
{
Snowflake::Snowflake(uint64_t datacenterId, uint64_t workerId)
: m_flag(0), m_datacenterId(datacenterId), m_workerId(workerId), m_sequence(0)
{
auto ntp = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
m_timestamp = (ntp.time_since_epoch().count() & 0x1FFFFFFFFFF);
}
uint64_t Snowflake::generate(void)
{
auto ntp = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
uint64_t newTime = (ntp.time_since_epoch().count() & 0x1FFFFFFFFFF);
if (newTime == m_timestamp)
{
++m_sequence;
}
else
{
m_sequence = 0;
m_timestamp = newTime;
}
return (m_timestamp << 22) + ((m_datacenterId & 0x1F) << 17) + ((m_workerId & 0x1F) << 12) + (m_sequence & 0xFFF);
}
uint64_t Snowflake::easyGenerate(void)
{
static std::uniform_int_distribution<std::mt19937::result_type> s_dist(1, 99999);
static std::mt19937 s_rng;
s_rng.seed(std::random_device()());
static Snowflake s_sf(s_dist(s_rng), s_dist(s_rng));
static std::atomic_flag s_glock = ATOMIC_FLAG_INIT;
uint64_t req = 0;
while (s_glock.test_and_set()) /* 等待原子锁 */
;
req = s_sf.generate();
s_glock.clear();
return req;
}
} // namespace algorithm