当前位置: 首页 > news >正文

分布式生成 ID 策略的演进和最佳实践,含springBoot 实现(Java版本)

一、背景

在单体架构中,ID 通常使用数据库自增或 UUID 即可满足需求。但在微服务、分布式环境中,这些方式存在 性能瓶颈、重复冲突、时序不全 等问题。因此,分布式 ID 生成策略应运而生,用于确保在高并发、跨节点、异地部署的系统中,生成全局唯一、趋势递增、高性能的 ID


二、演进历程

  1. 单机自增 ID(如数据库自增)
  2. Java 原生 UUID
  3. 工具类生成(如雪花算法、KeyUtil 等)
  4. 中间件分布式协调(如 Zookeeper、Redis)
  5. 分布式 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();
}

补充建议

场景推荐方案说明
读写频繁、业务 IDLeaf号段模式高性能但需额外部署
单机/容器化部署百度 UidGenerator轻量化、易嵌入
多服务/多节点Redisson + SnowflakeworkerId 由 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 设计
http://www.lryc.cn/news/582241.html

相关文章:

  • 【R语言】Can‘t subset elements that don‘t exist.
  • LastActivityView -查看电脑上的所有操作记录
  • 初识Neo4j之入门介绍(一)
  • 【Linux系统】Linux权限 | Shell命令以及运行原理
  • Python爬虫图片验证码和滑块验证码识别总结
  • Taro+Vue3实现微信小程序富文本编辑器组件开发指南
  • OpenCV人脸分析------绘制面部关键点函数drawFacemarks()
  • 虚幻引擎UE5 GAS开发RPG游戏-02 设置英雄角色-18 改成网络多人游戏
  • turborepo 如何解决git管理包过大的问题
  • 5、Receiving Messages:Message Listener Containers
  • Python实现文件夹中文件名与Excel中存在的文件名进行对比,并进行删除操作
  • 【无标题】三维拓扑量子色动力学模型:理论重构与实验验证
  • day16——Java集合进阶(Collection、List、Set)
  • windows安装python环境以及对应编辑器的详细流程
  • 从依赖地狱到依赖天堂PNPM
  • VmWare 安装 mac 虚拟机
  • 大模型在肾囊肿诊疗全流程预测及应用研究报告
  • 【保姆级喂饭教程】Git图形化客户端Sourcetree安装及使用教程
  • Linux系统从入门到精通!第四天(shell编程和Docker)
  • codeforces Round 1021-1030(部分题解)
  • 【Note】《Kafka: The Definitive Guide》第7章 Building Data Pipelines
  • 源哈希(sh)解析
  • etcd-cpp-apiv3 二次封装
  • [学习] C语言数学库函数背后的故事:`double erf(double x)`
  • 【数据分析】R语言基于虚弱指数的心血管疾病风险评估
  • JS实现基础算法与dom的结构
  • Spring MVC HandlerInterceptor 拦截请求及响应体
  • 【Netty高级】Netty的技术内幕
  • token非对称加密
  • AI的出现,是否能替代IT从业者