一、美团秒杀的完整实现逻辑(全链路分层管控)
大厂秒杀的核心是“先拦后放、层层过滤”,从用户端到数据库,每一层都在拦截无效请求,只让极少数请求到达核心逻辑,具体分6层:
1. 前端层:用户感知的“第一关”
这是你点抢券按钮后,最先触发的拦截:
- 按钮置灰防重复:抢券按钮点击后,1-2秒内会变成灰色(无法再次点击),避免你疯狂点按钮产生一堆无效请求;
- 本地限流:同一手机/账号,每秒最多发1次抢券请求,多余的请求直接在你手机上拦截(不会发到美团服务器);
- 预加载活动配置:秒杀开始前,你的手机会提前从CDN下载活动信息(比如券有1万张、10点整开始),不用等秒杀开始再去查,减少服务器压力。
2. CDN/边缘节点层:静态资源“不回源”
- 秒杀页面的所有静态内容(按钮、图片、规则),都提前存在离你最近的CDN节点里,你打开页面时,直接从CDN加载,不用请求美团的主服务器;
- 只有“抢券请求”才会发到美团后端,其他操作(看规则、看倒计时)都不占用后端资源。
3. Nginx接入层:“服务繁忙”的主要来源
这是你看到“服务繁忙请刷新”的核心环节,美团会在这里直接拒绝90%以上的请求:
- IP限流:同一IP每秒最多允许发5次抢券请求,超过的话,Nginx直接返回“服务繁忙”;
- 封禁异常IP:如果是秒杀器、爬虫的IP,直接拉黑,根本不让请求进后端;
- 节点负载保护:如果后端服务器已经忙不过来,Nginx会直接拒绝新请求,避免服务器崩溃。
4. 网关/应用层:精准筛选有效请求
能走到这层的请求已经是“筛选过的”,但还要再拦:
- 按活动限流:比如这场秒杀只准备了1万张券,网关会设置“每秒最多处理1万次请求”,超过的请求要么排队(你看到“一直加载中”),要么返回繁忙;
- 用户风控校验:检查你是不是新注册的小号、有没有频繁抢券的异常行为,有风险的账号直接拒绝;
- 先查Redis库存:先看Redis里的券库存是不是0,如果已经抢完,直接返回“券已抢空”,不用再走后面的逻辑。
5. MQ队列层:削峰填谷(避免数据库崩溃)
秒杀的瞬时请求是“洪峰”(比如1万张券,100万人抢),但数据库每秒只能处理1000次请求,MQ的作用是“缓冲”:
- 所有通过网关的请求,先扔进MQ队列里,后端按数据库能承受的速度(比如每秒1000次)慢慢处理;
- 如果队列满了、或者你排队超时(比如等了5秒),就会显示“加载中超时→服务繁忙”;
- 这也是“难抢”的关键:大部分请求连MQ都进不去,只有极少数能被慢慢处理。
6. 核心业务层(Redis+MySQL):防超发、防发重的关键
这是秒杀的“心脏”,绝对不会直接用MySQL扣库存,而是靠Redis做原子性管控:
- Redis预扣库存(防超发) :秒杀开始前,把1万张券的库存写到Redis里,抢券时用Redis的
DECR命令(原子减1)——这个操作是Redis单线程执行的,绝对不会超发(减到0就不会再减了); - Redis防发重:用“券ID+你的用户ID”做Redis的key,抢券成功后,这个key就会被标记为“已抢”,你再抢的话,Redis直接返回“你已经抢过了”;
- MySQL落地+对账:Redis抢券成功后,再把你的抢券记录写到MySQL里(保证数据能查到);后台会每1分钟对比Redis和MySQL的库存,如果不一致(比如Redis扣了但MySQL没写),会立刻修正,避免数据错漏。
二、为什么总遇到“服务繁忙/加载中、难抢”?
不是系统崩了,是美团主动的限流策略:
- 保护系统:100万人抢1万张券,如果让所有请求都进核心逻辑,数据库会直接崩,所有人都抢不到;
- 控制成本:1分钱券是美团贴钱的,不能让太多人抢到;
- 防恶意抢券:拦截秒杀器、小号,只让正常用户有机会抢。
三、大厂怎么解决“超发、发重”?
绝对不会出现超发/发重,靠这2个核心手段:
- 超发解决:Redis的
DECR是原子操作,库存减到0就不会再减,加上MySQL对账兜底,100%不会多发; - 发重解决:用“券ID+用户ID”做唯一标识,Redis标记已抢后,同一用户再抢会直接被拦,MQ消费时也会校验这个标识,避免重复发券。