前言
你有没有想过:在分布式系统中,订单ID、用户ID、消息ID是怎么生成的?为什么它们能保证全局唯一且趋势递增?
分布式ID生成器是微服务架构的基础组件。
今天我们从零实现两种分布式ID生成器:
· 雪花算法(Snowflake)—— 高性能、趋势递增
· 号段模式(Segment)—— 批量获取、高可用
---
一、分布式ID的核心要求
要求 说明
全局唯一 所有服务生成的ID不重复
趋势递增 ID按时间有序,利于数据库索引
高性能 单机每秒生成百万级ID
高可用 不依赖单一节点
可反解 从ID能解析出生成时间等信息
---
二、完整代码实现
1. 雪花算法
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <stdint.h>
// 雪花算法配置
typedef struct snowflake_config {
int worker_id_bits; // 机器ID位数(默认5)
int datacenter_id_bits; // 数据中心ID位数(默认5)
int sequence_bits; // 序列号位数(默认12)
uint64_t worker_id;
uint64_t datacenter_id;
uint64_t epoch; // 起始时间戳(毫秒)
} snowflake_config_t;
// 雪花算法生成器
typedef struct snowflake_generator {
snowflake_config_t config;
uint64_t last_timestamp;
uint64_t sequence;
uint64_t max_sequence;
uint64_t worker_id_shift;
uint64_t datacenter_id_shift;
uint64_t timestamp_shift;
uint64_t twepoch;
pthread_mutex_t mutex;
} snowflake_generator_t;
// 创建雪花算法生成器
snowflake_generator_t *snowflake_create(uint64_t worker_id, uint64_t datacenter_id) {
snowflake_generator_t *gen = malloc(sizeof(snowflake_generator_t));
memset(gen, 0, sizeof(snowflake_generator_t));
gen->config.worker_id_bits = 5;
gen->config.datacenter_id_bits = 5;
gen->config.sequence_bits = 12;
gen->config.worker_id = worker_id & ((1 << 5) - 1);
gen->config.datacenter_id = datacenter_id & ((1 << 5) - 1);
gen->config.epoch = 1288834974657ULL;
gen->max_sequence = (1 << gen->config.sequence_bits) - 1;
gen->worker_id_shift = gen->config.sequence_bits;
gen->datacenter_id_shift = gen->config.sequence_bits + gen->config.worker_id_bits;
gen->timestamp_shift = gen->config.sequence_bits +
gen->config.worker_id_bits +
gen->config.datacenter_id_bits;
gen->twepoch = gen->config.epoch;
gen->last_timestamp = 0;
gen->sequence = 0;
pthread_mutex_init(&gen->mutex, NULL);
return gen;
}
// 获取当前时间戳(毫秒)
uint64_t get_timestamp_ms(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
// 等待下一个毫秒
uint64_t wait_next_millis(uint64_t last_timestamp) {
uint64_t ts = get_timestamp_ms();
while (ts <= last_timestamp) {
ts = get_timestamp_ms();
usleep(100);
}
return ts;
}
// 生成ID
uint64_t snowflake_next_id(snowflake_generator_t *gen) {
pthread_mutex_lock(&gen->mutex);
uint64_t timestamp = get_timestamp_ms();
// 时钟回拨处理
if (timestamp < gen->last_timestamp) {
int64_t diff = gen->last_timestamp - timestamp;
if (diff < 5) {
usleep(diff * 1000);
timestamp = get_timestamp_ms();
} else {
pthread_mutex_unlock(&gen->mutex);
return 0;
}
}
if (timestamp == gen->last_timestamp) {
gen->sequence = (gen->sequence + 1) & gen->max_sequence;
if (gen->sequence == 0) {
timestamp = wait_next_millis(gen->last_timestamp);
}
} else {
gen->sequence = 0;
}
gen->last_timestamp = timestamp;
uint64_t id = ((timestamp - gen->twepoch) << gen->timestamp_shift) |
(gen->config.datacenter_id << gen->datacenter_id_shift) |
(gen->config.worker_id << gen->worker_id_shift) |
gen->sequence;
pthread_mutex_unlock(&gen->mutex);
return id;
}
// 解析ID
void snowflake_parse_id(uint64_t id, snowflake_config_t *config,
uint64_t *timestamp, uint64_t *datacenter_id,
uint64_t *worker_id, uint64_t *sequence) {
uint64_t timestamp_shift = config->sequence_bits +
config->worker_id_bits +
config->datacenter_id_bits;
*timestamp = (id >> timestamp_shift) + config->epoch;
*datacenter_id = (id >> (config->sequence_bits + config->worker_id_bits)) &
((1 << config->datacenter_id_bits) - 1);
*worker_id = (id >> config->sequence_bits) &
((1 << config->worker_id_bits) - 1);
*sequence = id & ((1 << config->sequence_bits) - 1);
}
```
2. 号段模式
```c
// 号段生成器
typedef struct segment_generator {
char biz_tag[64];
uint64_t max_id;
uint64_t step;
uint64_t current_id;
uint64_t segment_start;
uint64_t segment_end;
int initialized;
pthread_mutex_t mutex;
struct segment_generator *next;
} segment_generator_t;
// 号段管理器
typedef struct segment_manager {
segment_generator_t *generators;
pthread_mutex_t mutex;
} segment_manager_t;
segment_manager_t *g_segment_manager = NULL;
// 创建号段管理器
segment_manager_t *segment_manager_create(void) {
segment_manager_t *sm = malloc(sizeof(segment_manager_t));
sm->generators = NULL;
pthread_mutex_init(&sm->mutex, NULL);
return sm;
}
// 加载或创建号段
segment_generator_t *segment_load_or_create(segment_manager_t *sm,
const char *biz_tag, uint64_t step) {
pthread_mutex_lock(&sm->mutex);
segment_generator_t *gen = sm->generators;
while (gen) {
if (strcmp(gen->biz_tag, biz_tag) == 0) {
pthread_mutex_unlock(&sm->mutex);
return gen;
}
gen = gen->next;
}
gen = malloc(sizeof(segment_generator_t));
memset(gen, 0, sizeof(segment_generator_t));
strcpy(gen->biz_tag, biz_tag);
gen->step = step;
gen->current_id = 0;
gen->initialized = 0;
pthread_mutex_init(&gen->mutex, NULL);
gen->next = sm->generators;
sm->generators = gen;
pthread_mutex_unlock(&sm->mutex);
return gen;
}
// 获取下一段号段
void segment_fetch_next(segment_generator_t *gen) {
pthread_mutex_lock(&gen->mutex);
if (!gen->initialized) {
gen->max_id = 0;
gen->initialized = 1;
}
gen->segment_start = gen->max_id + 1;
gen->segment_end = gen->max_id + gen->step;
gen->max_id = gen->segment_end;
gen->current_id = gen->segment_start - 1;
printf("[Segment] 分配号段: %s [%llu, %llu]\n",
gen->biz_tag, gen->segment_start, gen->segment_end);
pthread_mutex_unlock(&gen->mutex);
}
// 获取下一个ID
uint64_t segment_next_id(segment_generator_t *gen) {
pthread_mutex_lock(&gen->mutex);
if (!gen->initialized || gen->current_id >= gen->segment_end) {
pthread_mutex_unlock(&gen->mutex);
segment_fetch_next(gen);
pthread_mutex_lock(&gen->mutex);
}
uint64_t id = ++gen->current_id;
pthread_mutex_unlock(&gen->mutex);
return id;
}
```
3. 混合生成器
```c
// 混合生成器
typedef struct hybrid_generator {
snowflake_generator_t *snowflake;
segment_generator_t *segment;
int mode;
} hybrid_generator_t;
hybrid_generator_t *hybrid_create(uint64_t worker_id, uint64_t datacenter_id,
const char *biz_tag, uint64_t step) {
hybrid_generator_t *hybrid = malloc(sizeof(hybrid_generator_t));
hybrid->snowflake = snowflake_create(worker_id, datacenter_id);
hybrid->segment = segment_load_or_create(g_segment_manager, biz_tag, step);
hybrid->mode = 0;
return hybrid;
}
uint64_t hybrid_next_id(hybrid_generator_t *hybrid) {
if (hybrid->mode == 0) {
return snowflake_next_id(hybrid->snowflake);
} else {
return segment_next_id(hybrid->segment);
}
}
```
4. 测试代码
```c
void test_snowflake() {
printf("=== 雪花算法测试 ===\n\n");
snowflake_generator_t *gen = snowflake_create(1, 1);
printf("生成10个ID:\n");
for (int i = 0; i < 10; i++) {
uint64_t id = snowflake_next_id(gen);
printf(" %llu\n", id);
uint64_t ts, dc, worker, seq;
snowflake_parse_id(id, &gen->config, &ts, &dc, &worker, &seq);
printf(" -> 时间:%llu, 数据中心:%llu, 机器:%llu, 序列:%llu\n",
ts, dc, worker, seq);
}
free(gen);
}
void test_segment() {
printf("\n=== 号段模式测试 ===\n\n");
segment_manager_t *sm = segment_manager_create();
g_segment_manager = sm;
segment_generator_t *gen = segment_load_or_create(sm, "order", 100);
segment_fetch_next(gen);
printf("生成20个ID:\n");
for (int i = 0; i < 20; i++) {
printf(" %llu\n", segment_next_id(gen));
}
free(sm);
}
void test_performance() {
printf("\n=== 性能测试 ===\n");
snowflake_generator_t *gen = snowflake_create(1, 1);
int count = 1000000;
clock_t start = clock();
for (int i = 0; i < count; i++) {
snowflake_next_id(gen);
}
clock_t end = clock();
double elapsed = (double)(end - start) / CLOCKS_PER_SEC;
printf("生成 %d 个ID, 耗时 %.3f 秒\n", count, elapsed);
printf("QPS: %.0f\n", count / elapsed);
free(gen);
}
int main() {
test_snowflake();
test_segment();
test_performance();
return 0;
}
```
---
三、编译和运行
```bash
gcc -o id_generator id_generator.c -lpthread
./id_generator
```
---
四、两种算法对比
特性 雪花算法 号段模式
ID类型 64位整数 64位整数
性能 极高 高
依赖 时钟同步 持久化存储
有序性 趋势递增 连续递增
可反解 ✅ ❌
适用场景 高并发 数据库主键
---
五、总结
通过这篇文章,你学会了:
· 分布式ID的核心要求
· 雪花算法的结构(时间戳+机器ID+序列号)
· 号段模式的批量获取
· 两种算法的适用场景
分布式ID生成器是微服务架构的基础组件。掌握它,你就理解了订单号、流水号等业务ID的设计原理。
下一篇预告:《从零实现一个分布式限流器:令牌桶与漏桶》
---
评论区分享一下你用过什么分布式ID方案~