本文将结合自己使用RocketMQ的经验,对消息发送常见的问题进行分享,基本会遵循出现问题,分析问题、解决问题。

1、No route info of this topic

无法找到路由信息,其完整的错误堆栈信息如下:
而且很多读者朋友会说Broker端开启了自动创建主题也会出现上述问题。

RocketMQ的路由寻找流程如下图所示:
上面的核心关键点如下:

  • 如果Broker开启了自动创建Topic,在启动的时候会默认创建主题:TBW102,并会随着Broker发送到Nameserver的心跳包汇报给Nameserver,继而从Nameserver查询路由信息时能返回路由信息。
  • 消息发送者在消息发送时首先会查本地缓存,如果本地缓存中存在,直接返回路由信息。
  • 如果缓存不存在,则向Nameserver查询路由信息,如果Nameserver存在该路由信息,就直接返回。
  • 如果Nameserver不存在该topic的路由信息,如果没有开启自动创建主题,则抛出 No route info of this topic。
  • 如果开启了自动创建主题,则使用默认主题向Nameserver查询路由信息,并使用默认Topic的路由信息为自己的路由信息,将不会抛出 No route info of this topic。

通常情况下 No route info of this topic 这个错误一般是在刚搭建RocketMQ,刚入门 RocketMQ遇到的比较多,通常的排查思路如下:

  • 可以通过rocketmq-console查询路由信息是否存在,或使用如下命令查询路由信息:

    cd ${ROCKETMQ_HOME}/bin
    sh ./mqadmin topicRoute -n 127.0.0.1:9876 -t dw_test_0003
    

    其输出结果如下所示:

  • 如果通过命令无法查询到路由信息,则查看Broker是否开启了自动创建topic,参数为:autoCreateTopicEnable,该参数默认为true。但在生产环境不建议开启。

  • 如果开启了自动创建路由信息,但还是抛出这个错误,这个时候请检查客户端(Producer)连接的Nameserver地址是否与Broker中配置的nameserver地址是否一致。

经过上面的步骤,基本就能解决该错误。

2、消息发送超时

消息发送超时,通常客户端的日志如下:

客户端报消息发送超时,通常第一怀疑的对象是RocketMQ服务器,是不是Broker性能出现了抖动,无法抗住当前的量。

那我们如何来排查RocketMQ当前是否有性能瓶颈呢?

首先我们执行如下命令查看RocketMQ 消息写入的耗时分布情况:

cd /${USER.HOME}/logs/rocketmqlogs/
grep -n 'PAGECACHERT' store.log | more

输出结果如下所示:

RocketMQ会每一分钟打印前一分钟内消息发送的耗时情况分布,我们从这里就能窥探RocketMQ消息写入是否存在明细的性能瓶颈,其区间如下:

  • [<=0ms] 小于0ms,即微妙级别的。
  • [0~10ms] 小于10ms的个数。
  • [10~50ms] 大于10ms小
  • 于50ms的个数

其他区间显示,绝大多数会落在微妙级别完成,按照笔者的经验如果100-200ms及以上的区间超过20个后,说明Broker确实存在一定的瓶颈,如果只是少数几个,说明这个是内存或pagecache的抖动,问题不大。

通常情况下超时通常与Broker端的处理能力关系不大,还有另外一个佐证,在RocketMQ broker中还存在快速失败机制,即当Broker收到客户端的请求后会将消息先放入队列,然后顺序执行,如果一条消息队列中等待超过200ms就会启动快速失败,向客户端返回[TIMEOUT_CLEAN_QUEUE]broker busy,这个在本文的第3部分会详细介绍。

在RocketMQ客户端遇到网络超时,通常可以考虑一些应用本身的垃圾回收,是否由于GC的停顿时间导致的消息发送超时,这个我在测试环境进行压力测试时遇到过,但生产环境暂时没有遇到过,大家稍微留意一下。

