这里我主要讲述自己安装和测试使用的大概流程,概念性的东西不做过多介绍,大家可以自行百度,资料也比较多。

这里我主要阐述的是 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任务即可。

    

.  

 

posted on 2021-10-25 11:03  龟仙人  阅读(77)  评论(0编辑  收藏  举报