laravel+Redis简单实现队列通过压力测试的高并发处理
秒杀活动
在一般的网络商城中我们会经常接触到一些高并发的业务状况,例如我们常见的秒杀抢购等活动,
在这些业务中我们经常需要处理一些关于请求信息过滤以及商品库存的问题。
在请求中比较常见的状况是同一用户发出多次请求或者包含恶意的攻击,以及一些订单的复购等情况。
而在库存方面则需要考虑超卖这种状况。
下面我们来模拟一个简单可用的并发处理。
直接上代码
代码的流程
1.模拟用户请求,将用户写入redis队列中
2.从用户中取出一个请求信息进行处理(可以在这个步骤做更多的处理,请求过滤,订单复购等)
3.用户下单(支付等),减少库存。下面使用了两种方式进行了处理,一种使用了Redis中单线程原子操作的特性使程序一直线性操作从而保持了数据的一致。
另外一种是用了事务进行操作,可以根据业务进行调整,这里就不一一描述了。
实际的业务状况更为复杂,但更多的是出于对基础思路的拓展。
<?php namespace App\Http\Controllers\SecKill; use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis; class SecKillControllers extends Controller { public function SecKillTest() {
///在此之前我们已经将一千过用户写入了redis中了
$num = Redis::lpop('user_list');
///取出一个用户
///
///一些对请求的处理
///
if (!is_null($num)) {
///将需要秒杀的商品放入队列中
$this->AddGoodToRedis(1);
///需要注意的是我们如果写的是秒杀活动的话,需要做进一步的处理,例如设置商品队列的缓存等方式,这里就实现了 ///下订单减库存
$this->GetGood(1,$num);
}
} public function DoLog($log) {
file_put_contents("test.txt", $log . '\r\n', FILE_APPEND);
} /**
* 重点在于Redis中存储数据的单线程的原子性,!!!无论多少请求同时执行这个方法,依然是依次执行的!!!!!
* 这种方式性能较高,并且确保了对数据库的单一操作,但容错率极低,一旦出现未可预知的错误会导致数据混乱;
*/
public function GetGood($id,$user_id) {
$good = \App\Goods::find($id);
if (is_null($good)) {
$this->DoLog("商品不存在");
return 'error';
} ///去除一个库存
$num = Redis::lpop('good_list');
///判断取出库存是否成功
if (!$num) {
$this->DoLog("取出库存失败");
return 'error';
} else {
///创建订单
$order = new \App\Order();
$order->good_id = $good->good_id;
$order->user_id = $user_id;
$order->save(); $ok = DB::table('Goods')
->where('good_id', $good->good_id)
->decrement('good_left', $num);
if (!$ok) {
$this->DoLog("库存减少失败");
return;
}
echo '下单成功';
}
} public function AddUserToRedis() {
$user_count = 1000;
for ($i = 0; $i < $user_count; $i++) {
try {
Redis::lpush('user_list', rand(1, 10000));
} catch (Exception $e) {
echo $e->getMessage();
}
}
$user_num = Redis::llen('user_list');
dd($user_num);
} public function AddGoodToRedis($id) { $good = \App\Goods::find($id);
if ($good == null) {
$this->DoLog("商品不存在");
return;
} ///获取当前redis中的库存。
$left = Redis::llen('good_list');
///获取到当前实际存在的库存,库存减去Redis中剩余的数量。
$count = $good->good_left - $left;
// dd($good->good_left);
///将实际库存添加到Redis中
for ($i = 0; $i < $count; $i++) {
Redis::lpush('good_list', 1);
}
echo Redis::llen('good_list');
} public function getGood4Mysql($id) {
DB::beginTransaction();
///开启事务对库存以及下单进行处理
try {
///创建订单
$order = new \App\Order();
$order->good_id = $good->good_id;
$order->user_id = rand(1, 1000);
$order->save(); $good = DB::table("goods")->where(['goods_id' => $id])->sharedLock()->first();
//对商品表进行加锁(悲观锁)
if ($good->good_left) {
$ok = DB::table('Goods')
->where('good_id', $good->good_id)
->decrement('good_left', $num);
if ($ok) {
// 提交事务
DB::commit();
echo'下单成功';
} else {
$this->DoLog("库存减少失败");
}
} else {
$this->DoLog("库存剩余为空");
}
DB::rollBack();
return 'error';
} catch (Exception $e) {
// 出错回滚数据
DB::rollBack();
return 'error';
//执行其他操作
}
} }
AB测试
这里我使用了apache bench对代码进行测试
不了解的可以参阅这篇文章,有非常详细的讲解
https://www.jianshu.com/p/43d04d8baaf7
调用 代码中的
AddUserToRedis()
方法将一堆请求用户放进redis队列中
先看库存

这里设置了一千个库存
开始压力测试

向我们的程序发起1200个请求,并发量为200

