一、背景
在单体架构中,ID 通常使用数据库自增或 UUID 即可满足需求。但在微服务、分布式环境中,这些方式存在 性能瓶颈、重复冲突、时序不全 等问题。因此,分布式 ID 生成策略应运而生,用于确保在高并发、跨节点、异地部署的系统中,生成全局唯一、趋势递增、高性能的 ID。
二、演进历程
- 单机自增 ID(如数据库自增)
- Java 原生 UUID
- 工具类生成(如雪花算法、KeyUtil 等)
- 中间件分布式协调(如 Zookeeper、Redis)
- 分布式 ID 服务系统(如美团 Leaf、百度 UidGenerator)
三、基础 ID 生成策略
1. MySQL 自增 ID
1.1 优点
- 简单易用,零开发成本
- 自增有序,便于数据库索引管理
1.2 缺点
- 分布式扩展困难(主键冲突)
- 依赖数据库,存在性能瓶颈、单点问题
- 无法保证全局唯一
1.3 示例
sql
CREATE TABLE user (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255)
);
2. Java 原生 UUID
2.1 优点
- 纯 Java,无需第三方依赖
- 唯一性强,几乎无重复风险
2.2 缺点
- 长度大(128-bit),占空间
- 无序,不适合数据库主键
- 不可读,不适合日志分析
2.3 示例
java
String uuid = UUID.randomUUID().toString().replace("-", "");
3. 第三方工具生成 UUID
3.1 糊涂工具包(Hutool 的雪花算法)
3.1.1 优点
- 实现了雪花算法,趋势递增
- 本地生成,高性能
- 可配置机器标识
3.1.2 缺点
- 依赖时间戳,受系统时钟影响
- 多节点部署需手动配置 workerId,易冲突
3.1.3 示例
java
Snowflake snowflake = IdUtil.getSnowflake(1, 1);
long id = snowflake.nextId();
3.2 KeyUtil 工具类
3.2.1 优点
- 可自定义规则(前缀+时间戳+随机数)
- 可用于订单号等业务 ID
3.2.2 缺点
- 并不保证全局唯一
- 高并发下可能存在重复(需加锁)
3.2.3 示例
java
public static synchronized String generateKey() {
return System.currentTimeMillis() + String.valueOf(new Random().nextInt(1000));
}
四、分布式可用 ID 生成策略
1. Zookeeper 生成 UUID(临时顺序节点)
1.1 优点
- 利用有序节点,自带递增特性
- 强一致性保障
1.2 缺点
- ZK 写性能一般,QPS 低(几百级别)
- 可用性依赖于 ZK 集群稳定性
1.3 示例
java
client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
.forPath("/order/order_", data);
2. Redis 生成 UUID(原子自增)
2.1 优点
- 支持高并发,性能优于 ZK
- Redis 自增操作天然原子性
2.2 缺点
- Redis 挂掉或失去连接会影响生成
- 无内置时间维度
2.3 示例
java
Long id = redisTemplate.opsForValue().increment("order_id");
3. 雪花算法(Snowflake)
3.1 优点
- 高性能,本地生成,无需 RPC
- 结果有序,适合数据库索引
3.2 缺点
- 时间依赖强,NTP 回拨可能会导致重复 ID
- 需解决 workerId 冲突问题
3.3 示例
java
public class SnowflakeIdWorker {
private long datacenterId; // 数据中心ID
private long workerId; // 机器ID
// ...
}
4. UUID 的两种方式(划重点)
4.1 批量生成 UUID
4.1.1 优点
- 减少 Redis/ZK 的频繁访问
- 支持预分配,离线缓存
4.1.2 缺点
- 批量失效会导致 ID 浪费
- 实现复杂度高
4.1.3 示例
java
// 预申请 1000 个 ID
List<Long> idList = leafService.getBatchId("order", 1000);
4.2 单点生成 UUID
4.2.1 优点
- 简单直接,集中式统一管理
- 易于控制和监控
4.2.2 缺点
- 容易成为性能瓶颈
- 容错性差,需 HA
4.2.3 示例
调用中心服务接口:
http
GET http://id-service/api/uuid
5. 分布式 ID 生成架构(划重点)
典型架构:
- 前端应用 → 统一 ID 服务(高可用)→ 本地缓存池 + Redis 预分配 + 雪花算法回退
常见方案:
- 美团 Leaf(号段模式 + Snowflake)
- 百度 UidGenerator(ringbuffer + Snowflake)
NTP 问题说明(备注)
-
雪花算法、Leaf 都强依赖时间戳
-
若服务器时钟出现回拨,将导致 ID 重复或不递增
-
最佳实践:
- 启用 NTP 自动同步
- 对时钟回拨进行容错处理(阻塞、报警)
五、适应场景及落地方案
1. 业务 ID 生成方案设计
方案示例:
text
区域码(2) + 货架(2) + 机器码(2) + 时间戳(10) + 自增序列(6)
= 22位数字型ID
- 保证唯一性、可读性、趋势有序
- 支持分库分表、日志追踪
2. 小厂、中厂、大厂方案建议
小厂(单体应用 / 小型微服务)
- Redis + 简单工具类(如雪花算法)
- 实现快速、轻量可控
中厂(10+服务,千级并发)
- Redis 分布式生成 + Leaf/UidGenerator 服务
- 引入批量生成、缓存机制
大厂(亿级 ID 需求)
- 专门 ID 生成服务集群
- 混合架构:Leaf + Snowflake + 数据中心部署
- 配合 CMDB 管理 workerId,容灾自动切换
六、 Leaf、百度UidGenerator、Redisson+Snowflake 的Spring Boot实践样例代码和架构图
下面我将为你提供完整的三种主流分布式 ID 生成方案的 Spring Boot 实践样例代码以及架构图设计,涵盖:
- Leaf(号段模式)
- 百度 UidGenerator
- Redisson + 雪花算法(本地生成)
一、Leaf(美团)实现
架构图:
+-----------+ +-------------+ +-----------+
| 应用服务A | --> | Leaf Server | --> | MySQL DB |
+-----------+ +-------------+ +-----------+
|
| -> 返回号段ID(如1000~1999)
1.1 引入依赖
Leaf 开源地址:https://github.com/Meituan-Dianping/Leaf
xml
<dependency>
<groupId>com.sankuai.inf.leaf</groupId>
<artifactId>leaf-core</artifactId>
<version>1.0.0</version>
</dependency>
1.2 MySQL 表结构(号段模式)
sql
CREATE TABLE leaf_alloc (
biz_tag VARCHAR(128) NOT NULL,
max_id BIGINT NOT NULL,
step INT NOT NULL,
description VARCHAR(256),
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (biz_tag)
);
1.3 示例代码集成
java
@Autowired
private SegmentService segmentService;
@GetMapping("/id/leaf")
public Long getLeafId(@RequestParam String key) {
Result result = segmentService.getId(key);
return result.getId();
}
配置文件中需配置 leaf.name 和数据源,建议单独部署 Leaf Server。
二、百度 UidGenerator 实现
架构图:
+-----------+ +------------------+ +-----------+
| 应用服务A | --> | UidGenerator组件 | --> | 本地RingBuffer |
+-----------+ +------------------+ +-----------+
|
| -> 基于Snowflake生成并缓存在RingBuffer中
2.1 引入依赖
xml
<dependency>
<groupId>com.baidu.fsg</groupId>
<artifactId>uid-generator</artifactId>
<version>1.0.0</version>
</dependency>
注意:百度未发布至 Maven 中央仓库,可使用 GitHub 地址 自行打包。
2.2 Spring Boot 配置
java
@Configuration
public class UidConfig {
@Bean
public UidGenerator uidGenerator() {
DefaultUidGenerator uidGenerator = new DefaultUidGenerator();
uidGenerator.setWorkerIdAssigner(() -> 1L); // workerId 可根据实际配置
return uidGenerator;
}
}
2.3 示例接口
java
@Autowired
private UidGenerator uidGenerator;
@GetMapping("/id/uid")
public Long getUid() {
return uidGenerator.getUID();
}
三、Redisson + 雪花算法实现
架构图:
+-----------+ +------------------------+
| 应用服务A | --> | SnowflakeIdGenerator |
+-----------+ | + Redisson WorkerId |
+------------------------+
3.1 引入依赖
xml
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.27.2</version>
</dependency>
3.2 雪花算法封装类
java
@Component
public class RedissonSnowflakeIdGenerator {
private final Snowflake snowflake;
public RedissonSnowflakeIdGenerator(RedissonClient redissonClient) {
RAtomicLong workerId = redissonClient.getAtomicLong("worker-id-generator");
long id = workerId.incrementAndGet() % 32;
this.snowflake = IdUtil.getSnowflake(id, 1); // dataCenterId = 1
}
public long nextId() {
return snowflake.nextId();
}
}
3.3 示例接口
java
@Autowired
private RedissonSnowflakeIdGenerator idGenerator;
@GetMapping("/id/snowflake")
public Long getSnowflakeId() {
return idGenerator.nextId();
}
补充建议
场景 | 推荐方案 | 说明 |
---|---|---|
读写频繁、业务 ID | Leaf号段模式 | 高性能但需额外部署 |
单机/容器化部署 | 百度 UidGenerator | 轻量化、易嵌入 |
多服务/多节点 | Redisson + Snowflake | workerId 由 Redis 控制分配 |
七 代码整合
🚀 项目结构说明
com.example.id
├── controller/IdController.java // 提供对外统一 ID 生成接口
├── leaf/LeafIdService.java // Leaf 号段模式服务封装
├── uid/UidGeneratorConfig.java // 百度 UID 配置
├── uid/UidService.java // 百度 UID 接口封装
└── snowflake/RedissonSnowflakeIdGenerator.java // Redisson + 雪花实现
☑️ 示例接口(IdController.java)
java
@RestController
@RequestMapping("/id")
public class IdController {
@Autowired private LeafIdService leafService;
@Autowired private UidService uidService;
@Autowired private RedissonSnowflakeIdGenerator snowflake;
@GetMapping("/leaf")
public Long getLeafId(@RequestParam String key) {
return leafService.getId(key);
}
@GetMapping("/uid")
public Long getUid() {
return uidService.getUid();
}
@GetMapping("/snowflake")
public Long getSnowflakeId() {
return snowflake.nextId();
}
}
✅ LeafIdService.java
java
@Component
public class LeafIdService {
@Autowired
private SegmentService segmentService;
public Long getId(String key) {
return segmentService.getId(key).getId();
}
}
需引入 Leaf Core,并正确配置 leaf.properties 与数据源。
✅ UidGeneratorConfig.java
java
@Configuration
public class UidGeneratorConfig {
@Bean
public DefaultUidGenerator uidGenerator() {
DefaultUidGenerator generator = new DefaultUidGenerator();
generator.setWorkerIdAssigner(() -> 1L); // 本地配置/动态分配
return generator;
}
}
✅ UidService.java
java
@Component
public class UidService {
@Autowired
private UidGenerator uidGenerator;
public Long getUid() {
return uidGenerator.getUID();
}
}
✅ RedissonSnowflakeIdGenerator.java
java
@Component
public class RedissonSnowflakeIdGenerator {
private final Snowflake snowflake;
public RedissonSnowflakeIdGenerator(RedissonClient redissonClient) {
long workerId = redissonClient.getAtomicLong(\"worker-id\").incrementAndGet() % 32;
this.snowflake = IdUtil.getSnowflake(workerId, 1);
}
public long nextId() {
return snowflake.nextId();
}
}
📄 application.yml 示例配置
yaml
server:
port: 8080
spring:
redis:
host: localhost
port: 6379
leaf:
name: leaf-server
✅ 后续填坑
- Leaf Server 独立部署和配置指引
- UID Generator 的 Docker 镜像构建方式
- Redisson 的集群化 workerId 设计