分布式 ID 生成方案实战指南:从选型到落地的全场景避坑手册(三) - 实践

news/2025/9/27 8:19:11/文章来源:https://www.cnblogs.com/ljbguanli/p/19114711

分布式 ID 生成方案实战指南:从选型到落地的全场景避坑手册(三) - 实践

五、方案 4:Redis 自增 ID—— 极高并发的轻量选择

5.1 问题场景:直播平台礼物 ID 生成

某直播平台,峰值 QPS 达 10 万(用户送礼物),需生成全局唯一、高性能的礼物 ID,无需强有序(仅需唯一标识),且避免依赖数据库 / ZooKeeper。

5.2 方案原理:利用 Redis 的 INCR 命令

Redis 的INCR key命令是原子操作,支持每秒万级 / 十万级自增,核心思路:

  1. 用 Redis 的INCR生成自增 ID(如INCR gift:id);

  2. 为避免 Redis 单点故障,部署 Redis 集群(主从 + 哨兵);

  3. 可选:添加业务前缀(如礼物类型 + 日期),增强 ID 语义(如gift_1_20240520_123456)。

5.3 实战代码:Redis 自增 ID 实现(Spring Boot)

5.3.1 1. 依赖配置(pom.xml)
<!-- Spring Data Redis --><dependency><groupId>org.springframework.boot\</groupId><artifactId>spring-boot-starter-data-redis\</artifactId></dependency><!-- Redis客户端(Lettuce,支持集群) --><dependency><groupId>io.lettuce\</groupId><artifactId>lettuce-core\</artifactId></dependency>
5.3.2 2. Redis 配置(application.yml)
spring:
redis:
# Redis集群地址(主从+哨兵)
sentinel:
master: mymaster # 主节点名称
nodes: 192.168.1.100:26379,192.168.1.101:26379,192.168.1.102:26379
# 连接池配置
lettuce:
pool:
max-active: 16 # 最大连接数
max-idle: 8 # 最大空闲连接数
min-idle: 4 # 最小空闲连接数
# 密码(生产环境必填)
password: Redis@123456
# 超时时间
timeout: 2000ms
5.3.3 3. Redis 自增 ID 服务实现(Java)
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@Service
public class GiftIdGenerator
{
// Redis key前缀(区分不同业务)
private static final String REDIS\_KEY\_PREFIX = "gift:id:";
// 时间格式(用于ID前缀,如20240520)
private static final SimpleDateFormat DATE\_FORMAT = new SimpleDateFormat("yyyyMMdd");
// 本地缓存ID的过期时间(5分钟,避免频繁访问Redis)
private static final long CACHE\_EXPIRE\_MINUTES = 5;
@Resource
private RedisTemplate\<
String, Long> redisTemplate;
// 生成礼物ID(格式:gift\_礼物类型\_日期\_自增ID,如gift\_1\_20240520\_123456)
public String generateGiftId(int giftType) {
// 1. 构建Redis key(按日期分片,避免单key自增过大)
String date = DATE\_FORMAT.format(new Date());
String redisKey = REDIS\_KEY\_PREFIX + date;
// 2. 执行Redis INCR命令(原子自增)
ValueOperations\<
String, Long> valueOps = redisTemplate.opsForValue();
Long incrId = valueOps.increment(redisKey);
// 3. 设置Redis key过期时间(按天过期,避免key堆积)
if (incrId != null && incrId == 1) {
// 首次生成时设置过期时间(2天)
redisTemplate.expire(redisKey, 2, TimeUnit.DAYS);
}
// 4. 构建带业务前缀的ID(增强语义)
return String.format("gift\_%d\_%s\_%d", giftType, date, incrId);
}
// 优化:本地缓存ID(减少Redis访问,适合极高并发)
private volatile Long localCacheId;
private volatile long cacheExpireTime;
public String generateGiftIdWithLocalCache(int giftType) {
long currentTime = System.currentTimeMillis();
// 1. 检查本地缓存是否过期
if (localCacheId == null || currentTime > cacheExpireTime) {
// 2. 从Redis获取自增ID(一次获取100个,批量缓存)
String date = DATE\_FORMAT.format(new Date());
String redisKey = REDIS\_KEY\_PREFIX + date;
Long batchId = redisTemplate.opsForValue().increment(redisKey, 100);
// 一次增100
if (batchId == null) {
throw new RuntimeException("Redis自增ID获取失败");
}
// 3. 更新本地缓存(起始ID=batchId-100,过期时间=当前+5分钟)
localCacheId = batchId - 100;
cacheExpireTime = currentTime + CACHE\_EXPIRE\_MINUTES \* 60 \* 1000;
}
// 4. 本地缓存ID递增
long currentId = localCacheId++;
// 5. 构建最终ID
String date = DATE\_FORMAT.format(new Date());
return String.format("gift\_%d\_%s\_%d", giftType, date, currentId);
}
// 测试:生成10个礼物ID
public static void main(String\[] args) {
// 模拟Spring注入RedisTemplate(实际项目中由Spring管理)
GiftIdGenerator generator = new GiftIdGenerator();
for (int i = 0; i <
10; i++) {
// 输出示例:gift\_1\_20240520\_123456
System.out.println(generator.generateGiftId(1));
}
}
}
5.3.4 4. Redis 集群一致性保障(RedLock)

