# hmdp-plus
**Repository Path**: java-up-up/hmdp-plus
## Basic Information
- **Project Name**: hmdp-plus
- **Description**: 🔥 🔥 热门推荐 🔥 🔥将黑马点评进行完全地重构升级,围绕优惠券秒杀与热点查询,补齐高并发稳定性、动态令牌、限流、消息可靠性与数据一致性闭环,并添加订阅通知、候补排队等新亮点功能,解决烂大街和亮点不足问题!并打造成真正企业级别实战项目,全面工程化落地。
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: https://javaup.chat
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 1
- **Created**: 2025-10-28
- **Last Updated**: 2025-11-25
## Categories & Tags
**Categories**: Uncategorized
**Tags**: 春招, 秋招, 就业, SpringBoot, 高并发
## README
**开源不易,还请您点个Star 多谢!🎉**
对于 Java 程序员而言,项目是简历与面试的核心竞争力。仅停留在 CRUD 或 Demo 级项目,很难体现工程化能力与架构思维。“黑马点评” 这个项目相信对于很多人来说并不陌生,甚至它是很多人开始学习 Java 语言的启蒙实战项目,也有不少人用它去面试,拿到了 Offer。它把“八股文”转化为可落地的工程方案:不背答案,直接在项目中应用与验证。
## 黑马点评项目介绍
黑马点评是“本地生活与商户运营”场景的综合实战项目,包含商户浏览与查询、优惠券发放与抢购、达人探店、好友关注、签到与 UV 统计等核心业务。围绕“高并发下的优惠券秒杀”与“热点查询”的真实问题,提供端到端的稳定性与一致性解决方案。
## 黑马点评功能回顾
**主要重点围绕 Redis 的多种数据结构与实战场景展开:**
- **短信登录:** 基于 Redis 共享 Session 实现分布式会话管理。
- **商户查询缓存:** 认知并实战缓存穿透、缓存击穿、缓存雪崩问题的应对方式。
- **优惠券秒杀:** 基于 Redis 计数器 + Lua 的原子扣减;理解分布式锁(含 Redisson);掌握三种消息队列的用法与对比。
- **附近的商户:** 使用 Redis GEO 实现地理位置检索与排序。
- **UV 统计:** 使用 HyperLogLog 完成海量去重统计。
- **用户签到:** 利用 BitMap 进行用户签到与统计。
- **好友关注:** 基于 Set 实现关注、取消关注、共同关注等社交关系。
- **达人探店:** 用 List 实现点赞列表,用 SortedSet 实现点赞排行榜。
**库存扣减相关功能**:
- 优惠券秒杀中的库存超卖问题与乐观锁方案。
- Redis 分布式锁与 Redisson 锁的选型与用法。
- 使用 Redis 判断秒杀资格与消息队列的简单应用。
## 黑马点评的问题
黑马点评项目作为练手学习来说,很不错能够快速进入实战,但是要拿去面试使用,特别是要面大厂的话,就有点不够看了,很容易问到:
- **流量突发时,如何动态的限流?**
- **Redis宕机了怎么办?**
- **Redis数据丢失了怎么办?**
- **MQ宕机了怎么办?**
- **MQ消息丢失了怎么办?**
- **MQ消息延迟消费了怎么办?**
- **数据库的库存数量和Redis中的不一致怎么办?**
- **Redis恢复后,丢失的数据要怎么恢复?**
这些问题在黑马点评中并没有得到解决,而恰恰这些还正是大厂特别看中的 **“解决问题的能力”**,所以本人推出 **黑马点评 Plus 版本**,来解决这些疑难重症,并且额外再引入新的功能,让这个项目彻底的无懈可击!
点评中并没有得到解决,而恰恰这些还正是大厂特别看中的 “解决问题的能力”,所以本人推出 **黑马点评 Plus 版本**,来解决这些疑难重症,并且额外再引入新的功能,让这个项目彻底的无懈可击!
# 一、黑马点评 Plus 是什么 🚀
首先,黑马点评 Plus 将 SpringBoot 版本升级到了主流成熟的 SpringBoot3,并将其他的中间件,如:MybatisPlus、Redis、Redisson、Kafka都升级到了最新版本。
并且功能在普通版能力的基础上,补齐 **“高并发稳定性、限流功能、令牌的发送、数据一致性保障、可观测与故障闭环”** 等多种维度
### 黑马点评 Plus 项目详细讲解 🔗:[👉 点击查看讲解](https://www.javaup.chat/hmdp-plus/overview/project-change)
- 🚦 **全链路流控:** 令牌前置授权 + 令牌桶限流,将“资格判断”与“流量控制”前置到入口,显著降低突发流量对系统的冲击。
- 🗄️ **多层缓存策略:** 本地缓存 + Redis 缓存 + 空值缓存 + 布隆过滤器,有效降低 DB 压力与热点击穿风险。
- ✅ **缓存问题的完美解决:** 多层缓存与双重锁检测,辅以空值缓存与布隆过滤器,弥补普通版本的不足,彻底缓解穿透与击穿。
- 🔁 **一致性闭环:** Redis 扣减、订单创建、消息投递、数据库落库之间建立明确的状态流转与补偿策略。
- 📦 **MQ 可靠性:** 发布确认、重试退避、死信与延迟队列、消费幂等与去重,提升消息处理鲁棒性。
- 🔍 **可观测与故障分析:** 聚焦链路瓶颈、异常源定位与版本压测对比,形成闭环优化机制。
- 📈 **运营能力:** 支持“每日 Top 买家”和“订阅-通知-领取”的活动玩法,提升用户参与度与复购。
- 🗂️ **分库分表与路由设计:** 分库分表与全局 ID 生成,订单与对账日志按需拆分,为数据规模增长与高并发写入提供保障。

