首页 > 数据库 >php + redis 实现秒杀

php + redis 实现秒杀

时间:2024-05-14 10:09:35浏览次数:31  
标签:return redisService userId redis 秒杀 20 php

一、概述

秒杀这个问题在很多面试的时候都会提到,会有各个方面的调优,配置等等,本文在这里举个简单的例子来演示下秒杀的过程,供大家参考发散思维。

 

二、准备介绍

  • thinkPHP6框架
  • redis6.0
  • php7.4
  • redis操作包predis
  • apache-jmeter-5.6

 

三、代码实现

秒杀controller层的简易代码:

<?php
/**
 * Created by PhpStorm
 * Author: fengzi
 * Date: 2024/4/8
 * Time: 10:07
 */

namespace app\admin\controller\seckill;

use app\admin\service\seckill\SeckillService;

class SeckillController
{
    public function __construct()
    {
    }

    /**
     * 设置商品数量
     * @param SeckillService $seckillService
     * @return \think\response\Json
     * @Author: fengzi
     * @Date: 2024/4/8 10:00
     */
    public function setNumber(SeckillService $seckillService)
    {
        $seckillService->setProductNumber();

        try {
            $seckillService->setProductNumber();

            return success('设置成功');
        } catch (\Exception $e) {
            return error($e->getMessage());
        }
    }

    /**
     * 购买入口
     * @param SeckillService $seckillService
     * @return \think\response\Json
     * @Author: fengzi
     * @Date: 2024/4/8 11:00
     */
    public function index(SeckillService $seckillService)
    {
        try {
            $seckillService->seckill();

            return success();
        } catch (\Exception $e) {
            return error($e->getMessage());
        }
    }

}

 

秒杀service层的简易代码:

<?php
/**
 * Created by PhpStorm
 * Author: fengzi
 * Date: 2024/4/8
 * Time: 10:09
 */

namespace app\admin\service\seckill;

use Predis\Client;

class SeckillService
{
    private Client $redisService;

    public function __construct()
    {
        // 初始化Redis连接
        $this->redisService = new Client(config('cache.stores.redis'));
    }

    /**
     * 设置秒杀的产品数量
     * @return void
     * @Author: fengzi
     * @Date: 2024/4/8 10:11
     */
    public function setProductNumber()
    {
        $this->redisService->set('product_number', 20);
    }

    /**
     * 实现秒杀过程
     * 一个用户只能购买一次商品
     * @return void
     * @Author: fengzi
     * @Date: 2024/4/8 16:45
     */
    public function seckill()
    {
        //lua脚本,保证原子性
        $lua_script = <<<LUA
local number = redis.call('get', KEYS[1])
if (redis.call('exists', KEYS[1]) == 1 and tonumber(number) > 0 ) then
    redis.call('decr', KEYS[1])
    redis.call('sadd', KEYS[2], ARGV[1])
    return true
else
    return false
end
LUA;
        //模拟用户ID
        $userId = mt_rand(1, 50);
        //抢购成功的用户列表
        $userLists = 'user_lists_id';
        try {
            $res = $this->redisService->sismember($userLists, $userId);
            if ( $res == 0 ) {
                $result = $this->redisService->eval($lua_script, 2, 'product_number', 'user_lists_id', $userId);
                if ($result) {
                    // 处理订单逻辑
                    echo "秒杀成功!!!!";
                } else {
                    echo "秒杀结束!";
                }
            } else {
                echo "秒杀失败,用户{$userId}已经秒杀过了!";
            }
        } catch (\Exception $e) {
            echo "秒杀失败:" . $e->getMessage();
        }
    }
}

 

接口路由:

<?php
use think\facade\Route;


/**秒杀*/
Route::group('/seckill', function () {
    //设置秒杀数量
    Route::any('set_number', '/seckill.Seckill/setNumber');
    //购买
    Route::any('index', '/seckill.Seckill/index');
});

 

四、测试

使用jmeter对接口进行压测,查看是否有超卖,一人购买多次的情况。

1、设置20个商品数量

 

 

2、配置 jmeter ,一秒请求200个,请求结果如下:

 

