这里我主要讲述自己安装和测试使用的大概流程,概念性的东西不做过多介绍,大家可以自行百度,资料也比较多。
这里我主要阐述的是 centos7 下面的安装方法,不过windows的也大同小异
首先、 RabbitMQ是 AMQP 协议的 Erlang
的实现,是由Erlang语言编写的,所以首先我们要安装 Erlang 语言。
大家可以参考 https://www.jianshu.com/p/95a720e6c955 这个地址的安装流程。
需要注意的就是版本不要太老,不然可能下面安装 rabbitmq 的时候会提示错误
接下来就是安装 rabbitmq 了,这里的细节网上也比较多,我自己的话也是参考别人的,然后走了一些坑,看了好几篇才顺利完成。
https://www.cnblogs.com/fengyumeng/p/11133924.html 这里随便贴一个可参考的。
这里会遇到一些问题,可能是上面你的 erlang 版本太老的问题,其他的问题倒是比较少。
安装成功之后是可以从端口 localhost:15672 看到mq的管理页面的,账号密码默认为 guest,因为是纯英文界面,可能刚开始看起来比较吃力,推荐大家多看下 rabbitmq 的介绍和管理,等测试通了大概就了解了。
然后就是和编程语言对接了。犹豫由于本人是做php的,所以专门讲解 php 下使用mq的流程:
1、安装 ampq 扩展
https://www.cnblogs.com/brady-wang/p/13742032.html 这里也是随便贴一篇吧,都是大同小异,大家要注意的就是扩展和php的版本对应问题。windows下就更简单了,直接下载dll文件。
2、代码测试
这里我主要介绍 php-amqplib 的使用,大家可以使用 composer 去下载 “ composer require php-amqplib/php-amqplib --ignore-platform-reqs ”
客户端代码: ( 这里是我框架里面封装好的,大家也可以根据自己情况直接把代码提出来,单个文件测试 )
<?php namespace App\Http\Controllers; use App\Support\Tcp; use Illuminate\Http\Request; use PhpAmqpLib\Connection\AMQPStreamConnection; use PhpAmqpLib\Message\AMQPMessage; class RabbitMq { public function mq_send(Request $request) { $connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest','/'); $channel = $connection->channel(); $channel->queue_declare('hello', false, false, false, false); $msg_str = []; for($i=1;$i<20;$i++) { $str = '发送消息'.time().'-'.rand(1,1000000); $msg = new AMQPMessage($str); $channel->basic_publish($msg, '', 'hello'); $msg_str[] = " [x] Sent $str"; } $channel->close(); $connection->close(); } }
服务端代码:( 需要用 CLI 模式运行 )
<?php use PhpAmqpLib\Connection\AMQPStreamConnection; require __DIR__.'/../vendor/autoload.php'; $connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest', '/'); $channel = $connection->channel(); $channel->queue_declare('hello', false, false, false, false); // echo ' [*] Waiting for messages. To exit press CTRL+C', "\n"; $callback = function ($msg) { // echo " [x] Received ", $msg->body, "\n"; }; $channel->basic_consume('hello', '', false, true, false, false, $callback); while (count($channel->callbacks)) { $channel->wait(); } $channel->close(); $connection->close();
这里主要是介绍怎么使用和测试,具体的代码逻辑和使用大家可自行百度其他文档,因为东西比较散,难度不高。也就是一个 生产者->消费者 的模型,一个推送,一个监听消费的意思,当然里面路由还是比较丰富的,有兴趣的可以多深究一些。
我们理解这些扩展的时候,不防把mysql甚至redis等的使用联系到一起,其实都是创建连接,然后调用方法使用,也没有说多复杂,真正复杂的是我们怎么把他融入到我们项目中使用。
这里只讲一个问题。
由于生产者可以直接嵌入到我们的api里面,直接http请求就可以执行生产消息,这里倒没有太多要说的了,可根据自己项目自行封装
那么消费者因为是 cli 运行模式来监听的,那么我们就不能用传统的api方式去做了,而且也不合适,因为要时时监听。这里可以想到的有好几种,比方说 crontab 定时任务,但是linux 定时任务只能做到分钟级,或者可以借助 workman或者swoole做到秒级毫
秒级等等,又或者写 php demo.php start 等,但是关闭当前xshell窗口可能进程就失效了。这里我主要用到的是 php监听脚本+shell脚本 的方式,有兴趣的同学可以详细看一下 https://zhuanlan.zhihu.com/p/52965561 这篇文章。
具体实现逻辑:
1. 创建php监听脚本,子进程数量可自行控制,加载好业务代码,测试通即可。 这里附带一下我个人的demo,可供参考
<?php use PhpAmqpLib\Connection\AMQPStreamConnection; function daemon() { global $child; //1.1 创建子进程 $pid = pcntl_fork(); switch($pid){ case -1: exit("Fork failed"); break; case 0: //child //2、设置sid if(($sid = posix_setsid()) <= 0){ die("Set sid failed!\n"); } //3、改变目录 if(chdir('/') === false){ die("Change directory failed!\n"); } //4、更改为宽松掩码 umask(0); //5、关闭标准I/O fclose(STDIN); //fclose(STDOUT); //fclose(STDERR); break; default: //parent exit; break; } } $sign = $_SERVER['argv'][1]; switch($sign){ case 'start': if(file_exists('/tmp/masterPid')){ die("MasterPid already running!"); } break; case 'stop': $masterPid = file_get_contents('/tmp/masterPid'); exec("ps --ppid {$masterPid} | awk '/[0-9]/{print $1}'",$output,$status); if($status == 0){ print_r($output); } break; case 'reload': break; default: die("Please enter commond...\n"); break; } daemon(); $child = []; $masterPid = posix_getpid(); file_put_contents('/tmp/masterPid',$masterPid);//存放主进程ID function forkPro() { global $child; //echo "Master process id: " . posix_getpid() . PHP_EOL; $pid = pcntl_fork(); switch($pid){ case -1: exit("Fork failed"); break; case 0: // echo "\nI'm the child process: " . posix_getpid() . ' and $pid='.$pid.PHP_EOL; require __DIR__.'/../vendor/autoload.php'; $connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest', '/'); $channel = $connection->channel(); $channel->queue_declare('hello', false, false, false, false); // echo ' [*] Waiting for messages. To exit press CTRL+C', "\n"; $callback = function ($msg) { // echo " [x] Received ", $msg->body, "\n"; }; $channel->basic_consume('hello', '', false, true, false, false, $callback); while (count($channel->callbacks)) { $channel->wait(); } $channel->close(); $connection->close(); break; default: $child[$pid] = $pid; //echo "I'm the parent process: " . posix_getpid() .' and $pid='.$pid .PHP_EOL; break; } } $fork_nums = 2; for($i = 0;$i < $fork_nums;$i++) { forkPro(); } while(count($child)) { if(($exit_id = pcntl_wait($status)) > 0){ // echo "有子进程退出,进程ID是:" . $exit_id . PHP_EOL; // echo "被中断的子进程的信号值是:" . pcntl_wtermsig($status) . PHP_EOL; unset($child[$exit_id]);//从子进程集合中移除已经退出的子进程 } if(count($child) < $fork_nums){ //当集合中的子进程数量小于一定量时,自动fork新的子进程 forkPro(); } }
2. 编写shell脚本,这里大家有空可以自行百度一下基础教程即可,我也不是很精通,只是写一些简单的
mq_count=`ps -ef|grep fork_demo.php | grep -v grep | wc -l`
if [ $mq_count -lt 4 ]
then
cd /mnt/www/lmrs/public && php fork_demo.php reload
else
echo 1
fi
这里的 fork_demo.php 文件是你的php监听脚本文件,这里主要是检测你当前有多少个进程,如果不足的时候就新增等等。写完shell脚本,可以自行添加到crontab任务即可。
.