动态增减Namesrv机器
NameServer是RocketMQ集群的协调者,集群的各个组件是通过NameServer获取各种属性和地址信息的。
主要功能包括两部分:
1)一个各个Broker定期上报自己的状态信息到NameServer;
2)另一个是各个客户端,包括Producer、Consumer,以及命令行工具,通过NameServer获取最新的状态信息。
所以,在启动Broker、生产者和消费者之前,必须告诉它们NameServer的地址,为了提高可靠性,建议启动多个NameServer。NameServer占用资源不多,可以和Broker部署在同一台机器。有多个NameServer后,减少某个NameServer不会对其他组件产生影响。
有四种种方式可设置NameServer的地址,下面按优先级由高到低依次介绍:
1)通过代码设置,比如在Producer中,通过Producer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port")来设置。
在mqadmin命令行工具中,是通过-n name-server-ip1:port;name-server-ip2:port参数来设置的,如果自定义了命令行工具,也可以通过defaultMQAdminExt.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port")来设置。
2)使用Java启动参数设置,对应的option是rocketmq.namesrv.addr。
3)通过Linux环境变量设置,在启动前设置变量:NAMESRV_ADDR。
4)通过HTTP服务来设置,当上述方法都没有使用,程序会向一个HTTP地址发送请求来获取NameServer地址,默认的URL是http://jmenv.tbsite.net:8080/rocketmq/nsaddr (淘宝的测试地址),通过rocketmq.namesrv.domain参数来覆盖jmenv.tbsite.net;通过
rocketmq.namesrv.domain.subgroup参数来覆盖nsaddr。
第4种方式看似繁琐,但它是唯一支持动态增加NameServer,无须重启其他组件的方式。使用这种方式后其他组件会每隔2分钟请求一次该URL,获取最新的NameServer地址。
动态增减Broker机器
由于业务增长,需要对集群进行扩容的时候,可以动态增加Broker角色的机器。只增加Broker不会对原有的Topic产生影响,原来创建好的Topic中数据的读写依然在原来的那些Broker上进行。
集群扩容后,一是可以把新建的Topic指定到新的Broker机器上,均衡利用资源;另一种方式是通过updateTopic命令更改现有的Topic配置,在新加的Broker上创建新的队列。比如TestTopic是现有的一个Topic,因为数据量增大需要扩容,新增的一个Broker机器地址是192.168.0.1:10911,
这个时候执行下面的命令:sh./bin/mqadmin updateTopic-b 192.168.0.1:10911-t TestTopic-n 192.168.0.100:9876,结果是在新增的Broker机器上,为TestTopic新创建了8个读写队列。
mqadmin updateTopic -b <arg> | -c <arg> [-h] [-n <arg>] [-o <arg>] [-p <arg>] [-r <arg>] [-s <arg>] -t <arg> [-u <arg>] [-w <arg>]
[root@node1 ~]# mqadmin topicStatus -n localhost:9876 -t tp_demo_07
[root@node1 ~]# mqadmin updateTopic -b node2:10911 -t tp_demo_07 -n
'node1:9876;node2:9876' -w 8 -r 8
[root@node1 ~]# mqadmin topicStatus -n localhost:9876 -t tp_demo_07
如果因为业务变动或者置换机器需要减少Broker,此时该如何操作呢?减少Broker要看是否有持续运行的Producer,当一个Topic只有一个Master Broker,停掉这个Broker后,消息的发送肯定会受到影响,需要在停止这个Broker前,停止发送消息。
当某个Topic有多个Master Broker,停了其中一个,这时候是否会丢失消息呢?答案和Producer使用的发送消息的方式有关,如果使用同步方式send(msg)发送,在DefaultMQProducer内部有个自动重试逻辑,其中一个Broker停了,会自动向另一个Broker发消息,不会发生丢消息现象。如果使用异步方式发送send(msg,callback),或者用sendOneWay方式,会丢失切换过程中的消息。
因为在异步和sendOneWay这两种发送方式下,Producer.setRetryTimesWhenSendFailed设置不起作用,发送失败不会重试。DefaultMQProducer默认每30秒到NameServer请求最新的路由消息,Producer如果获取不到已停止的Broker下的队列信息,后续就自动不再向这些队列发送消息。
如果Producer程序能够暂停,在有一个Master和一个Slave的情况下也可以顺利切换。可以关闭Producer后关闭Master Broker,这个时候所有的读取都会被定向到Slave机器,消费消息不受影响。把Master Broker机器置换完后,基于原来的数据启动这个Master Broker,然后再启动Producer程序正常发送消息。
用Linux的kill pid命令就可以正确地关闭Broker,BrokerController下有个shutdown函数,这个函数被加到了ShutdownHook里,当用Linux的kill命令时(不能用kill-9),shutdown函数会先被执行。也可以通过RocketMQ提供的工具(mqshutdown broker)来关闭Broker,它们的原理是一样的。