分布式系统通过雪花算法生成唯一ID

服务器系列



前言

在分布式系统中,经常涉及到时间同步问题,这样由于时间校准,以及其他因素,可能导致服务器时间回退,如果恰巧回退前生成过一些id,而时间回退后,生成的id就有可能重复。现有
技术中对于此问题并没有给出明确的解决方案,而是简单的抛错处理,这样会造成在时间
被追回之前的这段时间服务不可用,导致交易失败,用户体验极其不好。


一、雪花算法

雪花算法是一种用于生成唯一ID的算法,它的核心思想是将时间戳、机器ID和序列号组合起来生成一个唯一的ID。具体实现过程如下:

获取当前时间戳,精确到毫秒级别。
将时间戳转换成二进制,并左移22位,腾出前22位用于存储机器ID。
获取机器ID,可以是MAC地址、IP地址或者自定义的ID。
将机器ID转换成二进制,并左移12位,腾出中间的12位用于存储序列号。
生成序列号,可以是自增的数字或者随机数。
将时间戳、机器ID和序列号进行位运算或者相加,生成一个64位的唯一ID。

二、C++的代码示例

#include <iostream>
#include <chrono>
#include <thread>

class Snowflake {
    
    
public:
    Snowflake(uint16_t worker_id) : worker_id_(worker_id), sequence_(0) {
    
    }

    uint64_t next_id() {
    
    
        uint64_t timestamp = get_timestamp();
        uint64_t id = ((timestamp - epoch_) << timestamp_left_shift_) |
                      (worker_id_ << worker_id_left_shift_) |
                      (sequence_++ & sequence_mask_);
        if (sequence_ > sequence_mask_) {
    
    
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
            sequence_ = 0;
        }
        return id;
    }

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

    const uint64_t epoch_ = 1609459200000; // 2021-01-01 00:00:00
    const uint64_t worker_id_left_shift_ = 12;
    const uint64_t timestamp_left_shift_ = 22;
    const uint64_t sequence_mask_ = 0xFFF;
    uint16_t worker_id_;
    uint64_t sequence_;
};

int main() {
    
    
    Snowflake snowflake(1);
    for (int i = 0; i < 10; i++) {
    
    
        std::cout << snowflake.next_id() << std::endl;
    }
    return 0;
}

总结

以上代码中,Snowflake类表示雪花算法,next_id()函数用于生成唯一ID。在构造函数中传入worker_id,表示机器ID。get_timestamp()函数用于获取当前时间戳,精确到毫秒级别。在next_id()函数中,根据时间戳、机器ID和序列号生成唯一ID,并将序列号自增,如果序列号超过了最大值,则等待1毫秒后重置序列号。最后输出生成的唯一ID。

猜你喜欢

转载自blog.csdn.net/zyq880625/article/details/131126425