若 Redis 集群存在脑裂风险(主节点下线,从节点未同步完数据),可使用 RedLock(红锁)确保 ID 生成一致性:

  1. 部署 3 个独立的 Redis 集群(无主从关系);

  2. 生成 ID 时,向 3 个集群同时执行INCR命令;

  3. 至少 2 个集群执行成功,才认为 ID 生成有效,避免脑裂导致的 ID 重复。

RedLock 实现代码(Java + Redisson)

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import java.util.concurrent.TimeUnit;
public class RedLockGiftIdGenerator
{
// 3个独立Redis集群地址
private static final String REDIS\_CLUSTER\_1 = "redis://192.168.1.100:6379";
private static final String REDIS\_CLUSTER\_2 = "redis://192.168.1.101:6379";
private static final String REDIS\_CLUSTER\_3 = "redis://192.168.1.102:6379";
// 初始化3个Redisson客户端
private RedissonClient redisson1 = createRedissonClient(REDIS\_CLUSTER\_1);
private RedissonClient redisson2 = createRedissonClient(REDIS\_CLUSTER\_2);
private RedissonClient redisson3 = createRedissonClient(REDIS\_CLUSTER\_3);
// 创建Redisson客户端
private RedissonClient createRedissonClient(String address) {
Config config = new Config();
config.useSingleServer().setAddress(address).setPassword("Redis@123456");
return Redisson.create(config);
}
// RedLock生成礼物ID
public String generateGiftIdWithRedLock(int giftType) {
String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
String redisKey = "gift:id:" + date;
long incrId = 0;
int successCount = 0;
// 1. 向3个Redis集群执行INCR
try {
// 集群1执行
Long id1 = redisson1.getBucket(redisKey).incrementAndGet();
if (id1 != null) {
successCount++;
incrId = id1;
}
// 集群2执行
Long id2 = redisson2.getBucket(redisKey).incrementAndGet();
if (id2 != null) {
successCount++;
incrId = id2;
}
// 集群3执行
Long id3 = redisson3.getBucket(redisKey).incrementAndGet();
if (id3 != null) {
successCount++;
incrId = id3;
}
// 2. 至少2个集群成功,才返回ID
if (successCount >= 2) {
return String.format("gift\_%d\_%s\_%d", giftType, date, incrId);
} else {
throw new RuntimeException("RedLock ID生成失败:成功集群数=" + successCount);
}
} finally {
// 3. 关闭Redisson客户端(实际项目中无需关闭,全局单例)
// redisson1.shutdown();
// redisson2.shutdown();
// redisson3.shutdown();
}
}
}

5.4 故障案例:Redis 宕机导致 ID 生成中断

5.4.1 问题背景

某短视频平台用 Redis 自增生成评论 ID,Redis 主节点宕机后,哨兵未及时切换从节点,导致评论服务无法生成 ID,评论功能中断 5 分钟。

5.4.2 根因分析
  1. Redis 集群仅部署 1 主 1 从,从节点同步延迟(约 1 秒),主节点宕机后,从节点数据未完全同步;

  2. 哨兵切换超时(配置为 5 秒),期间服务无法访问 Redis;

  3. 评论服务无 “降级方案”,Redis 不可用时直接抛出异常,导致业务中断。

5.4.3 解决方案
  1. 部署 Redis 集群(3 主 3 从),减少单点故障风险;

  2. 缩短哨兵切换时间(配置down-after-milliseconds=1000failover-timeout=2000);

  3. 服务添加降级方案:Redis 不可用时,临时使用 “本地自增 + 节点 ID” 生成 ID(如comment_123_456,123 = 节点 ID,456 = 本地自增),Redis 恢复后合并数据;

  4. 配置 Redis 持久化(AOF+RDB),避免宕机后数据丢失。

5.5 避坑总结

适用场景:极高并发(10 万 + QPS)、无强有序要求、轻量依赖的场景(礼物 / 评论 / 点赞);

