生產者發送訊息到雲訊息佇列 RocketMQ 版服務端時,雲訊息佇列 RocketMQ 版將根據生產者負載平衡策略將訊息均勻的儲存在多個隊列中,避免產生熱點隊列和效能瓶頸。本文介紹雲訊息佇列 RocketMQ 版生產者的負載平衡策略。
背景資訊
- 訊息發送的容災策略:您可以根據生產者負載平衡策略,明確當局部節點出現故障時,訊息發送如何進行容災切換。
- 訊息發送的順序性機制:通過生產者負載平衡策略,您可以進一步瞭解順序訊息發送時,如何保證相同訊息組內訊息的先後順序。
- Message Service能力的均衡性策略:瞭解生產者負載平衡策略,您可以知曉訊息在不同節點間分配的規律,您可以按照負載策略針對性地設計流量遷移和水平擴縮容的方案。
RoundRobin模式
使用範圍
對於非順序訊息(普通訊息、定時/延時訊息、事務訊息)情境,預設且只能使用RoundRobin模式的負載平衡策略。
策略原理:輪詢方式
RoundRobin模式下,生產者發送訊息時,以訊息為粒度,按照輪詢方式將訊息依次發送到指定主題中的所有可寫目標隊列中,保證訊息儘可能均衡地分布到所有隊列。

如上圖所示,M1、M2表示生產者發送的第一條訊息、第二條訊息,Queue1、Queue2、Queue3表示主題中的三個隊列。
生產者按照輪詢方式分別將訊息依次發送到這三個隊列中,M1發送至Queue1中、M2發送至Queue2中、M3發送至Queue3中,以此類推,第四條訊息M4又發送至Queue1中,迴圈往複。
異常處理
當發送某條訊息發送失敗時,雲訊息佇列 RocketMQ 版會根據失敗原因決定在接下來一段時間內,選擇隊列目標時跳過本地失敗隊列所在的節點,快速實現自適應的故障隔離。
策略特點
RoundRobin模式的生產者負載平衡策略僅適用於無順序性的訊息,該模式下是以訊息為粒度進行輪詢負載,因此訊息能夠儘可能實現均勻分布,使得主題的傳輸能力儘可能達到最大。
使用樣本
RoundRobin模式不需要額外設定,對於非順序類型的訊息預設啟用。
//普通訊息發送模式預設採用RoundRobin負載平衡策略。
//普通訊息發送。
MessageBuilder messageBuilder = null;
for (int i = 0; i < 10; i++) {
//普通訊息發送時無需用戶端額外設定,由SDK內建邏輯實現隊列輪詢和平均分配。
Message message = messageBuilder.setTopic("normalTopic")
//設定訊息索引鍵,可根據關鍵字精確尋找某條訊息。
.setKeys("messageKey")
//設定訊息Tag,用於消費端根據指定Tag過濾訊息。
.setTag("messageTag")
//訊息體。
.setBody("messageBody".getBytes())
.build();
try {
//發送訊息,需要關注發送結果,並捕獲失敗等異常。
SendReceipt sendReceipt = producer.send(message);
System.out.println(sendReceipt.getMessageId());
} catch (ClientException e) {
e.printStackTrace();
}
}
MessageGroupHash模式
使用範圍
對於順序訊息情境,預設且只能使用MessageGroupHash模式的負載平衡策略。
策略原理:Hash演算法
MessageGroupHash模式下,生產者發送訊息時,以訊息組為粒度,按照內建的Hash演算法,將相同訊息組的訊息分配到同一隊列中,保證同一訊息組的訊息按照發送的先後順序儲存。

如上圖所示,訊息G1-M1、G1-M2、G1-M3屬於訊息組1中的第一條訊息、第二條訊息和第三條訊息,生產者按照Hash演算法將這幾條訊息分配到同一隊列MessageQueue1中,且在隊列中儲存的先後順序和發送順序一致。
策略特點
MessageGroupHash模式的生產者負載平衡策略僅適用於順序性的訊息,可以很好地保證同訊息組內訊息的順序性。
但是若不同訊息組的訊息數量差異較大,MessageGroupHash模式將不能很好地保障訊息的均衡分配和效能擴充能力。在極端情境下,可能會出現大部分訊息集中在少數隊列中的情況,建議設計訊息組時盡量將訊息離散開,不要集中在少量訊息組中。
使用樣本
MessageGroupHash模式不需要額外設定,對於順序訊息類型預設啟用。
//順序訊息發送,預設採用MessageGroupHash模式負載平衡策略。
for (int i = 0; i < 10; i++) {
Message message = messageBuilder.setTopic("fifoTopic")
//設定訊息索引鍵,可根據關鍵字精確尋找某條訊息。
.setKeys("messageKey")
//設定訊息Tag,用於消費端根據指定Tag過濾訊息。
.setTag("messageTag")
//順序訊息情境需要設定MessageGroup,相同MessageGroup的訊息通過Hash演算法會被分配到同一個隊列。
.setMessageGroup("fifoGroupA")
//訊息體。
.setBody("messageBody".getBytes())
.build();
try {
//發送訊息,需要關注發送結果,並捕獲失敗等異常。
SendReceipt sendReceipt = producer.send(message);
System.out.println(sendReceipt.getMessageId());
} catch (ClientException e) {
e.printStackTrace();
}
}版本相容性
- MessageGroupHash模式
MessageGroupHash模式的負載平衡策略從雲訊息佇列 RocketMQ 版服務端5.x版本開始支援,歷史版本4.x/3.x版本不支援。
因此,若將順序訊息的發送機制從歷史4.x/3.x版本升級到5.x版本時,您需要自行保證訊息的順序性。例如,您可以將主題內的訊息消費完,再切換到新的5.x版本上。
- RoundRobin模式
RoundRobin模式的負載平衡策略服務端5.x版本和歷史版本4.x/3.x版本均支援,不涉及版本相容性。
使用建議
使用MessageGroupHash模式時,避免出現熱點隊列
MessageGroupHash模式下,雲訊息佇列 RocketMQ 版保證相同訊息組的訊息儲存在同一個隊列中。如果業務側將訊息都集中在少量或唯一的訊息組,則此時服務端儲存訊息時,也會集中儲存在少量或唯一的隊列中。極大增加了服務端的儲存壓力,導致出現隊列熱點,不利於主題處理能力的水平擴充。
因此,建議您在設計訊息組時,盡量將訊息分散開。例如,採用較離散的訂單ID、使用者名稱作為訊息組的關鍵字,既能保證訊息被分散到多個訊息組中,又能保證同一終端使用者的訊息按順序處理。
避免綁定單隊列發送
不管順序訊息還是非順序訊息,為了保證服務端效能的水平擴充和容災能力,建議都儘可能使用多個隊列,盡量避免負載平衡後只使用單個隊列。例如,若某主題只有一個隊列,則不管怎麼負載平衡,訊息也只能發送到這一個隊列中,單個隊列容易產生效能瓶頸及容災風險。