【RabbitMQ.Client笔记】Qos与消息应答
QOS:服务质量保证功能
Prefetch count (预取数目)
prefetch
是指单一消费者最多能消费的unacked messages
数目。
mq为每一个consumer
设置一个缓冲区,大小就是prefetch
。每次收到一条消息,MQ会把消息推送到缓存区中,然后再推送给客户端。当收到一个ack消息时(consumer
发出baseack指令
),mq会从缓冲区中空出一个位置,然后加入新的消息。但是这时候如果缓冲区是满的,MQ将进入堵塞状态。
更具体点描述,假设prefetch
值设为10
,共有两个consumer
。也就是说每个consumer
每次会从queue
中预抓取10
条消息到本地缓存着等待消费。同时该channel
的unacked
数变为20。而Rabbit投递的顺序是,先为consumer1
投递满10
个message,再往consumer2
投递10
个message。如果这时有新message需要投递,先判断channel
的unacked
数是否等于20
,如果是则不会将消息投递到consumer
中,message继续呆在queue
中。之后其中consumer
对一条消息进行ack
,unacked此时等于19,Rabbit就判断哪个consumer
的unacked
少于10,就投递到哪个consumer
中。
前面我们提到了如果有多个消费者同时订阅同一个Quque
中的消息,Quque
中的消息会被平摊给多个消费者。这时如果每个消息的处理时间不同,就有可能导致某些消费者一直很忙,而另一些消费者很快处理完手头上工作,并一直空闲的情况下。我们可以通过设置prefetch count=1
,则Quque
每次给每个消费者发送一条消息;消费者处理完这条消息后Quque
会再给消费者发送一条消息。
试想一下,如果我们单个消费者1分钟最多处理60条消息,但是生产者1分钟可能会发送300条消息,如果我们一台消费者客户端,1分钟同时要接收到300条消息,已经超过我们最大的负载,这时,就可能导致,服务器资源被耗尽,消费者客户端卡死等情况。
RabbitMQ提供了一种qos
(服务质量保证)功能,即在非自动确认消息的前提下,如果一定数目的消息(通过基于consume
或者channel
设置Qos
的值)未被确认前,不进行消费新的消息。
启用Qos
和手动Ack
可能导致队列阻塞:
如果consumer接收到消息后没有ack
或者unack
,并且使用Qos
限制了prefetch数量
,当unacked消息
太多就会造成堵塞
应答方式:
basicAck
:成功消费,消息从队列中删除
basicNack
:拒绝消息,requeue=true,消息重新进入队列,false被删除
basicReject
:等同于basicNack
basicRecover
:消息重入队列,requeue=true,发送给新的consumer,false发送给相同的consumer
basicQoc:
设置服务端每次发送给消费者的消息数量
/**
* prefetchSize:服务器传送最大内容量(以八位字节计算),如果没有限制,则为0
* prefetchCount:服务器每次传递的最大消息数,如果没有限制,则为0;
* global:如果为true,则当前设置将会应用于整个Channel(频道)
**/
void basicQos(int prefetchSize, int prefetchCount, boolean global)
消息回复:
Ack(确认)收到一个或者多个消息
/**
* 消费者确认收到一个或者多个消息
* deliveryTag:服务器端向消费者推送消息,消息会携带一个deliveryTag参数,也可以成此参数为消息的唯一标识,是一个递增的正整数
* multiple:true表示确认所有消息,包括消息唯一标识小于等于deliveryTag的消息,false只确认deliveryTag指定的消息
**/
void basicAck(long deliveryTag, boolean multiple)
basicRecover:重新发送
/**
* 要求代理重新发送未确认的消息
* requeue:如果为true,消息将会重新入队,可能会被发送给其它的消费者;如果为false,消息将会发送给相同的消费者
**/
Basic.basicRecover(boolean requeue)
basicNack:拒绝消息
/**
* 拒绝接收到的一个或者多个消息
* deliveryTag:接收到消息的唯一标识
* multiple: true表示拒绝所有的消息,包括提供的deliveryTag;false表示仅拒绝提供的deliveryTag
* requeue:true 表示拒绝的消息应重新入队,而不是否丢弃
*/
void basicNack(long deliveryTag, boolean multiple, boolean requeue)