用PHP+redis做电商秒杀

用PHP+redis做电商秒杀
最新回答
天边シ深海

2026-07-30 11:17:21

使用PHP+Redis实现电商秒杀系统的核心在于利用Redis的高性能和原子性操作来处理高并发请求。以下是实现方案及关键代码解析:

核心实现原理
  1. Redis队列(List)

    使用LPUSH将商品库存预存为链表元素,LPOP原子性弹出元素确保超卖防护。

    队列为空时直接返回失败,避免无效数据库操作。

  2. 库存预热

    活动前将商品库存初始化到Redis,避免秒杀时频繁读写数据库。

  3. 缓存过期时间

    设置队列的TTL(如60秒),防止异常未处理数据长期占用内存。

完整代码实现1. 初始化库存(预热阶段)<?php$redis = new Redis();$redis->connect("127.0.0.1", 6379);$goods_number = 100; // 假设库存100件$redis->del('goods_store'); // 清空旧数据for ($i = 0; $i < $goods_number; $i++) { $redis->lpush('goods_store', 1); // 头部插入库存标识}echo "初始化库存:" . $redis->llen('goods_store'); // 输出100?>2. 秒杀请求处理(核心逻辑)<?php$redis = new Redis();$redis->connect("127.0.0.1", 6379);// 原子性弹出库存$stock = $redis->lpop('goods_store');if (!$stock) { echo json_encode(['code' => 0, 'msg' => '秒杀已结束']); exit;}// 生成订单(此处需结合数据库事务)try { $order_id = createOrderInDB(); // 伪代码:数据库插入订单 echo json_encode(['code' => 1, 'msg' => '秒杀成功', 'order_id' => $order_id]);} catch (Exception $e) { $redis->rpush('goods_store', 1); // 回滚库存 echo json_encode(['code' => 0, 'msg' => '系统繁忙,请重试']);}?>3. 支付校验(防止超卖)<?php// 支付前检查订单关联的商品库存状态$order_id = $_GET['order_id'];$order = getOrderFromDB($order_id); // 伪代码:查询订单if ($order && $order['status'] == 'unpaid') { $stock = $redis->llen('goods_store'); // 实时库存(可选) if ($stock >= 0) { // 实际应关联商品ID校验 // 允许支付 } else { echo "商品已售罄,无法支付"; }}?>关键优化点
  1. 异步处理

    秒杀请求先通过Redis队列缓冲,后续订单处理异步化(如消息队列),提升吞吐量。

  2. 限流措施

    结合Nginx限流或Redis的INCR+过期时间实现接口限流,避免过多请求穿透到后端。

  3. 库存同步

    活动结束后,通过脚本将Redis剩余库存同步回数据库,保证数据一致性。

  4. 分布式锁

    多服务器部署时,用SETNX实现分布式锁,防止重复扣减库存(如$redis->set('lock:seckill', 1, ['nx', 'ex' => 5]))。

为什么不用MySQL直接处理?
  • 性能瓶颈:高并发下MySQL的行锁竞争会导致TPS急剧下降。
  • 原子性差异:Redis的LPOP是单线程原子操作,而MySQL事务需在连接池中竞争资源。
示意图说明
  1. 库存初始化

  2. 队列消费

总结
  • 优势:Redis队列完美解决超卖问题,支撑万级QPS。
  • 扩展:结合令牌桶算法、库存预热预热+动态加载可进一步提升系统稳定性。

如需更详细的架构设计(如分库分表、多级缓存),可参考《PHP高并发场景实战》等资料。