在优锐课的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】有资源共享。
不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代