跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

黑马点评项目实战:Redis 缓存与 RabbitMQ 异步秒杀优化

基于 SpringBoot 构建的点评类项目,深入探讨高并发场景下的技术方案。涵盖 Redis 集群 Session 共享、Cache Aside 缓存一致性策略、缓存穿透雪崩击穿解决方案。重点解析 Lua 脚本原子性预检、乐观锁防超卖、以及从 Redis Stream 迁移至 RabbitMQ 实现异步秒杀下单的优化实践。此外还包含 ZSet 点赞排行、GEO 附近商户、BitMap 签到及 HyperLogLog UV 统计等 Redis 高级应用案例。

宁静发布于 2026/3/22更新于 2026/5/2217 浏览
黑马点评项目实战:Redis 缓存与 RabbitMQ 异步秒杀优化

项目概述

本项目基于 SpringBoot 构建,采用前后端分离架构。核心目标是模拟大众点评业务场景,重点解决高并发下的性能瓶颈。技术栈涵盖 SpringBoot、MyBatis-Plus、MySQL、Redis 集群以及 RabbitMQ 消息队列。

主要功能模块包括短信登录、商户查询缓存、优惠券秒杀、附近商户搜索、UV 统计、用户签到、好友关注及达人探店等。其中分布式锁、缓存一致性策略及异步处理是贯穿项目的关键技术点。

会话管理与权限控制

Redis 替代 Session 的必要性

在集群部署模式下,多台 Tomcat 服务器并不共享内存中的 Session 存储空间。当请求被负载均衡切换到不同节点时,会导致用户状态丢失。因此,我们采用 Redis 集中存储用户信息,以 Token 作为唯一 Key 值。

Token 机制流程:

  1. 用户注册或登录后,生成随机 Token 存入 Redis。
  2. 客户端在后续请求中携带该 Token。
  3. 服务端拦截器校验 Token 有效性,并刷新过期时间。

拦截器分层设计

系统设置了双层拦截器以实现职责分离与性能优化:

  • 第一层(全局处理):负责获取 Token、查询 Redis 中的用户信息、将用户数据存入 ThreadLocal,并统一刷新 Token 有效期。这确保了所有请求都能获取到当前用户上下文。
  • 第二层(业务验证):专注于特定路径的登录校验。如果路径需要登录但用户未通过验证,直接拦截。

这种设计避免了在每个方法中重复查询 Redis,同时保证了非登录接口不会无谓地消耗资源。

缓存一致性与常见问题

Cache Aside 模式

为了保证数据库与缓存的一致性,我们采用 Cache Aside 模式。更新数据时,先更新数据库,再删除缓存。对于读操作,若缓存未命中则回源数据库并回填缓存。

在高并发写场景下,使用 Redisson 实现的读写锁来保证线程安全。读操作加共享锁,允许读读不互斥;写操作加排他锁,确保读写互斥,避免脏数据产生。

缓存穿透、雪崩与击穿

1. 缓存穿透

指大量请求访问数据库中不存在的数据,导致缓存无法命中,压力直达数据库。

解决方案:

  • 参数校验:如 ID 必须为长整型,非法请求直接返回。
  • 布隆过滤器:提前将有效 ID 存入过滤器,过滤掉无效请求。
  • 缓存空值:对查询结果为空的请求,也缓存一个短过期的空值对象。
2. 缓存雪崩

大量 Key 在同一时刻失效,导致瞬间流量冲击数据库。

解决方案:

  • 随机过期时间:在基础过期时间上增加随机偏移量,避免集体失效。
  • 热点数据预热:提前将高频数据加载至缓存。
  • 限流降级:配合熔断机制保护数据库。
3. 缓存击穿

热点 Key 失效时,大量并发请求同时访问数据库。

解决方案:

  • 互斥锁:利用 Redis setnx 实现分布式锁,同一时刻只允许一个线程重建缓存。注意设置合理的锁超时时间,防止死锁。
  • 逻辑过期:不设置物理过期时间,而是在数据结构中维护逻辑过期字段。后台异步线程重建缓存,主线程直接返回旧数据。此方案牺牲空间换取时间,适用于读多写少的热点场景。

高并发秒杀方案

资格预检与原子性

秒杀的核心在于库存扣减的准确性。我们使用 Redis + Lua 脚本实现资格预检。Lua 脚本在 Redis 中是原子执行的,能够一次性完成库存判断、用户去重、扣减库存等操作,避免了多线程竞态条件。

乐观锁防超卖

数据库层面采用乐观锁机制。更新语句中加入 stock > 0 的条件,利用 CAS (Compare And Swap) 算法确保只有库存充足且未被其他事务修改的记录才能更新成功。

voucherOrderService.update()
    .setSql("stock = stock - 1")
    .eq("voucher_id", voucherId)
    .gt("stock", 0)
    .update();

异步下单优化

串行执行查询、扣减、创建订单耗时较长。我们将耗时较长的数据库落库操作移至消息队列异步处理。

