RabbitMq qos prefetch 消息堵塞问题
mq是实现代码扩展的有利手段,个人喜欢用概念来学习新知识,介绍堵塞问题的之前,先来段概念的学习。
ConnectionFactory:创建connection的工厂类
Connection: 简单理解为socket
Channel:和mq交互的接口,定义queue、exchange和绑定queue、exhange等接口都是它。
接下来就是和mq的交互类
exchange:简单地看成路由,类型不是重点,看看官网即可
queue:客户端监听的是queue,而不是exchange,但是使用queue的前提要先将exchange和queue绑定。用过java queue工具类应该很容易上手,queue分为写和读,各自可以有自己频率,写得快读得慢,容易堵塞;写得慢读得快又容易造成消费者的空闲。
Prefetc:一个重要却容易被忽略的指标,也是这次遇到的问题。
prefetch与消息投递
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中。
我遇到的问题是一个粗心的程序员,在编写代码的时候,他对某些消息处理方式是这样的
if (success) {
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} else {
logger.error("######### The message is not delete from queue : {}", body);
}
首先他讲ack机制设置为手动的,然后他的理解是如果处理成功的消息,就ack给MQ,期望MQ就可以删除完成的数据。不然,保留数据再次被处理。
这里的误区就是就是对ack的理解,失败的时候,如果需要让程序继续处理,应该使用basicNack,并告诉mq将消息再次放入队列
if (success) {
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} else {
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
}
对于客户端意外宕机的情况,没有ack服务器确实不会删除掉数据,但是consumer重启以后,对于服务器就是一个新的消费者了,也就是它的缓冲区又被重置为原来的n-prefetch,所以这个问题被粗心的小哥想当然地测试通过了。
prefetch的大小应该为多少
这篇文章给了很好的建议,我简单地说一下我的理解。
理想状况下,计算MQ SERVER 从缓冲区中拿到消息并推送到消费端,加上消费端处理完ack消息到MQ server,的时间,假设为100ms,其中消费端处理业务话费了10ms。
这里可以得出我们 prefetch = 100ms / 10ms = 10,也就是消息来回的总时间/业务处理的时间,这里要求我们 prefetch >= 10。一般计算这个时间不会太准确只能毛姑姑的,所以prefetch一般要大一点。但是这个值也不能太大,不然消费端就一只处于空闲状态了。
所以如果你保证所有的消息都ack了,但是还是出现比较长时间的堵塞,你就或者加大一点prefetch,或者多加一些机器,或者减少业务处理的时间了。一开始建议采用或者,使用一个线程池来处理这些业务逻辑。
--------转载原路径-------------
作者:james_searcher
来源:CSDN
原文:https://blog.csdn.net/james_searcher/article/details/70308565
RabbitMq qos prefetch 消息堵塞问题的更多相关文章
- RabbitMQ---5、qos内存溢出+prefetch消息堵塞问题
1.prefetch消息堵塞问题 mq是实现代码扩展的有利手段,个人喜欢用概念来学习新知识,介绍堵塞问题的之前,先来段概念的学习. ConnectionFactory:创建connection的工厂类 ...
- rabbitmq qos prefetch count的设置与作用
因为原来使用了MQ作为rpc机制,随着客户交易量越来越大,很多服务器推送行情的压力很大,最近打算重写为批量模式,又重新看了下qos和prefetch设置的作用以确定优化的具体细节. 消费者在开启ack ...
- RabbitMQ AMQP (高级消息队列协议)
目录 RabbitMQ AMQP (高级消息队列协议) Message Queue 简介 概念 基本组成 场景及作用 AMQP简介 模型架构 基础组件 AMQP-RabbitMQ 简介 模型 特性 参 ...
- rabbitmq队列中消息过期配置
最近公司某个行情推送的rabbitmq服务器由于客户端异常导致rabbitmq队列中消息快速堆积,还曾导致过内存积压导致rabbitmq客户端被block的情况.考虑到行情信息从业务上来说可以丢失部分 ...
- rabbitmq之确保消息不丢失
1.背景引入 在使用消息中间件(rabbitmq)时,令开发者最头痛的就是防止消息丢失问题,而消息丢失可能发生的位置主要为三种,分别为(1)消息发送到MQ中消费者消费未成功时突然宕机:(2)消息发送到 ...
- rabbitMQ学习1:消息队列介绍与rabbitmq安装使用
1. 什么是消息队列 生活里的消息队列,如同邮局的邮箱, 如果没邮箱的话, 邮件必须找到邮件那个人,递给他,才玩完成,那这个任务会处理的很麻烦,很慢,效率很低 但是如果有了邮箱, 邮件直接丢给邮箱,用 ...
- RabbitMq中的消息应答与持久化
一:消息应答 1.介绍 涉及到的程序: boolean autoAck=false; channel.basicConsume(QUENE_NAME,autoAck,consumer); 2.auto ...
- AMQP协议与RabbitMQ、MQ消息队列的应用场景
什么是AMQP? 在异步通讯中,消息不会立刻到达接收方,而是被存放到一个容器中,当满足一定的条件之后,消息会被容器发送给接收方,这个容器即消息队列,而完成这个功能需要双方和容器以及其中的各个组件遵守统 ...
- SpringBoot整合RabbitMQ,实现消息发送和消费以及多个消费者的情况
下载安装Erlang和RabbitMQ Erlang和RabbitMQ:https://www.cnblogs.com/theRhyme/p/10069611.html AMQP协议 https:// ...
随机推荐
- 2018.08.21 NOIP模拟 unlock(模拟+找规律)
unlock 描述 经济危机席卷全球,L国也收到冲击,大量人员失业. 然而,作为L国的风云人物,X找到了自己的新工作.从下周开始,X将成为一个酒店的助理锁匠,当然,他得先向部门领导展示他的开锁能力. ...
- Exce行列变色
- centos6 mysql 安装与配置
MySQL简介: 由于其体积小.速度快.总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库.MySQL是一个多用户.多线程的关系型数据库管理 ...
- scanf和fscanf读取文件
这篇是针对推箱子游戏而写的,某个时候在学C语言,最近转到windows设计,不知道是否有同样的感受,后面的东西学了,前面的就有点生疏了.其实,我的理解是,注意力转移了,当集中于当前问题的时候就会忽略以 ...
- Android线程和线程Handler基础一览
线程概览 线程是任何多任务系统的基石.可以被认为是一个主进程的多个子进程.这样做的目的就是了增加应用的性能. 应用主线程 当一个Android应用被打开的时候,系统会默认开辟一个线程.这个线程就被叫做 ...
- (线段树 点更新 区间求和)lightoj1112
链接: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=88230#problem/D (密码0817) Description Robin ...
- angular2+ 初理解
一.Angular Module 1.angular 模块是一个类,它需要NgModule这个装饰器函数接受一个原数据对象作为参数来描述这个模块类属性. 其中最重要的属性有: ...
- Codeforces801C Voltage Keepsake 2017-04-19 00:26 109人阅读 评论(0) 收藏
C. Voltage Keepsake time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- java.util.Date与java.sql.Date的关系和转换方法(转)
在ResultSet中我们经常使用的setDate或getDate的数据类型是java.sql.Date,而在平时java程序中我们一般习惯使用 java.util.Date. 因此在DAO层我们经常 ...
- lua的table的删除操作
直接使用table的remove方法 , , } table.remove(tab) --默认删除最后一个元素,第二个参数可以指定删除位置 删除后,后面的元素会往前移动.有点像C++的std::vec ...