PHP 使用 Redis 队列制做秒杀抢购的初步实现与思考

先说一下我是如何一步步被逼使用Redis去解决秒杀的问题的 !前端

最开始没有考虑高并发库存超卖这些问题,简单的实现一套订单系统,结果是悲剧的,前台还傻X似的查商品库存显示,活动开始后都变成负数了 … 老脸一横,找解决方案数据库

最先的时候使用一些限流手段,好比输入验证码啊,受权抢购啊,以期下降并发数,但整体体验太差,遂放弃服务器

以后使用文件锁之类的解决方案,发现根本很差使,当文件被写入锁住的时候,实际上并发已经发生了 …并发

不得已采用 Redis , 开始的时候,将商品库存存入 List ,而后下单从 List 中 Pop 库存出来,而后入库减库存 !! 这套方案能够确保库存不超卖,可是有几点遗憾异步

一、用户抢购成功,可是不支付;这个时候就须要将订单按期回收,这就形成抢购一开始不少人抢不到,过一会捡漏却是很轻松 !
二、抢购成功即生成单号入库,由于还有一些列操做(生成单号、生成二维码、发送下单通知 …),并发的时候会形成系统卡住 !就是活动开始那几秒,整个项目是卡死的 …
三、以上两点综合起来,就是抢购成功,页面无响应,只能一直等待,用户不知道状况,页面也一直没响应,结果就关闭了,而后订单建立好页面响应成功了订单又被回收了 … 死循环高并发

—————— 很糟糕的体验性能

后来我又继续找解决方案,发现 RabbitMq 队列,大为惊喜,我只须要将 Pop成功的用户队列起来,而后定时消费入库,就行了 !!
说归说,实现起来各类想不通,总结以下,期待有经验的大神回复 !
Win 环境,成功安装并启动 ERLANG、RabbitMq,成功安装 AMQP - PHP扩展队列

一、根据官方文档,当我得到库存Pop资格后,将用户及用户抢购的商品信息以队列的形式提交到 Rmq,这个并发的过程,投递失败及其余情况不知道怎么捕捉
二、消费者端不知道如何部署,假如是定时任务,轮询某个URL,而后该URL负责消费的话,会产生太多太多消费者,服务器会拖死,网上有说作个 RD 锁,即当存在消费的时候,直接Return,这个机制不知道是否合适
三、当消费成功,应答成功后,如何通知前端 ?消费成功后将订单号和用户ID,写入 Redis Hash散列 ?前端轮询 ?文档

------------------- 搞不颠,但愿有大神能说说这个机制 ,完整详细一点的部署

最终选择经过 Redis 队列实现并发订单,大体实现思路以下

一、抢购时 Pop 库存队列,成功则写入用户即商品信息到一个 Hash 散列,(同时:将用户ID PUSH 到一个 List),前端进入排队页,失败直接进入失败页 (确保不超卖)
二、定时任务消费队列,经过 LLEN 判断用户LIST,而后根据用户ID消费 Hash 键,生成订单入库,(同时写入订单信息到一个 Hash散列,一样以用户ID为键)
这两部能实现库存不超卖、响应很快
三、前端抢购成功排队页轮询,根据本身ID,hGet 散列,当拿到数据,进入支付页,生成预支付参数 !
四、定时任务轮询数据库订单,必定时间未支付的订单,关闭 (再也不回收库存)
五、支付异步通知,减库存
六、每日定时轮询商品表,若是有库存,从新生成库存 List ,前端可再次抢购

以上为当前实现的逻辑,个中确定有不少不理想的地方,我本身能考虑到的有
一、Redis 性能问题,它一旦崩溃了怎么办,整个数据链就断了
二、轮询异常怎么办,进入排队页迟迟获取不到订单,假使给个轮询时间阈值,这个值没有合理时间啊 …

其余还有不少地方不足,期待大神指出 !

相关文章
相关标签/搜索