一个秒杀就把 MySQL 打挂了?我用 Redis + 异步削峰扛住了 100 倍流量
一个秒杀就把 MySQL 打挂了我用 Redis 异步削峰扛住了 100 倍流量 前言“服务器竟然挂了”——下午 14:00秒杀准时开启你盯着监控面板QPS 瞬间飙到 3 万数据库连接池爆满慢查询堆积成山Tomcat 线程全部阻塞。用户端疯狂重试nginx 日志全是 502页面白屏转圈一分钟后弹出网络异常。产品经理冲过来问还能不能恢复你盯着数据库连接数的折线图——已经是一条垂直线了。MySQL CPU 100%磁盘 IO 打满慢查询队列里排着上万个UPDATE stock正在死锁回滚。这不是虚构的生产事故。我经历过。而且不止一次。本文会把那次完整的技术选型、排查过程、优化方案、底层原理全部拆开讲清楚。如果你团队下一个版本也要上秒杀这可能是你今天读到最值的一篇文章。 环境说明组件版本/说明应用服务器Spring Boot 2.7 Tomcat 9数据库MySQL 8.0 集群1主2从缓存Redis 6.x 单机操作系统CentOS 7, 8C16G × 3 节点压测工具JMeter 5.5预估峰值3 万 QPS实际扛到 5000 开始雪崩 问题复现先看优化前的架构。简单到令人放心用户请求经过 nginx 负载均衡到 TomcatTomcat 直接操作 MySQL 集群。看起来没什么问题对吧MySQL集群TomcatNginx用户MySQL集群TomcatNginx用户点击立即秒杀转发请求检查库存库存充足校验一人一单未购买过UPDATE stock SET countcount-1INSERT INTO order ...订单创建成功返回抢购成功这套流程在低并发时表现完美。但在秒杀场景下暴露了三个致命问题问题 1MySQL 行锁变表锁噩梦库存表的核心 SQL 长这样UPDATEseckill_stockSETcountcount-1WHEREgoods_id?ANDcount0;-- -- 同一商品所有用户竞争同一行锁秒杀开始瞬间上万请求涌入。MySQL行锁排队事务等待时间飙升到秒级大量请求超时回滚后立刻重试——形成死锁风暴 雪崩。问题 2一人一单校验反复查库// 优化前的校验逻辑OrderorderorderMapper.selectByUserIdAndGoodsId(userId,goodsId);// -- 每次查MySQLif(order!null){thrownewBusinessException(每人限购一件);}假设 3 万 QPS一人一单这一步就产生 3 万次 MySQL 查询。对于秒杀这种写多读更多的场景MySQL 的 IO 根本扛不住。问题 3Tomcat 线程池耗尽Tomcat 默认线程池 200。200 个线程全部阻塞在数据库连接获取上——等待排队、等待锁释放、等待回滚。新请求进不来HTTP 连接超时后用户疯狂 F5 重试把服务器推向更深的雪崩。压测数据说明一切指标优化前3 万并发数据库连接池满120/120MySQL CPU100%平均响应时间8.7 s下单成功率3.2%Tomcat 线程200/200 阻塞这不是秒杀——这是自毁程序。 排查过程尝试 1: 加 MySQL 连接池和索引 ❌第一反应是MySQL 太忙了给它加点资源。把连接池从 120 加到 500给seckill_stock表加了(goods_id, user_id)联合索引把UPDATE改为只更新乐观锁版本号。结果连接多了行锁竞争更激烈——500 个线程同时争同一行死锁频次翻倍。TPS 从 200 降到 80。教训秒杀的本质矛盾不是 MySQL 连接不够是同一行记录的写竞争。MySQL 的行锁机制决定了它不适合高并发热点写。尝试 2: 前端限流 按钮置灰 ❌前端倒计时结束后按钮置灰 3 秒后端 nginxlimit_req限制单 IP 1r/s。结果阻止不了专业黄牛他们发包不经过前端、阻止不了海量并发IP 分布极广。真正用户也被限流挡在外面——误杀率 40%。教训前端限流只能做辅助不能依赖。秒杀的核心矛盾不在入口在数据库层。尝试 3: 引入 Redis 预减库存 异步下单 ✅第二次大促前花了两周重构了秒杀链路。核心思路只有一句话把秒杀的资格校验和正式下单解耦。让 Redis 扛住瞬时流量做资格判断把真正写入 MySQL 的操作放到队列里异步执行。MySQL集群异步线程阻塞队列RedisNginx用户MySQL集群异步线程阻塞队列RedisNginx用户异步解耦点击立即秒杀LUA脚本检查库存 一人一单返回抢购成功 订单ID保存订单信息到阻塞队列独立线程读取队列减库存无锁竞争创建订单落库成功变更后重新压测指标优化前优化后数据库连接池满120/120稳定 12 个连接MySQL CPU100%15%平均响应时间8.7 s12 ms下单成功率3.2%99.7%Tomcat 线程200/200 阻塞20 活跃️ 解决方案详细实现核心一Redis LUA 脚本做资格校验为什么用 LUA 脚本因为 Redis 的 LUA 脚本原子执行在整个脚本运行期间不会被其他命令打断。-- check_and_dec.lua-- KEYS[1]: 商品库存 key-- KEYS[2]: 用户已购 set key-- ARGV[1]: 用户 ID-- ARGV[2]: 商品 ID-- 1. 检查库存localstocktonumber(redis.call(GET,KEYS[1]))ifnotstockorstock0thenreturn-1-- 库存不足end-- 2. 检查一人一单localisBoughtredis.call(SISMEMBER,KEYS[2],ARGV[1])ifisBought1thenreturn-2-- 已购买过end-- 3. 预减库存 记录用户redis.call(DECR,KEYS[1])redis.call(SADD,KEYS[2],ARGV[1])-- 4. 生成唯一订单号localorderIdredis.call(INCR,order:id:gen)returnorderId调用这段 LUA 脚本整个秒杀资格校验在一次网络 IO 几微秒内完成彻底绕过了 MySQL。核心二线程池 阻塞队列异步落库ComponentpublicclassSeckillAsyncProcessor{privatefinalExecutorServiceexecutornewThreadPoolExecutor(1,// corePoolSize1,// maxPoolSize0L,TimeUnit.SECONDS,newLinkedBlockingQueue(10000),// -- 阻塞队列做缓冲区newThreadPoolExecutor.CallerRunsPolicy());PostConstructpublicvoidstartConsumer(){executor.submit(()-{while(true){try{SeckillMessagemsgqueue.take();// -- 阻塞获取processOrder(msg);}catch(Exceptione){log.error(异步下单失败,e);}}});}publicbooleanaddTask(SeckillMessagemsg){returnqueue.offer(msg,100,TimeUnit.MILLISECONDS);// -- 超时保护}}关键设计点单线程消费避免数据库写冲突天然解决行锁问题LinkedBlockingQueue作为缓冲区削峰填谷offer()带超时队列满时快速失败不让上游阻塞秒杀场景要用快速拒绝策略然后让用户重试核心三nginx 层面做网关限流limit_req_zone $binary_remote_addr zoneseckill:10m rate100r/s; location /seckill/ { limit_req zoneseckill burst50 nodelay; proxy_pass http://backend_servers; limit_req_status 429; error_page 429 /seckill_busy.html; }nginx 限流放在最外层挡住 90% 的无效流量让 Redis 只处理真正有资格进来的请求。踩坑记录README 没有告诉你的Redis DECR 可能变成负数——LUA 脚本里必须先 GET 判断库存 0 再 DECR不要直接 DECR 后判断。阻塞队列不能无限大——上限设为 10000超过直接拒绝。否则内存被打满OOM 了连日志都写不出去。异步线程要单独处理失败重试——如果数据库写入失败不能简单重试。设计一张状态表记录异步订单的处理状态用定时任务补偿。 原理分析为什么 Redis 比 MySQL 快这么多当我说Redis 能在几微秒内完成资格校验你不是应该只记住这个结论而是要理解为什么。对比维度MySQLRedis数据存储磁盘 Buffer Pool内存数据模型行 表 索引B树Hash / Set / String哈希表事务模型ACID / MVCC / 行锁LUA 原子执行并发瓶颈行锁竞争 → 死锁 → 回滚单线程 事件循环 → 无锁典型延迟1-10 ms含网络0.1-1 ms3 万 QPS 表现CPU 100%连接池爆满CPU 20%连接稳定根本原因MySQL 为了 ACID每一行数据写入都要经过Buffer Pool → Redo Log → Binlog → 脏页刷盘同一行的 UPDATE 还会产生行锁排队。而 Redis 纯粹在内存操作LUA 脚本保证原子性单线程模型天然避免了并发写冲突。秒杀场景下Redis 做资格校验是降维打击。为什么要用异步削峰优化后3万请求Redis资格校验1%通过 99%快速拒绝阻塞队列 削峰填谷单线程异步 顺序写入MySQL优化前3万请求直接写MySQL行锁/死锁/雪崩优化前3 万请求同时打到 MySQL每个请求都需要完整的数据库写操作——这是同心圆式压力放大。优化后99% 的请求在 Redis 层就被快速拒绝了“库存不足或已购买”只有真正抢到的请求进入队列。队列作为缓冲区让 MySQL 的写入速率变成可控的每秒几百笔——这才是数据库能优雅处理的速度。LUA 原子性的边界在哪一个很多人问的问题如果 Redis 执行 LUA 脚本的瞬间宕机了怎么办场景Redis 已经执行了 DECR stock 和 SADD user_set但还没把订单号返回给客户端就宕机了。解决方案订单号不要依赖 Redis 返回。让 Redis 只判断有资格/没资格返回布尔值。真正的订单号用雪花算法在应用层生成并配套一个任务状态表CREATETABLEseckill_task(idBIGINTPRIMARYKEY,user_idBIGINTNOTNULL,goods_idBIGINTNOTNULL,statusTINYINTDEFAULT0COMMENT0-待处理 1-成功 2-失败,create_timeDATETIMEDEFAULTCURRENT_TIMESTAMP,INDEXidx_status(status));异步线程处理完后更新状态。定时任务每 5 秒扫描 status0 的记录超过 30 秒未处理的做补偿处理。这叫最终一致——秒杀场景下你不需要强一致性但必须保证数据不丢。 总结不要把 MySQL 当秒杀引擎。MySQL 的行锁和磁盘 IO 决定了它不适合做热点写让它做最终落库就够了。Redis LUA 原子脚本做资格校验把 3 万 QPS 降维到几百 TPS 的 DB 写入延迟从 8 秒降到 12 毫秒。**异步削峰阻塞队列 单线程消费者**让数据库写入速率变得可控完全避免死锁和雪崩。最终一致性 强一致性。秒杀不是银行转账短暂的缓存和数据库不一致可以接受但数据绝对不能丢。延伸思考如果你的秒杀规模更大比如双十一百亿级上面这套方案还需要补充什么Redis 单机不够 →Redis Cluster 本地标记缓存阻塞队列内存不够 →Kafka/RocketMQ 替代内存队列数据库还不够 →分库分表 读写分离技术选型的核心就一句话让合适的组件干合适的活。 参考资料Redis Lua 脚本官方文档Spring Boot 异步任务配置MySQL 行锁与死锁分析秒杀系统设计 · 美团技术博客nginx ngx_http_limit_req_module本文为原创内容转载请注明出处。如果这篇文章对你有帮助欢迎点赞 、收藏 ⭐、关注 ➕你的支持是我持续输出的动力

