原文:
https://blog.csdn.net/zuolj/article/details/53116439
單純根據(jù)《ActiveMQ In Action(Manning-2011)》一書介紹的總結(jié),部分介紹可能已經(jīng)和官網(wǎng)不一弟胀。
一楷力、ActiveMQ的高可用性
ActiveMQ使用master-slave模式實現(xiàn)高可用性喊式,提供兩種實現(xiàn)主從模式的配置:shared nothing、shared storage(a relational database and a shared file system)
1.shared nothing master-slave
每一個broker(包括master和slave)都有自己的消息存儲區(qū)萧朝,這是最簡單的高可用性實現(xiàn)的辦法岔留。
master復(fù)制所有的消息指令給slave,復(fù)制的動作發(fā)生在master回復(fù)client消息已接收之前检柬。
slave broker會在啟動的時候去連接master献联,所以理想上,master broker應(yīng)該先啟動何址,slave broker 不會打開任何transports里逆,也就是說,slave broker不接收任何client請求和網(wǎng)絡(luò)連接用爪,除非master掛掉原押。slave通過檢測它與master之間的連接失敗而判定master掛掉。
shared nothing master-slave模式的處理過程:當一個生產(chǎn)者發(fā)送一個持久化消息到master之后偎血,master會復(fù)制該消息給slave诸衔,再返回接收應(yīng)答給生產(chǎn)者,生產(chǎn)者才能發(fā)送下一個消息烁巫。
當master broker掛掉后署隘,slave有兩個選擇:
1.關(guān)掉自己,因此亚隙,它只會保存master的狀態(tài)磁餐。
2.打開transports并且初始化所有的network connections,因此阿弃,該slave自動成為新的master诊霹。
如果slave broker成為新的master broker,所有的client可以通過failover機制去連接上新的master渣淳。在默認的client連接中脾还,failover傳輸機制皆可以連接到master和slave:
failover://(tcp://masterhost:61616,tcp://slavehost:61616)?randomize=false
不過,使用shared nothing master-slave也有限制入愧,如果client先連上master進行工作鄙漏,而slave還沒與master進行連接,master掛掉棺蛛,消息很可能會丟失怔蚌。ActiveMQ提供了一個waitForSlave屬性去設(shè)置master broker,強制master如果還沒與slave建立好連接旁赊,那么不會接受任何client的連接桦踊,另一個限制是,一個master只允許有一個slave终畅。
配置shared nothing master-slave
配置一個broker成為slave很簡單籍胯,配置一個masterConnector service:
<services>
<!--
remoteURI:master broker的監(jiān)聽地址
userName:Optional竟闪,如果master需要身份驗證
password:Optional,如果master需要身份驗證
-->
<masterConnector remoteURI="tcp://remotehost:62001" userName="" password=""/>
</services>
2.shared storage master-slave
share nothing master-slave模式下杖狼,每一個broker都獨自維護自己的storage炼蛤,而shared storage master-slave模式允許多個broker共享存儲,但同一個時刻只有一個broker是存活的本刽。shared storage master-slave的好處在于鲸湃,它確保了當master掛掉之后赠涮,無需手動干預(yù)去保持應(yīng)用的完整性子寓,另一個好處是,slave的數(shù)量不再有所限制笋除。
share nothing master-slave模式的配置有兩種:a relational database和file system-based storage.
shared database master-slave
當一個ActiveMQ broker使用關(guān)系型數(shù)據(jù)庫時斜友,它持有表的鎖以確保沒有其他broker同時訪問這個數(shù)據(jù)庫。多個broker同時運行并嘗試去訪問數(shù)據(jù)庫時垃它,只有第一個broker會連接成功并拿到鎖鲜屏,其他隨后到來的broker會一直poll直到它可以獲得鎖為止。這些處于polling狀態(tài)的broker国拇,被視為slave洛史,它們不會開啟任何傳輸連接或者網(wǎng)絡(luò)連接。
該配置中所有的broker可以使用同一份配置文件酱吝,這使得activemq啟動起來簡單得多也殖。
shared file system master-slave
它建議使用 KahaDB 消息存儲,但是對于消息存儲使用底層的共享的文件系統(tǒng)务热。當KahaDB消息存儲啟動時忆嗜,它將嘗試獲取文件鎖,以防止任何其他broker同時訪問基于文件的消息存儲崎岂。
二捆毫、ActiveMQ是如何在brokers之間傳遞消息
ActiveMQ中有一個概念:networks of brokers,它指的是連接ActiveMQ的消息代理在一起形成不同的拓撲結(jié)構(gòu)。
接下來就是分析brokers是如何在一個network中發(fā)現(xiàn)彼此且如何配置broker使其在network中合作等恐。
1.存儲和轉(zhuǎn)發(fā)(store and forward)
ActiveMQ的存儲和轉(zhuǎn)發(fā)概念意味著瘫析,消息在通過network轉(zhuǎn)發(fā)到其他broker之前,總是被存儲在本地broker中濒憋,也就是說,如果一條消息由于連接原因沒有被交付嫁审,比如說跋炕,正在重連,broker將能夠通過網(wǎng)絡(luò)連接將未交付的消息發(fā)送到遠程broker律适。默認情況下辐烂,network僅以單向方式操作遏插,如圖:
當然,這并不是說network只能單向操作纠修,如果想要雙向操作胳嘲,同樣可以在遠程broker中配置一個network connector指向本地的broker,或者直接指定創(chuàng)建的network connector為雙向duplex扣草。
當本地broker和遠程broker之間建立好一條network后了牛,遠程broker會將其所有持久和處于活動的消費者的目的地信息傳遞給本地broker,本地broker使用這些信息去判斷遠程broker對哪種消息感興趣辰妙,并轉(zhuǎn)發(fā)該類型消息給它鹰祸。
這里,書中舉了一個場景密浑,假如我們有多個超市需要連接到一個后臺辦公訂購系統(tǒng)蛙婴,這將很難靈活擴展新的超市,后臺辦公訂購系統(tǒng)不好掌控所有新加入的超市即遠程broker尔破。
給個圖示街图,這里想象超市和后臺之間有一個防火墻。(至于為什么這么想象懒构,我并不得知)注意到這里餐济,超市broker和back office之間的network是雙向的,超市broker的配置:
<networkConnectors>
<networkConnector uri="static://(tcp://backoffice:61617)"
name="bridge"
duplex="true"
conduitSubscriptions="true"
decreaseNetworkConsumerPriority="false">
</networkConnector>
</networkConnectors>
這里關(guān)于配置胆剧,主要注意一點是絮姆,配置的順序是很重要的,關(guān)于networks赞赖,persistence滚朵,transports的順序如下:
Networks——必須在消息存儲之前創(chuàng)建
Message store——必須在傳輸配置好之前配置完
Transports——必須在broker配置的最后
舉個例子:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://activemq.apache.org/schema/core">
<broker brokerName="receiver" persistent="true" useJmx="true">
<networkConnectors>
<networkConnector uri="static:(tcp://backoffice:61617)"/>
</networkConnectors>
<persistenceAdapter>
<kahaDB directory = "activemq-data"/>
</persistenceAdapter>
<transportConnectors>
<transportConnector uri="tcp://localhost:62002"/>
</transportConnectors>
</broker>
</beans>
來一張,在大型開發(fā)場景下的高可用性和network配置結(jié)合:
2.Network發(fā)現(xiàn)機制
ActiveMQ提供兩種發(fā)現(xiàn)機制:
Dynamic——使用組播和會合方式搜索brokers
Static——通過一個URI列表配置brokers
使用組播發(fā)現(xiàn)的方式去創(chuàng)建network連接是最簡單粗暴的前域,當你啟動一個broker時辕近,它會通過組播IP去搜索其他的broker并創(chuàng)建network連接。配置方式如下:
<networkConnectors>
<networkConnector uri="multicast://default"/>
</networkConnectors>
這里“default”表示這個broker屬于哪個組匿垄,建議使用唯一的名字去標識移宅,以免你的broker連接到其他你不知道的應(yīng)用代理上。
組播發(fā)現(xiàn)機制有一些限制椿疗,比如說不能控制哪些broker被發(fā)現(xiàn)漏峰,事實上,它通常局限于本地網(wǎng)段上去發(fā)現(xiàn)其他broker届榄,因為組播IP不通過路由器延伸浅乔。
關(guān)于第二種方式,static,事實上靖苇,在這之前的配置一直都是static席噩,只不過broker的URL列表有點少而已,
<networkConnectors>
<networkConnector uri="static:(tcp://remote-master:61617,tcp://remote-slave:61617)"/>
</networkConnectors>
static的配置屬性:
3.Network配置
對于遠程broker現(xiàn)存在的目的地贤壁,可能沒有任何活動持久的訂閱者或消費者悼枢,因此,當network初始化連接到遠程broker時脾拆,遠程broker會讀取它現(xiàn)存目的地的消息馒索,并傳遞給本地broker,然后名船,本地broker也可以轉(zhuǎn)發(fā)那些目的地的消息绰上。
重要的是要注意,一個network將使用broker的名稱來代表遠程broker創(chuàng)建唯一的持久預(yù)訂代理包帚。 因此渔期,如果在稍后的時間點更改broker的名稱运吓,很可能會通過network丟失持久主題訂閱者的消息渴邦。 為避免這種情況,請確保為元素上的brokerName屬性使用唯一的名稱拘哨。 有關(guān)簡要示例谋梭,請參閱以下內(nèi)容:
<broker xmlns="http://activemq.apache.org/schema/core/"
brokerName="brokerA"
dataDirectory="${activemq.base}/data">
...
<networkConnectors>
<networkConnector name="brokerA to brokerB" uri="tcp://remotehost:61616"/>
</networkConnectors>
</broker>
關(guān)于Network配置還有很多,不一一列舉了倦青。
三瓮床、為大量并發(fā)應(yīng)用程序部署ActiveMQ
擴展使用ActiveMQ的應(yīng)用程序可能需要一些時間,需要一些努力产镐。 在本節(jié)中隘庄,將介紹三種技術(shù)來幫助完成此任務(wù)。首先是垂直擴展癣亚,單個broker用于數(shù)千個連接和隊列丑掺。然后將通過使用network水平擴展應(yīng)用程序來擴展到數(shù)萬個連接。 最后述雾,將研究流量分區(qū)街州,這將平衡擴展和性能,但會增加ActiveMQ應(yīng)用程序的復(fù)雜性玻孟。
1.垂直擴展
垂直擴展是一種用于增加單個ActiveMQ broker可以處理的連接數(shù)(因此增加負載)的技術(shù)唆缴。默認情況下,ActiveMQ broker設(shè)計為盡可能高效地移動消息黍翎,以確保低延遲和良好的性能面徽。但是我們可以做一些配置調(diào)整,以確保ActiveMQ broker可以處理大量的并發(fā)連接和大量的隊列匣掸。
默認情況下趟紊,ActiveMQ將使用阻塞I/O來處理傳輸連接质礼。 這導(dǎo)致每個連接使用一個線程。 我們可以在ActiveMQ broker上使用非阻塞I/O(而客戶端上仍然使用默認傳輸)來減少使用的線程數(shù)织阳。broker的非阻塞I/O配置如下:
<broker>
<transportConnectors>
<transportConnector name="nio" uri="nio://localhost:61616"/>
</transportConnectors>
</broker>
除了每個連接使用一個線程來阻塞I/O外眶蕉,ActiveMQ broker可以使用線程為每個客戶端連接分派消息∵蠖悖可以通過將名為org.apache.activemq.UseDedicatedTaskRunner的系統(tǒng)屬性設(shè)置為false造挽,讓ActiveMQ使用線程池。
ACTIVEMQ_OPTS="-Dorg.apache.activemq.UseDedicatedTaskRunner=false"
1
確保ActiveMQ broker具有足夠的內(nèi)存來處理大量并發(fā)連接有兩步過程弄痹。
首先饭入,需要確保啟動ActiveMQ broker的JVM配置了足夠的內(nèi)存。
ACTIVEMQ_OPTS="-Xmx1024M -Dorg.apache.activemq.UseDedicatedTaskRunner=false"
1
第二肛真,確保專門為ActiveMQ broker在JVM配置適當?shù)膬?nèi)存量谐丢。此調(diào)整通過< system-Usage >元素的limit屬性進行。(最好從512MB開始蚓让,如果測試不夠再往上加)乾忱,配置示例:
<systemUsage>
<systemUsage>
<memoryUsage>
<memoryUsage limit="512 mb"/>
</memoryUsage>
<storeUsage>
<storeUsage limit="10 gb" name="foo"/>
</storeUsage>
<tempUsage>
<tempUsage limit="1 gb"/>
</tempUsage>
</systemUsage>
</systemUsage>
還應(yīng)該降低每一個連接的CPU負載,如果使用的OpenWire連接方式历极,禁用緊密編碼窄瘟,否則會使得CPU過度緊張。
String uri = "failover://(tcp://localhost:61616?" + " wireFormat.tightEncodingEnabled=false)";
ConnectionFactory cf = new ActiveMQConnectionFactory(uri);
前面研究的是broker怎么調(diào)整去處理數(shù)千個連接趟卸,下面開始研究的是怎么調(diào)整broker去處理數(shù)千個隊列蹄葱。
默認隊列配置使用單獨的線程來將消息從消息存儲區(qū)分頁到隊列中,以便分發(fā)給感興趣的消息消費者锄列。 對于大量隊列图云,建議通過為所有隊列啟用optimize-Dispatch屬性來禁用此功能,
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry queue=">" optimizedDispatch="true"/>
</policyEntries>
</policyMap>
</destinationPolicy>
為了確保不僅可以擴展到數(shù)千個連接邻邮,而且還可以擴展到數(shù)萬個隊列竣况,使用JDBC消息存儲庫或更新和更快的KahaDB消息存儲庫。 KahaDB默認情況下在ActiveMQ中啟用饶囚。
到目前為止帕翻,我們已經(jīng)考慮了擴展連接,減少線程使用萝风,并選擇正確的消息存儲嘀掸。 調(diào)整用于擴展的ActiveMQ的示例配置如以下:
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="amq-broker" dataDirectory="${activemq.base}/data">
<persistenceAdapter>
<kahaDB directory="${activemq.base}/data" journalMaxFileLength="32mb"/>
</persistenceAdapter>
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry queue=">" optimizedDispatch="true"/>
</policyEntries>
</policyMap>
</destinationPolicy>
<systemUsage>
<systemUsage>
<memoryUsage>
<memoryUsage limit="512 mb"/>
</memoryUsage>
<storeUsage>
<storeUsage limit="10 gb" name="foo"/>
</storeUsage>
<tempUsage>
<tempUsage limit="1 gb"/>
</tempUsage>
</systemUsage>
</systemUsage>
<transportConnectors>
<transportConnector name="openwire" uri="nio://localhost:61616"/>
</transportConnectors>
</broker>
2.水平擴展
除了擴展單個broker之外,還可以使用networks來增加可用于應(yīng)用程序的ActiveMQ broker的數(shù)量规惰。 由于networks會自動將消息傳遞給具有感興趣的消費者的連接broker睬塌,因此可以將客戶端配置為連接到一個broker集群,隨機選擇一個來連接。
failover://(tcp://broker1:61616,tcp://broker2:61616)?randomize=true
為了確保隊列或持久主題訂閱者的消息不會在broker上孤立揩晴,需要將network配置為使用dynamicOnly和低網(wǎng)絡(luò)prefetchSize勋陪。
<networkConnector uri="static://(tcp://remotehost:61617)"
name="bridge"
dynamicOnly="true"
prefetchSize="1">
</networkConnector>
使用network進行水平擴展會帶來更多的延遲,因為潛在的消息必須在分發(fā)給消費者之前通過多個broker硫兰。
另一種替代部署提供了巨大的可擴展性和性能诅愚,但需要更多的應(yīng)用規(guī)劃。 這種混合解決方案稱為流量分區(qū)劫映。
3.流量分區(qū)
客戶端流量分割是垂直和水平分割的混合违孝。 通常不使用network,因為客戶端應(yīng)用程序決定什么流量應(yīng)該到哪個broker上泳赋。 客戶端應(yīng)用程序必須維護多個JMS連接雌桑,并決定哪些JMS連接應(yīng)用于哪些目標。
不直接使用network connection的優(yōu)點是祖今,減少在brokers之間轉(zhuǎn)發(fā)消息的開銷校坑。 需要平衡這與導(dǎo)致典型應(yīng)用程序的額外復(fù)雜性。Fig10.8是流量分區(qū)的一個使用代表: