Shadow
thinkphp原生插入和使用rabbitmq插入返回前端时间对比
thinkphp原生插入和使用rabbitmq插入返回前端时间对比
测试内容: 批量插入400条数据
环境如下:
- Thinkphp5.1
- 搭建好的一台RabbitMQ,安装方法:https://www.cnblogs.com/fengyumeng/p/11133924.html;安装好后,先新建一个新用户:admin ,密码为:123456;再新建一个
Virtual Host
,名称为dcr163
。也可以根据自己的需要新建其他名称,然后修改源码。 - LNMP或LAMP环境
- 数据库信息根据自己的环境配置
thinkphp 路由文件
route/route
里添加 `
Route::group('rabbit',[Route::get('rabbit','rabbitmq/index')
]);`
下面是两个数据表
CREATE TABLE `transfer` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`money` decimal(10,2) NOT NULL DEFAULT '0.00',
`from_name` varchar(20) NOT NULL DEFAULT '',
`to_name` varchar(20) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '事件记录表';
CREATE TABLE `transfer_logs` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`money` decimal(10,2) NOT NULL DEFAULT '0.00',
`from_name` varchar(20) NOT NULL DEFAULT '',
`to_name` varchar(20) NOT NULL DEFAULT '',
`msg` varchar(200) NOT NULL DEFAULT '',
`datetime` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '消息通知表';
thinkph安装rabbitmq
进入Thinkphp项目的根目录,先composer
安装Rabbitmq
扩展,安装命令:composer require php-amqplib/php-amqplib
新建测试的控制器 /application/index/controller/Rabbitmq.php
代码如下
<?php
namespace app\index\controller;
use think\Controller;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use think\Db;
class Rabbitmq extends Controller
{
//首页测试
public function index()
{
//统计脚本开始事件
list($usec, $sec) = explode(" ", microtime());
$stime = $sec + $usec;
$isRabbit = input('rabbit/d');
//模拟用户提交的事件
$datas = [
'money' => 200,
'from_name' => 'user1',
'to_name' => 'user2'
];
$db = db('transfer');
$id = $db->insertGetId($datas);
if (!$id) exit('插入失败');
$dayTime = date('Y-m-d H:i:s');
$db = Db::table('transfer_logs');
for ($i = 1; $i <= 200; $i++) {
$sendData1 = [
'from_name' => 'user1',
'to_name' => 'user2',
'msg' => '转出成功A-' . $i,
'datetime' => $dayTime
];
$sendData2 = [
'from_name' => 'user1',
'to_name' => 'user2',
'msg' => '接受成功B-' . $i,
'datetime' => $dayTime
];
//使用Rabbit
if ($isRabbit) {
$this->sendRabbitmq(json_encode($sendData1));
$this->sendRabbitmq(json_encode($sendData2));
continue;
}
$db->insertAll([$sendData1, $sendData2]);
}
//统计脚本结束事件
list($usec, $sec) = explode(" ", microtime());
$etime = $sec + $usec;
echo '<h2>' . ($isRabbit ? '使用Rabbit' : '未使用Rabbit') . ' 插入成功,费时间:' . ($etime - $stime) . 's</h2>';
}
/**
* 发送到rabbitmq 消息队列
* @param $datas
* @return string
* @throws \Exception
*/
protected function sendRabbitmq($datas)
{
//虚拟主机 这里可以写到配置文件
$vhost = 'dcr163';
//队列名称
$queueName = 'transfer';
//链接信息,可以放到配置文件里
$connection = new AMQPStreamConnection('192.168.254.132', '5672', 'admin', '123456', $vhost);
$channel = $connection->channel();
$channel->queue_declare($queueName, false, true, false, false);
$msg = new AMQPMessage($datas, AMQPMessage::DELIVERY_MODE_PERSISTENT);
$channel->basic_publish($msg, '', $queueName);
$channel->close();
$connection->close();
}
}
创建项目自定义命令类文件指令 /application/command/Rabbitmq.php
这个文件功能的功能是,类似开启一个常驻进程监听,代码如下:
<?php
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use think\Db;
class Rabbitmq extends Command
{
protected function configure()
{
// 指令配置
$this->setName('rabbitmq');
// 设置参数
}
protected function execute(Input $input, Output $output)
{
// 指令输出
$output->writeln('rabbitmq');
//虚拟主机
$vhost = 'dcr163';
//队列名称
$queueName = 'transfer';
//链接rabbitmq
$connection = new AMQPStreamConnection('192.168.254.132', '5672', 'admin', '123456', $vhost);
//获取一个通道
$channel = $connection->channel();
//声明队列,
$channel->queue_declare($queueName, false, true, false, false);
$channel->basic_qos(null, 1, null);
//消费队列里的消息
$channel->basic_consume($queueName, '', false, false, false, false, function ($msg) {
//控制台打印数据,调试使用,线上使用请删除
echo $msg->body . "\n";
$data = json_decode($msg->body, true);
$this->sendMsg($data);
$msg->ack();
});
//监听队列里的消息
while ($channel->is_open()) {
$channel->wait();
}
$channel->close();
$connection->close();
}
//处理队列里的消息
protected function sendMsg($datas)
{
Db::table('transfer_logs')->insert($datas);
}
}
测试之前,请自己手动测试和Rabbitmq的链接状态,这里可以不使用监听
先在项目根目录运行这个 think
指令
运行命令:php think rabbitmq
,可以看到,已经运行了监听了,打印了rabbitmq
是因为我们代码上有一行$output->writeln('rabbitmq');
输出的语句。这里我们开启两个终端进行监听,相当与 1对多
的消费模式
测试使用即时的数据库插入和使用Rabbitmq插入数据库
不使用 Rabbitmq,访问项目:http://yourdomain/rabbit?rabbit=0
同时插入400条数据看看执行时间:
这里花费了 7.375s 的时间
使用 Rabbitmq 队列插入数据,访问项目:http://yourdomain/rabbit?rabbit=1
thinkphp 的监听数据,就是我们刚刚执行php think rabbitmq
的进程状态,发现两个进程都同时处理了数据
这里花费了 5.0050001144409s 的时间
总结
可以看到 使用Tabbitmq 进行数据处理的时候,会减少和前台交互的时间,在很多中大型项目中都会使用到这类的中间件
使用Rabbitmq
的逻辑就是,程序先把数据发送到 Rabbitmq
这个中间件,然后 监听进程就不断从 Rabbitmq
里面读取数据处理。
Dcr163的博客
http://dcr163.cn/625.html(转载时请注明本文出处及文章链接)