RocketMQ-记RocketMQ启动后producer无法连接到broker的错误及解决方案

    • 背景
    • 排查
    • 解决方案
    • 总结
    • 参考

背景

最近在学习RocketMQ,第一步就是安装部署并启动RocketMQ.使用最新版本的RocketMQ,版本为4.2.0,安装后启动相关服务.
启动nameServer:

nohup mqnamesrv &

由于brokernameServer在同一台机器上,启动broker:

nohup mqbroker -n localhost:9876 &

接下来运行producer的demo,但是在运行demo的过程中出现了问题,异常堆栈如下:

org.apache.rocketmq.client.exception.MQClientException: Send [3] times, still failed, cost [3004]ms, Topic: MQ-MSG-TOPICS-TEST, BrokersSent: [iZnqntg5t2znd7Z, iZnqntg5t2znd7Z, iZnqntg5t2znd7Z]
See http://rocketmq.apache.org/docs/faq/ for further details.
    at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendDefaultImpl(DefaultMQProducerImpl.java:544)
    at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1069)
    at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1023)
    at org.apache.rocketmq.client.producer.DefaultMQProducer.send(DefaultMQProducer.java:214)
    at core.RocketMQProducer.send(RocketMQProducer.java:44)
    at core.RocketMQProducerTest.main(RocketMQProducerTest.java:20)
Caused by: org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to <172.18.46.234:10909> failed
    at org.apache.rocketmq.remoting.netty.NettyRemotingClient.invokeSync(NettyRemotingClient.java:388)
    at org.apache.rocketmq.client.impl.MQClientAPIImpl.sendMessageSync(MQClientAPIImpl.java:351)
    at org.apache.rocketmq.client.impl.MQClientAPIImpl.sendMessage(MQClientAPIImpl.java:335)
    at org.apache.rocketmq.client.impl.MQClientAPIImpl.sendMessage(MQClientAPIImpl.java:298)
    at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendKernelImpl(DefaultMQProducerImpl.java:696)
    at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendDefaultImpl(DefaultMQProducerImpl.java:463)
    ... 5 more

现将问题的排查及解决方法记录如下.

排查

遇到这个问题后,根据异常信息知道是无法连接到172.18.46.234:10909.那么这个地址是nameServer的还是broker的呢?
在demo中配置的nameServer地址是阿里云服务器的公网地址,而且端口号是默认的9876,因此172.18.46.234:10909broker的地址,即producer尝试连接broker时失败.
后来发现172.18.46.234是我的阿里云服务器的内网地址,我们回忆下RocketMQ的工作流程:

  1. 启动nameServer
  2. broker启动时使用-n localhost:9876指定nameServer,将自己的IP地址注册到nameServer
  3. producer首先连接nameServer,获取可用的broker地址
  4. producer根据从nameServer获取的broker地址,将信息发送给broker

因此错误的原因是broker将自己内网地址发送给了nameServer,producernameServer获取的是broker的内网IP地址,自然无法连接broker.

解决方案

由上可知,只要broker将自己的外网地址注册到nameServer即可,查阅资料发现,broker注册到nameServer的地址可以使用参数配置,参数为brokerIP1brokerIP2(个人推测这两个IP应该一个是普通channel,一个是vip channel),但是如何在broker启动时设置这两个参数呢?

查看RocketMQ中org.apache.rocketmq.broker.BrokerStartup源码可知,broker启动选项如下:

短选项 长选项 是否必填 是否需要参数 参数是否可选 含义
n nameSrvAddr Name server address list, eg: 192.168.0.1:9876;192.168.0.2:9876
c configFile Broker config properties file
h help - Print help
p printConfigItem - Print all config item
m printImportantConfig - Print important config item

备注:

  1. 若选项需要参数,则参数是否可选为否时表示该选项后必须跟一个参数
  2. 若选项无需参数,则参数是否可选无意义

由上可知,启动broker时共有5个选项,比较常用的是-n-c,-n用于指定nameServer的IP地址及端口号,-c用于指定配置文件,同时nameServer的IP地址及端口号也可用nameSrvAddr在配置文件中设置,这样启动broker时就不用使用选项指定nameServer了.
RocketMQ在$ROCKETMQ_HOME/conf下提供了几个默认的配置文件,如2m-2s-async文件夹中提供了4个配置文件,分别是2个master和2个slave,且masterslave使用异步方式同步数据;而broker.conf提供了集群中只有一个master,无slave的配置文件,在配置文件中添加brokerIP1,brokerIP2,nameSrvAddr属性,内容如下:

brokerClusterName = DefaultCluster
brokerName = broker-a
brokerId = 0
deleteWhen = 04
fileReservedTime = 48
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
# brokerIP1和brokerIP2默认获取本地ip地址,在云服务器上会获取内网ip地址,因此必须显式设置
brokerIP1=*.*.*.*
brokerIP2=*.*.*.*
# 将namesrvAddr设置在configfile中
namesrvAddr=localhost:9876     

其中brokerIP1brokerIP2修改为自己云服务器的外网地址.
启动broker(假设当前工作目录为$ROCKETMQ_HOME/bin):

nohup mqbroker -c ../conf/broker.conf &

再次运行demo,即可成功向broker发送消息.

总结

brokernameServer注册的地址是brokerIP1,brokerIP2,

    @ImportantField
    private String brokerIP1 = RemotingUtil.getLocalAddress();
    private String brokerIP2 = RemotingUtil.getLocalAddress();

在阿里云服务器上获取的是内网IP地址,因此producernameServer获取的broker地址是broker的内网IP地址,无法向broker发送消息.
可以通过-c指定broker启动时的配置文件,在配置文件中添加brokerIP1brokerIP2属性,其值为阿里云服务器的外网IP地址,即可解决上述问题.
除此之外,RocketMQ还提供了-h,-p,-m用于打印帮助,打印配置项和打印重要配置项供用户参考.
还可将nameServer的地址通过nameSrvAddr属性写在配置文件中,这样启动时就无需通过-n设置nameServer地址.

参考

  • rocketmq官网quick-start

你可能感兴趣的:(RocketMQ)