当前位置: 首页 > news >正文

解决秒杀高并发的一些方案


解决秒杀高并发的一些方案

秒杀场景的特点:

  • 瞬时高并发:大量请求在短时间内涌入
  • 库存有限:必须避免超卖
  • 一致性要求高:库存扣减和订单生成要保证正确

常见的几种实现方式:


一、Redis 方案(基于内存,效率高)

1. 库存预热队列

活动前把商品库存预先放入 Redis 队列,抢购时依次弹出。

// 预热库存
for ($i=0; $i<$count; $i++) {$redis->lpush('goods_store', 1);
}// 抢购时
$count = $redis->lpop('goods_store');
if (!$count) {insertLog('error:no store redis');return;
}
  • ✅ 优点:

    • FIFO 保证“先到先得”,不会超卖
    • 实现简单直观
  • ⚠️ 缺点:

    • 大量库存预热占用内存
    • Redis 宕机可能导致数据丢失
    • 需要定期与数据库对账,保持一致性

2. 分布式锁 (setnx)

do {$res = $redis->setnx("numKey", 1);$this->timeout -= 100;usleep(100);
} while ($res == 0 && $this->timeout > 0);if ($res == 0) {echo 'fail1';
} else {$num = $redis->get('num');if ($num > 0) {$redis->decr('num');$res = $redis->lPush('result', $num);echo $res ? "success:".$num : "fail2";} else {echo "fail3";}$redis->del("numKey");
}
  • ✅ 优点:

    • 保证并发情况下操作的互斥性
  • ⚠️ 缺点:

    • setnx 需搭配 expire,否则进程异常会死锁
    • 自旋锁 + usleep 性能浪费
    • 建议用 SET key value NX EX ttlRedLock 替代

3. 原子计数 (decr)

$retNum = $redis->decr('num');
if ($retNum >= 0) {// success
} else {// fail
}
  • ✅ 优点:

    • Redis 原子操作,性能极高
    • 实现最简洁
  • ⚠️ 缺点:

    • 仍需防止 retNum == -1 的情况(超卖)
    • Redis 数据和 MySQL 数据需异步对账

4. 乐观锁 (watch)

$num = $redis->get('num');
if ($num > 0) {$redis->watch('num');$res = $redis->multi()->decr('num')->lPush('result', $num)->exec();echo $res ? "success:".$num : "fail1";
} else {echo "fail2";
}
  • ✅ 优点:

    • CAS 思路,避免加锁
  • ⚠️ 缺点:

    • watchexec 之间容易冲突,失败率高
    • 高并发下需大量重试,性能差

二、MySQL 方案(简单,但效率差)

1. 悲观锁

SELECT stock 
FROM goods 
WHERE id = [商品ID] 
FOR UPDATE;
  • ✅ 优点:

    • 保证强一致性,逻辑简单
  • ⚠️ 缺点:

    • 高并发下阻塞严重,吞吐量极低
    • 一般只用于小规模并发或后台

2. 乐观锁(版本号 / 时间戳)

UPDATE goods 
SET stock = stock - 1, version = version + 1 
WHERE id = [商品ID] AND stock > 0 AND version = $currentVersion;
  • ✅ 优点:

    • 非阻塞,性能比悲观锁好
    • 并发下保证库存不超卖
  • ⚠️ 缺点:

    • 更新失败需业务层重试
    • 用户体验可能不佳(抢到也可能失败)

三、文件锁(不推荐)

1. 排他锁

$fp = fopen("lock.txt", "w+");
if (!flock($fp, LOCK_EX | LOCK_NB)) {echo "系统繁忙,请稍后再试";return;
}
  • ✅ 优点:

    • 实现简单,测试方便
  • ⚠️ 缺点:

    • 仅适合单机环境
    • IO 开销大,性能差
    • 生产环境基本不用

四、消息队列削峰(MQ)

思路:前端请求先进入 MQ(Kafka / RabbitMQ / RocketMQ),消费者再按顺序从队列中取出请求处理。

  • ✅ 优点

    • 削峰填谷,抵御流量洪峰
    • 系统解耦,请求不会直接打爆数据库
    • 易于扩展(消费者可水平扩展)
  • ⚠️ 缺点

    • 处理有一定延迟(最终一致性)
    • 消息丢失/重复需要保证幂等性

👉 实际上,Redis 扣减库存 + MQ 异步下单 是大厂标配方案。


五、令牌桶 / 漏桶限流

思路:在入口层(Nginx / API Gateway)加限流,比如 每秒只发放 100 个令牌,拿到令牌的请求才能继续执行。

  • ✅ 优点

    • 限制瞬时并发,保护下游服务
    • 拒绝多余请求,避免系统雪崩
  • ⚠️ 缺点

    • 抢不到令牌的用户直接失败(但符合秒杀场景特点)

