2025/12/30 11:23:58
网站建设
项目流程
电商网站开发服务,wordpress文档,网站开发环境的安装说明,天津进口网站建设电话最近在深入学习 Java 后端和 Redis 中间件时#xff0c;遇到了一个非常经典且重要的问题#xff1a;在分布式场景下#xff0c;如何生成一个全局唯一的 ID#xff1f;在单体架构时代#xff0c;我们习惯使用数据库的自增 ID#xff08;Auto Increment#xff09;#x…最近在深入学习 Java 后端和 Redis 中间件时遇到了一个非常经典且重要的问题在分布式场景下如何生成一个全局唯一的 ID在单体架构时代我们习惯使用数据库的自增 IDAuto Increment但在分库分表、微服务的高并发场景下这种方式由于性能瓶颈和单点问题显然已经力不从心。今天这篇博客就来总结一下目前业界最主流的 4 种全局唯一 ID 生成策略分析它们的原理、优缺点以及适用场景。什么样的 ID 才是好 ID在设计 ID 生成器之前我们需要明确“好 ID”的标准。通常有以下几个核心要求全局唯一性这是最基本的要求不能出现重复。高可用 高性能生成 ID 的动作非常频繁不能成为系统的瓶颈且服务要足够稳定。递增性趋势有序这一点常被忽略。对于使用 MySQLInnoDB 引擎的系统主键建议保持递增因为 InnoDB 使用 B 树索引有序的主键写入能避免频繁的“页分裂”极大提升写入性能。安全性某些业务场景下如订单号ID 不应过于明显地暴露业务量比如不能让人轻易猜出你一天有多少单。方案一UUID (Universally Unique Identifier)UUID 是最简单、最暴力的方案。JDK 原生支持一行代码搞定。代码实现public static void main(String[] args) { // 生成一个 UUID并去掉中间的横线 String id UUID.randomUUID().toString().replace(-, ); System.out.println(UUID: id); }优缺点分析优点性能极高完全在本地生成没有网络消耗。使用简单不依赖任何外部组件DB、Redis 等。缺点无序性致命伤UUID 是无序的字符串。如果作为 MySQL 主键会导致大量的数据页分裂和移动严重拖慢插入速度。存储成本高32 个字符或 16 字节相比 Long 类型特别占空间也会导致索引变大。信息不安全完全随机无法携带时间或业务含义。 结论适合生成 Token、Session ID 或非数据库主键的场景。坚决不建议用作 MySQL 的主键。方案二数据库自增 (Database Auto-Increment)利用 MySQL 的auto_increment特性或者 Oracle 的Sequence。原理应用服务向数据库插入数据数据库自动累计 ID。优缺点分析优点简单利用现有数据库功能成本低。单调递增对索引非常友好查询效率高。缺点并发瓶颈在高并发下数据库往往是最大的瓶颈。分库分表麻烦如果未来需要分库不同库的自增 ID 会重复。虽然可以通过设置不同的“步长”Step来解决如 DB1 生成 1,3,5... DB2 生成 2,4,6...但这增加了扩容和维护的难度。单点故障数据库挂了整个 ID 生成服务就不可用了。 结论适合并发量不高的中小项目或者不需要分库分表的数据表。方案三Redis 自增策略Redis 是单线程处理命令的其INCR命令是原子的天生适合做计数器。这是我最近在学 Redis 时觉得非常有意思的一个应用点。代码思路 (Java RedisTemplate)为了避免 ID 被推测出业务量通常会结合“时间戳”使用。格式示例yyyyMMdd Redis自增值。// 伪代码示例 public long generateId(String keyPrefix) { // 1. 生成时间戳部分 String dateStr DateTimeFormatter.ofPattern(yyyyMMdd).format(LocalDate.now()); // 2. 利用 Redis 原子递增 // key 举例: icr:order:20251216 Long increment stringRedisTemplate.opsForValue().increment(icr: keyPrefix : dateStr); // 3. 拼接 ID (实际生产中通常需要通过位运算或字符串填充补齐位数) return Long.parseLong(dateStr String.format(%06d, increment)); }优缺点分析优点高性能基于内存操作吞吐量远高于数据库。有序递增对数据库索引友好。灵活可以方便地把日期、业务类型编排进 ID 中。缺点强依赖组件如果 Redis 挂了ID 生成服务就断了需要配置 Sentinel 或 Cluster 高可用。运维成本引入了额外的中间件维护成本。 结论非常适合高并发的业务场景如秒杀、订单生成且生成的 ID 具有业务含义。方案四雪花算法 (Snowflake)这是目前分布式系统中最流行、最成熟的方案由 Twitter 开源。它的核心思想是将一个 64 位的long型数字切割成不同的部分。结构图解 (64 bit)1 bit符号位固定为0。41 bits时间戳毫秒级可以使用 69 年。10 bits机器 ID支持 1024 个节点。12 bits序列号同一毫秒内支持生成 4096 个 ID。代码实现通常不需要自己手写位运算推荐使用成熟的工具包例如Hutool。// 引入 Hutool 依赖后 public class IdTest { public static void main(String[] args) { // 参数1: 终端ID, 参数2: 数据中心ID Snowflake snowflake IdUtil.getSnowflake(1, 1); long id snowflake.nextId(); System.out.println(Snowflake ID: id); } }优缺点分析优点极高并发每秒可生成几百万个 ID。不依赖网络本地生成除了启动时校验机器 ID无单点故障。趋势递增整体按时间递增索引性能好。缺点时钟回拨问题严重依赖服务器时间。如果服务器时间被回调比如校准时间算法可能会生成重复 ID。 结论几乎所有互联网大厂的主流选择适合超大规模的分布式系统。总结对比最后用一张表来总结这几种策略策略唯一性有序性性能依赖组件核心痛点UUID高无极高无索引性能差ID太长DB自增高严格有序低数据库并发瓶颈扩展麻烦Redis高严格有序高Redis依赖 Redis 高可用Snowflake高趋势有序极高无时钟回拨问题个人建议如果你是初学者或者项目规模较小Redis 自增是一个非常好的练手方案既能满足性能要求又能加深对 Redis 的理解。而如果是企业级的大型项目Snowflake配合 Hutool 等工具库则是目前的最优解。希望这篇总结对大家有所帮助如果你有更好的方案欢迎在评论区交流。本文由一名热爱技术的研二学生整理持续分享 Java 后端与算法学习心得。