相关新闻

F429-HAL-Usart(2026/7/23)

F429-HAL-Usart(2026/7/23)

目录 一、printf → fputc 完整流程图 二、两个实际细节 2.1 fputc 参数里的 FILE *f 为什么从来没用到? 2.2 超时值 0xFFFF vs 1000 的区别 三、分层架构总览 四、HAL_UART_Transmit vs HAL_UART_Receive 函数原型对比 对应到代码 一个比喻 超时值的小结 …

2026/10/10 13:08:47 阅读更多 →
【AI数字人形象定制黄金法则】:20年实战总结的7大避坑指南与3步高转化定制流程

【AI数字人形象定制黄金法则】:20年实战总结的7大避坑指南与3步高转化定制流程

更多请点击: https://codechina.net 第一章:AI数字人形象定制的底层逻辑与价值本质 AI数字人形象定制并非简单的图像合成或3D建模叠加,其底层逻辑建立在多模态感知、神经辐射场(NeRF)重建、参数化人脸模型&#xff08…

2026/10/10 13:09:01 阅读更多 →
AI客服系统优化:Agentic思维与5大实战技巧

AI客服系统优化:Agentic思维与5大实战技巧

1. 项目概述:当AI客服遇上Agentic思维去年夏天,我接手了一个濒临崩溃的智能客服系统改造项目。这个日均处理20万次咨询的系统,当时正面临37%的转人工率和大量用户投诉。在重构过程中,我发现传统基于固定流程的对话设计已经遇到天花…

2026/10/10 14:50:11 阅读更多 →

最新新闻

阿里开源 open-code-review:用确定性流水线兜住 LLM,把代码审查评论钉到具体行

阿里开源 open-code-review:用确定性流水线兜住 LLM,把代码审查评论钉到具体行

在 PR 里挂一个通用大模型审代码,实际体验通常是:十几条"建议补充错误处理""这里可能有并发问题"的泛泛评论,指不到具体哪一行;同一次改动跑两遍,结果还能不一样;误报一多,…

2026/10/10 17:43:09 阅读更多 →
AgentR 开源 Webcmd:让 AI 智能体记住网站

AgentR 开源 Webcmd:让 AI 智能体记住网站

10 月 8 日,AgentR 在旧金山湾区发布 Webcmd——一套免费、开源的浏览器基础设施,卖点只有一句话:让 AI 智能体把一个网站学一次,之后反复复用,而不是每次访问都从零重来。痛点:没有记忆的智能体&#xff0…

2026/10/10 17:43:09 阅读更多 →
GitHub热门项目深度拆解:从仿生机器人到微服务架构

GitHub热门项目深度拆解:从仿生机器人到微服务架构

2026年3月14日晚上,我照例把GitHub的热门榜单从头到尾刷了一遍。当天的热门项目相当能说明问题:前几排里有会走路的鸭子这类嵌入式仿生机器人,有遥操作相关的机器人控制项目,也有Three.js驱动的3D展示项目、Spring Cloud微服务脚手…

