前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PHP 使用 redis 进行商品秒杀设计思路

PHP 使用 redis 进行商品秒杀设计思路

作者头像
泥豆芽儿 MT
发布2021-09-06 10:05:04
1K0
发布2021-09-06 10:05:04
举报
文章被收录于专栏:木头编程 - moTzxx

前期准备

  • 背景 相信很多在小公司打拼的小伙伴 对于秒杀系统真的是可遇不可求 我们只能通过模拟演练 一方面熟悉高并发场景、提升编码技能 另一方面,为进入大厂做好准备 此处,我主要还是阐述下设计思路 有不同见解,欢迎指摘 …
  • 模拟环境 PHP7.2、CentOS7.9、Redis6.0.8、ab 压测工具

☛ 设计思路

  • 首先,要明确的一点是,不能直接按照传统商品订单思路处理,毕竟大流量下不能丢失用户美好的交互性 然后,准备秒杀服务器,不影响主业务运行 用户在秒杀等待页面,使用 ajax 异步更新倒计时
  • 点击"抢购"触发时 使用 Redis 开启事务 提取用户唯一标识 ID,首先集中到 redis 的一个商品数量的集合"kill_user_que") 然后,将符合要求的 用户ID ,存入秒杀队列"kill_user") 注意商品数量的递减变化 最终的结果是得到一个,不会超售商品数量的 秒杀队列(kill_user)
  • 设置一个或多个线程,也可以是定时任务 去秒杀队列(kill_user) 中提取 用户ID,依次执行下单逻辑

具体的业务处理,要根据实际场景,再做代码优化 … 推荐文章 —— 【用 Redis 轻松实现秒杀系统】


测试参考

☛ 秒杀处理代码参考

假定要抢购的商品数量为 100 件,即 "kill_num" 要提前设置为 100

代码语言:javascript
复制
public function testFastSale(){
       $redis2 = new \Redis();
       $redis2->connect('192.168.80.224',6379);

       $killNumSet = 100;
       //初始化设置秒杀商品数量
       //$redis2->set('kill_num',$killNumSet);
       
       //模拟发起请求的用户ID
       $userID = rand(1111,2222);

       $killNum = $redis2->get('kill_num');
       if ($killNum > 0){
           //TODO 此时,还有商品可进行抢购
           if ($redis2->sIsMember('kill_user_que',$userID)){
               //TODO 此时说明用户已经抢到了
               $message = 'Sorry,一个账号只能抢一件!';
           }else{
               $countCanBuyer = $redis2->sCard('kill_user_que');
               if ($countCanBuyer >= $killNumSet){
                   $message = 'Sorry,当前排队已满员!';
               }else{
                   $redis2->watch('kill_num','kill_user','kill_user_que');
                   $redis2->multi(); //开启事务
                   $redis2->sAdd('kill_user_que',$userID); //加入集合
                   $redis2->decr('kill_num'); //商品数量减一
                   $redis2->rPush('kill_user',$userID);//将用户有序的压入队列
                   $redis2->exec(); //执行事务
                   $message = "恭喜,抢购成功!";
               }
           }
       }else{
           $message = "Sorry,商品已售完!";
       }
       return $message;
   }

【提示】:

  • 为了避免同一用户多抢商品,我使用的是集合 "kill_user_que"
  • 而对符合抢购的用户ID,使用队列 "kill_user" 进行存储 (有序性) 方便后期,对队列的弹出操作(POP),后续下单业务处理

建议,参考文档 —— Redis 事务|【菜鸟教程】

☛ ab 模拟高并发请求

  • 在此,我使用 ab 压力测试工具,模拟高并发的请求场景 运行命令如下:"ab -c 50 -n 3000 http://tp5pro.com/index/test"
  • 执行完成后,可在 redis 中查看数据("kill_num"、"kill_user"):

后续逻辑,就要见仁见智了 …

附录

总觉得写得太少,那就多做一点补充吧!

▶ 为什么我设置一个集合、一个队列?

  • 一开始,我只是想到使用一个队列 "kill_user"就好 但是,我发现: 如果同一个用户账号,可能不止一次能抢到商品 这在正常业务中,一般是不允许的
  • 为了保证用户的唯一性,想到了改用集合 但是,集合有个缺点:不能记录顺序 为了业务合理性 先排到的人自然会先下订单 虽然,也存在有序集合(sorted set)可以满足需求 但是,分析后发现会有很多关于排序取值的逻辑处理,很是繁杂
  • 此时想到 首先,使用一个集合"kill_user_que",负责前期对 用户ID 的筛选,保证唯一性 然后,将刷选符合要求的 用户ID 压入一个队列"kill_user" 后期,只需操作队列 "kill_user" 中的数据即可

如此一来,就出现了这种情况,当然这里主要是提供一种解决思路 !

▶ 可不是仅仅有了代码就行了!

对于秒杀类的需求,需要考虑的方面会比较多,可不只有编码

  • 一般来说 秒杀最容易引来用户流量(小项目没有客户群,那就么啥讨论性了) 可能要考虑 Redis 集群的部署、负载均衡、带宽等支持 其次,还有前端页面静态化、ajax 等代码的设限 以及流量削峰、限流等操作 最后还要有薅羊毛等恶意刷单的考量、人工最终审核等等 …
  • 个人拙见,谢谢 …
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/01/21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前期准备
    • ☛ 设计思路
    • 测试参考
      • ☛ 秒杀处理代码参考
        • ☛ ab 模拟高并发请求
        • 附录
          • ▶ 为什么我设置一个集合、一个队列?
            • ▶ 可不是仅仅有了代码就行了!
            相关产品与服务
            云数据库 Redis
            腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档