24.RocketMQ之动态增减NameServer

1,219 阅读2分钟

动态增减NameServer

一个消息队列集群由多台机器组成,持续稳定地提供服务,因为业务需求或硬件故障,经常需要增加或减少各个角色的机器,本节介绍如何在不影响服务稳定性的情况下动态地增减机器。

NameServer是RocketMQ集群的协调者,集群的各个组件是通过NameServer获取各种属性和地址信息的。

主要功能包括两部分:

1.各个Broker定期上报自己的状态信息到NameServer;

2.是各个客户端,包括Producer、Consumer,以及命令行工具,通过NameServer获取最新的状态信息。

所以,在启动Broker、生产者和消费者之前,必须告诉它们NameServer的地址,为了提高可靠性,建议启动多个NameServer。

NameServer占用资源不多,可以和Broker部署在同一台机器。有多个NameServer后,减少某个NameServer不会对其他组件产生影响。

有四种方式可设置NameServer的地址,下面按优先级由高到低依次介绍:

通过代码设置

比如在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")来设置。

使用Java启动参数设置

对应的option是rocketmq.namesrv.addr。

通过Linux环境变量设置

在启动前设置变量:NAMESRV_ADDR。

通过HTTP服务来设置

当上述方法都没有使用,程序会向一个HTTP地址发送请求来获取NameServer地址。

  public static String getWSAddr() {
        //jmenv.tbsite.net
        String wsDomainName = 
                    System.getProperty("rocketmq.namesrv.domain", 
                                                        DEFAULT_NAMESRV_ADDR_LOOKUP);
        //已硬编码为:nsaddr 
        String wsDomainSubgroup = 
                    System.getProperty("rocketmq.namesrv.domain.subgroup", "nsaddr");
      
       //http://jmenv.tbsite.net:8080/rocketmq/nsaddr
        String wsAddr = 
                    "http://" + wsDomainName + ":8080/rocketmq/" + wsDomainSubgroup;
        
        if (wsDomainName.indexOf(":") > 0) {
            wsAddr = "http://" + wsDomainName + "/rocketmq/" + wsDomainSubgroup;
        }
      
        return wsAddr;
    }

默认的URL是jmenv.tbsite.net:8080/rocketmq/ns…

通过rocketmq.namesrv.domain参数来覆盖jmenv.tbsite.net;

通过rocketmq.namesrv.domain.subgroup参数来覆盖nsaddr。

第4种方式看似繁琐,但它是唯一支持动态增加NameServer,无须重启其他组件的方式。

定时任务:MQClientInstance#startScheduledTask

使用这种方式后其他组件会每隔2分钟请求一次该URL,获取最新的NameServer地址。

推荐使用HTTP静态服务器寻址方式,好处是客户端部署简单,且Name Server集群可以热升级。

 private void startScheduledTask() {
        // http://jmenv.tbsite.net:8080/rocketmq/nsaddr
        // producer在初始化时通过向固定地址发送 httpGet请求,从而获得name server地址
        // 一般都是提前配置好 不存在动态增减的情况.
        //  因为是有个判断null == this.clientConfig.getNamesrvAddr() 才会启动这个定时任务
        // 2分钟更新一次nameServer的地址,该地址要求返回结果为一个ip列表,以;隔开
        // 如果获取回来的地址跟现有的地址不一致则会更新缓存的NameServer地址列表。      
        if (null == this.clientConfig.getNamesrvAddr()) {
            this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    try {
                        MQClientInstance.this.mQClientAPIImpl.fetchNameServerAddr();
                    } catch (Exception e) {
                        log.error("ScheduledTask fetchNameServerAddr exception", e);
                    }
                }
            }, 1000 * 10, 1000 * 60 * 2, TimeUnit.MILLISECONDS);
        }
 }