分布式生成 ID 策略的演进和最佳实践,含springBoot 实现(Java版本)
一、背景
在单体架构中,ID 通常使用数据库自增或 UUID 即可满足需求。但在微服务、分布式环境中,这些方式存在 性能瓶颈、重复冲突、时序不全 等问题。因此,分布式 ID 生成策略应运而生,用于确保在高并发、跨节点、异地部署的系统中,生成全局唯一、趋势递增、高性能的 ID。
二、演进历程
- 单机自增 ID(如数据库自增)
- Java 原生 UUID
- 工具类生成(如雪花算法、KeyUtil 等)
- 中间件分布式协调(如 Zookeeper、Redis)
- 分布式 ID 服务系统(如美团 Leaf、百度 UidGenerator)
三、基础 ID 生成策略
1. MySQL 自增 ID
1.1 优点
- 简单易用,零开发成本
- 自增有序,便于数据库索引管理
1.2 缺点
- 分布式扩展困难(主键冲突)
- 依赖数据库,存在性能瓶颈、单点问题
- 无法保证全局唯一
1.3 示例
CREATE TABLE user (id BIGINT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(255)
);
2. Java 原生 UUID
2.1 优点
- 纯 Java,无需第三方依赖
- 唯一性强,几乎无重复风险
2.2 缺点
- 长度大(128-bit),占空间
- 无序,不适合数据库主键
- 不可读,不适合日志分析
2.3 示例
String uuid = UUID.randomUUID().toString().replace("-", "");
3. 第三方工具生成 UUID
3.1 糊涂工具包(Hutool 的雪花算法)
3.1.1 优点
- 实现了雪花算法,趋势递增
- 本地生成,高性能
- 可配置机器标识
3.1.2 缺点
- 依赖时间戳,受系统时钟影响
- 多节点部署需手动配置 workerId,易冲突
3.1.3 示例
Snowflake snowflake = IdUtil.getSnowflake(1, 1);
long id = snowflake.nextId();
3.2 KeyUtil 工具类
3.2.1 优点
- 可自定义规则(前缀+时间戳+随机数)
- 可用于订单号等业务 ID
3.2.2 缺点
- 并不保证全局唯一
- 高并发下可能存在重复(需加锁)
3.2.3 示例
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 示例
client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/order/order_", data);
2. Redis 生成 UUID(原子自增)
2.1 优点
- 支持高并发,性能优于 ZK
- Redis 自增操作天然原子性
2.2 缺点
- Redis 挂掉或失去连接会影响生成
- 无内置时间维度
2.3 示例
Long id = redisTemplate.opsForValue().increment("order_id");
3. 雪花算法(Snowflake)
3.1 优点
- 高性能,本地生成,无需 RPC
- 结果有序,适合数据库索引
3.2 缺点
- 时间依赖强,NTP 回拨可能会导致重复 ID
- 需解决 workerId 冲突问题
3.3 示例
public class SnowflakeIdWorker {private long datacenterId; // 数据中心IDprivate long workerId; // 机器ID// ...
}
4. UUID 的两种方式(划重点)
4.1 批量生成 UUID
4.1.1 优点
- 减少 Redis/ZK 的频繁访问
- 支持预分配,离线缓存
4.1.2 缺点
- 批量失效会导致 ID 浪费
- 实现复杂度高
4.1.3 示例
// 预申请 1000 个 ID
List<Long> idList = leafService.getBatchId("order", 1000);
4.2 单点生成 UUID
4.2.1 优点
- 简单直接,集中式统一管理
- 易于控制和监控
4.2.2 缺点
- 容易成为性能瓶颈
- 容错性差,需 HA
4.2.3 示例
调用中心服务接口:
GET http://id-service/api/uuid
5. 分布式 ID 生成架构(划重点)
典型架构:
- 前端应用 → 统一 ID 服务(高可用)→ 本地缓存池 + Redis 预分配 + 雪花算法回退
常见方案:
- 美团 Leaf(号段模式 + Snowflake)
- 百度 UidGenerator(ringbuffer + Snowflake)
NTP 问题说明(备注)
-
雪花算法、Leaf 都强依赖时间戳
-
若服务器时钟出现回拨,将导致 ID 重复或不递增
-
最佳实践:
- 启用 NTP 自动同步
- 对时钟回拨进行容错处理(阻塞、报警)
五、适应场景及落地方案
1. 业务 ID 生成方案设计
方案示例:
区域码(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
<dependency><groupId>com.sankuai.inf.leaf</groupId><artifactId>leaf-core</artifactId><version>1.0.0</version>
</dependency>
1.2 MySQL 表结构(号段模式)
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 示例代码集成
@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 引入依赖
<dependency><groupId>com.baidu.fsg</groupId><artifactId>uid-generator</artifactId><version>1.0.0</version>
</dependency>
注意:百度未发布至 Maven 中央仓库,可使用 GitHub 地址 自行打包。
2.2 Spring Boot 配置
@Configuration
public class UidConfig {@Beanpublic UidGenerator uidGenerator() {DefaultUidGenerator uidGenerator = new DefaultUidGenerator();uidGenerator.setWorkerIdAssigner(() -> 1L); // workerId 可根据实际配置return uidGenerator;}
}
2.3 示例接口
@Autowired
private UidGenerator uidGenerator;@GetMapping("/id/uid")
public Long getUid() {return uidGenerator.getUID();
}
三、Redisson + 雪花算法实现
架构图:
+-----------+ +------------------------+
| 应用服务A | --> | SnowflakeIdGenerator |
+-----------+ | + Redisson WorkerId |+------------------------+
3.1 引入依赖
<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.27.2</version>
</dependency>
3.2 雪花算法封装类
@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 示例接口
@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)
@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
@Component
public class LeafIdService {@Autowiredprivate SegmentService segmentService;public Long getId(String key) {return segmentService.getId(key).getId();}
}
需引入 Leaf Core,并正确配置 leaf.properties 与数据源。
✅ UidGeneratorConfig.java
@Configuration
public class UidGeneratorConfig {@Beanpublic DefaultUidGenerator uidGenerator() {DefaultUidGenerator generator = new DefaultUidGenerator();generator.setWorkerIdAssigner(() -> 1L); // 本地配置/动态分配return generator;}
}
✅ UidService.java
@Component
public class UidService {@Autowiredprivate UidGenerator uidGenerator;public Long getUid() {return uidGenerator.getUID();}
}
✅ RedissonSnowflakeIdGenerator.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 示例配置
server:port: 8080spring:redis:host: localhostport: 6379leaf:name: leaf-server
✅ 后续填坑
- Leaf Server 独立部署和配置指引
- UID Generator 的 Docker 镜像构建方式
- Redisson 的集群化 workerId 设计