分布式生成 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 示例
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 设计
相关推荐
netyeaxi27 分钟前
Java:使用spring-boot + mybatis如何打印SQL日志?
java·spring·mybatis
收破烂的小熊猫~37 分钟前
《Java修仙传:从凡胎到码帝》第四章:设计模式破万法
java·开发语言·设计模式
小七mod42 分钟前
【MyBatis】MyBatis与Spring和Spring Boot整合原理
spring boot·spring·mybatis
猴哥源码1 小时前
基于Java+SpringBoot的动物领养平台
java·spring boot
老任与码1 小时前
Spring AI Alibaba(1)——基本使用
java·人工智能·后端·springaialibaba
小兵张健1 小时前
武汉拿下 23k offer 经历
java·面试·ai编程
FreeBuf_1 小时前
Apache组件遭大规模攻击:Tomcat与Camel高危RCE漏洞引发数千次利用尝试
java·tomcat·apache
无妄-20241 小时前
软件架构升级中的“隐形地雷”:版本选型与依赖链风险
java·服务器·网络·经验分享
qqxhb1 小时前
零基础数据结构与算法——第四章:基础算法-排序(上)
java·数据结构·算法·冒泡·插入·选择
华子w9089258591 小时前
基于 SpringBoot+VueJS 的农产品研究报告管理系统设计与实现
vue.js·spring boot·后端