六、预扣库存(缓存 + 数据库双写)

思路:活动开始前,将库存同步到 Redis,Redis 负责实时扣减,后台定时把结果异步写回 MySQL。

  • ✅ 优点

    • Redis 抗高并发,性能优
    • MySQL 保存最终结果,保证持久化
  • ⚠️ 缺点

    • 需要处理 Redis 与 MySQL 不一致问题
    • 可能出现超卖或少卖,需要补偿机制

七、用户排队(异步处理)

思路:先让用户进入排队系统(类似 12306 / JD 抢购),后台分批处理订单请求。

  • ✅ 优点

    • 用户体验较好,有“排队感知”
    • 系统压力均匀,不会瞬间打爆
  • ⚠️ 缺点

    • 实现复杂,需要额外的排队服务
    • 用户下单延迟高

八、静态页面 + 前端限流

思路:活动页提前生成静态页面,减少数据库和应用层压力。前端在秒杀按钮处增加限流逻辑(例如按钮灰化、随机延迟)。

  • ✅ 优点

    • 最大化减少应用层压力
    • 提前过滤一部分无效请求
  • ⚠️ 缺点

    • 不适合高安全性场景(前端逻辑容易被绕过)
    • 只能作为“辅助手段”

九、CDN 缓存 + 本地化校验

思路:把活动页、秒杀时间、商品信息放到 CDN,本地浏览器校验秒杀开始时间,减少集中请求的瞬时流量。

  • ✅ 优点

    • 降低源站压力
  • ⚠️ 缺点

    • 无法替代库存扣减逻辑,只能减少部分请求

十、硬件层面的支持

  • 内核调优(Linux TCP 参数、文件句柄数等)
  • 负载均衡(Nginx / LVS)
  • 分库分表 / 读写分离
  • 热点数据隔离(比如单独 Redis 实例处理秒杀库存)

总结与推荐实践

  • Redis 原子操作(decr 或 队列) → 负责扣减库存 + 限流,保证不超卖
  • 消息队列(Kafka/RabbitMQ) → 负责削峰填谷,把订单请求异步落库
  • MySQL 乐观锁 → 负责最终一致性,防止异常情况导致超卖
  • 消息队列削峰(Kafka / RabbitMQ)
  • 入口限流(令牌桶 / 漏桶)
  • 排队系统(用户体验层面)
  • CDN + 静态化(减少请求风暴)
  • 系统层面优化(分库分表 / 负载均衡 / 内核优化)

额外注意事项:

  • 接口限流(令牌桶/漏桶)
  • 防刷机制(限制 IP/用户频率)
  • 幂等性(同一用户不能重复下单)
  • Redis 与 MySQL 数据定期对账

最终架构推荐: Redis + MQ + MySQL 组合拳,既能抗高并发,又能保证数据安全。


http://www.hskmm.com/?act=detail&tid=20997

相关文章:

  • 构建移动网关:Air780EPM用4G为WiFi和LAN设备供网
  • 9.29模拟赛总结
  • 多corner综合
  • 优化 if/else 的四种设计模式
  • Day11-C:\Users\Lenovo\Desktop\note\code\JavaSE\Basic\src\com\oop\demo06
  • 牛客周赛 Round 111
  • OpenLayers地图交互 -- 章节十一:拖拽材料交互详解
  • 2025年人工智能与智能装备国际学术会议(AIIE 2025)
  • 通过IDOR实现权限提升导致未授权用户注入
  • APUE学习笔记之基础知识(一) - Invinc
  • Syslog日志集成搭建
  • 定义工业生产新范式!网易灵动发布全球首款全域智能无人装载机“灵载”
  • 国有银行人力资源数字化转型的合规突围与效能跃迁
  • Java 类类型
  • OpenFeign 继承FeignClient客户端注意事项
  • 9月29日
  • JVM调优实战及常量池详解
  • Cisco Identity Services Engine (ISE) 3.5 - 基于身份的网络访问控制和策略实施系统
  • 03-控制台项目创建与结构说明
  • 赋能智慧应急:国标GB28181平台EasyGBS视频技术如何成为气象灾害预警新工具
  • NET各个版本新增的特性和语法糖
  • xinference推理embedding等小模型
  • day15-项目上线
  • opencv学习记录6
  • 努力的轨迹,通往成长的旅程——赵欣彤的自我介绍
  • 第2章 day02 requests基础
  • 线性代数_工程实践-计算实现numpy
  • 在HAL库使用printf打印串口信息
  • 第4章 day04 防盗链
  • 第3章 day03 xpath+反爬虫