# 二、Plus 版本解决了普通版本的哪些问题与痛点!
## 2.1 抢购业务的关键痛点

- **流量入口缺少前置控制**
- ⚠️ **问题:** 缺乏权限令牌与令牌桶限流,突发洪峰直接压垮热点接口。
- 🔹 **Plus 方案:令牌前置授权与令牌桶限流,支持动态阈值与人群优先级(如 VIP)。**
- **扣减链路缺少一致性闭环**
- ⚠️ **问题:** Redis 扣减成功但订单创建失败、消息未投递或延迟,导致库表与缓存不一致。
- 🔹 **Plus 方案:Redis记录、本地消息表、订单对账日志、定时一致性校验与补偿队列,消费端幂等与去重。**
- **MQ 可靠性不足**
- ⚠️ **问题:** 使用 RedisStream,宕机后消息丢失,无发布确认、重试退避、延迟/死信队列,消息丢失/重复/乱序未处理。
- 🔹 **Plus 方案:使用 Kafka,并在生产端/消费端确认、指数退避重试、DLQ/延迟队列、消费幂等、发送失败/消费失败/消费超时的各种处理。**
- **数据层扩展不足**
- ⚠️ **问题:** 订单等热点数据未分库分表,大数量情况下性能低下,读扩散与热点聚集难抑制。
- 🔹 **Plus 方案:Sharding 路由、全局 ID 生成、分片内对账与差异补偿。**
- **故障场景处理缺失**
- ⚠️ **问题:** Redis 主从切换数据丢失、Lua 宕机、扣减成功但订单失败 等没有对应的处理策略。
- 🔹 **Plus 方案:消息记录信息、操作日志记录、可重入脚本设计、补偿扫描与自动回滚机制。**
## 2.2 扩展性的关键痛点

