记录一下php代码如何链接Rabbitmq,扩展采用composer维护,免去服务器安装PHP需要扩展的烦恼。composer包和php扩展安装两者方式的好坏与否这里不做讨论,可以自行百度了解
composer require php-amqplib/php-amqplib
1.配置rabbitmq.config
<?php
// +----------------------------------------------------------------------
// | rabbitMQ 示例配置
// +----------------------------------------------------------------------
return [
// 连接信息
'AMQP' => [
'host' => env('rabbit.host','127.0.0.1'),
'port' => env('rabbit.port','5672'),
'username' => env('rabbit.username','guest'),
'password' => env('rabbit.password','guest'),
'vhost' => env('rabbit.vhost','/')
],
//topic队列
'topic_queue' => [
'exchange_name' => 'topic_exchange',
'exchange_type' => 'topic',
'queue_name' => 'topic_queue',
'route_key' => '',
'consumer_tag' => 'topic'
],
//机审队列
'machine_risk_queue' => [
'exchange_name' => 'topic_exchange',
'exchange_type' => 'topic',
'queue_name' => 'risk_queue',
'route_key' => '*.risk',
'consumer_tag' => 'risk'
],
];
2.Rabbitmq类文件
<?php
namespace app\services;
use PhpAmqpLib\Message\AMQPMessage;
use think\facade\Config;
use think\facade\Log;
use PhpAmqpLib\Exchange\AMQPExchangeType;
use PhpAmqpLib\Connection\AMQPStreamConnection;
class RabbitMqService
{
/**
* 消费者
*/
public function consumer($name, $func = null)
{
//获取配置
$amqp = Config::get('rabbitmq.AMQP');
$amqpDefail = Config::get('rabbitmq.' . $name . '_queue');
//连接
$connection = new AMQPStreamConnection(
$amqp['host'],
$amqp['port'],
$amqp['username'],
$amqp['password']
);
$amqpDefail['queue_name'] = $amqpDefail['queue_name'].env('domain.app_id');
$amqpDefail['exchange_name'] = $amqpDefail['exchange_name'].env('domain.app_id');
//建立通道
$channel = $connection->channel();
//流量控制
$channel->basic_qos(null, 1, null);
//初始化交换机
$channel->exchange_declare($amqpDefail['exchange_name'], $amqpDefail['exchange_type'], false, true, false);
//初始化队列
$channel->queue_declare($amqpDefail['queue_name'], false, true, false, false);
//绑定队列与交换机
$channel->queue_bind($amqpDefail['queue_name'], $amqpDefail['exchange_name'], $amqpDefail['route_key']);
//消费消息
$channel->basic_consume($amqpDefail['queue_name'], $amqpDefail['consumer_tag'], false, false, false, false, function ($msg) use ($func) {
sublog(['消费者1', $msg->body], 'rabbitmq_debug');
$data = !empty($msg->body) ? json_decode($msg->body, true) : [];
if (!empty($data)) {
try {
sublog(['消费者2', $data], 'rabbitmq_debug');
$func($data);
$msg->ack();
} catch (\Exception $ee) {
sublog(['消费者2', $data,$ee->getMessage(), $ee->getFile(), $ee->getLine()], 'rabbitmq_debug_err');
$msg->nack(true);
}
}
});
//退出
register_shutdown_function([$this, 'shutdown'], $channel, $connection);
//监听
while (count($channel->callbacks)) {
$channel->wait();
}
}
/**
* 生产者
* @param $data
* @param $key
*/
public function publish($data, $key, $name)
{
//获取配置
$amqp = Config::get('rabbitmq.AMQP');
$amqpDefail = Config::get('rabbitmq.' . $name . '_queue');
//连接
$connection = new AMQPStreamConnection(
$amqp['host'],
$amqp['port'],
$amqp['username'],
$amqp['password']
);
$amqpDefail['queue_name'] = $amqpDefail['queue_name'].env('domain.app_id');
$amqpDefail['exchange_name'] = $amqpDefail['exchange_name'].env('domain.app_id');
//建立通道
$channel = $connection->channel();
//推送成功
$channel->set_ack_handler(function (AMQPMessage $message) use ($data) {
sublog(['生产者1', $message, $data], 'rabbitmq_debug');
});
//推送失败
$channel->set_nack_handler(
function (AMQPMessage $message) use ($data) {
sublog(['生产者1-error', $message, $data], 'rabbitmq_debug');
}
);
$channel->confirm_select();
//初始化交换机
$channel->exchange_declare($amqpDefail['exchange_name'], $amqpDefail['exchange_type'], false, true, false);
sublog(['生产者2', $amqpDefail, $amqp], 'rabbitmq_debug');
//申明队列
$channel->queue_declare($amqpDefail['queue_name'], false, true, false, false);
//绑定队列与交换机
$channel->queue_bind($amqpDefail['queue_name'], $amqpDefail['exchange_name'], $key);
//生成消息
$msg = new AMQPMessage(json_encode($data, 256), [
'content-type' => 'application/json',
'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT
]);
//推送消息到某个交换机
$channel->basic_publish($msg, $amqpDefail['exchange_name'], $key);
// $channel->confirm_select_ok();
$channel->wait_for_pending_acks();
$channel->close();
$connection->close();
return true;
}
/**
* 退出
* @param $channel [信道]
* @param $connection [连接]
*/
public function shutdown($channel, $connection)
{
$channel->close();
$connection->close();
}
}
调用范例
$res = app(services\RabbitMqService::class)->publish(['queue_id' => $queue_id], '*.risk', 'machine_risk');
其他说明:
1.需要特别注意每个exchange中的路由一定要匹配中,不然无法消费。
2.vhost参数配置相当于应用隔离,如果Mq服务需要应用到多个不同的项目中,这个参数就起码很大作用。