2026/10/10 17:43:09 阅读更多 →
低轨卫星产业全解析:从轨道设计到商业落地的完整框架

低轨卫星产业全解析:从轨道设计到商业落地的完整框架

低轨卫星产业这些年是真火了,火到做投资的、搞通信的朋友都跑来问我:这玩意到底是不是噱头?什么时候能真正用上?作为在这个领域跟过几个项目的人,我的真实感受是:低轨卫星被过度神化和过度唱衰的声音同时存…

2026/10/10 17:43:08 阅读更多 →
网上购物系统用例图实战:从边界、关系到评审避坑指南

网上购物系统用例图实战:从边界、关系到评审避坑指南

简介:网上购物系统用例图是一份面向软件工程、UML建模及数据库课程设计的文档资料,适合需要完成在线交易系统需求分析的学生、开发人员与系统设计者参考。资源包共1个文件,以doc文档形式呈现,压缩包大小约319KB,内含系…

2026/10/10 17:43:08 阅读更多 →
Python人流量上下行计数实战:YOLOv8+追踪+虚拟线实现双向客流统计

Python人流量上下行计数实战:YOLOv8+追踪+虚拟线实现双向客流统计

简介:面向Python开发者和计算机视觉入门者,这份人流量计数与上下行方向统计资源围绕OpenCV实现了一套完整的人数统计方案,适用于零售门店、交通枢纽、公共场所等需要分析人员流向的场景。压缩包共20个文件、约138MB,包含可直接运行…

2026/10/10 17:42:07 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →