消息队列之RabbitMQ

博客介绍了Lumen(5.5.2)、Laravel(5.5.*)和RabbitMQ的使用。包括使用Artisan命令行创建消费的worker脚本,Laravel消费者脚本和Lumen推送生产者消息的配置,均基于拓展包mookofe/tail的config/tail - settings.php文件,最后提醒不同版本文件路径有差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Environment

  1. Lumen (5.5.2) (Laravel Components 5.5.*)
  2. Laravel(5.5.*)
  3. RabbitMQ

Process

前提

Artisan 命令

  • 使用 Artisan 命令,创建作为消费的 worker 脚本。
php artisan make:command MoreRequestLogMQConsume

Laravel 消费者脚本

  • 配置文件还是基于 Laravel 拓展包 mookofe/tail 的 config/tail-settings.php
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Mookofe\Tail\Facades\Tail;
use Illuminate\Support\Facades\DB;
use PhpAmqpLib\Connection\AMQPStreamConnection;

class MoreRequestLogMQConsume extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'mq:request:log:consume';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'mq consume request log';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $connection = new AMQPStreamConnection(
            config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.host'),
            config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.port', '5672'),
            config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.username'),
            config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.password'),
            config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.vhost', '/')
        );
        $channel = $connection->channel();

        $channel->exchange_declare(
            config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.exchange', ''),
            config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.exchange_type'),
            false, false, false);
        $channel->queue_declare(config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.queue_name'), false, true, false, false);
        $channel->queue_bind(
            config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.queue_name'),
            config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.exchange', ''));

        $callback = function ($msg) {
            DB::connection('cappu')
                ->select
                ('
                CREATE TABLE
                IF
                    NOT EXISTS `m_interface_log_' . date('Ym') . '` (
                    `id` INT ( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT,
                    `path` VARCHAR ( 255 ) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT "" COMMENT "路径",
                    `method` VARCHAR ( 64 ) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT "" COMMENT "方法",
                    `ip` VARCHAR ( 32 ) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT "" COMMENT "客户端IP",
                    `request_header` text COLLATE utf8mb4_unicode_ci,
                    `request_body` text COLLATE utf8mb4_unicode_ci,
                    `response_header` text COLLATE utf8mb4_unicode_ci,
                    `response_body` text COLLATE utf8mb4_unicode_ci,
                    `created_at` TIMESTAMP NOT NULL DEFAULT "0000-00-00 00:00:00",
                    `updated_at` TIMESTAMP NOT NULL DEFAULT "0000-00-00 00:00:00" ON UPDATE CURRENT_TIMESTAMP,
                    PRIMARY KEY ( `id` ) USING BTREE 
                    ) ENGINE = INNODB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = COMPACT;
            ');

            DB::connection('cappu')
                ->table('m_interface_log_' . date('Ym'))
                ->insert(json_decode($msg->body, true));

//            Log::info('MoreRequestLogMQConsume:' . json_encode($msg));

            //$channel->basic_consume(),$no_ack 参数设置为 false ,必须写此段代码响应,其值为 true,则不必写。
            $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
        };
        $channel->basic_qos(null, config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.prefetch_count', 1), null);
        $channel->basic_consume(
                config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.queue_name'), 
                config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.consumer_tag', ''), 
                false, false, false, false, $callback
        );
        while (count($channel->callbacks)) {
            $channel->wait();
        }
        $channel->close();
        $connection->close();
    }
}
  • 消费者接收的信息体「$msg」
{
    "body":"{"path":"v2\/users","method":"GET","request_body":"[]","created_at":"2019-07-17 16:04:34"}",//生产者传递的数据(此处系Json数据)
    "body_size":1614,
    "is_truncated":false,
    "content_encoding":null,
    "delivery_info":{
        "channel":{
            "callbacks":{
                "more.request.log.producer":{

                }
            }
        },
        "consumer_tag":"more.request.log.producer",
        "delivery_tag":"1",
        "redelivered":true,
        "exchange":"request.log",
        "routing_key":""
    }
}
  • 运行脚本
nohup php artisan mq:request:log:consume >> mq-request-consume.log  2>&1 &
  • 查看启动的进程
ps -aux | grep php

Lumen 推送生产者消息

  • 配置文件还是基于拓展包 mookofe/tail 的 config/tail-settings.php
<?php

namespace App\Http\Middleware;

use Closure;
use Validator;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

class InterfaceLog
{
    public function handle($request, Closure $next)
    {
        return $next($request);
    }

    public function terminate($request, $response)
    {
        if (env('INTERFACE_LOG_SWITCH', 0) && $request->path() != 'v2/anchors') {
            if (! empty($_SERVER["HTTP_CLIENT_IP"])) {
                $ip = $_SERVER["HTTP_CLIENT_IP"];
            } elseif (! empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
                $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
            } elseif(! empty($_SERVER["REMOTE_ADDR"])) {
                $ip = $_SERVER["REMOTE_ADDR"];
            } else {
                $ip = '';
            }

            $connection = new AMQPStreamConnection(
                config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.host'),
                config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.port', '5672'),
                config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.username'),
                config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.password'),
                config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.vhost', '/')
            );
            $channel = $connection->channel();

            $channel->exchange_declare(
                config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.exchange', ''),
                config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.exchange_type'),
                false, false, false);
            $channel->queue_declare(config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.queue_name'), false, true, false, false);

            //在RabbitMQ PHP版Gitbook使用说明书里面,生产者代码示例没有这种写法,但是事实上,$channel->queue_bind()函数完成可以在此使用。如果没有这样写,生产者先启动,可能会造成数据丢失,因为没有存入到相应的队列。
            $channel->queue_bind(
                config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.queue_name'),
                config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.exchange', ''),
            );

            $msg = new AMQPMessage(json_encode([
                'path' => $request->path(),
                'method' => $request->method(),
                'ip' => $ip,
                'request_header' => json_encode($request->header(),JSON_UNESCAPED_UNICODE),
                'request_body' => json_encode($request->all(),JSON_UNESCAPED_UNICODE),
                'response_header' => json_encode($response->headers,JSON_UNESCAPED_UNICODE),
                'response_body' => json_encode($response->original,JSON_UNESCAPED_UNICODE),
                'created_at' => date('Y-m-d H:i:s')
            ]),
                array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT)
            );
            $channel->basic_publish($msg, config('tail-settings.connections.' . env('MQ_REQUEST_LOG_CONNECTION') . '.exchange', ''));

            $channel->close();
            $connection->close();
        }
    }
}

Conclusion

不同的版本,对应的文件路径会有些出入,以上仅供参考,请君灵活处理。

转载本文,请注明出处、作者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值