这里我们完成了1200个请求,其中标记失败的有1199个。这个是因为apache bench会以第一个请求响应的内容作为基准,
如果后续请求响应内容不一致会标记为失败,如果看到length中标记的数量不要方,基本可以忽略,我们的请求实际是完成了的。
laravel+Redis简单实现队列通过压力测试的高并发处理的更多相关文章
- redis的线程模型 与 压力测试
当客户端与ServerSocket产生连接时,会产生一个 AE_REABLE / AE_WRITABL 事件, 多个Socket可能并发产生不同的事件,IO多路复用程序会监听这些Socket,按照顺序 ...
- 简单模拟一下ab压力测试
简单了解下ab ab全程是apache benchmark,是apache官方推出的一个工具,创建多个并发访问线程,模拟多个访问者同时对一个URL地址进行访问.它的测试目标是基于URL的,因此它既可以 ...
- Redis+Restful 构造序列号和压力测试【原创】
[本人原创],欢迎交流和分享技术,转载请附上如下内容:如果你觉得这篇文章对你有帮助,请记得帮我点赞, 谢谢!作者:kevin[转自]http://www.cnblogs.com/itshare/ 很多 ...
- Redis简单延时队列
Redis实现简单延队列, 利用zset有序的数据结构, score设置为延时的时间戳. 实现思路: 1.使用命令 [zrangebyscore keyName socreMin socreMax] ...
- Redis+Restful 构造序列号和压力测试【后续】
大家还记上篇博文https://www.cnblogs.com/itshare/p/8643508.html,测试redis构造流水号的tps是600多/1s. 这个速度显然不能体现redis 集群在 ...
- redis简单消息队列
<?php $redis = new Redis(); $redis->connect('127.0.0.1',6379); $redis->flushall(); $redis-& ...
- 虚拟机压力测试延迟高的可能原因及 ILPIP 配置 / 查询脚本
测试初期 Client VM 的延迟结果正常: 测试后期 Client VM 的延迟偶尔突增/连接失败,越后期超高延迟(比如 30 秒)出现越多: 问题分析 造成这一现象的根本原因很可能是 SNAT( ...
- ab压力测试工具的简单使用
ab是一种用于测试Apache超文本传输协议(HTTP)服务器的工具.apache自带ab工具,可以测试 apache.IIs.tomcat.nginx等服务器 但是ab没有Jmeter.Loadru ...
- 压力测试工具tsung
tsung是用erlang开发的一款简单易用的压力测试工具,可以生成成千上万的用户模拟对服务器进行访问.目前对tsung的理解也仅限于会简单的应用,其内部结构没有深入研究过. 1.安装 tsung是用 ...
随机推荐
- c++中sort()函数的用法
用法: 1.sort函数可以三个参数也可以两个参数,必须的头文件#include < algorithm>和using namespace std; 2.它使用的排序方法是类似于快排的方法 ...
- nginx配置支持http2
1.简介 nginx 配置支持http2.目前大多数网站都是http1.1(如果你没有特别配置过的话) 一切都是为了访问更快. 2.如何查看自己网站的http版本 最简单的方法就F12啊,我这里是火狐 ...
- Spring源码学习(5)—— bean的加载 part 2
之前归纳了从spring容器的缓存中直接获取bean的情况,接下来就需要从头开始bean的加载过程了.这里着重看单例的bean的加载 if(ex1.isSingleton()) { sharedIns ...
- Fasttext原理
fastText 模型输入一个词的序列(一段文本或者一句话),输出这个词序列属于不同类别的概率.序列中的词和词组组成特征向量,特征向量通过线性变换映射到中间层,中间层再映射到标签.fastText 在 ...
- c/c++ include 头文件的方式
在编写c/c++代码时,#include 头文件有两种方式:一个是#include “文件名”,一个是#include <文件名>.区别在于: 前者在程序编译时系统首先在源程序所在的目录( ...
- 我的学习目标(目前已初步学习完Java语言基础)
操作系统.尤其是内存/线程/进程方面 计算机网络协议,重点关注 TCP/UDP/HTTP. 数据结构与算法. 数据库 设计模式,熟练掌握常用的几种设计模式. Java语言基础.熟悉java语言基础,了 ...
- 解决 c3p0报错 Establishing SSL connection without server's identity verification is not recommended
_ 报错: Establishing SSL connection without server's identity verification is not recommended. Accordi ...
- 微信小程序 image属性 mode
mode属性可以改变图片的填充容器方式
- laravel 错误提示Fatal Error: Class 'Pheanstalk\Pheanstalk' not found
本地环境版本: composer -V Composer version -- ::10 php artisan -V Laravel Framework 5.6.39 错误提示: Fatal Err ...
- POJ - 1830:开关问题 (开关问题-高斯消元-自由元)
pro:有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开. ...