RocketMQ:高可用性实施

在优锐课的java学习分享中,我们探索了RocketMQ的HA实现。我们可以看到,码了很多专业的相关知识, 分享给大家参考学习。

介绍

当我们谈论HA时,通常人们会想到故障转移机制。 但是,使群集可用于消息也被认为是HA。 在某种程度上,我认为这比仅提供经纪人更重要。 毕竟,用户可以并且将会感受到这种可用性的影响。

代码段

这是场景:
假设集群中有2个代理:master-a和master-b。 每个都有四个队列:master-a(q0,q1,q2,q3)和master-b(q0,q1,q2,q3)。 最后一条消息已发送给master-a q0。 现在,master-a退出了。

这里的目标是尽最大努力继续传递消息。
有两种可能性:

如果未检测到中断

在这种情况下,RocketMQ将重试3次:

org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl#sendDefaultImpl:
int timesTotal = communicationMode == CommunicationMode.SYNC ? 1 + this.defaultMQProducer.getRetryTimesWhenSendFailed() : 1;
for (; times < timesTotal; times++) {
    // ...
}

默认数字为三,并且是可配置的。 有三种发送机制:SYNC,ASYNC和ONEWAY。

如果已检测到中断

好。 现在的问题变成了:我们如何避免去掌握-a?
首先,我们需要设置sendLatencyFaultEnable = true,然后选择一个消息队列:

org.apache.rocketmq.client.impl.producer.TopicPublishInfo#selectOneMessageQueue:
public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final String lastBrokerName) {
   if (this.sendLatencyFaultEnable) {
     try {
      int index = tpInfo.getSendWhichQueue().getAndIncrement();
      for (int i = 0; i < tpInfo.getMessageQueueList().size(); i++) {
        int pos = Math.abs(index++) % tpInfo.getMessageQueueList().size();
        if (pos < 0)
          pos = 0;
        MessageQueue mq = tpInfo.getMessageQueueList().get(pos);
        if (latencyFaultTolerance.isAvailable(mq.getBrokerName())) {
          if (null == lastBrokerName || mq.getBrokerName().equals(lastBrokerName))
            return mq;
        }
      }
      final String notBestBroker = latencyFaultTolerance.pickOneAtLeast();
      int writeQueueNums = tpInfo.getQueueIdByBroker(notBestBroker);
      if (writeQueueNums > 0) {
        final MessageQueue mq = tpInfo.selectOneMessageQueue();
        if (notBestBroker != null) {
          mq.setBrokerName(notBestBroker);
          mq.setQueueId(tpInfo.getSendWhichQueue().getAndIncrement() % writeQueueNums);
        }
        return mq;
      } else {
        latencyFaultTolerance.remove(notBestBroker);
      }
    } catch (Exception e) {
      log.error("Error occurred when selecting message queue", e);
    }
    return tpInfo.selectOneMessageQueue();
  }
  return tpInfo.selectOneMessageQueue(lastBrokerName);
}

重要的部分是:
delayFaultTolerance.isAvailable(mq.getBrokerName()); (第13行)
在正常时间,发送消息时,它将调用updateFaultItem():

org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl#sendDefaultImpl
sendResult = this.sendKernelImpl(msg, mq, communicationMode, sendCallback, topicPublishInfo, timeout - costTime);
endTimestamp = System.currentTimeMillis();
this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false);

当发生中断时,将调用相同的方法:

endTimestamp = System.currentTimeMillis();
this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true);

incurrentLatency表示当前延迟,隔离是是否避免使用此代理的标志。即,传输成功后,请勿避免使用此代理。 否则请避免。

delaymax和notAvailableDuration算法中的两个核心变量。 如果发生故障,他们还决定startTimestamp的值。

从代码中,我们可以看到经纪人是否缺席,等待时间为30秒。 然后,我们将从下往上扫描latencyMax'' 直到找到一个小于currentLatency的数字。这是latencyMax’'和notAvailableDuration的默认值:

private long[] latencyMax = {50L, 100L, 550L, 1000L, 2000L, 3000L, 15000L};
private long[] notAvailableDuration = {0L, 0L, 30000L, 60000L, 120000L, 180000L, 600000L};

如果Isolation = true,则此代理将避免10分钟。 否则,它取决于消息的延迟。

FalutItem存储失败的代理的信息,包括其名称,延迟和避免开始的时间。

org.apache.rocketmq.client.latency.LatencyFaultToleranceImpl#updateFaultItem
public void updateFaultItem(final String name, final long currentLatency, final long notAvailableDuration) {
  FaultItem old = this.faultItemTable.get(name);
  if (null == old) {
    final FaultItem faultItem = new FaultItem(name);
    faultItem.setCurrentLatency(currentLatency);
    faultItem.setStartTimestamp(System.currentTimeMillis() + notAvailableDuration);
    old = this.faultItemTable.putIfAbsent(name, faultItem);
    if (old != null) {
      old.setCurrentLatency(currentLatency);
      old.setStartTimestamp(System.currentTimeMillis() + notAvailableDuration);
    }
  } else {
    old.setCurrentLatency(currentLatency);
    old.setStartTimestamp(System.currentTimeMillis() + notAvailableDuration);
  }
}

此类将更新失败的代理的状态。 并且还将决定是否恢复了代理并重新加入集群。 这是方法:

org.apache.rocketmq.client.latency.LatencyFaultToleranceImpl.FaultItem#isAvailable:

public boolean isAvailable() {
  return (System.currentTimeMillis() - startTimestamp) >= 0;
}

结论

到目前为止,我们已经检查了用于实现HA机制的主要代码块。 基本上,将尽最大努力来传递消息。 我们看到许多持续的轮询和重试。 这确实是企业级解决方案的现实。 通过显示此代码,我们想证明在确保集群的高可用性方面所做的努力。

喜欢这篇文章的可以点个赞,欢迎大家留言评论,记得关注我,每天持续更新技术干货、职场趣事、海量面试资料等等
如果你对java技术很感兴趣也可以加入我的java学习群 V–(ddmsiqi)来交流学习,里面都是同行,验证【CSDN2】有资源共享。
不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章