谈谈分布式ID生成器
谈谈分布式ID生成器
在后端开发中,唯一 ID 是一个基础而关键的需求。无论是用户注册时生成的用户 ID、下单时的订单号,还是日志系统中的 TraceId,唯一 ID 都承担着 数据唯一标识 的核心作用。
在单体应用时代,很多系统直接依赖数据库的自增主键来生成 ID,这种方式简单易用,能够满足小规模系统的需求。但随着系统规模不断扩大,传统自增ID逐渐暴露出数据泄露风险、分库分表困难、性能瓶颈等严重问题,促使我们寻找更适合分布式环境的ID生成方案。
常见分布式唯一 ID 方案
一、自增ID
利用数据库的 AUTO_INCREMENT 实现,这是最直观的ID生成方式,也是初学者的首选方案。
CREATE TABLE user (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL
);
优点 :实现简单,性能良好,ID具有递增特性,适合作为数据库主键。
缺点 :
- 安全风险 :自增ID具有明显的规律性,容易被恶意用户通过枚举方式获取敏感数据,存在严重的数据泄露风险
- 分库分表困难 :在分布式环境下,多个数据库实例的自增ID可能发生冲突,需要引入复杂的分配策略(如库号 + 表号拼接)
- 扩展性限制 :单点依赖数据库,无法满足高并发场景下的ID生成需求
二、UUID
UUID(Universally Unique Identifier)是一种标准化的128位标识符,通过Java官方的 java.util.UUID.randomUUID() 方法可以轻松生成全局唯一的ID。
import java.util.UUID;
public class UUIDExample {
public static void main(String[] args) {
String id = UUID.randomUUID().toString();
System.out.println(id); // 输出类似:550e8400-e29b-41d4-a716-446655440000
}
}
优点 :
- 全局唯一性 :基于时间戳、随机数和MAC地址生成,理论上保证全局唯一
- 安全性 :无序特性使其难以被枚举攻击
- 无中心化 :无需依赖外部服务,本地即可生成
缺点 :
- 存储开销 :长度较长(36个字符),占用更多存储空间
- 索引性能 :无序特性导致B+树索引频繁分裂,严重影响数据库写入和查询性能
- 业务适用性 :不具备时间递增性,不适合需要按时间排序的业务场景
三、雪花ID(Snowflake)
主要组成:
- 固定值 :符号位
- 时间戳 :调用时间戳(ms)减去程序设计时间戳的差值
- 机器id 、服务id:区别不同的生成机器
- 序号 :同一毫秒的自增位数
雪花Id基本能应付大多数业务开发场景,能够保证:
优点 :
- 高性能 :本地生成,无网络开销,单机QPS可达百万级别
- 趋势递增 :时间戳在前,保证ID整体递增,适合数据库主键
- 分布式友好 :通过机器ID保证不同节点生成的ID唯一性
- 存储高效 :64位长整型,存储空间占用小
缺点 :
- 时钟依赖 :严重依赖系统时钟,时钟回拨可能导致ID重复
- 机器ID管理 :需要为每台机器分配唯一的机器ID,增加运维复杂度
方案对比
| 方案 | 性能 | 唯一性 | 有序性 | 存储开销 | 适用场景 |
|---|---|---|---|---|---|
| 自增ID | 高 | 单库唯一 | 严格递增 | 小 | 小规模单体应用 |
| UUID | 中 | 全局唯一 | 无序 | 大 | 对性能要求不高的场景 |
| 雪花ID | 极高 | 分布式唯一 | 趋势递增 | 小 | 大规模分布式系统 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Aromatic!



