基础
- RabbitMQ是个消息代理(broker),接收并传递消息;
术语
- 生产者(producer):生产(producing)并发送消息的程序
- 消费者(consumer):等待接收消息的程序
- 交换机(exchange):交换机接收来自消费者推送的消息,并根据设置决定如何处置该信息,发给与之绑定的一个队列或多个队列,否则无视掉
- 队列(queue):一个消息缓存区;存储上限是主机内存和磁盘
- 路由键(routing key):指定消息路由方向的地址名称
代理、生产者、消费者大多不在同一服务器上
一个程序可以既是生产者同时也是消费者
交换机类型:direct, topic, headers 和 fanout
- fanout(分发型):广播所有消息给所有队列
- direct(指向型):消息根据路由键发送给指定的队列
- topic(主题型):消息根据主题形式的路由键发送给指定的队列,主题形式的路由键由多个单词组成,用.分隔,绑定时可模糊匹配
- headers(头信息型):利用头信息键值对作为路由键发送诶指定的队列
Work Queue(Task Queues)
- 若一个消息的处理需要花跟多时间,则可以配置多个消费者作为worker,broker会尽可能的平均分配消息
消息应答(Message acknowledgment)
- 简单模式中,broker将信息发给消费者后,将立即删除该消息,此时如果某个消费者挂了,消息将丢失
- mq支持消息应答,消费者在妥善处理消息后可发送一个ack给mq,通知mq可以删除该消息了
- 若某个消费者挂了,mq将不会收到ack,mq会将该消息发给其他消费者
- 默认的,消息应答是关闭的,可以在消费者中开启
- ack必须发送给对应的channel
消息持久化(Message durability)
- 如果mq服务挂了,队列及其中的消息会丢失,可以声明队列和消息为持久化的(durable)来解决这个问题
- 生产者和消费者在声明队列(queue)时可将其设置为持久化的,二者要一致,持久化的队列在mq重启后仍存在
- 生产者可将消息声明为持久化的,mq会将消息存入磁盘,持久化的消息在mq重启后仍存在
qos(Quality Of Service)
- 默认的,mq将消息按顺序依次发送给多个消费者,像发牌一样,并不考虑消费者是否空闲
- 可通过channel的qos设置"预接收数量(prefetch)"为1,来解决这个问题
发布与订阅模式(Publish/Subscribe)
- ps模式可以将一个消息发个多个消费者
- 生产者不再直连队列,而是链接交换机,交换机与队列绑定,由消费者链接队列
- fanout交换机类型:广播所有消息给所有队列
$channel->exchange_declare('exchange_name', 'fanout', false, false, false);//创建fanout类型的交换机
- ps模式中,队列是临时的,每次连接mq,都由mq创建随机名称的队列,这些临时队列会在消费者断链时被自动删除
list($queue_name, ,) = $channel->queue_declare("");
// $queue_name中是一个随机队列名,类似amq.gen-JzTY20BRgKO-HjmUJj0wLg
- 交换机和队列通过绑定(binding)建立关系
$channel->queue_bind($queue_name, 'exchange_name');
路由(Routing)
- 当一个交换机绑定多个队列时,如果需要指定消息发给特定的队列,则需要定义路由
- 将队列绑定到交换机和发布消息时,可以设置路由键(routing key)
// 生产者中
$channel->basic_publish($msg, $exchange_name, $routing_key);
// 消费者中
$channel->queue_bind($queue_name, $exchange_name, $routing_key);
- 设置路由键的消息会被交换机发送给对应路由键的队列上
- 一个队列可以绑定多个路由键,该队列会收到所有路由键对应的消息
- 多个队列可以绑定同一个路由键,交换机对待这些队列的行为会向fanout模式一样
fanout类型的交换机无视路由键
topic exchange
- 发给topic交换机的消息不能随意指定路由键,路由键必须是用点(.)分隔的多个词组成的字符串,长度上限255 bytes
- 推送消息时设置的路由键必须完整,绑定队列时设置的路由键可以制定模糊匹配的路由规则,*可以代表一个单词,#可以代表0或多个单词
- 当一个队列绑定多个路由键,并且某条消息同时满足多个路由规则时,消息不会发送多次