一、队列
在AMQP模型中的队列和其他的消息和任务队列系统非常相似:他们存储用于被应用程序消费的消息。并且和交换机共享一些属性,但是也有自己额外的属性。
- 名字(Name)
- 持久性(Durable):当broker重启的时候,队列依然存活。
- 互斥性(Exclusive):只被一个连接(connection)使用,而且当连接关闭后队列即被删除。
- 自动删除(Auto-delete):当最后一个消费者退订后即被删除。
- 参数(Arguments):一些消息代理用他来完成类似与TTL的某些额外功能。
队列在声明(declare)后才能被使用。如果一个队列尚不存在,声明一个队列会创建它。如果声明的队列已经存在,并且属性完全相同,那么此次声明不会对原有队列产生任何影响。如果声明中的属性与已存在队列的属性有差异,那么一个错误代码为406的通道级异常就会被抛出。
- 对列名称
应用可以取一个队列的名字,也可以要broker生成一个队列的名字。队列的名字可以是255个字符的UTF-8。传空字符串给队列的名字参数,broker将产生一个唯一的名字给你的队列。在同一个channel上使用一个空字符串作为队列名参数调用子类的方法可能得到相同的队列名。这是由于channel记住了最新产生的队列名。
以“amq.”开始的队列名,是留给broker内部使用的保留队列名。以amq.定义一个队列名将获得一个channel级别的异常,异常码为403(ACCESS_REFUSED)
- 队列持久化
持久化队列(Durable queues)会被存储在磁盘上,当消息代理(broker)重启的时候,它依旧存在。没有被持久化的队列称作暂存队列(Transient queues)。并不是所有的场景和案例都需要将队列持久化。
持久化的队列并不会使得路由到它的消息也具有持久性。倘若消息代理挂掉了,重新启动,那么在重启的过程中持久化队列会被重新声明,无论怎样,只有经过持久化的消息才能被重新恢复。
二、绑定
绑定,顾名思义,是交换机将消息路由给队列所遵循的规则。如果要指示交换机“E”将消息路由给队列“Q”,那么“Q”就需要与“E”进行绑定。绑定操作需要定义一个可选的路由键(routing key)属性给某些类型的交换机。路由键的意义在于从发送给交换机的众多消息中选择出某些消息,将其路由给绑定的队列。
使用这种分层的架构,使不可能的路由场景或者用直接发送到队列非常难实现场景成为可能,并且避免了应用开发人员不得不做的某些重复工作。
如果AMQP的信息不能投递到任何队列(比如,由于没有bindings到exchange上),她可以删除信息也可以返回给发送者,完全取决于发送者消息属性的设置。
三、消费者
与生产者相对应。生产者生产食物(消息),就赢由消费者去消费。不然消息没有一点价值可言。应用消费消息有两种方式:
- 将消息投递给应用(“push API”),这是方式是被动的。
- 应用根据需要主动获取消息 ("pull API"),这种方式是主动的。
使用push API,应用(application)需要明确表示出它在某个特定队列里所感兴趣的,想要消费的消息。如是,我们可以说应用注册了一个消费者,或者说订阅了一个队列。一个队列可以注册多个消费者,也可以注册一个独享的消费者(当独享消费者存在时,其他消费者即被排除在外)。
每个消费者(订阅者)都有一个叫做消费者标签的标识符。它可以被用来退订消息。消费者标签实际上是一个字符串。
四、消息确认
消费和处理消息的应用很有可能处理失败或者发生某些冲突。也可能是网络的问题。这些问题导致AMQP的broker什么时候该从队列中移走消息?AMQP规范规定broker有两个选择可以做这个事:
- 在broker发送信息给应用之后(可以使用basic.deliver或者basic.get-ok两个AMQP方法)
- 应用返回一个确认信息(使用basic.ack的AMQP方法)
第一种方式叫做自动确认模式,后面一种叫做手动确认模式。在手动确认模式中,应用程序选择何时发送确认信息。可以是在收到消息之后,也可以是保存信息到数据库之后,也可以是所有步骤都执行之后。
如果消费者死去而没有发送任何的确认信息,broker将重新发送消息给另一个消费者,或者如果没有一个消费是可用的,broker将一直等待(rabbitmq中没有超时的概念),直到至少有一个消费者注册到相同的队列,他将把消息发送给这个注册者。
- 拒绝消息
消费者处理接收的消息,执行过程中可能会失败。消费者可以通过驳回信息的方式告诉broker自己的执行过程失败了。当驳回一个信息时,消费者可以要broker丢弃或者重新放回到队列。当只有一个消费者注册在队列上时,注意不要不合理的驳回产生驳回,再入列,在消费的死循环!
- 否定确认消息
消息可以使用basic.reject的AMQP方法驳回。但是有限制:没有办法驳回已经确认的信息。但是,如果你使用RabbitMQ,将有解决方案,RabbitMQ提供了一个AMQP 0-9-1的去扩展叫否定确认或者叫做否定回答。
- 预抓信息
在多个消费者共享一个队列的案例中,明确指定在收到下一个确认回执前每个消费者一次可以接受多少条消息是非常有用的。这可以在试图批量发布消息的时候起到简单的负载均衡和提高消息吞吐量的作用。
注意:RabbitMQ只提供channel级别的prefetch-count,不提供connection或者基本个数的预抓