3、如下图所示,20个商品已经售卖完,未出现超卖。

 

4、如下图所示,购买人是20个,且无重复购买的人。

 

五、总结

实际生产环境的“秒杀”业务是很繁杂的,有许多地方需要注意。本文只是对“秒杀”这个场景做了简单的试验,仅给大家提供个思路和样本。如有不同见解欢迎大家留言讨论。

 

标签:return,redisService,userId,redis,秒杀,20,php
From: https://www.cnblogs.com/mklblog/p/18121829

相关文章

  • 运维必备Linux学习day2(mysql,jdk,redis,docker安装)
    一.MySQL安装①Linux环境:1.虚拟机Centos7.6版本安装,2.准备类似版本 mysql-5.7.26-1.el7.x86_64.rpm-bundle.tar包1.新建文件夹/opt/mysql,并cd进去,首先:mkdir/opt/mysql2.运行 wgethttp://dev.mysql.com/get/mysql-5.7.26-1.el7.x86_64.rpm-bundle.tar,下载mysql安装包......
  • PHP代码学习
    在php传参过程中,如果服务器运行的Linux环境,可以加入命令的执行,比如参数名是a,命令可以是:a=ls,通过用;,&&,||来分割,还可以同时执行多个命令。在Windows环境下dir等价于ls.cat是读文件命令,如果被过滤可以用tac来读。通配符:*和?如我们需要找寻flag,就可以用catf*来读取所有f开......
  • Redis安装教程
    1.redis官方下载地址:https://redis.io/download,redis64位下载地址:https://github.com/ServiceStack/redis-windows,测试使用的是redis-64.3.0.503版本。一、配置1.找到并修改redis.windows.conf文件,按住Ctrl+f输入maxmemory找到它,并设置maxmemory大小最佳为10240000002.red......
  • Redis网络模型
    主从复制原理建立连接从节点在配置了replicaof配置了主节点的ip和port从库执行replicaof并发送psync命令同步数据到从库主库bgsave生成RDB文件,并发送给从库,同时为每一个slave开辟一块replicationbuffer缓冲区记录从生成rdb文件开始收到的所有写命令。从库清空......
  • redis 如果修改key之后, 其有效时间会变吗
    在开发中遇到一个问题,使用redis中的set更新一个含有有效时间的key时,会使这个key的有效时间变成永久有效:127.0.0.1:6379>settesttestOK127.0.0.1:6379>expiretest1000(integer)1127.0.0.1:6379>settesttestOK127.0.0.1:6379>ttltest(integer)-1查阅redis官......
  • redis 部署
    redisdocker环境部署1.方式一,dockerrundockerrun--rm-p6379:6379-v/home/qtimes/workspace/docker_space/redis_space/data/redis/redis.conf:/etc/redis/redis.conf-v/home/qtimes/workspace/docker_space/redis_space/data/redis/data:/dataredis:latestr......
  • 基于Java的redis客户端的基本使用
    1.简介Java中redis客户端有jedis、lettuce、Redission等2.jedis的基本使用引入依赖<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>4.2.3</version></dependency>从jedis连接池获取je......
  • Redis配置登录密码并使用认证密码登录
    Redis配置登录密码并使用认证密码登录1.修改配置文件Redis的配置文件redis.conf,找到如下行:#requirepassfoobared去掉注释,并修改为所需要的密码:requirepass123456(其中123456就是要设置的密码)2.重启Redis如果Redis已经配置为service服务,可以通过以下方式重启:serviceredis......
  • PHP使用file_get_contents发送get和post请求
    1、GET请求点击查看代码functiongetData($url,$data=null){if($data){$url.='?'.http_build_query($data);}returnfile_get_contents($url);}2、POST请求点击查看代码functionpostData($url,$data=[],$json=false){if($json){......
  • CentOS7部署Redis(离线单机)
    一、检查是否安装##检查是否安装了Redis[root@localhost/]#ps-ef|grepredis##存在就删除[root@localhost/]#sudoyumremoveredis##检查是否安装了gcc[root@localhost/]#gcc--version安装gcc1、手动离线安装下载gcc安装包,下载地址:http://mirrors.ali......