PHP + Redis 实现秒杀功能详解
创作时间:
作者:
@小白创作中心
PHP + Redis 实现秒杀功能详解
引用
1
来源
1.
https://www.cnblogs.com/mklblog/p/18121829
本文通过一个简单的示例演示了如何使用PHP和Redis实现秒杀功能。文章详细介绍了使用ThinkPHP6框架、Redis6.0、PHP7.4以及Predis操作包来实现秒杀功能,并提供了具体的代码实现和测试步骤。
一、概述
秒杀这个问题在很多面试的时候都会提到,会有各个方面的调优,配置等等,本文在这里举个简单的例子来演示下秒杀的过程,供大家参考发散思维。
二、准备介绍
- 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个,且无重复购买的人。
五、总结
实际生产环境的“秒杀”业务是很繁杂的,有许多地方需要注意。本文只是对“秒杀”这个场景做了简单的试验,仅给大家提供个思路和样本。如有不同见解欢迎大家留言讨论。
热门推荐
江苏省苏州市昆山市千灯镇歇马桥村:古韵悠长 福满水乡
到底要母乳喂养还是奶粉喂养?别让“应该”绑架了母亲的选择
情感共鸣与智慧引导:家长如何帮助女儿在挫折中找到前进的方向
体制内聚餐邀请这样回,既不失礼又不伤和气
三岁之前带孩子学英语,早吗?
解密化学中的关键概念:摩尔质量到底是什么?
海上仙山的秘密:探索蓬莱与中国古代宗教的深层联系
值班表:定义、最佳实践等
丰盈的青春表达让文学传播更主动更有力
融合蒙特梭利与阿德勒理念,专为3岁以内宝宝打造科学成长计划
掌握止损策略:及时操作的关键与实际应用
劳动仲裁中的劳动保护与安全卫生
“不请家堂不过年”!越来越消失的家族祭祖文化载体
山东理工大学怎么样?优势专业有哪些?
开车起步时频繁熄火的原因是什么?这种问题如何诊断和解决?
解开大脑的秘密:人工智能与神经形态计算的下一个飞跃
2024年各省高考试卷使用情况汇总,共有几套试卷,对应省份有哪些?
橡胶密封条的分类,性能及用途
属牛涧下水命好不好:1997年出生者的命运全解析
人生名利场,羁绊无休假。47句关于人生感悟的古诗词:专治焦虑
一个人认知高低的标志:辩证思维的建立
大众商务七座车有哪些选择?三款车型对比分析
农历生日和阳历生日差多少天
拘留所内的劳动教育:探讨其在改造服刑人员中的作用与意义
暗黑不朽技能嘲讽:解析魔法师的技能搭配与策略
中国迎来第五次财富浪潮,比电商与短视频还震撼,将催生大批新富
“小魔王”孙颖莎,荣获微博年度关注女运动员,是对她辛勤付出的肯定
驾驭生命奇迹:追溯中国大陆第一例试管婴儿的诞生
9本已完结主世界是斗破的诸天流小说,傲啸无敌,斗战苍穹
镜玄:动画《眷思量》男主角人物介绍