跳到主要内容

黑马点评升级版:价值与亮点

plus 版本专属

此章节是黑马点评 Plus 版本中专有的内容,而在整套文档中将普通版本和 Plus 版本都融合在了一起,让大家更方便的学习。

对于 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都升级到了最新版本。

并且功能在普通版能力的基础上,补齐 “高并发稳定性、限流功能、令牌的发送、数据一致性保障、可观测与故障闭环” 等多种维度:

  • 🚦 全链路流控: 令牌前置授权 + 令牌桶限流,将“资格判断”与“流量控制”前置到入口,显著降低突发流量对系统的冲击。
  • 🗄️ 多层缓存策略: 本地缓存 + 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 方案: 链路埋点、请求画像与异常聚合,关键接口压测与版本对比报告。

三、关键问题解决的能力详解

3.1 缓存穿透与缓存击穿的组合解法

核心思路: 在读取链路中构建“多道防线”,保证数据库与热点数据的稳定性。

1) 防穿透:

  • 空值缓存: 数据库查不到时,将空结果写入 Redis,设置短 TTL,避免同一非法键反复打到 DB。
  • 布隆过滤器: 将合法 ID 集合放入布隆过滤器,拦截绝大多数非法请求(误判率可控)。

2) 防击穿:

  • 本地缓存 + Redis 缓存: 双层缓存减少瞬时热点对 Redis 的压力,降低跨网络成本。
  • 双重锁检测(Double-Check-Locking): 只有一个线程进入重建逻辑,其余线程走缓存或短路返回,避免并发重建风暴。
  • 逻辑过期与异步重建: 热点数据过期时不立刻失效,先返回旧值,再异步重建新值,削峰填谷。
  • 预热与热点标记: 提前将热门商户/优惠券加载至缓存,结合定时刷新与失效策略。

3) 读流程参考(简化伪流程):

查本地缓存 → 命中返回
未命中 → 查布隆过滤器(非法直接空值返回)
合法 → 查 Redis(命中返回;空值则短路返回)
Redis 未命中 → 获取重建锁 → 双重检查 → 负载保护 + DB 查询 → 写入空值/实体缓存 → 释放锁 → 返回

3.2 令牌前置授权 + 令牌桶限流

  • 权限令牌: 抢购前先申请“权限令牌”,未持有令牌者不进入扣减链路,保障后端资源。
  • 令牌桶: 在入口按速率放行请求,避免瞬时洪峰压垮系统;支持动态桶容量与优先级(VIP/历史高价值用户)。
  • 实现要点: 基于 Redis 的限流器,实现分布式环境下的统一流控;令牌与资格在 Redis 中统一管理与过期清理。

3.3 Redis 架构问题与故障闭环

典型问题与应对:

  • 扣减成功后服务宕机: 使用“扣减记录 + 事务外的可靠投递(Outbox)”模型,服务恢复后自动补发消息并对账。
  • Lua 执行过程中宕机: Lua 脚本设计幂等与可重入;扣减与记录整体原子;补偿任务扫描半事务状态进行回滚或重试。
  • 主从切换的数据丢失: 评估复制与持久化策略(AOF/RDB),关键扣减记录落地到“对账日志”并周期性校验。
  • Redis 与数据库对账: 引入“扣减记录表/订单对账日志表”,按照订单流水与扣减流水做一致性比对,差异项进入补偿队列。
  • 数据库有订单、Redis 丢数据: 按订单路由表回查对应分片,补写 Redis 或同步触发补偿流程。
  • Redis 扣减成功但订单创建失败: 消费端幂等 + 事务边界控制,失败写入对账日志并触发补偿(回滚余票或再次下单)。

3.4 MQ 架构问题与一致性保障

围绕“扣减 → 下单 → 通知/发券”的链路设计消息可靠性:

  • 生产端: 发布确认(Confirm)、失败回退与重试(指数退避),消息持久化(可靠队列)。
  • 消费端: 幂等处理(基于业务唯一键与去重表)、异常重试、死信队列(DLQ)隔离。
  • 延迟队列: 用于“开抢前预通知”“订单超时关闭”等场景。
  • 一致性策略: 配合 Outbox 模式或本地消息表,实现“写库成功即投递消息”的最终一致性。
  • 乱序与延迟: 在消费端做版本校验或时间窗容忍策略,保障数据与状态不被旧消息覆盖。

