硬核讲解秒杀设计
1 秒杀场景秒杀场景登陆12306进行火车票抢座1599元购入飞天茅台周董演唱会的门票双十一秒杀活动秒杀场景关注点严格防止超卖库存1000件卖了1020件要杀个码农祭天了防止超卖是秒杀系统设计最核心的部分。防止黑产防止不怀好意的羊毛党薅羊毛。保证用户体验高并发下给用户提供友善的购物体验尽可能支持比较高的QPS等等。接下来就让我们按照关注点不断细化秒杀场景。2 第1版-裸奔裸奔秒杀不加思考上来直接按照SpringBoot MyBatis模式进行秒杀系统的设计流程如下Controller层获得用户秒杀请求后调用Service层。Service层获得请求后要要检查已售数据跟库存总量是否一致一致说明商品卖没了不一致说明还有库存那就调用DAO层对已售数量进行加1。DAO层获得请求后直接通过MyBatis操作数据库实现已售数量加1跟订单创建。如果你用Postman去测试会发现是OK的但如果你用专业的并发测试工具JMeter模式多用户并发请求会发现订单创建数量库存量 - 已售量。原因解释下比如用户A、B并发进行秒杀请求此时库存100已售64。A用户进行描述请求此时调用到了Service层发现已售不等于库存此时拿到库存数是64A将库存更新为63然后创建订单。B用户进行描述请求此时调用到了Service层发现已售不等于库存此时拿到库存数是64B将库存更新为63然后创建订单。此时库存减少了1个但是订单创建多个卖超了无锁并发请求卖超了3 第2版-悲观锁syn悲观锁遇见 并发问题 很容易想到以前学过并发编程嘛既然Controller默认是单例模式那我用 synchronized 将Controller层调用Service层的代码进行加锁同步即可。这样就可以解决卖超问题了但是须知既然是悲观锁如果有1000个并发请求那只有1个拿到锁了。有999个会去竞争这个锁的。Transactional Service Transactional Slf4j public class OrderServiceImpl implements OrderService { //校验库存 Stock stock checkStock(id); //更新库存 updateSale(stock); //创建订单 return createOrder(stock); }当然了你也可以用Spring自带的事务注解来实现悲观锁的操作因为用了Transactional就可以实现通过事务来控制要么全部成功要么全部失败用事务时有两点需注意尽可能将MySQL执行语句往方法体后面靠因为MySQL事务的commit语句是在第一次执行MySQL相关语句开始一直到方法的结束。设置事务的超时时间如果不设置默认是-1是无限长。并且事务中设置的耗时timeout 最后一个MySQL语句耗时 以及最后一个MySQL之前的所有耗时。需注意悲观锁状态下会保证商品卖出去如果没拿到锁的线程会阻塞的等待拿锁。但是他的阻塞也会给用户带来非常不良好的体验。4 第3版-乐观锁MySQL版本号我们为每个数量的已售数据配备个版本号在Service层调用时获得用户的已售数跟对应版本号然后更新时将已售数跟版本号同时更新。因为 MySQL在更新时会自带乐观加速机制如果更新成功则表示抢购成功更新失败则表示抢购失败此时你会发现不是手速越快就一定能抢到的哦但起码保证了不会超卖update 库存表 set 已售数已售数1,版本号版本号1 where 秒杀id #{id} and 版本号 #{version}需注意乐观锁状态下由于是随机性的秒杀失败所以可能活动结束后还会有几个没售出去的5 第4版-限流最核心的超卖问题已经解决了接下来就是各种优化手段了。在高并发请求中如果不对接口限流会对后台服务器造成极大压力所以一般秒杀系统为了不影响其他业务会单独部署到个某个服务器上同时还会设置好限流。常用的限流方法有我们在 Redis 中曾经说过主要有漏桶算法、令牌桶算法。而Google开源项目Guava中RateLimiter使用的就是令牌桶控制算法。在开发高并发系统时有三把利器用来保护系统缓存、降级、限流缓存缓存的目的是提升系统访问速度和增大系统处理容量。降级降级是当服务器压力剧增的情况下根据当前业务情况及流量对一些服务和页面有策略的降级以此释放服务器资源以保证核心任务的正常运行。限流限流的目的是通过对并发访问/请求进行限速或者对一个时间窗口内的请求进行限速来保护系统一旦达到限制速率则可以拒绝服务、排队或等待、降级等处理。5.1 漏桶算法漏桶算法思路把水比作是请求漏桶比作是系统处理能力极限水先进入到漏桶里漏桶里的水按一定速率流出当流出的速率小于流入的速率时由于漏桶容量有限后续进入的水直接溢出拒绝请求以此实现限流。5.2 令牌桶算法令牌桶算法原理可以理解成医院的挂号看病只有拿到号以后才可以进行诊病。流程大致所有的请求在处理之前都需要拿到一个可用的令牌才会被处理。根据限流大小设置按照一定的速率往桶里添加令牌。设置桶最大可容纳值当桶满时新添加的令牌就被丢弃或者拒绝。请求达到后首先要获取令牌桶中的令牌拿着令牌才可以进行其他的业务逻辑处理完业务逻辑之后将令牌直接删除。如果用户无法获得令牌可以选择一直阻塞等待也可以选择设置好timeout机制。令牌桶有最低限额当桶中的令牌达到最低限额的时候请求处理完之后将不会删除令牌以此保证足够的限流。工程中一般用令牌桶算法为多一般用Google的Guava中RateLimiter即可。//创建令牌桶实例 private RateLimiter rateLimiter RateLimiter.create(20); // 阻塞式获得令牌才继续往下执行 rateLimiter.acquire(); // 就等3秒看是否可以获得令牌返回Boolean值。 rateLimiter.tryAcquire(3, TimeUnit.SECONDS)6 第5版- 细节优化有了乐观锁跟限流接下来再思考写细节问题。秒杀要有时间范围限制的不能再任意时刻都可以接受秒杀请求要实行限时抢购。如果有懂IT人员通过抓包获取了秒杀接口地址在秒杀开始时不通过按钮直接通过脚本秒杀咋办要实行秒杀接口隐藏。每个用户单位时间内访问次数要做频率限制。6.1 限时抢购很简单将秒杀商品放入Redis并设置超时比如我们以kill 商品id作为key以商品id作为value设置180秒超时。127.0.0.1:6379 set kill1 1 EX 180 OK加入时间校验public Integer createOrder(Integer id) { //redis校验抢购时间 if(!stringRedisTemplate.hasKey(kill id)){ throw new RuntimeException(秒杀超时,活动已经结束啦!!!); } //校验库存 Stock stock checkStock(id); //扣库存 updateSale(stock); //下订单 return createOrder(stock); }6.2 秒杀接口隐藏接口隐藏用户秒杀前先通过getMd5方法获得一个请求秒杀URL的MD5值。请求getMd5算法Key 商品id 用户idvalue 商品id 用户id 盐 。将KV存入redis并且设置过期时间最终返回value作为md5值。用户请求秒杀URL的时候需携带MD5值然后Service层会根据商品id 用户id从redis中获取下对应的value看这个value跟MD5值是否一致绝对下一步操作。// 根据商品id 跟 用户id生成个md5。 Override public String getMd5(Integer id, Integer userid) { //检验用户的合法性 User user userDAO.findById(userid); if(usernull)throw new RuntimeException(用户信息不存在!); //检验商品的合法行 Stock stock stockDAO.checkStock(id); if(stocknull) throw new RuntimeException(商品信息不合法!); String hashKey KEY_ userid _ id; //生成md5此处的 !AW# 是一个盐可以跟找个Random随机生成。 String key DigestUtils.md5DigestAsHex((userid id !AW#).getBytes()); stringRedisTemplate.opsForValue().set(hashKey, key, 3600, TimeUnit.SECONDS); return key; }此时如果用户直接请求秒杀接口就会被限制了但如果黑客技术升级将请求MD5跟请求秒杀接口写到一起还是无法防止被薅羊毛咋办呢再限制下用户访问频率。6.3 访问频率限制通过前面请求后根据用户id生成个redis中的keyvalue为访问次数默认为0并且设置好该KV的过期时间。用户在验证是否通过秒杀隐藏接口验证前先看下他的单位时间内访问次数是多少如果超过阈值则直接拒绝没超过再进行隐藏接口的验证。这里只是举例为用户访问次数限制IP访问次数限制类似。秒杀源码公众号回复秒杀获取。访问频率限制7 第6版-众多细节优化CDN加速为何京东物流快因为人在全国各地配置了多个仓库。同理我们可以将前端的一些静态东西配置在全国各个不同的地方用户请求时直接请求距离自己最近的前端资源即可。前端按钮灰色化如果参与过秒杀活动会发现没到秒杀时间时秒杀按钮是灰色状态的只有时间到了才是可点击状态。并且秒杀开始咯也不是一直可以点的可能只允许1秒内点10次那种的。Nginx负载均衡一个tomcat的QPS一般在200~1000左右如果淘宝或京东性质的秒杀就需要搞个Nginx负载均衡来支持几万级别的并发了。信息存储Redis化单独的MySQL是无法支撑上万的QPS的既然Redis号称可支持10W级的QPS我们把数据信息存到Redis中就好咯嘛有人可能会说MySQL有乐观锁跟事务性啊Redis不是没有事务性么其实我们可以通过Lua脚本来实现并发情况下Redis的事务性操作。消息中间件-流量削峰秒杀成功后如果秒杀的成功量过大全部订单直接写入MySQL也是不太恰当的可以把秒杀成功的用户信息写入消息中间件。比如RabbitMQ、Kafka给用户返回抢购成功信息然后专门代码消费中间件信息(生成订单数据持久化)因为是异步消费为防止用户秒杀成功后无法看到订单信息在订单生成前给用户提示订单提交排队中啥时候订单异步消费成功了再告知用户成功。辅助手段秒杀前做个预演练是必须的吧系统上线后QPS监控、CPU监控、IO监控、缓存监控也是必须要搞的。同时一旦服务真的扛不住了熔断跟限流也要考虑进去。短URL有时你别人发给你个超短的URL你打开后就直接跳转为日常看到的购物页面了这就涉及到短URL映射了大致思路就是做个链接映射在此基础上也可以玩出各种花样反正挺有趣的(有兴趣可以水一篇)。秒杀大致流程图工业化秒杀真正工业化的秒杀绝对不止我前面说的那么简单哦起码你会接触到MQ、SpringBoot、Redis、Dubbo、ZK、Maven、lua等知识点我也从同性交友网站GitHub找到了份爆赞的工业化秒杀项目公众号回复秒杀就可以获取啦。

相关新闻

数据库跟缓存的双写一致性

数据库跟缓存的双写一致性

1 关于一致性 为加速系统性能一般都会引入缓存机制,比如 Redis。这种情况下当用户读数据时一般会按照如下流程: 读流程 关于读的流程大家是没有异议的,但是对于数据的更新呢,如何操作才算合理呢? 先更新数据库再更新缓…

2026/7/3 19:08:09 阅读更多 →
48 张图 | 手摸手教你微服务的性能监控、压测和调优

48 张图 | 手摸手教你微服务的性能监控、压测和调优

一、何为压力测试 1.1、 大白话解释 性能压测是什么:就是考察当前软件和硬件环境下,系统所能承受的最大负荷,并帮助找出系统的瓶颈所在。 性能压测的目的:为了系统在线上的处理能力和稳定性维持在一个标准范围内,做到…

2026/7/4 19:35:41 阅读更多 →
Redis最佳实践:7个维度+43条使用规范,带你彻底玩转Redis | 附实践清单

Redis最佳实践:7个维度+43条使用规范,带你彻底玩转Redis | 附实践清单

这篇文章我想和你聊一聊 Redis 的最佳实践。 你的项目或许已经使用 Redis 很长时间了,但在使用过程中,你可能还会或多或少地遇到以下问题: 我的 Redis 内存为什么增长这么快? 为什么我的 Redis 操作延迟变大了? 如何…

2026/7/6 15:31:00 阅读更多 →

最新新闻

ASM330LHH与STM32L041C6运动跟踪系统设计与优化

ASM330LHH与STM32L041C6运动跟踪系统设计与优化

1. ASM330LHH与STM32L041C6的硬件组合解析1.1 ASM330LHH的6DoF IMU特性详解ASM330LHH这颗汽车级6轴惯性模块堪称运动跟踪领域的精密仪器。它采用系统级封装(SiP)技术,在3.3mm2.6mm0.83mm的微型封装内集成了三轴数字加速度计和三轴数字陀螺仪。实测中我发现&#xff…

2026/7/7 7:24:00 阅读更多 →
IDM注册表锁定激活技术深度解析:永久试用期管理方案

IDM注册表锁定激活技术深度解析:永久试用期管理方案

IDM注册表锁定激活技术深度解析:永久试用期管理方案 【免费下载链接】IDM-Activation-Script IDM Activation & Trail Reset Script 项目地址: https://gitcode.com/gh_mirrors/id/IDM-Activation-Script Internet Download Manager(IDM&…

2026/7/7 7:21:59 阅读更多 →
AlmaLinux 9、Rocky Linux 9 升级到 10 版本

AlmaLinux 9、Rocky Linux 9 升级到 10 版本

注:本文原在2025年6月24日发表于笔者的个人博客《IT人的工作生活》,原文 链接 :https://www.cntse.com/3293.html,如需转载,请私信笔者,征得笔者同意后,方可转载,并且需要保留本段文…

2026/7/7 7:19:58 阅读更多 →
【专业服务】游戏试玩广告全流程定制开发:从创意到数据,助力高效获客

【专业服务】游戏试玩广告全流程定制开发:从创意到数据,助力高效获客

🎯 服务概述 我们是专注于游戏试玩广告(Playable Ads)创意策划与技术开发的团队。我们致力于将您的游戏核心乐趣,浓缩成几十秒的沉浸式互动体验,直接触达目标用户,大幅提升广告点击率、转化率与用户质量。 …

2026/7/7 7:17:58 阅读更多 →
开源AI模型本地部署实战:从环境搭建到性能优化全解析

开源AI模型本地部署实战:从环境搭建到性能优化全解析

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 本地部署开源AI模型实战指南:从环境搭建到应用落地 最近在技术社区中,关于开源AI模型本地部署的讨论越来越热…

2026/7/7 7:17:58 阅读更多 →
月入五万的蓝海赛道,两年做到头部

月入五万的蓝海赛道,两年做到头部

最近好几个同学来问节气礼盒项目,说翻了一圈,发现我们宣传得不多,问我能不能再讲透一点。行,今天咱们敞开聊聊。先说一个大多数人认为的误区:提到端午粽子、中秋月饼,第一反应是不是街边糕点店、网红零食&a…

2026/7/7 7:13:57 阅读更多 →

日新闻

鸿蒙新特性:图片画廊与轮播导航——构建沉浸式图片浏览体验

鸿蒙新特性:图片画廊与轮播导航——构建沉浸式图片浏览体验

图片浏览是移动应用中最高频的场景之一。从社交应用的照片流到电商平台的商品图集,从旅游应用的景点相册到摄影作品展示——用户对图片浏览的体验要求不断提高:流畅的切换动画、直观的缩略图导航、便捷的收藏操作、自动播放模式。HarmonyOS NEXT ArkUI 虽…

2026/7/7 0:05:16 阅读更多 →
24V DC-DC降压芯片PW2312B/PW2815,SOT23-6到SOP8-EP方案对比

24V DC-DC降压芯片PW2312B/PW2815,SOT23-6到SOP8-EP方案对比

24V稳压芯片完整选型指南 PW8600 PW75XX PW2815 PW2312B LDODC/DC全方案 一、24V稳压方案概述 24V直流电源在工业自动化、门禁系统、电梯控制、汽车电子、LED驱动、监控设备等场景中应用极广,是最常见的中压直流母线电压。要将24V母线稳定降压至下游MCU、传感器…

2026/7/7 0:05:16 阅读更多 →
RAG+知识图谱混合检索与Graph RAG核心对比

RAG+知识图谱混合检索与Graph RAG核心对比

做企业RAG落地的团队,往往容易卡在一容易踩坑的选型难题: 当需求单纯靠向量RAG搞不定、单纯靠知识图谱也搞不定,必须同时依赖「文本语义理解 实体关系推理」时,到底是做「向量图谱混合检索」就够了,还是必须上「Grap…

2026/7/7 0:07:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/6 8:11:50 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/6 8:11:52 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/6 6:52:56 阅读更多 →

月新闻