- **分布式锁使用粗糙**
- ⚠️ **问题:** 锁的设计类型单一,没有考虑到多种锁类型,锁超时处理方式。
- 🔹 **Plus 方案:对 Redisson 重构设计,支持的锁类型:读锁、写锁、公平锁、非公平锁。锁的使用:注解化、命令式、方法级。可自定义处理失败策略。**
- **缓存策略单一**
- ⚠️ **问题:** 缓存穿透/击穿的解决方案不够完美:仅依赖单层 Redis,未引入空值缓存、布隆过滤器、本地缓存与逻辑过期。
- 🔹 **Plus 方案:本地 + Redis 双层缓存、空值缓存、布隆过滤器、双重锁检测、逻辑过期与异步重建。**
- **运营策略不足**
- ⚠️ **问题:** 缺少 Top 买家统计、订阅通知与开抢前预通知,拉新促活能力有限。
- 🔹 **Plus 方案:SortedSet 榜单、ZSet 订阅、Redisson 延迟队列分片设计提高效率,执行预通知与去重控频,降噪通知。**
- **可观测性薄弱**
- ⚠️ **问题:** 缺少耗时画像、异常聚合、版本压测对比,难以定位瓶颈与评估优化。
- 🔹 **Plus 方案:链路埋点、请求画像与异常聚合,关键接口压测与版本对比报告。**
# 三、如何启动项目
- [准备项目启动条件](https://javaup.chat/hmdp-plus/startup/prerequisites)
- [如何安装项目需要的中间件环境](https://javaup.chat/hmdp-plus/startup/install-middlewares)
- [后端项目部署启动](https://javaup.chat/hmdp-plus/startup/backend-deploy)
- [前端项目部署启动](https://javaup.chat/hmdp-plus/startup/frontend-deploy)
- [项目文档和视频目录](https://javaup.chat/hmdp-plus/overview/project-change)
# 四、关键问题解决的能力详解
## 4.1 缓存穿透与缓存击穿的组合解法
**核心思路:** 在读取链路中构建“多道防线”,保证数据库与热点数据的稳定性。
### 1) 防穿透 :
- **空值缓存:** 数据库查不到时,将空结果写入 Redis,设置短 TTL,避免同一非法键反复打到 DB。
- **布隆过滤器:** 将合法 ID 集合放入布隆过滤器,拦截绝大多数非法请求(误判率可控)。
### 2) 防击穿 :
- **本地缓存 + Redis 缓存:** 双层缓存减少瞬时热点对 Redis 的压力,降低跨网络成本。
- **双重锁检测(Double-Check-Locking):** 只有一个线程进入重建逻辑,其余线程走缓存或短路返回,避免并发重建风暴。
- **逻辑过期与异步重建:** 热点数据过期时不立刻失效,先返回旧值,再异步重建新值,削峰填谷。
- **预热与热点标记:** 提前将热门商户/优惠券加载至缓存,结合定时刷新与失效策略。
### 3) 读流程参考(简化伪流程) :
```
查本地缓存 → 命中返回
未命中 → 查布隆过滤器(非法直接空值返回)
合法 → 查 Redis(命中返回;空值则短路返回)
Redis 未命中 → 获取重建锁 → 双重检查 → 负载保护 + DB 查询 → 写入空值/实体缓存 → 释放锁 → 返回
```
## 4.2 令牌前置授权 + 令牌桶限流
- **权限令牌:** 抢购前先申请“权限令牌”,未持有令牌者不进入扣减链路,保障后端资源。
- **令牌桶:** 在入口按速率放行请求,避免瞬时洪峰压垮系统;支持动态桶容量与优先级(VIP/历史高价值用户)。
- **实现要点:** 基于 Redis 的限流器,实现分布式环境下的统一流控;令牌与资格在 Redis 中统一管理与过期清理。
## 4.3 Redis 架构问题与故障闭环
**典型问题与应对:**
- **扣减成功后服务宕机:** 使用“扣减记录 + 事务外的可靠投递(Outbox)”模型,服务恢复后自动补发消息并对账。
- **Lua 执行过程中宕机:** Lua 脚本设计幂等与可重入;扣减与记录整体原子;补偿任务扫描半事务状态进行回滚或重试。
- **主从切换的数据丢失:** 评估复制与持久化策略(AOF/RDB),关键扣减记录落地到“对账日志”并周期性校验。
- **Redis 与数据库对账:** 引入“扣减记录表/订单对账日志表”,按照订单流水与扣减流水做一致性比对,差异项进入补偿队列。
- **数据库有订单、Redis 丢数据:** 按订单路由表回查对应分片,补写 Redis 或同步触发补偿流程。
- **Redis 扣减成功但订单创建失败:** 消费端幂等 + 事务边界控制,失败写入对账日志并触发补偿(回滚余票或再次下单)。
## 4.4 MQ 架构问题与一致性保障
**围绕“扣减 → 下单 → 通知/发券”的链路设计消息可靠性:**
- **生产端:** 发布确认(Confirm)、失败回退与重试(指数退避),消息持久化(可靠队列)。
- **消费端:** 幂等处理(基于业务唯一键与去重表)、异常重试、死信队列(DLQ)隔离。
- **延迟队列:** 用于“开抢前预通知”“订单超时关闭”等场景。
- **一致性策略:** 配合 Outbox 模式或本地消息表,实现“写库成功即投递消息”的最终一致性。
- **乱序与延迟:** 在消费端做版本校验或时间窗容忍策略,保障数据与状态不被旧消息覆盖。
## 4.5 请求疑难杂症与链路观测
- **废弃订单获取:** 按订单状态与超时时间进行清理与标记,沉淀“废弃订单视图”,供运营与对账使用。
- **链路耗时分析:** 埋点统计每个关键步骤耗时,生成请求画像,识别瓶颈(DB/Redis/MQ/锁等待等)。
- **异常定位:** 将错误栈与请求上下文相关联,按版本/接口/商户维度聚合,提升排障效率。
- **压测画像:** 对“节目详情”“生成订单”等关键接口做版本化压测报告,横向对比优化效果。
## 4.6 分库分表设计与路由
- **拆分对象:** 用户表、用户信息表、用户手机号表、优惠券表、秒杀优惠券表、优惠券订单表、订单路由表、订单对账日志表。
- **路由策略:** 按用户或店铺维度做分片,订单类表按订单号或用户 ID 做路由,保证热点均衡与查询可达。
- **全局 ID:** 引入全局 ID 生成器(如雪花、号段、Leaf 等),保障跨分片唯一性与有序性。
- **对账与补偿:** 定时任务在分片内做一致性校验,差异项进入补偿流程,结合 MQ 与 Redis 进行回滚或重试。

## 4.7 统计“店铺每日 Top 买家”
- **设计:** 每个店铺每天一个 Key,采用 SortedSet 记录用户购买额或订单数,分值为贡献值,成员为用户 ID。
- **写入:** 订单创建成功后写入统计集;设置合理 TTL(如 7~30 天)以控制存储;每日零点归档与榜单快照。
- **展示:** 支持按店铺维度查询 TopN;可结合用户等级做营销触达。
## 4.8 订阅通知(余票补充与取消回流)
- **设计:** 当库存不足时,用户加入订阅集合(ZSet,分值为订阅时间或优先级)。
- **触发:** 库存补充或订单取消回流时,按订阅时间最早(或优先级最高)挑选用户,发送通知或自动为其保留资格。
- **保障:** 通知链路纳入 MQ 可靠投递与延迟重试;控制幂等,避免重复通知。
## 4.9 通知领取(开抢前 2 分钟预通知)
- **延迟队列:** 使用 Redisson 重构优化的延迟队列在活动开始前 2 分钟发送消息。
- **人群:** 从“用户等级集合”“每日 Top 买家”集合中抽取用户,支持随机与优先级混合策略。
- **去重与速率控制:** 保证通知不重复与速率不超限,维护良好用户体验与系统负载。

# 五、架构设计的能力详解 🏗️
## 5.1 MQ 组件设计
- **目标:** 为“扣减 → 下单 → 通知/发券”等链路提供可靠消息能力,覆盖生产确认、重试退避、死信隔离、延迟/定时消息与全链路可观测。
- **可靠投递与一致性:**
- 采用 Outbox 模式(本地消息表):业务事务提交后写入 Outbox,由异步分发器投递至 MQ,保障“写库成功即可投递”的最终一致性。
- 消息状态机:`PENDING → SENT → ACKED/FAILED`;失败进入重试,超过阈值入 DLQ(死信队列),支持人工与自动回溯。
- **成功情况的处理:** 在消息发送成功、消费成功,都有灵活的扩展钩子,方便后续埋点与监控。
- **各种失败情况的考虑:** 当消息发送失败、消费超时、消费异常、消费失败,等各种失败异常的情况,都有对应的扩展策略,回滚、补偿、上报、通知等。
- **消费幂等与去重:** 以业务唯一键 `messageId`(uuid)为幂等键,结合幂等组件和幂等标识,避免重复消费影响状态。
- **可观测与运维:** 暴露发布/消费成功率、重试次数、DLQ 积压量、端到端耗时等指标;提供“停车场(parking-lot)”模式对个别异常消息人工处置。

## 5.2 Redis 组件设计
- **目标:** 标准化缓存读写与热点治理,统一 Key 规范、TTL 策略、逻辑过期与异步重建、空值缓存与布隆过滤器、L1+L2 双层缓存。
- **读写流程与策略:**
- 读:本地缓存 → 布隆过滤器 → Redis 命中返回;未命中走“重建锁 + 双重检查 + 负载保护 + DB 查询”,写回实体或空值缓存。
- 过期:逻辑过期优先,热点数据先返回旧值再异步重建,削峰填谷;普通数据按 TTL 自然失效。
- 预热:活动前/热点店铺提前预热,定时刷新与冷热迁移。
- **降级与容错:** 支持开关与熔断,异常时走短 TTL 的降级数据或直接回源 DB;关键写路径配合对账日志保障一致性。
- **布隆与空值缓存:** 布隆过滤器拦截非法键;空值缓存避免穿透风暴,结合短 TTL 与访问计数自动清理。
- **可观测指标:** 命中率、重建次数/耗时、锁等待、空值比、热点 TopN、序列化开销等。
## 5.3 Redis 限流与令牌桶组件设计
- **目标:** 在分布式环境下提供高性能、可配置、可观测的令牌桶限流,支撑入口流控与“令牌前置授权”协同。
- **限流维度:** 支持按 `IP/用户/接口/店铺/活动` 等维度限流,组合维度形成精细化配额;支持突发 `burst` 与滑动窗口辅助。
- **优先级与白名单:** 支持 VIP/历史高价值用户优先配额、白名单/黑名单、动态在线配置与热更新。
- **与令牌前置授权协同:** 抢购前需获取“资格令牌”(Redis 统一管理与过期),进入扣减链路前再经令牌桶放行,实现“资格控制 + 速率控制”的双重保障。
- **接入方式与返回契约:** 网关/接口统一拦截器,调用是否放行及剩余配额;拒绝时返回原因码与重试建议。
- **监控与告警:** 暴露限流触发次数、放行比、剩余令牌、拒绝原因分布等指标;异常突增触发告警与应急限流策略。
## 5.4 布隆过滤器的设计
- **目标:** 在读链路前置拦截非法 Key/ID,降低缓存穿透与数据库压力,确保热点场景下的稳定性。
- **核心抽象:** 统一封装添加、存在性判断、批量初始化与误判率配置、按业务分区管理。
- **构建与维护:**
- 初始化:基于数据库合法 ID 集合批量加载;支持分批/分片加载,避免长事务与阻塞。
- 增量:新资源上线/变更时通过任务/消息增量写入,保证线上布隆与真实集合一致性收敛。
- **接入点与协同:**
- 在缓存读取前进行 `mightContain(id)` 判断;不存在直接返回空值或错误码,存在则继续缓存/DB 链路。
- 与“空值缓存”“缓存客户端”协同,形成防穿透的双保险。
- **可观测与参数:** 支持误判率、容量与哈希函数数量的动态配置;暴露阻断率、误判样本率与重建开销。
## 5.5 分布式锁的设计
- **目标:** 为热点重建、扣减/下单关键段提供互斥控制,避免并发写冲突与重建风暴。
- **锁模型与语义:**
- 可重入锁与租约(leaseTime)控制,自动续期(看门狗)保障长耗时任务不被误释放。
- `tryLock(timeout)` 与 `lock()` 两种语义,支持阻塞/非阻塞与超时回退策略。
- **接入策略:**
- 双重检查 + 锁:重建热点数据前获取锁,完成后释放;失败降级返回旧值或短 TTL 数据。
- 关键扣减段使用细粒度锁(按活动/店铺/券),避免大锁引发串行化与吞吐下降。
- **锁类型:** 支持读锁、写锁、公平锁、非公平锁,满足不同场景需求。
- **锁的使用:** 提供注解方式、命令式方式、方法级锁等多种接入方式,方便业务方使用。

## 5.6 分布式幂等功能的设计
- **目标:** 防重复提交/重复消费,保障“最多一次/恰好一次”的业务语义,降低并发抖动带来的状态污染。
- **核心抽象:** 注解式接入:,无侵入保护 Controller/Service 方法。
- **优化策略:** 引入本地锁的功能,实现在同一实例下快速幂等。
- **应用场景:** 下单接口防重复、MQ 消费端防重、通知发放防重;结合“Outbox + 幂等”形成一致性闭环。
- **异常与反馈:** 幂等冲突返回明确原因码与重试建议;自动过期释放。
## 5.7 分布式延迟队列的设计
- **目标:** 提供高可靠的定时/延迟任务能力,覆盖“开抢前预通知”“订单超时关闭”“补货触达”等场景。
- **核心抽象:** 提交/拉取/消费接口,支持批量与并发度控制。
- **实现机制:** 在 Redisson 延迟队列基础下,进行分片拆分设计与线程池结合异步消费,极大提高执行效率。
- **一致性保障:** 与 Outbox/本地消息表协同,确保“写库成功即产生延迟任务”;消费幂等与去重策略同 MQ 模块。
- **接入示例:** 活动开始前 2 分钟预通知、订单超时自动关闭与库存回流、订阅用户按优先级触达。
- **监控与运维:** 队列积压量、到期偏差、任务成功率与重试次数;异常任务进入“停车场”人工处置。
# 六、各种中间件宕机和数据丢失的解决方案
将真实生产环境中遇到的宕机问题、数据丢失、问题排查等实际逻辑的解决的方案,都会在黑马点评 Plus 版本中进行应用。
# 七、前端新功能的添加
黑马点评 Plus 不仅在后端做了大量的改进和优化,同时在前端也新增了一些功能,提升用户体验和系统的整体性能。
## 7.1 抢购优惠券前的流程优化
在抢购优惠券的过程中,重新将页面样式进行了优化,提升了用户的视觉体验。
## 7.2 抢购优惠券过程中的提示优化
在抢购优惠券的过程中,会弹出提示框,提示用户正在抢购中,只有在真正的抢购成功后,才会告知用户抢购成功,否则会提示抢购失败。
## 7.3 如果抢购成功,后续还可以取消
在抢购成功后,用户可以选择取消抢购的优惠券,这样可以提升用户的灵活性和体验。
## 7.4 到券提醒
如果优惠券被售罄了,用户还可以选择“到券提醒”,当有新的优惠券放出来时,系统会自动通知用户。
## 7.5 订阅通知
当用户选择“到券提醒”后,系统会通知用户已订阅到券提醒。
