RabbitMQ

持久化、高可用、高可靠 的企业级消息队列系统,集成强大的监控、限流、负载均衡等功能

基于Docker安装

# 默认要求至少200M空闲磁盘空间
- hostname影响存储数据路径
- 默认management账号密码guest / guest
docker run -d --hostname rabbit --name rabbit -p 8080:15672 -e RABBITMQ_DEFAULT_USER=guest -e RABBITMQ_DEFAULT_PASS=guest rabbitmq:3.6.10-management-alpine

Broker

架构
  • 一个Exchange对接多个Queue场景
  • 一个Queue可以承载同一类型的多个具体Job(通过bingding_key区分),例如短信job邮件job都可以投放到nofication队列

RabbitMQ工作流

工作流
生产者 —交换机—>RoutingKey— VS  —BindingKey—> 队列 ——> 消费者

1. 交换机和队列通过key匹配绑定,多个绑定可使用相同key
2. 生产者投递一个消息及key,并经由交换机路由到key匹配的队列中存储
3. 消费者监听队列获取由其分发的消息并进行处理
交换机模式
  • fanout — 发布订阅模式(广播给exchange绑定的所有队列,无视key配置)
  • direct — RoutingKey==BindingKey
  • topic — RoutingKey match BindingKey,且Key均由点号分隔的主题词构成(*表一个词,#表多个词)
队列分发模式(QOS配置)
  • 循环发放(Round-robin dispatching) - 消费者按序分发(默认分发模式)
  • 公平发放(Fair dispatching) - 消费者空闲就分发,忙则检查下一个消费者
消息确认模式
  • 默认模式 - 消息分发后即删除消息
  • 确认模式 - 消息处理完后消费者返回Acknowledgment,接着队列删除相应消息(避免消息丢失)
几个重要指标
  • Consumer utilisation:队列的消费者利用率(尽量提高该指标)
  • Process memory:队列的内存消耗(ack回执、消费者缺乏时将导致消息积压,该指标升高)

基于Laravel驱动调用

安装
# composer
composer require vladimir-yuldashev/laravel-queue-rabbitmq:5.4

# 注册
VladimirYuldashev\LaravelQueueRabbitMQ\LaravelQueueRabbitMQServiceProvider::class

# 环境变量
QUEUE_DRIVER=rabbitmq
RABBITMQ_HOST=127.0.0.1
RABBITMQ_PORT=5672
RABBITMQ_VHOST=/  #虚拟机(用户和权限配置的最小单位,默认/)
RABBITMQ_LOGIN=guest
RABBITMQ_PASSWORD=guest
RABBITMQ_QUEUE=queue_name
队列配置
  • config/queue.php中新增链接
  • 每个connection固定host、vhost、exchange,但可以使用多个queue
  • 可以通过$job->onConnection())切换链接来使用其他的RabbitMQ主机和交换机
'rabbitmq' => [
    'driver' => 'rabbitmq',
    'host' => env('RABBITMQ_HOST', '127.0.0.1'),
    'port' => env('RABBITMQ_PORT', 5672),
    'vhost'    => env('RABBITMQ_VHOST', '/'),
    'login'    => env('RABBITMQ_LOGIN', 'guest'),
    'password' => env('RABBITMQ_PASSWORD', 'guest'),
    'queue' => env('RABBITMQ_QUEUE'),
    // name of the default queue,
    'exchange_declare' => env('RABBITMQ_EXCHANGE_DECLARE', true),
    // create the exchange if not exists
    'queue_declare_bind' => env('RABBITMQ_QUEUE_DECLARE_BIND', true),
    // create the queue if not exists and bind to the exchange
    'queue_params' => [
        'passive'     => env('RABBITMQ_QUEUE_PASSIVE', false),
        'durable'     => env('RABBITMQ_QUEUE_DURABLE', true),
        'exclusive'   => env('RABBITMQ_QUEUE_EXCLUSIVE', false),
        'auto_delete' => env('RABBITMQ_QUEUE_AUTODELETE', false),
    ],
    'exchange_params' => [
        'name' => env('RABBITMQ_EXCHANGE_NAME', null),
        'type' => env('RABBITMQ_EXCHANGE_TYPE', 'direct'),
        // more info at http://www.rabbitmq.com/tutorials/amqp-concepts.html
        'passive' => env('RABBITMQ_EXCHANGE_PASSIVE', false),
        'durable' => env('RABBITMQ_EXCHANGE_DURABLE', true),
        // the exchange will survive server restarts
        'auto_delete' => env('RABBITMQ_EXCHANGE_AUTODELETE', false),
    ],
],

基于AmqpLib包调用

安装
composer require php-amqplib/php-amqplib:2.6.*
公共文件
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

$connection = new AMQPStreamConnection(HOST, PORT, USER, PASS, VHOST);
$channel = $connection->channel();

/** 队列服务质量配置
 * @param int $prefetch_size  推荐null
 * @param int $prefetch_count  消费者一次预取消息数
 * @param bool $a_global  推荐null
**/
$channel->basic_qos($prefetch_size, $prefetch_count, $a_global);

