資料來源
項目里大量用到了ActiveMQ集群配置,根據(jù)官網(wǎng)和網(wǎng)絡(luò)上資料的說法:當ActiveMQ面對大量消息存儲和大量Client交互時,性能消耗將會達到單個broker極限,此時我們需要對ActiveMQ進行水平擴展。ActiveMQ提供了“network”機制,可以把多個broker實例“串聯(lián)”一起,形成“Forward Bridge”模型(轉(zhuǎn)發(fā)橋)。這些Broker通過有向網(wǎng)絡(luò)(networkerConnector)鏈接在一起,組成broker集群,任何一個Borker都可以與Client數(shù)據(jù)交互,消息也將在Broker網(wǎng)絡(luò)中“流動”直到被消費,之所以“流動”,因為“producer”和“consumer”會與不同的broker建立鏈接,我們認為“轉(zhuǎn)發(fā)橋”架構(gòu)模式是“較大”集群數(shù)據(jù)的解決方案。
我們使用了非持久化訂閱,可是在實際使用中卻發(fā)現(xiàn)有時候出現(xiàn)了丟消息的情況,也就是生產(chǎn)者將消息發(fā)送到Broker A,消費者連接Broker B,可是A并沒有將消息轉(zhuǎn)發(fā)給B。
下午仔細看了看ActiveMQ的集群配置,希望可以找到解決方法。先整理一下關(guān)于集群的配置吧。項目中用到的配置為
<networkConnectors>
<networkConnector duplex="false" networkTTL="2" uri="static:(tcp://broker1:61616)"/>
</networkConnectors>
可支持的配置有:
dynamicOnly:用來表明connector是否只支持動態(tài)激活“durable訂閱者”,默認為false,表示networkConnector在創(chuàng)建成功后,將立即激活所有的“durable Topic”,即使本地沒有Topic的消費者(如果本地Broker已經(jīng)有消費者,肯定會激活),本地Broker也會創(chuàng)建一個“典型的”訂閱者,并將訂閱信息發(fā)送給remote Broker,此后remote Broker接收到的Topic消息也將轉(zhuǎn)發(fā)給本地Broker。如果為true,那么netwokrConnector將不會立即激活它們(本地沒有消費者的durable Topic),直到從“Advisory”通知獲取到激活消息(有Durable Consumer創(chuàng)建)時,才會做上述操作。它將對Durable Topic中消息在網(wǎng)絡(luò)中轉(zhuǎn)發(fā)的時機有重要影響。通常設(shè)定為false,以避免broker大面積失效時,Client遷移到那些尚沒有接收到任何“Advisory”的新Broker節(jié)點上;不過如果網(wǎng)絡(luò)比較穩(wěn)定,設(shè)定dymanicOnly為true,可以有效的提升Topic消息的轉(zhuǎn)發(fā)效率。該配置應(yīng)該對持久化訂閱生效,項目里不涉及。
decreaseNetworkConsumerPriority:是否降低網(wǎng)絡(luò)消費者(Queue)的權(quán)重,默認為false,即remote Broker中的Consumers與本地Consumer具有相同的權(quán)重(默認值=0,我們可以為每個消費者指定權(quán)重),消費者“權(quán)重”決定了它獲取消息的優(yōu)先級,較高權(quán)重的消費者將優(yōu)先消費消息。如果此值為true,那么remote Broker中的Consumer將具有最低的優(yōu)先級(-7),那么只有當Queue在Local Broker中沒有Consumer,或者所有的Consumers都滿負荷(prefetch Buffe已滿)時,才會將消息轉(zhuǎn)發(fā)給remote Broker中的Consumer。這是一種較好的調(diào)優(yōu)策略,不僅可以降低消息轉(zhuǎn)發(fā)的開支,而且還能較好的確保消息順序,通常我們設(shè)置為true,唯一的缺點就是不利于Queue consumers在全局范圍內(nèi)負載均衡。 (這個配置可以解決的問題:首先保證消息被當前broker上的consumer消費,只有當本地所有的消費者都繁忙時才轉(zhuǎn)發(fā)給remote broker上的consumer。)
可考慮配置一下試試networkTTL:消息和訂閱在網(wǎng)絡(luò)中轉(zhuǎn)發(fā)的最大生命周期,默認為1,即消息只會在網(wǎng)絡(luò)中轉(zhuǎn)發(fā)一次,訂閱也只會在網(wǎng)絡(luò)中傳播一次。消息在網(wǎng)絡(luò)中每轉(zhuǎn)發(fā)一次,都會將TTL-1,并且將當前的brokerId添加到路由信息中,當TTL=0或者當前brokerId已經(jīng)在路由表中(此broker已經(jīng)轉(zhuǎn)發(fā)過此消息,避免loop),那么消息將不會繼續(xù)轉(zhuǎn)發(fā)下去。通常此值小與broker節(jié)點的個數(shù),如果集群中brokers有回環(huán)網(wǎng)絡(luò),則建議為1,比如:A->B,B->C,C->A。(避免networkConnector是鏈狀,且有回環(huán)情況,良好的架構(gòu)下,應(yīng)該是星狀結(jié)構(gòu),即每個broker都與其他brokers建立連接,而不是鏈狀結(jié)構(gòu)--pipleline)。在我們的項目里,設(shè)置值為2,主要是因為設(shè)置為1時經(jīng)常發(fā)現(xiàn)出現(xiàn)集群無法轉(zhuǎn)發(fā)的問題。相關(guān)問題在AMQ的JIRA上也有split usage of networkTTL for mesh topology
懷疑這個配置我們配的有點問題。下周可以試驗一下把messageTTL設(shè)置為-1(無限循環(huán))試試duplex:網(wǎng)絡(luò)是否為雙向的,默認為false。如果為true,則remote Broker不僅是“訂閱者”,還可以作為消息的“生產(chǎn)者”,即remote Broker也會向Local Broker轉(zhuǎn)發(fā)消息。我們通常是,每個broker均與其他broker建立單向的networkConnector,比如有三個broker A/B/C,那么在A上配置2個單向的:A->B,A->C,那么在B上配置:B->A,B->C,以此論推。
alwaysSyncSend: 向remote Broker轉(zhuǎn)發(fā)消息時,是否總是同步發(fā)送。默認為false,即只對持久化消息采用同步發(fā)送;如果為true,那么對于非持久化消息也將采用同步發(fā)送。所謂同步發(fā)送,就是local Broker通過networkerConnector將消息發(fā)送給remote Broker后,阻塞并等到remote Broker返回ACK指令。這是消息存儲擔保的方式。我們使用默認值,這個配置對非持久化的topic訂閱不生效。
staticBridge:是否為“靜態(tài)”Bridge,默認false,即networkConnector可以通過Advisory通知來獲取Consumer的變更,并調(diào)整轉(zhuǎn)發(fā)策略。如果為true,那么broker將不關(guān)注任何Advisory(Consumer變更),只會使用“staticallyIncludeDestination”配置創(chuàng)建必要的訂閱。
未完待續(xù)