在優銳課的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】有資源共享。
不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代