在RocketMQ中通常遇到网络超时,通常与网络的抖动有关系,但由于我对网络不是特别擅长,故暂时无法找到直接证据,但能找到一些间接证据,例如在一个应用中同时连接了kafka、RocketMQ集群,发现在出现超时的同一时间发现连接到RocketMQ集群内所有Broker,连接到kafka集群都出现了超时。

但出现网络超时,我们总得解决,那有什么解决方案吗?

我们对消息中间件的最低期望就是高并发低延迟,从上面的消息发送耗时分布情况也可以看出RocketMQ确实符合我们的期望,绝大部分请求都是在微妙级别内,故我给出的方案时,减少消息发送的超时时间,增加重试次数,并增加快速失败的最大等待时长。具体措施如下:

  • 增加Broker端快速失败的时长,建议为1000,在broker的配置文件中增加如下配置:

    maxWaitTimeMillsInQueue=1000
    

    主要原因是在当前的RocketMQ版本中,快速失败导致的错误为SYSTEM_BUSY,并不会触发重试,适当增大该值,尽可能避免触发该机制,详情可以参考本文第3部分内容,会重点介绍system_busy、broker_busy。

  • 如果RocketMQ的客户端版本为4.3.0以下版本(不含4.3.0)
    将超时时间设置消息发送的超时时间为500ms,并将重试次数设置为6次(这个可以适当进行调整,尽量大于3),其背后的哲学是尽快超时,并进行重试,因为发现局域网内的网络抖动是瞬时的,下次重试的是就能恢复,并且RocketMQ有故障规避机制,重试的时候会尽量选择不同的Broker,相关的代码如下:

    DefaultMQProducer producer = new DefaultMQProducer("dw_test_producer_group");
    producer.setNamesrvAddr("127.0.0.1:9876");
    producer.setRetryTimesWhenSendFailed(5);// 同步发送模式:重试次数
    producer.setRetryTimesWhenSendAsyncFailed(5);// 异步发送模式:重试次数
    producer.start();
    producer.send(msg,500);//消息发送超时时间
    
  • 如果RocketMQ的客户端版本为4.3.0及以上版本

    如果客户端版本为4.3.0及其以上版本,由于其设置的消息发送超时时间为所有重试的总的超时时间,故不能直接通过设置RocketMQ的发送API的超时时间,而是需要对其API进行包装,重试需要在外层收到进行,例如示例代码如下:

    public static SendResult send(DefaultMQProducer producer, Message msg, int retryCount) {Throwable e = null;for(int i =0; i < retryCount; i ++ ) {try {return producer.send(msg,500); //设置超时时间,为500ms,内部有重试机制} catch (Throwable e2) {e = e2;}}throw new RuntimeException("消息发送异常",e);}
    

3、System busy、Broker busy

在使用RocketMQ中,如果RocketMQ集群达到1W/tps的压力负载水平,System busy、Broker busy就会是大家经常会遇到的问题。例如如下图所示的异常栈。
纵观RocketMQ与system busy、broker busy相关的错误关键字,总共包含如下5个:

  • [REJECTREQUEST]system busy
  • too many requests and system thread pool busy
  • [PC_SYNCHRONIZED]broker busy
  • [PCBUSY_CLEAN_QUEUE]broker busy
  • [TIMEOUT_CLEAN_QUEUE]broker busy

3.1 原理分析

我们先用一张图来阐述一下在消息发送的全生命周期中分别在什么时候会抛出上述错误。

根据上述5类错误日志,其触发的原有可以归纳为如下3种。

  • pagecache压力较大

    其中如下三类错误属于此种情况

    • [REJECTREQUEST]system busy
    • [PC_SYNCHRONIZED]broker busy
    • [PCBUSY_CLEAN_QUEUE]broker busy

    判断pagecache是否忙的依据就是在写入消息时,在向内存追加消息时加锁的时间,默认的判断标准是加锁时间超过1s,就认为是pagecache压力大,向客户端抛出相关的错误日志。

  • 发送线程池挤压的拒绝策略
    在RocketMQ中处理消息发送的是一个只有一个线程的线程池,内部会维护一个有界队列,默认长度为1W,如果当前队列中挤压的数量超过1w,执行线程池的拒绝策略,从而抛出[too many requests and system thread pool busy]错误。

  • Broker端快速失败

    默认情况下Broker端开启了快速失败机制,就是在Broker端还未发生pagecache繁忙(加锁超过1s)的情况,但存在一些请求在消息发送队列中等待200ms的情况,RocketMQ会不再继续排队,直接向客户端返回system busy,但由于rocketmq客户端目前对该错误没有进行重试处理,所以在解决这类问题的时候需要额外处理。

3.2 PageCache繁忙解决方案

一旦消息服务器出现大量pagecache繁忙(在向内存追加数据加锁超过1s)的情况,这个是比较严重的问题,需要人为进行干预解决,解决的问题思路如下:

  • transientStorePoolEnable

    开启transientStorePoolEnable机制,即在broker中配置文件中增加如下配置:

    transientStorePoolEnable=true
    

    transientStorePoolEnable的原理如下图所示:


引入transientStorePoolEnable能缓解pagecache的压力背后关键如下:

  • 消息先写入到堆外内存中,该内存由于启用了内存锁定机制,故消息的写入是接近直接操作内存,性能能得到保证。

  • 消息进入到堆外内存后,后台会启动一个线程,一批一批将消息提交到pagecache,即写消息时对pagecache的写操作由单条写入变成了批量写入,降低了对pagecache的压力。

    引入transientStorePoolEnable会增加数据丢失的可能性,如果Broker JVM进程异常退出,提交到PageCache中的消息是不会丢失的,但存在堆外内存(DirectByteBuffer)中但还未提交到PageCache中的这部分消息,将会丢失。但通常情况下,RocketMQ进程退出的可能性不大,通常情况下,如果启用了transientStorePoolEnable,消息发送端需要有重新推送机制(补偿思想)。

  • 扩容

    如果在开启了transientStorePoolEnable后,还会出现pagecache级别的繁忙,那需要集群进行扩容,或者对集群中的topic进行拆分,即将一部分topic迁移到其他集群中,降低集群的负载。

温馨提示:在RocketMQ出现pagecache繁忙造成的broker busy,RocketMQ Client会有重试机制。

3.3 TIMEOUT_CLEAN_QUEUE 解决方案

由于如果出现TIMEOUT_CLEAN_QUEUE的错误,客户端暂时不会对其进行重试,故现阶段的建议是适当增加快速失败的判断标准,即在broker的配置文件中增加如下配置:

#该值默认为200,表示200ms
waitTimeMillsInSendQueue=1000

温馨提示,关于Broker busy,笔者发表过两篇文章,大家也可以结合着看:

1、RocketMQ 消息发送system busy、broker busy原因分析与解决方案

2、再谈RocketMQ broker busy


本文来自笔者的另一力作《RocketMQ实战与进阶》,专栏从使用场景入手介绍如何使用 RocketMQ,使用过程中遇到什么问题,如何解决这些问题,以及为什么可以这样解决,即原理讲解(图)穿插在实战中。专栏的设计思路重在强调实战二字,旨在让一位 RocketMQ 初学者通过对本专栏的学习,快速“打怪升级”,理论与实战结合,成为该领域的佼佼者。

RocketMQ消息发送常见错误与解决方案相关推荐

  1. mq发送消息到两个服务器问题,RocketMQ消息发送常见错误与解决方案

    本文将结合本身使用RocketMQ的经验,对消息发送常见的问题进行分享,基本会遵循出现问题,分析问题.解决问题.web 一.No route info of this topic 没法找到路由信息,其 ...

  2. 大数据常见错误及解决方案

    大数据常见错误及解决方案(转载) 1.用./bin/spark-shell启动spark时遇到异常:java.net.BindException: Can't assign requested add ...

  3. gulp压缩js转义es6的常见错误及解决方案

    gulp压缩js转义es6的常见错误及解决方案 参考文章: (1)gulp压缩js转义es6的常见错误及解决方案 (2)https://www.cnblogs.com/uimeigui/p/11797 ...

  4. RocketMQ消息发送之pull和push

    RocketMQ学习(五)--RocketMQ消息发送之pull和push import org.apache.rocketmq.client.exception.MQClientException; ...

  5. Mac提示app损坏、Error,Mac电脑最常见错误的解决方案

    这篇文章蓝同学给大家分享一下Mac电脑上最常见错误的解决方案. 以下仅给出部分错误提示截图,类似的错误提示还有磁盘映像损坏.xxx.app有啥啥问题.... ①提示xxx.app已损坏,让你移到废纸篓 ...

  6. NDK编译php,Android NDK编译常见错误及解决方案

    Android NDK编译常见错误及解决方案 Error 1:$ ndk-build/cygdrive/c/andy/abc/obj/local/armeabi-v7a/objs/abc//hello ...

  7. Hadoop常见错误及解决方案、Permission denied: user=dr.who, access=WRITE, inode=“/“:summer:supergroup:drwxr-xr-x

    文章目录 4.常见错误及解决方案 1)防火墙没关闭.或者没有启动YARN 7)不识别主机名称 8)DataNode和NameNode进程同时只能工作一个. 9)执行命令不生效,粘贴Word中命令时,遇 ...

  8. MySQL数据库常见错误及解决方案

    MySQL数据库常见错误及解决方案 1 MySQL无法重启问题解决Warning: World-writable config file '/etc/my.cnf' is ignored 原因 今天帮 ...

  9. Hadoop中的MapReduce框架原理、数据清洗(ETL)、MapReduce开发总结、常见错误及解决方案

    文章目录 13.MapReduce框架原理 13.7 数据清洗(ETL) 13.7.1 需求 13.7.1.1 输入数据 13.7.1.2 期望输出数据 13.7.2 需求分析 13.7.3实现代码 ...