#配置交换机(不存在则创建)
$channel->exchange_declare(
	string $exchangeName,
	string $type='direct', #交换机类型
	bool $passive=false,
	bool $durable=true, #交换机是否持久化(如果可靠性要求不高则推荐设定为非持久化,性能差异10倍以上)
	bool $auto_delete=false
);

register_shutdown_function(function() use($channel,$connection){
    $channel->close();
    $connection->close();
})
生产者

按需执行消息投递

include 公共文件;

$message1 = new AMQPMessage(
	string $messageBody1,
	[
		'content_type' => 'text/plain',
		'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT #声明消息为持久化(推荐),
	]
);
$message2 = $message1->setBody(string $messageBody2); #复用原消息体提升速度

## 单发消息到交换机 ##
$channel->basic_publish($message1, $exchange[, $routing_key]); #未指定交换机则直接路由至routing_key匹配的队列
$channel->basic_publish($message2, $exchange[, $routing_key]);

## 批发消息到交换机(批量模式提升速度) ##
$channel->batch_basic_publish($message1, $exchange[, $routing_key]);
$channel->batch_basic_publish($message2, $exchange[, $routing_key]);
$channel->publish_batch();
消费者使用

要求服务常驻,持续监听队列

include 公共文件;

#配置队列(不存在则创建)
$channel->queue_declare(
	string $queueName='', #传入空串则创建自动命名队列($return[0]为队列名)
	bool $passive=false,
	bool $durable=false, #队列是否持久化(如果可靠性要求不高则推荐设定为非持久化,性能差异10倍以上)
	bool $exclusive=false, #声明独占式队列(connection中断后队列自动删除)
	bool $auto_delete=true
);
$channel->queue_bind($queueName, $exchangeName[, $binding_key]);  #队列绑定交换机

function handler(AMQPMessage $message){
	$message->body;
	$message->delivery_info['channel']->basic_ack(string $message->delivery_info['delivery_tag'], bool $multiple = false);
}

$channel->basic_consume(
	string $queueName,
	string $consumerTag,
	bool $no_local=false,
	bool $no_ack=true, #是否启用ack确认消息(如果可靠性要求不高则推荐设定为非ack)
	bool $exclusive=false,
	bool $nowait=false,
	callback $handler
);

### 正式结束进程:程序运转至calllbacks空 ###
while (count($channel->callbacks)) {
    $channel->wait();
}

### 临时结束进程:监听Linux系统中断信号 ###
$pcntlHandler = function ($signal) {
    switch ($signal) {
        case \SIGTERM:
        case \SIGUSR1:
        case \SIGINT:
            // 一些消费者退出前的收尾工作 . . .
            pcntl_signal($signal, SIG_DFL);
            posix_kill(posix_getpid(), $signal);
        case \SIGHUP:
            // 一些消费者启动前的准备工作 . . .
            break;
        default:
            // do nothing
    }
};
pcntl_signal(\SIGTERM, $pcntlHandler);
pcntl_signal(\SIGINT,  $pcntlHandler);
pcntl_signal(\SIGUSR1, $pcntlHandler);
pcntl_signal(\SIGHUP,  $pcntlHandler);
服务初始化
  1. 先启动消费者服务
  2. 后启动生产者服务

AMQP更对象写法

//公共部分
$connection = new AMQPConnection(['host'=>HOST, 'port'=>PORT, 'vhost'=>VHOST, 'login'=>USER, 'password'=>PWD]);
$connection->connect() OR die('can`t connect to rabbit');
register_shutdown_function(function()use($connection){
    $connection->disconnect();
});

$channel = new AMQPChannel($connection);
$channel->qos($size=null, $count=1);

$exchange = new AMQPExchange($channel);
$exchange->setName($exchangeName='my_exchange');
$exchange->setType(AMQP_EX_TYPE_DIRECT);
$exchange->setFlags(AMQP_DURABLE);
$exchange->declareExchange();



//生产者
$exchange->publish($message = '', $routing_key = null, $flags = AMQP_NOPARAM);



//消费者
$queue = new AMQPQueue($channel);
$queue->setName($queueName='my_queue');
$queue->setFlags(AMQP_DURABLE);
$queue->bind($exchangeName='my_exchange', $routingKey='');
$queue->consume(function($envelope, $queue){
    $routingKey = $envelope->getRoutingKey();
    $msg = $envelope->getBody(;
}, AMQP_AUTOACK);

服务管理

  • 启动管理插件rabbitmq-plugins enable rabbitmq_management(host:15672)
  • 罗列交换机rabbitmqctl list_exchanges
  • 罗列队列rabbitmqctl list_queues [fields]
  • 罗列绑定rabbitmqctl list_bindings
  • 增加虚拟机rabbitmqctl add_vhost 虚拟机名(用户和权限配置的最小单位)
  • 增加用户rabbitmqctl add_user 账号 密码
  • 配置权限rabbitmqctl set_permissions -p 虚拟机名 账号 ".*" ".*" ".*"

转载于:https://my.oschina.net/u/2400083/blog/911098

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值