当前位置: 首页 > 科技观察

rocketMQ很慢?引出未解之谜

时间:2023-03-20 23:57:11 科技观察

本文转载自微信公众号《建筑搬运工》,转载请联系建筑搬运工公众号。前段时间发现在使用rockerMQ控制台时,出现查询消息很慢,查询时间需要10多秒,从5、6秒到14+秒不等。如下图所示:这是为什么呢?为什么查询消息这么耗时?目前使用的开发环境:操作系统为Windows10,JDK8,rocketMQ为4.5.2。在其他机器上没有这个问题,本机虚拟机VMware上安装的linux部署rocketMQ和console,验证没问题。那我的机器怎么了???既然是接口的耗时问题,我们不知道耗时主要在哪里,所以我们使用Arthas来跟踪调用链的耗时。使用trace命令:trace命令方法内部调用路径,输出方法路径上每个节点花费的时间。trace命令可以主动搜索class-pattern/method-pattern对应的方法调用路径,渲染统计整个调用链路上的所有性能开销,并对调用链路进行跟踪。traceorg.apache.rocketmq.console.service.impl.MessageServiceImplqueryMessageByTopic从当前调用路径获取主要耗时:DefaultMQPullConsumer构造函数初始化+DefaultMQPullConsumer启动耗时。那我们继续在里面跟进。此时我们关注DefaultMQPullConsumer构造函数的初始化:traceorg.apache.rocketmq.client.consumer.DefaultMQPullConsumer从构造函数初始化入口来看,并没有花费很多时间。再看DefaultMQPullConsumer的启动方法:[E]开启正则表达式匹配,默认为通配符匹配然后发现耗时主要是获取MQClientInstance实例。traceorg.apache.rocketmq.client.impl.MQClientManagergetAndCreateMQClientInstancetraceorg.apache.rocketmq.client.ClientConfigcloneClientConfig接着看ClientConfig#cloneClientConfig方法:publicClientConfigcloneClientConfig(){ClientConfigcc=newClientConfig();cc.namesrvAddr=namesrvAddr;cc.clientIP.=clientIP;instanceName=instanceName;cc.clientCallbackExecutorThreads=clientCallbackExecutorThreads;cc.pollNameServerInterval=pollNameServerInterval;cc.heartbeatBrokerInterval=heartbeatBrokerInterval;cc.persistConsumerOffsetInterval=persistConsumerOffsetInterval;cc.unitMode=unitMode;cc.unitName=unitName;cc.vipChannel.cchanneld=vipChannelduseTLS;cc.namespace=namespace;cc.language=language;returncc;}可以看到很多赋值操作,不需要关注这些,关注newClientConfig():traceorg.apache.rocketmq即可。client.ClientConfig可以看出主要耗时3~4秒,耗时主要是这个工具类方法:RemotingUtil#getLocalAddressraceorg.apache.rocketmq.remoting.common.RemotingUtilgetLocalAddress至此,JDK方法调用已被跟踪:NetworkInterface#getNetworkInterfaces然后我想查看JDK函数调用:trace--skipJDKMethodfalsejava.net.NetworkInterfacegetNetworkInterfaces--skipJDKMethod跳过jdk方法trace,默认值true。默认情况下,trace不会包含jdk中的函数调用。如果要跟踪jdk中的函数,则需要显式设置--skipJDKMethodfalse。这个时候是无法追踪的,所以按照4个tips排查问题:https://github.com/alibaba/arthas/issues/47https://github.com/alibaba/arthas/issues/807最后,确定需要启用unsafe。optionsunsafetrue已启用。再次执行,可以看到jdk的调用链。至此,我们找到了rocketMQ控制台查询慢的罪魁祸首:获取本地网卡接口耗时过长。这其实是jdk和操作系统层面的意思,和rocketMQ中间件无关。一开始我怀疑是不是持久化存储加载的时候慢了(基本排除)。那么为什么调用当前操作系统的网卡接口会很耗时呢?这个时候我关注了java.net.NetworkInterface#getNetworkInterfacespublicstaticEnumerationgetNetworkInterfaces()throwsSocketException{finalNetworkInterface[]netifs=getAll();//specifiedtoreturnnullifnonetworkinterfacesif(netifs==null)returnnull;returnnewEnumeration(){privateinti=0;publicNetworkInterfacenextElement(){if(netifs!=null&&i