SpringBoot
关于雪花算法ID问题
Redis 缓存穿透、缓存击穿、缓存雪崩
分布式锁与单服务事务
分布式锁与分布式事务
SpringBoot 返回 BigDecimal ,数值太小导致返回科学计数法
本文档使用 MrDoc 发布
-
+
首页
关于雪花算法ID问题
你希望在SpringBoot项目中找到能替代雪花算法(Snowflake)的分布式唯一ID生成方案,核心需求是满足分布式场景下ID的唯一性,同时适配SpringBoot的开发和集成方式。 雪花算法的核心痛点是依赖时钟(时钟回拨会导致ID重复)、依赖机器ID/数据中心ID配置,因此替代方案主要围绕**无时钟依赖、低配置成本、高可用** 展开,以下是几种主流且易集成的方案: --- ## 方案1:UUID/优化版UUID(最简易) UUID是Java原生支持的唯一ID生成方式,本地生成无中心依赖,是替代雪花算法最轻量化的选择。 ### 核心特点 - 优点:无依赖、无需配置、分布式友好、生成速度快 - 缺点:原始UUID是36位字符串(含横线),无序且长度长,不利于数据库索引;纯字符串ID占用存储空间大 ### SpringBoot实现代码 封装工具类,可选择生成原始UUID、去掉横线的UUID,或转成数字型(部分场景): ```java import org.springframework.stereotype.Component; import java.util.UUID; /** * UUID生成工具类(替代雪花算法的简易方案) */ @Component public class UuidGenerator { /** * 生成原始UUID(36位,含横线) */ public String generateOriginalUuid() { return UUID.randomUUID().toString(); } /** * 生成无横线的UUID(32位) */ public String generateShortUuid() { return UUID.randomUUID().toString().replace("-", ""); } /** * (可选)UUID转数字型(仅前16位,避免过长,适合对数字ID有要求的场景) */ public Long generateNumericUuid() { String uuid = generateShortUuid().substring(0, 16); return Long.parseUnsignedLong(uuid, 16); } } ``` ### 使用示例 ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class IdController { @Autowired private UuidGenerator uuidGenerator; @GetMapping("/uuid/original") public String getOriginalUuid() { return uuidGenerator.generateOriginalUuid(); // 输出示例:550e8400-e29b-41d4-a716-446655440000 } @GetMapping("/uuid/short") public String getShortUuid() { return uuidGenerator.generateShortUuid(); // 输出示例:550e8400e29b41d4a716446655440000 } } ``` --- ## 方案2:Redis自增ID(高性能、有序) 利用Redis的`INCR`/`INCRBY`命令的原子性生成自增ID,兼顾唯一性和有序性,性能优于数据库自增,是雪花算法的高性能替代方案。 ### 核心特点 - 优点:ID有序(利于数据库索引)、高性能(Redis单节点QPS可达10万+)、支持分段生成(避免ID过大) - 缺点:依赖Redis服务(需做集群保证高可用)、重启Redis后若未持久化会导致ID断号(可通过RDB/AOF持久化解决) ### SpringBoot集成步骤 #### 1. 引入Redis依赖(pom.xml) ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` #### 2. 配置Redis(application.yml) ```yaml spring: redis: host: 127.0.0.1 port: 6379 password: # 你的Redis密码 database: 0 lettuce: pool: max-active: 8 max-idle: 8 min-idle: 0 ``` #### 3. 编写Redis ID生成工具类 ```java import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.concurrent.TimeUnit; /** * Redis自增ID生成工具(替代雪花算法,有序+高性能) */ @Component public class RedisIdGenerator { @Resource private RedisTemplate<String, Long> redisTemplate; // ID前缀(区分不同业务) private static final String ID_PREFIX = "biz:id:"; // 分段步长(避免每次都调用Redis,提升性能) private static final long STEP = 100; /** * 生成业务唯一ID(分段模式,减少Redis调用) * @param bizType 业务类型(如order、user) * @return 自增ID */ public Long generateId(String bizType) { String key = ID_PREFIX + bizType; ValueOperations<String, Long> valueOps = redisTemplate.opsForValue(); // 原子性自增,步长100 Long currentId = valueOps.increment(key, STEP); // 首次生成时设置过期时间(可选,避免key堆积) if (currentId == STEP) { valueOps.set(key, currentId, 365, TimeUnit.DAYS); } // 计算当前可用的ID范围(如当前是100,则返回1-100,下次从101开始) return currentId - STEP + 1; } /** * 简单自增ID(无分段,每次调用Redis) */ public Long generateSimpleId(String bizType) { String key = ID_PREFIX + bizType; return redisTemplate.opsForValue().increment(key, 1); } } ``` #### 4. 使用示例 ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class RedisIdController { @Autowired private RedisIdGenerator redisIdGenerator; @GetMapping("/redis/id/{bizType}") public Long getRedisId(@PathVariable String bizType) { return redisIdGenerator.generateId(bizType); // 调用示例:/redis/id/order → 输出1、2、3...(分段模式下每次返回100个连续ID) } } ``` --- ## 方案3:美团Leaf(成熟开源,解决雪花算法痛点) Leaf是美团开源的分布式ID生成框架,支持**号段模式**(基于数据库)和**优化版雪花算法模式**,专门解决原生雪花算法的时钟回拨、配置复杂等问题,是生产环境中替代雪花算法的首选。 ### 核心特点 - 优点:成熟稳定、高可用、解决雪花算法时钟回拨问题、支持两种模式切换 - 缺点:需要集成数据库/Zookeeper、部署成本略高 ### SpringBoot集成步骤(号段模式为例) #### 1. 引入Leaf依赖(pom.xml) ```xml <!-- 美团Leaf核心依赖 --> <dependency> <groupId>com.sankuai.inf.leaf</groupId> <artifactId>leaf-core</artifactId> <version>1.6.1</version> </dependency> <!-- Leaf SpringBoot Starter --> <dependency> <groupId>com.sankuai.inf.leaf</groupId> <artifactId>leaf-spring-boot-starter</artifactId> <version>1.6.1</version> </dependency> ``` #### 2. 创建数据库表(号段模式依赖) ```sql CREATE TABLE `leaf_alloc` ( `biz_tag` varchar(128) NOT NULL COMMENT '业务标识', `max_id` bigint(20) NOT NULL DEFAULT '1' COMMENT '当前最大ID', `step` int(11) NOT NULL COMMENT '号段步长', `description` varchar(256) DEFAULT NULL COMMENT '业务描述', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`biz_tag`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 插入测试数据 INSERT INTO `leaf_alloc` (`biz_tag`, `max_id`, `step`, `description`) VALUES ('order', 1, 1000, '订单ID'); ``` #### 3. 配置Leaf(application.yml) ```yaml leaf: # 启用号段模式(推荐) segment: enable: true # 数据库配置(复用SpringBoot的数据源) jdbc: url: jdbc:mysql://127.0.0.1:3306/leaf_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 # (可选)启用优化版雪花算法模式(解决时钟回拨) snowflake: enable: false zk: address: 127.0.0.1:2181 port: 2181 ``` #### 4. 使用Leaf生成ID ```java import com.sankuai.inf.leaf.IDGen; import com.sankuai.inf.leaf.common.Result; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class LeafIdController { @Autowired private IDGen idGen; @GetMapping("/leaf/id/{bizTag}") public Long getLeafId(@PathVariable String bizTag) { Result result = idGen.get(bizTag); if (result.isSuccess()) { return result.getId(); // 输出示例:1、2、3...(按号段步长递增) } throw new RuntimeException("生成ID失败:" + result.getStatus()); } } ``` --- ## 总结 | 方案 | 核心特点 | 适用场景 | |--------------|-----------------------------------|-------------------------------------------| | UUID/优化版 | 最简易、无依赖、无序、长度长 | 对ID有序性无要求、快速开发的场景 | | Redis自增ID | 高性能、有序、依赖Redis | 高并发、需要有序ID、已部署Redis的场景 | | 美团Leaf | 成熟稳定、解决雪花算法痛点、略复杂 | 生产环境、高可用要求、需替代原生雪花算法 | ### 关键点回顾 1. 快速替代选**UUID**,无需额外依赖,开箱即用; 2. 需有序ID且有Redis选**Redis自增ID**,兼顾性能和易用性; 3. 生产环境高可用需求选**美团Leaf**,解决雪花算法时钟回拨等核心问题; 4. 所有方案均能在SpringBoot中无缝集成,无需复杂配置。
admin
2026年1月6日 16:58
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码