RocketMQ原理解析-Producer

1.启动
    producer通过配置的namesrv列表,启动时随机选择一个进行相连。首先引出,设置namesrv的几种方式,优先级依次由高到低:
  • 第一种:代码中指定namesrv地址
  •       producer.setNamesrvAddr(namesrvAddr);
          consumer.setNamesrvAddr(namesrvAddr);
  • 第二种:Java启动参数中指定:
  •       -Drocketmq.namesrv.addr=192.168.0.1:9876
  • 第三种:环境变量
  •       NAMESRV_ADDR
  • 第四种为http方式获取。
  •       如果启动前未配置namesrv地址,那么每2分钟从http://jmenv.tbsite.net:8080/rocketmq/nsaddr以http的方式获取namesrv地址。Namesrv寻址可通过hosts文件从定向或者通过设置系统属性进行更改。
    原地址为http://" + WS_DOMAIN_NAME + ":8080/rocketmq/" + WS_DOMAIN_SUBGROUP。
    WS_DOMAIN_NAME对应启动参数rocketmq.namesrv.domain
    WS_DOMAIN_SUBGROUP对应启动参数rocketmq.namesrv.domain.subgroup。
        在3.2.4官方文档中,作者释迦也比较推荐通过http方式获取namesrv地址。好处就是客户端部署简单,并且namesrv可以热升级。

  producer启动后,定时每30s从namesrv更新topic的路由信息。设么意思?假如某个topic的队列从4个增加到8个,或者新增了broker且包含此topic,那么可以重新拿到topic的路由信息。Topic的路由信息有brokerName,queueId组成。定时30s清理下线broker及发送心跳和订阅关系。Producer的启动首先会和namesrv建立连接,然后拿到topic的路由信息后,当在发送消息时会和broker建立连接并将broker信息缓存本地。这里的清理下线broker指检查本地broker列表信息,如果此broker没有topic的路由信息,即从本地列表移除。

2.发送接口
public List<MessageQueue> fetchPublishMessageQueues(String topic)获取某个topic下的队列信息。
public SendResult send(Message msg)同步发送消息。
public void send(Message msg, SendCallback sendCallback)异步发送消息
public void sendOneway(Message msg)发送消息,无返回结果。
public SendResult send(Message msg, MessageQueue mq)同步发送消息到指定的队列
public void send(Message msg, MessageQueue mq, SendCallback sendCallback)异步发送消息到指定队列。
public void sendOneway(Message msg, MessageQueue mq)发送消息到指定队列,无返回值
public SendResult send(Message msg, MessageQueueSelector selector, Object arg, long timeout)通过指定的队列选择器同步发送消息,arg参数会回传给队列选择器。
public void send(Message msg, MessageQueueSelector selector, Object arg, SendCallback sendCallback)通过指定的队列选择器异步发送消息,arg参数会回传给队列选择器。
public long searchOffset(MessageQueue mq, long timestamp)根据时间获取某队列的offset
public long maxOffset(MessageQueue mq)获取队列的最大offset
public long minOffset(MessageQueue mq)获取队列的最小offset
public MessageExt viewMessage(String msgId)根据id获取消息信息
public QueryResult queryMessage(String topic, String key, int maxNum, long begin, long end)根据消息key获取消息。

    viewMessage和queryMessage有两点说明:
  • MQ会根据storehostaddress和offset来生成msgId,所以在集群下,可以通过msgId查询到消息。
  • MQ会根据topic和uniqKey以及topic和keys进行消息的索引构建,所以可以通过索引查询消息。

     
3.负载均衡
  默认,producer采用轮询的策略发送消息。Producer从namesrv更新到topic的路由信息后,根据queueId和brokerName组成发送列表。假如,名为test的topic有8个队列,0-7,那么和broker-a组成的发送列表为broker-a-0,broker-a1...broker-a7,然后依次轮训列表进行发送。

    public MessageQueue selectOneMessageQueue(final String lastBrokerName) {
        if (lastBrokerName == null) {
            return selectOneMessageQueue();
        } else {
            int index = this.sendWhichQueue.getAndIncrement();
            for (int i = 0; i < this.messageQueueList.size(); i++) {
                int pos = Math.abs(index++) % this.messageQueueList.size();
                if (pos < 0)
                    pos = 0;
                MessageQueue mq = this.messageQueueList.get(pos);
                if (!mq.getBrokerName().equals(lastBrokerName)) {
                    return mq;
                }
            }
            return selectOneMessageQueue();
        }
    }


4.发送的一些其他说明
 
  • 默认发送超时为3s。
  • 消息超过4k,即启用消息的压缩。
  • 发送失败,默认重发2次。
  • 消息最大限制为4M,即超过4M会提示发送失败。

5.注意
    在MQ内部,发送者是没有group的概念的。Group只是业务上的划分。Producer在启动时,会选择一个namesrv相连,通过topic关系找到broker,并和存有topic的所有master broker相连,也就是说,消息只会发到master的broker上去。

猜你喜欢

转载自technoboy.iteye.com/blog/2353663