流程演进:

  1. Redis Stream:早期版本使用 Redis Stream 实现消费者组模式,支持消息确认和重试。
  2. RabbitMQ:生产环境建议迁移至 RabbitMQ,提供更稳定的投递保障和死信处理机制。

RabbitMQ 配置要点:

  • 普通队列绑定:交换机 Common 路由键 CQ 绑定队列 CQ。
  • 死信队列:配置 TTL 过期后自动转发至死信交换机 DLQ,最终进入死信队列 DLQ,便于排查异常消息。

发送者代码示例:

String jsonStr = JSONUtil.toJsonStr(order);
try {
    rabbitTemplate.convertAndSend("Common", "CQ", jsonStr);
} catch (Exception e) {
    log.error("发送 RabbitMQ 消息失败,订单 ID: {}", orderId, e);
    throw new RuntimeException("发送消息失败");
}
return Result.ok(orderId);

消费者监听逻辑:

@RabbitListener(queues = "CQ")
public void receivedC(Message message, Channel channel) throws Exception {
    String msg = new String(message.getBody());
    VoucherOrder voucherOrder = JSONUtil.toBean(msg, VoucherOrder.class);
    
    // 保存订单
    voucherOrderService.save(voucherOrder);
    // 扣减库存
    seckillVoucherService.update()
        .setSql("stock = stock - 1")
        .eq("voucher_id", voucherOrder.getVoucherId())
        .gt("stock", 0)
        .update();
    
    // 手动 ACK
    channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}

社交与地理位置功能

点赞排行榜 (ZSet)

利用 ZSet 的有序特性存储用户 ID 和点赞时间戳(Score)。支持快速查询点赞列表及取消点赞操作。相比 MySQL,Redis 能显著降低高频写入的压力。

关注与共同关注 (Set)

使用 Set 集合存储关注关系。通过 SADD 添加关注,SREM 移除关注。计算共同关注时使用 SINTER 求交集,效率极高。

附近商铺搜索 (GEO)

基于 GEO 数据结构存储商户经纬度。底层由 ZSet 实现,支持按距离排序和范围查询。

GEOADD shops:geo 116.397128 39.916527 "shop:1001"
GEORADIUS shops:geo 116.403847 39.915526 5 km WITHDIST ASC

用户签到 (BitMap)

使用 BitMap 记录每日签到状态。每个 bit 位代表一天,0 表示未签,1 表示已签。极大节省存储空间,适合海量用户的签到统计。

UV 统计 (HyperLogLog)

针对独立访客数统计,使用 HyperLogLog 概率算法。仅需占用约 16KB 内存即可估算百万级用户基数,误差率控制在 0.81% 以内,非常适合高并发下的 UV 统计场景。

目录

  1. 项目概述
  2. 会话管理与权限控制
  3. Redis 替代 Session 的必要性
  4. 拦截器分层设计
  5. 缓存一致性与常见问题
  6. Cache Aside 模式
  7. 缓存穿透、雪崩与击穿
  8. 1. 缓存穿透
  9. 2. 缓存雪崩
  10. 3. 缓存击穿
  11. 高并发秒杀方案
  12. 资格预检与原子性
  13. 乐观锁防超卖
  14. 异步下单优化
  15. 社交与地理位置功能
  16. 点赞排行榜 (ZSet)
  17. 关注与共同关注 (Set)
  18. 附近商铺搜索 (GEO)
  19. 用户签到 (BitMap)
  20. UV 统计 (HyperLogLog)
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Windows 7 系统下 Git 安装与配置
  • Flutter 三方库 shelf_modular 的鸿蒙化适配指南
  • Linux 环境变量详解:概念、操作与代码获取
  • AI 绘画精讲与 AIGC 时代游戏美术设计:从入门到精通
  • C++ 基础语法与算法初步:从循环到递归
  • Trae 配置 C++ 编译环境指南
  • OpenClaw 飞书机器人权限配置与安全实践
  • 深入解析 C 与 C++ 的核心差异与特性对比
  • DeepSeek-R1 大模型基于 MS-Swift 框架的部署与微调实践
  • DeepFace 与 OpenCV 实现实时情绪分析器
  • FPGA 实现 OV5640 摄像头视频采集与 VGA 显示
  • 后端转前端:一份实用的技术路线图
  • 线性 DP 经典四题详解:台阶、子段和、传球游戏与乌龟棋
  • 回溯算法与动态规划核心知识点及 Java 实现总结
  • Dify MCP Server 插件实战:将工作流发布为第三方服务
  • 使用 Anaconda 安装 NumPy、Pandas、Scikit-learn 及 Seaborn
  • ComfyUI 与潜空间:AI 绘画技术原理解析
  • VSCode 调试大模型训练代码的三种高效方法
  • 七大排序算法详解(下):冒泡、快速与归并排序
  • 数据结构:二叉树基础与 C 语言实现

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online