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

分布式 ID

分布式 ID 完整选型 + 落地方案(生产可用,分场景直接选)

一、主流 5 种方案优缺点总览

1. UUID / UUID36

  • 优点:本地生成,无 RPC、简单
  • 缺点:无序、太长 36 位、数据库索引差、泄露 MAC 地址(旧版)
  • 适用:简单日志、临时业务 ID,严禁做主键

2. 数据库自增主键(单库)

  • 优点:连续有序、稳定、最简单
  • 缺点:单点瓶颈,分库分表完全不能用
  • 适用:单体小型系统

3. 数据库号段模式(Leaf、百度 UidGenerator)

原理:业务一次性批量拿一段 ID 缓存本地,用完再去 DB 申请下一号段

  • 优点:有序、性能极高、稳定、可持久化、故障不重复
  • 缺点:需要单独一张号段表,轻微开发量
  • 适用:绝大多数企业业务、订单、财务、主业务主键(最稳妥通用选型

4. Redis INCR / 号段

  • 优点:性能爆炸,原子自增
  • 缺点:宕机丢未持久化增量、依赖 Redis 集群稳定性
  • 适用:高并发秒杀、临时流水号

5. Snowflake 雪花算法(Twitter)

64bit 结构:时间戳 (41)+ 机器 ID (10)+ 序列号 (12)

  • 优点:全局有序、纯本地生成、不依赖第三方、64 位 long 型
  • 缺点:时钟回拨致命问题、机器 ID 要手动分配维护
  • 适用:高并发互联网业务、海量数据场景;必须解决时钟回拨

6. 美团 Leaf(同时支持雪花 + 号段)

企业级成熟开源框架,直接拿来用,业界落地最多。

二、明确选型决策表(直接对照业务选)

场景 1:传统 ERP/MES/ 财务 / 支付、要求绝对不重复、数据稳妥

优先:Leaf 号段模式

  • 强一致性、无时钟问题、运维简单、数据库可溯源
  • 分库分表天然支持

场景 2:超高并发、百万 QPS、海量流水、不在乎短暂时钟风险

Snowflake(自研 / Leaf 雪花模式)必须配套:时钟监控、回拨拒绝策略、机器 ID 注册中心

场景 3:简单临时 ID、内部埋点、非主键

✅ UUID / 简单雪花

场景 4:秒杀短时效流水号

✅ Redis 自增

三、雪花算法详细落地关键点(避坑核心)

64 位标准结构

1bit 符号位 | 41bit 毫秒时间戳 | 10bit 机器 ID | 12bit 序列号

  • 机器 ID 10bit:最多 1024 台机器
  • 序列号 12bit:每毫秒单节点最多 4096 个 ID

三大致命坑 & 解决方案

  1. 时钟回拨(最严重)
  • 现象:服务器 NTP 同步回拨,生成重复 ID
  • 解决:
    • 本机记录上一次生成时间,当前时间 < 上次时间 → 直接抛出异常 / 自旋等待
    • Leaf 雪花自带时间回拨补偿
    • 禁止虚拟机时间漂移
  1. 机器 ID 重复
  • 方案:
    • 启动注册到 Zookeeper/Redis,自动分配唯一机器号
    • 物理机用 IP 最后 10 位、容器用 K8s pod 固定标识
  1. 单机毫秒内 4096 序列号耗尽
  • 自旋等到下一毫秒即可

四、号段模式落地架构(强烈推荐制造业 / 企业系统)

1. 单独号段数据表

CREATE TABLE id_segment ( business_tag VARCHAR(50) PRIMARY KEY COMMENT '业务标识:order,receivable', max_id BIGINT NOT NULL COMMENT '当前已分配最大号', step INT NOT NULL COMMENT '每次申请步长', update_time DATETIME );

示例初始化一条:order,max_id=10000,step=1000

2. 运行逻辑

  1. 服务启动拉取一段:10001~11000 缓存在内存
  2. 业务直接内存取号,无 DB 请求
  3. 内存剩余 10% 阈值,异步去 DB 抢占下一段号段(CAS 更新 max_id)
  4. 数据库只有简单 UPDATE:update id_segment set max_id = max_id + step where business_tag = ?
  • 原子更新,绝对不会重复

3. 优势

  • DB 宕机,内存号段还能继续支撑很久
  • 完全没有时钟问题,金融财务零风险
  • 有序数字 ID,MySQL 主键索引性能拉满

五、开源成熟框架直接落地(不用重复造轮子)

  1. 美团 Leaf(首选)两种模式自由切换:Segment 号段 + Snowflake 支持监控、号段自动扩容、雪花时钟回拨处理、RPC 接入简单
  2. 百度 UidGenerator:基于雪花,借助 Redis 解决机器 ID 与时钟
  3. 滴滴 TinyId:纯号段方案,轻量

六、Java 生产极简落地建议

  1. 企业内部管理系统、MES、WMS、财务单据采用:Leaf Segment 号段
  2. 高并发 C 端业务、千万级订单采用:Leaf Snowflake 模式,开启时钟回拨保护
  3. 禁止自己手写简易雪花,时钟回拨一定会踩坑

七、分库分表配套规则

  • 雪花 ID:取 ID 取模分片
  • 号段 ID:同样取模,全局连续完全兼容分片

三套完整可直接投产代码:自研号段工具类 + 安全雪花算法 + SpringBoot 接入美团 Leaf

一、自研数据库号段分布式 ID(企业 ERP/MES/ 财务最稳)

1、号段数据表

CREATE TABLE `id_segment` ( `business_tag` varchar(50) NOT NULL COMMENT '业务标识:order、receivable、work_order', `max_id` bigint NOT NULL DEFAULT 0 COMMENT '已分配最大ID', `step` int NOT NULL DEFAULT 1000 COMMENT '每次申请号段长度', `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`business_tag`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分布式号段表'; -- 初始化测试数据 INSERT INTO id_segment(business_tag,max_id,step) VALUES ('order',10000,2000);

2、MyBatis Mapper

@Mapper public interface IdSegmentMapper { @Update("UPDATE id_segment SET max_id = max_id + step WHERE business_tag = #{tag}") int increaseSegment(@Param("tag") String tag); @Select("SELECT max_id,step FROM id_segment WHERE business_tag = #{tag}") IdSegment selectByTag(@Param("tag") String tag); } @Data public class IdSegment { private Long maxId; private Integer step; }

3、号段生成器核心工具类

import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.Map; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicLong; @Component public class SegmentIdGenerator { @Resource private IdSegmentMapper idSegmentMapper; // 本地缓存号段 private final Map<String, SegmentBuffer> bufferMap = new ConcurrentHashMap<>(); // 异步预加载线程池 private final ExecutorService pool = Executors.newSingleThreadExecutor(); private static class SegmentBuffer { // 当前号段起始、截止、当前取值 AtomicLong current; long end; int step; volatile boolean isLoading; } public Long nextId(String businessTag) { SegmentBuffer buffer = bufferMap.computeIfAbsent(businessTag, k -> initBuffer(k)); long id = buffer.current.getAndIncrement(); // 剩余10%阈值,异步拉取下一号段 if (id >= buffer.end - buffer.step * 0.1 && !buffer.isLoading) { loadNextAsync(buffer, businessTag); } if (id > buffer.end) { synchronized (buffer) { while (id > buffer.end) { try { buffer.wait(); } catch (InterruptedException e) { throw new RuntimeException("获取号段超时"); } } id = buffer.current.getAndIncrement(); } } return id; } private SegmentBuffer initBuffer(String tag) { IdSegment seg = idSegmentMapper.selectByTag(tag); SegmentBuffer buf = new SegmentBuffer(); buf.step = seg.getStep(); buf.end = seg.getMaxId(); buf.current = new AtomicLong(buf.end - buf.step + 1); return buf; } private void loadNextAsync(SegmentBuffer buffer, String tag) { if (!buffer.isLoading) { buffer.isLoading = true; pool.submit(() -> { try { // CAS原子递增 idSegmentMapper.increaseSegment(tag); IdSegment newSeg = idSegmentMapper.selectByTag(tag); synchronized (buffer) { buffer.end = newSeg.getMaxId(); buffer.current.set(buffer.end - buffer.step + 1); buffer.notifyAll(); } } finally { buffer.isLoading = false; } }); } } }

使用

@Autowired private SegmentIdGenerator segmentIdGenerator; Long orderId = segmentIdGenerator.nextId("order");

二、自带时钟回拨防护的雪花算法(可直接上线)

public class SafeSnowflakeIdGenerator { // 64位划分 private static final long TIME_BIT = 41L; private static final long WORKER_BIT = 10L; private static final long SEQ_BIT = 12L; private static final long MAX_WORKER_ID = (1L << WORKER_BIT) - 1; private static final long MAX_SEQ = (1L << SEQ_BIT) - 1; private static final long WORKER_SHIFT = SEQ_BIT; private static final long TIME_SHIFT = SEQ_BIT + WORKER_BIT; // 基准时间:2025-01-01 private static final long EPOCH = 1735689600000L; private final long workerId; private long lastTime = 0L; private long sequence = 0L; public SafeSnowflakeIdGenerator(long workerId) { if (workerId < 0 || workerId > MAX_WORKER_ID) { throw new IllegalArgumentException("机器ID超出0~1023"); } this.workerId = workerId; } public synchronized long nextId() { long now = System.currentTimeMillis(); // 时钟回拨 if (now < lastTime) { long offset = lastTime - now; // 回拨小于50ms自旋等待,超过直接抛异常拒绝生成 if (offset < 50) { try { Thread.sleep(offset); now = System.currentTimeMillis(); } catch (InterruptedException e) { throw new RuntimeException("时钟回拨,生成ID失败"); } } else { throw new RuntimeException("严重时钟回拨,禁止生成ID"); } } // 同一毫秒自增序列号 if (now == lastTime) { sequence = (sequence + 1) & MAX_SEQ; if (sequence == 0) { // 序列号用尽,等到下一毫秒 while (now <= lastTime) { now = System.currentTimeMillis(); } } } else { sequence = 0; } lastTime = now; return ((now - EPOCH) << TIME_SHIFT) | (workerId << WORKER_SHIFT) | sequence; } }

机器 ID 分配方案

  1. 物理机:IP最后两段取模1024
  2. K8s 容器:注册到 Redis/ZK 自动分配唯一 workerId

三、SpringBoot 接入美团 Leaf 完整配置(生产首选)

1、架构选择

同时部署Segment 号段做主业务 ID,Snowflake 做高并发流水 ID

2、application.yml

leaf: segment: enable: true url: jdbc:mysql://localhost:3306/leaf_db?useUnicode=true username: root password: xxx snowflake: enable: true # 使用ZK自动分配workerId,杜绝重复 zk-address: 127.0.0.1:2181

3、依赖 Maven

<dependency> <groupId>com.sankuai.inf.leaf</groupId> <artifactId>leaf-core</artifactId> <version>1.0.4</version> </dependency>

4、注入使用

@Autowired private SegmentIDGenImpl segmentIDGen; @Autowired private SnowflakeIDGenImpl snowflakeIDGen; // 号段ID(订单、财务单据) Long orderId = segmentIDGen.get("order").getId(); // 雪花ID(高并发流水) Long flowId = snowflakeIDGen.get("flow").getId();

四、三种方案选型极简总结

  1. MES/WMS/ 财务 / ERP 单据、要求绝对稳定无时钟风险→ 自研号段 / Leaf Segment
  2. 高并发千万级 C 端订单、海量数据→ 安全雪花 / Leaf 雪花
  3. 小型单体项目→ 简单雪花即可
http://www.jsqmd.com/news/1244217/

相关文章:

  • 2026年工商业储能系统推荐:系统效率、循环寿命与安全认证全解析 - 科技焦点
  • AI写作金句植入的5个致命误区:92%的创作者正在 silently 毁掉爆款基因
  • 市场知名的测功机工厂
  • gh_mirrors/log/logback授权控制详解:基于角色与权限的访问管理
  • C语言控制语句-循环
  • 如何用Niva快速构建第一个跨平台桌面应用?5分钟上手教程
  • 2026年7月博世壁挂炉售后服务电话24小时全新专属热线升级公示最新公告 - 家电技术百科
  • Linux下MyIpAdd库的使用
  • 羽球搭子 HarmonyOS 实战(17):比分撤销与边界校验
  • 终极解密利器AES-Killer:网络安全测试中的AES加密流量实时解密指南
  • 【超详细】二分查找(折半查找)核心知识点全解析(含多场景代码实现)
  • 2026年7月最新萧邦大连来福士维修保养服务电话 - 萧邦中国官方服务中心
  • 5个关键问题:GoFrame如何帮助企业级应用提升3倍开发效率?
  • DPPO环境扩展指南:如何将新机器人仿真环境接入训练框架
  • 2026年工商业储能系统选型指南:六款主流一体机深度对比 - 科技焦点
  • 树莓派部署BirdNET-Go常见问题解答:从硬件要求到性能优化
  • [JCMSuite] JCMSuite应用:等离子波导
  • json-swift高级技巧:函数式API带你玩转JSON数据处理
  • 2026记者采访整理录音,软件测评哪个好更适合新人使用
  • IT66318:HDMI 2.0 Retimer
  • 第四篇:《函数、指针与结构体:组织代码的核心工具》
  • Nativ:100%开源,让你在Mac本地运行AI模型,无需账户订阅!
  • 做公司PPT最烦的不是写内容,是套模板
  • B3843 [GESP202306 三级] 密码合规 题解
  • LLM输出稳定性差3倍?——从token级置信度、逻辑连贯性到领域适配度的8项硬指标深度拆解
  • 2026年经期记录小程序哪个好用?日常记录与周期预测实操经验 - 软件测评小帮手
  • 大数据hadoop的高校照明智慧监测预警系统
  • 2026 餐饮收银系统横向科普:二维火与客如云适配场景、能力差异解析
  • 2026 年文县专业的景区园林花岗岩石材订做厂家哪家专业,别让你的景区毁在石材选错上-天翔石业 - 行业推荐官[官方】--
  • AI全栈开发指南 2026 :从想法到代码只需几分钟:揭秘高效产品原型设计的AI工具栈