3.5 请求疑难杂症与链路观测

  • 废弃订单获取: 按订单状态与超时时间进行清理与标记,沉淀“废弃订单视图”,供运营与对账使用。
  • 链路耗时分析: 埋点统计每个关键步骤耗时,生成请求画像,识别瓶颈(DB/Redis/MQ/锁等待等)。
  • 异常定位: 将错误栈与请求上下文相关联,按版本/接口/商户维度聚合,提升排障效率。
  • 压测画像: 对“节目详情”“生成订单”等关键接口做版本化压测报告,横向对比优化效果。

3.6 分库分表设计与路由

  • 拆分对象: 用户表、用户信息表、用户手机号表、优惠券表、秒杀优惠券表、优惠券订单表、订单路由表、订单对账日志表。
  • 路由策略: 按用户或店铺维度做分片,订单类表按订单号或用户 ID 做路由,保证热点均衡与查询可达。
  • 全局 ID: 引入全局 ID 生成器(如雪花、号段、Leaf 等),保障跨分片唯一性与有序性。
  • 对账与补偿: 定时任务在分片内做一致性校验,差异项进入补偿流程,结合 MQ 与 Redis 进行回滚或重试。

3.7 统计“店铺每日 Top 买家”

  • 设计: 每个店铺每天一个 Key,采用 SortedSet 记录用户购买额或订单数,分值为贡献值,成员为用户 ID。
  • 写入: 订单创建成功后写入统计集;设置合理 TTL(如 7~30 天)以控制存储;每日零点归档与榜单快照。
  • 展示: 支持按店铺维度查询 TopN;可结合用户等级做营销触达。

3.8 订阅通知(余票补充与取消回流)

  • 设计: 当库存不足时,用户加入订阅集合(ZSet,分值为订阅时间或优先级)。
  • 触发: 库存补充或订单取消回流时,按订阅时间最早(或优先级最高)挑选用户,发送通知或自动为其保留资格。
  • 保障: 通知链路纳入 MQ 可靠投递与延迟重试;控制幂等,避免重复通知。

3.9 通知领取(开抢前 2 分钟预通知)

  • 延迟队列: 使用 Redisson 重构优化的延迟队列在活动开始前 2 分钟发送消息。
  • 人群: 从“用户等级集合”“每日 Top 买家”集合中抽取用户,支持随机与优先级混合策略。
  • 去重与速率控制: 保证通知不重复与速率不超限,维护良好用户体验与系统负载。

四、架构设计的能力详解

4.1 MQ 组件设计

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

4.2 Redis 组件设计

  • 目标: 标准化缓存读写与热点治理,统一 Key 规范、TTL 策略、逻辑过期与异步重建、空值缓存与布隆过滤器、L1+L2 双层缓存。
  • 读写流程与策略:
    • 读:本地缓存 → 布隆过滤器 → Redis 命中返回;未命中走“重建锁 + 双重检查 + 负载保护 + DB 查询”,写回实体或空值缓存。
    • 过期:逻辑过期优先,热点数据先返回旧值再异步重建,削峰填谷;普通数据按 TTL 自然失效。
    • 预热:活动前/热点店铺提前预热,定时刷新与冷热迁移。
  • 降级与容错: 支持开关与熔断,异常时走短 TTL 的降级数据或直接回源 DB;关键写路径配合对账日志保障一致性。
  • 布隆与空值缓存: 布隆过滤器拦截非法键;空值缓存避免穿透风暴,结合短 TTL 与访问计数自动清理。
  • 可观测指标: 命中率、重建次数/耗时、锁等待、空值比、热点 TopN、序列化开销等。

