1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > php redis下单 redis 队列简单实现高并发抢购/秒杀

php redis下单 redis 队列简单实现高并发抢购/秒杀

时间:2023-07-08 11:09:11

相关推荐

php redis下单 redis 队列简单实现高并发抢购/秒杀

redis 队列简单实现高并发抢购/秒杀

-03-21 14:34

阅读数 82

前提为每人限购1件

<>开抢前

把秒杀商品库存存进 Redis 队列中

$redis = new redis(); $redis->connect('127.0.0.1', 6379); //库存 $num = 10;

//往队列 goods_store 插入商品, 队列的长度为库存 for($i=0;$ilpush(

'goods_store', 1);

<>开抢中

方法1

前端: 用户点击购买按钮进行form表单提交

后端: 执行下面代码

//用户等待队列 $wait_key = "user_wait"; //库存队列 $store_key = "goods_store"; //根据Redis

hash特性, 设置成功返回1, 旧值被覆盖则返回0, 用来控制同一用户多买现象 $result = $redis->hset($wait_key,

$user_id, $user_id); if($result){ $count = $redis->lpop($store_key); if(!$count)

return '已经抢光了'; //下单流程, 数据库入库等操作 //下单失败或报错则执行 $redis->hdel($wait_key,

$user_id); 和加库存 $redis->lpush('goods_store', 1); 并跳转回上一页提示下单失败 ......

//下单成功则跳转到相应页面 return '抢购成功'; }

问题: 高并发下可能造成服务器压力瞬间过大, 导致数据入库失败, 可将下单入库等流程用crontab定时器异步执行

方法2

前端: 用户点击购买按钮, 按钮变灰防止用户重复点击, 并且弹出小窗口提示排队中

ajax异步调用抢购接口

* 成功: js轮询请求是否下单成功接口

* 成功: 跳转相应页面进行支付流程

* 失败: 提示用户重新进行购买流程

* 失败: 提示用户重新进行购买流程

抢购接口代码

//用户等待队列 $wait_key = "user_wait"; //抢购成功的用户队列 $user_key = "user"; //库存队列

$store_key = "goods_store"; //根据Redis hash特性, 设置成功返回1, 旧值被覆盖则返回0, 用来控制同一用户多买现象

$result = $redis->hset($wait_key, $user_id, $user_id); if($result){ $count =

$redis->lpop($store_key); if(!$count) return '已经抢光了'; $redis->lpush($user_key,

$user_id); return '抢购成功'; }

crontab定时器异步执行下单入库代码

//用户等待队列 $wait_key = "user_wait"; //抢购成功的用户队列 $user_key = "user"; $count =

$redis->rpop($user_key); if(!$count) return; //下单流程, 数据库入库等操作 //下单失败或报错则执行

$redis->hdel($wait_key, $user_id); 和加库存 $redis->lpush('goods_store', 1); ......

是否下单成功接口代码

//数据库查询order订单表返回是否存在未支付订单数据

待解决:

假设用户A流程进行到以下逻辑时

流程1.下单流程, 数据库入库等操作

流程2.下单失败或报错则执行 $redis->hdel($wait_key, $user_id); 和加库存

$redis->lpush('goods_store', 1);

假设1由于未知错误导致程序崩溃, 没有执行2就退出了, 用户A不能重新抢购

假设1由于未知错误导致入库失败, 2在执行 $redis->hdel 失败了, 用户A不能重新抢购

优化:

前端静态资源上CDN

设置nginx的最大连接数

假设秒杀商品库存有10个, 当用户等待队列 user_wait 长度大于 30~100 后的请求全部过滤

添加一个延时队列, 把下单规定时间内没有付款的订单取消掉, 并加库存

附送 Redis 锁简易代码

// 加锁 $random:随机数 $expire_time:有效时间 $lock_status = $redis->set($lock_key,

$random, array('nx', 'ex' => $expire_time)); if($lock_status){ // do something .

..... if($redis->get($lock_key) == $random){ // 解锁 $redis->del($lock_key); } }

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。