不适用场景:需强有序 ID、Redis 集群维护成本高的场景;

⚠️ 必避坑点

  1. Redis 必须部署集群(主从 + 哨兵),避免单点故障;

  2. 用 “按日期分片” 的 Redis key(如gift:id:20240520),避免单 key 自增过大;

  3. 必须配置持久化(AOF+RDB),防止 Redis 宕机后 ID 重置;

  4. 服务需添加降级方案,Redis 不可用时确保业务不中断。

六、方案对比与选型指南

6.1 四大方案核心指标对比

方案唯一性有序性性能(QPS)可用性依赖服务适用场景
UUID / 优化版10 万 +内部系统、低并发、无有序要求
数据库分段 / 号段1 万 - 10 万数据库分库分表、中低并发、强有序
雪花算法10 万 +ZooKeeper / 配置中心高并发、强有序、水平扩容
Redis 自增10 万 +Redis 集群极高并发、无强有序、轻量依赖

6.2 选型决策树

在这里插入图片描述

6.3 实战选型案例

  1. 电商订单系统:强有序、并发 5 万 QPS→雪花算法;

  2. 物流单号系统:强有序、分库分表、并发 1 万 QPS→数据库号段模式;

  3. 直播礼物系统:无强有序、并发 10 万 QPS→Redis 自增;

  4. 内部 CRM 系统:无强有序、并发 1 千 QPS→UUID 优化版;

  5. 支付流水系统:强有序、高可用、并发 8 万 QPS→雪花算法(ZooKeeper+Redis 冗余校验)。

七、总结:分布式 ID 生成的核心原则

  1. 唯一性优先:无论选择哪种方案,全局无重复是底线(可通过冗余校验、机器 ID、时间戳确保);

  2. 性能匹配业务:低并发用简单方案(UUID),高并发用复杂方案(雪花 / Redis),避免过度设计;

  3. 可用性兜底:所有方案需考虑单点故障(如数据库主从、Redis 集群、ZooKeeper 集群),并添加降级方案;

  4. 可扩展预留:机器 ID、号段大小、Redis key 分片等设计需预留扩容空间(如雪花算法支持 1024 个节点);

  5. 故障早发现:添加 ID 生成监控(如 Prometheus 监控 ID 生成耗时、重复率),并配置告警(如生成耗时 > 1ms、重复率 > 0)。

通过本文的 4 大方案拆解与实战案例,你可根据业务场景快速选型,并避开 90% 的落地坑,真正实现 “分布式 ID 生成” 从理论到落地的无缝衔接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/919235.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实用指南:鸿蒙NEXT安全控件解析:实现精准权限管控的新范式

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

做教育的有哪些网站wordpress模板破解版

最后一道大题题目再现 写一个person类&#xff0c;有姓名&#xff0c;性别&#xff0c;年龄。然后在此基础上派生出教师类和学生类。教师类增加了以下数据&#xff1a;工号&#xff0c;职称&#xff0c;工资。学生类增加了以下数据成员&#xff1a;学号&#xff0c;专业&#…

网站推广的看法不用写代码做网站

椭圆在数学中占有一定的比重&#xff0c;是中学时代必学的圆锥曲线之一&#xff0c;也是历来考试的重点和难点。几何画板作为专业的几何绘图工具&#xff0c;可以用来画椭圆图形。前面的教程学习了在几何画板中利用椭圆定义画椭圆的方法&#xff0c;其实我们还可以利用自定义工…

为什么做彩票网站会被提示危险辽宁省开原市城乡建设投资有限公司网站

企业即时通讯(以下称“企业IM” ) 激战正酣&#xff0c;中国移动也有意搅局。中国移动方面日前向北京商报记者透露&#xff0c;中国移动的IM产品将于下月正式上线&#xff0c;此次中国移动拿出的是淡出人们视线许久的飞信。由于传统通信业务持续下滑&#xff0c;正在蓬勃发展的…

详细介绍:Golang语言基础篇007_结构体详解

详细介绍:Golang语言基础篇007_结构体详解2025-09-27 08:05 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: blo…

实用指南:集成学习全解析:Bagging、Boosting、Stacking原理与实战(2025版)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

队列+宽搜(BFS)-662.二叉树最大宽度-力扣(LeetCode) - 指南

队列+宽搜(BFS)-662.二叉树最大宽度-力扣(LeetCode) - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consol…

Istio服务网格方案 - 实践

Istio服务网格方案 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &…

网站服务商是什么wordpress评论框不见了

文章目录 空间域上的滤波器- 线性滤波器盒状滤波器Box Filter锐化Sharpening相关运算 vs. 卷积运算 Correlation vs. Convolution - 非线性滤波器高斯滤波器Gaussian filter - 实际问题- 纹理texture 频域上的滤波器 滤波的应用- 模板匹配- 图像金字塔 空间域上的滤波器 图像…

杭州微网站wordpress 旅游

继 ChatGPT 后&#xff0c;OpenAI 又发布了爆炸级产品——Sora 文生视频模型&#xff0c;当其他模型还在努力突破几秒内的连贯性问题时&#xff0c;Sora 已经将视频时长拉到了 60s。不过&#xff0c;目前 Sora 模型仅对小部分研究人员和创意人士开放访问权限。 别担心&#xf…

JWT攻防实战:混淆、破解与红队利用技术详解

本文深入解析JWT安全机制,涵盖Base64编码结构、混淆技术、密钥破解(HS256/RS256算法混淆)、none算法攻击等实战手法,并结合TryHackMe/HTB真实靶场演示漏洞利用流程,最后提供JWT安全防护最佳实践。JWT攻防实战:混…

“中国英伟达”投资人,赚翻了

微信视频号:sph0RgSyDYV47z6快手号:4874645212抖音号:dy0so323fq2w小红书号:95619019828B站1:UID:3546863642871878B站2:UID: 3546955410049087还未上市,摩尔线程的朋友圈却已经赚翻了。 在这家国产GPU公司要上…

网站标签怎么设置雏光 网络推广 网站建设

目录 总结一、步骤前端1.第一步-编写tabs的modelBody2.第二步编辑表扩展js 后端--重写表的add和Update方法1.第一步 总结 编写tabs的modelBody后编辑表扩展js在重写后端partial的Service 一、步骤 前端 1.第一步-编写tabs的modelBody 复制下面代码该改的改 <template&…

云主机怎么做网站厦门网站推广费用

及时雨宋江及时的不是雨&#xff0c;而是银子。 年轻的时候&#xff0c;以为聚义厅聚的是义&#xff0c;中年以后才看明白&#xff0c;聚义厅聚的是利。 利益是纽带&#xff0c;是动力。 懂得从他人利益的角度出发&#xff0c;我们才能调动更多的人和资源&#xff0c;成就一…

单位网站的方案wordpress示例页面在哪删除

优先级队列&#xff08;Priority Queue&#xff09;是一种特殊的队列类型&#xff0c;它允许在其元素中分配优先级。与传统的先进先出&#xff08;FIFO&#xff09;队列不同&#xff0c;优先级队列中元素的出队顺序取决于它们的优先级。优先级较高的元素会被优先处理&#xff0…

The 3rd UCUP Stage 29: Metropolis(QOJ contest 1913) 总结

附:出题组题解(繁中)。 A(不可做) B 递归贪心地构造,若当前点有未走的相邻点,且没有 \(p_{i+1}\),那么当前点就要连 \(p_{i+1}\),递归 \(p_{i+1}\)。否则我们可以先回溯。 C 发现其中有一个人每次都只能选偶数…

推进门户网站建设工作会议河北建设厅网站首页

【PC电脑windows环境下-[jetson-orin-NX]Linux环境下-下载工具esptool工具使用-相关细节-简单样例-实际操作】 1、概述2、实验环境3、 物品说明4-2、自我总结5、本次实验说明1、准备样例2、设置芯片3、编译4、下载5、验证 &#xff08;1&#xff09;windows环境下进行烧写1、下…

空白金兰契的多维解构与实践路径:从价值表征困境到人机共生伦理

"空白金兰契"的多维解构与实践路径:从价值表征困境到人机共生伦理 一、价值表征困境的哲学反思 1.1 价值表征暴力的本质与根源 在人工智能伦理研究中,价值表征困境已成为一个核心难题。任何试图用固定规则…

山西建设机械网站首页硬件开发公司

一、问题场景 项目有个需求&#xff0c;在登录页面&#xff0c;输入好账号密码后&#xff0c;直接可以点击回车就能够登录&#xff0c;效果和点击登录按钮一样&#xff0c;登录页面源码如下 <template><body id"poster"><el-form class"login-…

做网站的工作有发展空间没有安全工程师

什么是事务&#xff1f; 我们在开发企业应用时&#xff0c;对于业务人员的一个操作实际是对数据读写的多步操作的结合。由于数据操作在顺序执行的过程中&#xff0c;任何一步操作都有可能发生异常&#xff0c;异常会导致后续操作无法完成&#xff0c;此时由于业务逻辑并未正确…