最新文章

  1. WSRP调用中的一些问题
  2. R语言构建仿真数据库(sqlite)并使用dplyr语法和SQL语法查询数据库、将dplyr语法查询语句翻译为SQL查询语句
  3. 傅里叶变换性质证明卷积_傅里叶变换(三) 采样与离散序列
  4. html页面左对齐 不换行,css如何设置不换行?
  5. 关于Java你不知道的那些事之Java注解和反射
  6. leetcode37. 解数独
  7. 【Shell教程】三----运算符,条件判断
  8. .NetCore中EFCore for MySql整理(二)
  9. tbslog乱码转换_日文游戏乱码怎么办 乱码转换工具LocaleEmulator
  10. 关于打开NVIDIA控制面板闪退问题
  11. 苹果平板有Linux终端吗,Apple:如何在iphone、ipad上安装一些常用命令行命令
  12. 「自动搬运+CDN」FFmpeg + x264 t_mod + x265 yuuki
  13. 阿里云盾AliYunDun服务IO超高
  14. Java、JSP服装销售管理系统
  15. sql server数据库卡问题排查
  16. P7721 [Ynoi2007] rcn
  17. 软件工程知识点总结——第三、四部分
  18. 《社会动物——爱、性格和成就的潜在根源》读后感及摘录(1)
  19. 本土程序员杀进硅谷的第一步---突破英语瓶颈
  20. Android在线工具

热门文章

  1. 2.5D风格场景插画立体图案一键生成PS插件_安装教程
  2. 三毛最伤心的100句话
  3. 解决Mac下使用emmyLua调试遇到“dynamic libraries not enabled; check your Lua installation”
  4. 《算法思维——一种问题驱动的思维方式》之第9篇:数据结构之动态栈篇——采用JavaScript编程语言实现
  5. 既能提升权重又能强势引流的外链建设方法汇总
  6. 几种风控算法的原理和代码实现
  7. 关于尚硅谷微信支付开发解决跨域访问
  8. 2014年电大统考计算机试题,2013年电大网考计算机应用基础1统考试题
  9. DBCO-PEG-OH,Hydroxyl-PEG-DBCO,二苯并环辛炔-聚乙二醇-羟基试剂供应
  10. Linux内核学习笔记(6)-- 进程优先级详解(prio、static_prio、normal_prio、rt_priority)...