RabbitMQ消息队列
RabbitMQ具有更加灵活的路由规则,且拥有消息确认机制,所以RabbitMQ比较适合作为任务池和指令池的载体。下面将对RabbitMQ的工作原理及常用场景进行深入讲解。
RabbitMQ的内部可以分成两部分:交换机部分和消息队列部分。一般情况下,交换机和消息队列都需要手动创建,且需要使用绑定键以绑定交换机和消息队列的关系。交换机和消息队列的绑定关系可以是多对多的,绑定键可以标识多个绑定关系。
当生产者程序发送消息时,需要指定交换机和路由键。生产者程序所发送的消息会先被指定交换机接收,之后RabbitMQ会根据三个因素把消息发送到相关的消息队列中。判断的三个因素为该交换机的类型(直发、广播等)、该交换机与消息队列的绑定关系,以及生产者程序指定的路由键与绑定键是否匹配。当消息匹配不到相关消息队列时,会被丢弃。
消费者程序监听指定消息队列,当指定消息队列接收到信息后,RabbitMQ会把消息发送到该消费者程序中。默认情况下,消息需要被确认(消费者程序向RabbitMQ发送消息确认信息)后才会被删除。在消息还没被确认的情况下,如果消费者程序异常退出(如断开连接),则该消息会被重新放回消息队列中。当然,在监听消息队列时如果设置了自动确认,则消息会被自动删除。另外,多个消费者程序可以监听同一个消息队列,但一个消息只会被一个消费者程序获取。RabbitMQ的工作原理如图5.19所示。
1.RabbitMQ的基本操作
RabbitMQ的基本操作如代码5.8所示,包括创建与销毁连接、创建与销毁交换机、创建与销毁消息队列、绑定交换机和消息队列、发送消息及接收消息。值得一提的是,无论是生产者程序还是消费者程序,都最好在发送消息或接受消息前做一下创建交换机、创建消息队列和绑定交换机与消息队列的动作,避免因为消息队列或交换机不存在而发生的错误。
说明:示例代码5.8是使用C++编写的,除了C++以外,RabbitMQ还支持其他语言,如Python、Java、Ruby、PHP等。虽然实际使用的开发语言不尽相同,但RabbitMQ的调用方式是大同小异的。
代码5.8 RabbitMQ的基本操作
//RabbitMQ相关头文件,需要先安装相关的库(librabbitmq-dev)
#include <amqp.h>
#include <amqp_tcp_socket.h>
//定义连接变量,connecton为连接,channel为连接的通道,与RabbitMQ通信都需要加上
二者
amqp_connection_state_t connection = amqp_new_connection();
int channel = 1;
//创建连接
//打开连接,并登录RabbitMQ,需要指定RabbitMQ的IP地址、端口、账号和密码
//"/"为默认的虚拟主机,一个RabbitMQ服务可以开设多个虚拟主机,用作服务隔离
//虚拟主机需要设置开通
amqp_socket_open(socket, "IP地址", "端口");amqp_socket_t *socket = amqp_tcp_socket_new(connection);
amqp_login(connection, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
"账号", "密码");
//建立通道,channel为通道序号。一个程序可以打开多个通道以达到建立多个连接的效果
amqp_channel_open(connection, channel);
//销毁连接
//关闭通道和关闭连接
amqp_channel_close(connection, channel, AMQP_REPLY_SUCCESS);
amqp_connection_close(connection, AMQP_REPLY_SUCCESS);
//创建与销毁交换机
//创建交换机,需要设置交换机名称和交换机类型
//交换机类型包括direct(直发,默认类型)、fanout(广播)和topic(主题)
amqp_exchange_declare(connection, channel, amqp_cstring_bytes("交换机
名称"),
amqp_cstring_bytes("交换机类型"), 0, 0, 0, 0,
amqp_empty_table);
//销毁交换机,需要设置交换机名称
amqp_exchange_delete(connection, channel, amqp_cstring_bytes("交换机
名称"), 1);
//创建与销毁消息队列
//创建消息队列
const char* queueNameStr = "消息队列名称";
//消息队列是否持久化(重启后消息仍不丢失),0/1对应false/true
amqp_boolean_t durable = 1;
//消息队列是否在断开连接后自动删除,0/1对应false/true
amqp_boolean_t autodelete = 0;
amqp_queue_declare(connection, channel, amqp_cstring_bytes
(queueNameStr), 0,
durable, 0, autodelete, amqp_empty_table);
//销毁消息队列
amqp_queue_delete(connection, channel, amqp_cstring_bytes
(queueNameStr), 1, 0);
//绑定与解绑
//绑定交换机与消息队列,交换机和消息队列可以绑定多个绑定键
const char* queueNameStr = "消息队列名称";
const char* exchange = "交换机名称";
//当交换机类型为fanout(广播)时不生效
const char* bindingkey = "绑定键名称";
amqp_queue_bind(connection, channel, amqp_cstring_bytes(queueNameStr),
amqp_cstring_bytes(exchange), amqp_cstring_bytes
(bindingkey),
amqp_empty_table);
//解除绑定
amqp_queue_unbind(