4.3 Redis 限流与令牌桶组件设计

  • 目标: 在分布式环境下提供高性能、可配置、可观测的令牌桶限流,支撑入口流控与“令牌前置授权”协同。
  • 限流维度: 支持按 IP/用户/接口/店铺/活动 等维度限流,组合维度形成精细化配额;支持突发 burst 与滑动窗口辅助。
  • 优先级与白名单: 支持 VIP/历史高价值用户优先配额、白名单/黑名单、动态在线配置与热更新。
  • 与令牌前置授权协同: 抢购前需获取“资格令牌”(Redis 统一管理与过期),进入扣减链路前再经令牌桶放行,实现“资格控制 + 速率控制”的双重保障。
  • 接入方式与返回契约: 网关/接口统一拦截器,调用是否放行及剩余配额;拒绝时返回原因码与重试建议。
  • 监控与告警: 暴露限流触发次数、放行比、剩余令牌、拒绝原因分布等指标;异常突增触发告警与应急限流策略。
表关系

4.4 布隆过滤器的设计

  • 目标: 在读链路前置拦截非法 Key/ID,降低缓存穿透与数据库压力,确保热点场景下的稳定性。
  • 核心抽象: 统一封装添加、存在性判断、批量初始化与误判率配置、按业务分区管理。
  • 构建与维护:
    • 初始化:基于数据库合法 ID 集合批量加载;支持分批/分片加载,避免长事务与阻塞。
    • 增量:新资源上线/变更时通过任务/消息增量写入,保证线上布隆与真实集合一致性收敛。
  • 接入点与协同:
    • 在缓存读取前进行 mightContain(id) 判断;不存在直接返回空值或错误码,存在则继续缓存/DB 链路。
    • 与“空值缓存”“缓存客户端”协同,形成防穿透的双保险。
  • 可观测与参数: 支持误判率、容量与哈希函数数量的动态配置;暴露阻断率、误判样本率与重建开销。

4.5 分布式锁的设计

  • 目标: 为热点重建、扣减/下单关键段提供互斥控制,避免并发写冲突与重建风暴。
  • 锁模型与语义:
    • 可重入锁与租约(leaseTime)控制,自动续期(看门狗)保障长耗时任务不被误释放。
    • tryLock(timeout)lock() 两种语义,支持阻塞/非阻塞与超时回退策略。
  • 接入策略:
    • 双重检查 + 锁:重建热点数据前获取锁,完成后释放;失败降级返回旧值或短 TTL 数据。
    • 关键扣减段使用细粒度锁(按活动/店铺/券),避免大锁引发串行化与吞吐下降。
  • 锁类型: 支持读锁、写锁、公平锁、非公平锁,满足不同场景需求。
  • 锁的使用: 提供注解方式、命令式方式、方法级锁等多种接入方式,方便业务方使用。

4.6 分布式幂等功能的设计

  • 目标: 防重复提交/重复消费,保障“最多一次/恰好一次”的业务语义,降低并发抖动带来的状态污染。
  • 核心抽象: 注解式接入:,无侵入保护 Controller/Service 方法。
  • 优化策略: 引入本地锁的功能,实现在同一实例下快速幂等。
  • 应用场景: 下单接口防重复、MQ 消费端防重、通知发放防重;结合“Outbox + 幂等”形成一致性闭环。
  • 异常与反馈: 幂等冲突返回明确原因码与重试建议;自动过期释放。

4.7 分布式延迟队列的设计

  • 目标: 提供高可靠的定时/延迟任务能力,覆盖“开抢前预通知”“订单超时关闭”“补货触达”等场景。
  • 核心抽象: 提交/拉取/消费接口,支持批量与并发度控制。
  • 实现机制: 在 Redisson 延迟队列基础下,进行分片拆分设计与线程池结合异步消费,极大提高执行效率。
  • 一致性保障: 与 Outbox/本地消息表协同,确保“写库成功即产生延迟任务”;消费幂等与去重策略同 MQ 模块。
  • 接入示例: 活动开始前 2 分钟预通知、订单超时自动关闭与库存回流、订阅用户按优先级触达。
  • 监控与运维: 队列积压量、到期偏差、任务成功率与重试次数;异常任务进入“停车场”人工处置。

五、各种中间件宕机和数据丢失的解决方案

将真实生产环境中遇到的宕机问题、数据丢失、问题排查等实际逻辑的解决的方案,都会在黑马点评 Plus 版本中进行应用。

表关系