安装
根据操作系统不同官网提供了相应的安装说明:Windows、Debian / Ubuntu、RPM-based Linux、Mac
Mac 用户推荐使用 HomeBrew 来安装:
brew install rabbitmq
安装过程中会自动其所依赖的 Erlang 。
启动
RabbitMQ server scripts 和 CLI tools
被安装在/usr/local/sbin
添加环境变量:
export PATH=$PATH:/usr/local/sbin
启动:
rabbitmq-server
如下图则表示正常启动,completed with 6 plugins 表示启动的时候默认加载了6个插件:
日志:
/var/log/rabbitmq目录下找到名为rabbit@[hostname].log日志文件
常用命令:
首先介绍两个概念,Erlang的节点和应用程序:节点可以理解为Erlang 的虚拟机,一个节点可以同时运行多个应用程序。节点之间可以进行本地通信(不管他们是不是运行在同一台服务器之上)。比如一个运行在节点A上的应用程序可以调用节点B上应用程序的方法,就好像调用本地函数一样。如果应用程序由于某些原因奔溃,Erlang 节点会自动尝试重启应用程序。
//守护进程方式后台运行
rabbitmq-server -detached
//查询服务器状态
rabbitmqctl status
//关闭 RabbitMQ 节点,默认 node 名称是 rabbit@server
rabbitmqctl stop
//关闭指定node
rabbitmqctl -n [email protected] stop
//关闭 RabbitMQ 应用程序,保持Erlang节点运行(这个命令在集群模式中将会很有用)
rabbitmqctl stop_app
//启动 RabbitMQ 应用程序
rabbitmqctl start_app
//重置 RabbitMQ 节点(该命令会清除所有的队列):
rabbitmqctl reset
//查看已声明的队列
rabbitmqctl list_queues
//查看交换器
rabbitmqctl list_exchanges
//该命令还可以附加参数,比如列出交换器的名称、类型、是否持久化、是否自动删除:
rabbitmqctl list_exchanges name type durable auto_delete
//查看绑定
rabbitmqctl list_bindings
更多命令参照官网
PHP Client
详细文档参照官网
- 下载安装php-amqplib扩展,建议使用Composer安装
{
"require": {
"php-amqplib/php-amqplib": ">=2.6.1"
}
}
- send.php
channel();
//declare a queue for us to send to
$channel->queue_declare('hello', false, false, false, false);
//publish a message to the queue
$msg = new AMQPMessage('Hello World!');
$channel->basic_publish($msg, '', 'hello');
echo " [x] Sent 'Hello World!'\n";
//close the channel and the connection;
$channel->close();
$connection->close();
发送消息前,必须先声明一个队列。值得注意的是,这里的队列声明是幂等的,即只有才队列不存在的情况才会去创建。消息的主体是一个二进制数组(byte array),因此我们可以自己随意选择编码方式,而不影响传输。
- receive.php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
//Note that we declare the queue here, as well. Because we might start the consumer before the publisher, we want to make sure the queue exists before we try to consume messages from it.
$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();
}
注意:这里接受消息我们也要先声明队列,因为实际应用中我们可能需要producer发送前先启动worker,所以我们要确保在我们消费消息之前队列存在。
consumer获取消息的方式是MQ按照push的方式分发给worker的,如果我们启动多个worker,那么我们就会发现每次我们推给mq的消息会被依次分发给各个worker消费。
4.消息确认(Message Acknowledgement)
rabbitmq的消息确认机制默认是被关闭的。如果我们在worker处理消息过程中杀死worker,那么worker重启之后,这条任务就会丢失。如果要确保任务不会丢失,就要使用以下代码:
$callback = function ($msg) {
echo ' [x] Received ', $msg->body, "\n";
//ack回调
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
};
$channel->basic_consume('task_queue', '', false, false, false, false, $callback);
增加以上ack机制后,mq只有在收到确认之后才会将任务从队列中删除。
- 消息持久化(Message durability)
上面介绍的是如何在consumer崩溃的时候,task不丢失。但是当rabbitmq崩溃的时候queue和task仍然会丢失,很明显这是我们不能接受的,下面的代码就是如何让我们的queue和task持久化:
//声明持久化的队列
$channel->queue_declare('task_queue', false, true, false, false); //第三个参数为true
//消息持久化存储在队列中
$msg = new AMQPMessage(
$data,
array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT)
);