![]() |
下面,咱們再看看ActiveMQ是如何實現高可用的。數據庫
ActiveMQ實現高可用有兩類方案:編程
第一類方案是構建服務器網絡,消息在服務器網絡中進行傳遞,客戶端經過failover或discovery鏈接網絡中的一個服務器發送或接收消息,當服務器失效時,客戶端自動重連另外一個服務器。安全
第二類方案是構建服務器主從集羣,在某個時間只有一個服務器做爲主對外提供服務,當主服務器失效時,從服務器切換成主服務器對外提供服務,客戶端自動重連至新的主服務器。服務器
MasterSlave有4種具體實現方案,下面將介紹一下前3種,第4種在官網上已有介紹,是基於HahaDBA和Zookeeper的,但目前還不支持該功能。網絡
![]() |
PureMaster Slave須要兩個啓動兩個ActiveMQbroker,主broker不須要作額外配置,從broker中須要做以下配置,在其中設定主broker的鏈接,這樣在從broker啓動後,會創建與主broker的鏈接,並對主broker的消息進行同步。當主broker失敗時,從broker自動切換成主broker。併發
另外,在使用PureMaster Slave時,須要客戶端使用failover方式鏈接ActiveMQbroker,並設定randomize的值爲false,這樣,客戶端在鏈接主broker失敗後,會自動嘗試鏈接從broker。負載均衡
PureMaster Slave配置簡單,易於實現,以前是ActiveMQ比較推薦的高可用解決方案,但在Pure Master Slave中,消息傳送必須通過主、從服務器的確認,另外Pure Master Slave還存在如下不足:dom
1)主服務器只能有一個從服務器;ide
2)主服務器失敗重啓後,還必須重啓從服務器才能恢復主服務器;插件
3) 主、從服務器之間沒有自動同步機制。
咱們在實踐中也遇到過由沒有自動同步機制致使的問題:有一次使用中咱們建立持久訂閱者鏈接服務器,開始時,持久訂閱者的狀態在主從上是同步的,均爲活躍,但在作了一次重啓從服務器的操做後,從服務器中原先活躍的持久訂閱者變動爲了非活躍,與主服務器狀態不一致,因此發往主從的消息因爲從服務器上訂閱者爲非活躍狀態不消費形成消息阻塞。
因爲PureMaster Slave具備以上不足,所以在ActiveMQ5.8.0版本中已去掉了該功能。
![]() |
使用基於JDBC的Master Slave時,多個消息服務器實例嘗試獲取數據庫排他鎖(exclusive lock),只有一個成功獲取鎖,對外提供服務,成爲主服務器,其餘等待。
客戶端鏈接採用failover方式,從多個地址中找到當前可用的消息服務器實例並鏈接。
當Master失去排他鎖或失去數據庫鏈接時,Master將會關閉,其餘服務器實例經過競爭,由一個實例獲取鎖成爲新Master,客戶端經過failover從新鏈接至新Master。
原Master在從新啓動後成爲Slave等待鎖。
SharedFile System MasterSlave的實現原理與JDBCMaster Slave相似,多個服務器共用一個存儲消息的文件系統(SAN);須要確認文件系統存在文件讀寫鎖,獲取讀寫鎖的服務器自動成爲主服務器,直至失敗放棄讀寫鎖;客戶端也是使用failover進行鏈接。
![]() |
下面是關於ActiveMQ的安全機制。
ActiveMQ的安全機制包括兩部分:
驗證,經過訪問者的用戶名和密碼實現用戶身份的驗證;
受權,爲消息目標(隊列或主題)的讀、寫、管理指定具備相應權限的用戶組,併爲用戶分配權限。
ActiveMQ的安全機制基於插件實現,能夠靈活配置。
ActiveMQ提供兩種驗證插件,分別是:
1)簡單驗證插件;
2)JAAS驗證插件。
ActiveMQ提供一種受權插件。
![]() |
以上是簡單驗證和JAAS驗證插件的配置示例,均須要配置用戶名、用戶組和密碼。
設置插件後,在建立鏈接時,須要輸入帳號和密碼。
connectionFactory.createConnection(「user」,」password」);
![]() |
以上是受權插件的配置示例,能夠設置某一個隊列、主題或某一類隊列、主題的讀、寫、管理權限組。
![]() |
下面再經過簡單驗證插件源碼介紹一下ActiveMQ的插件機制以及驗證是如何實現的
ActiveMQ的插件機制如圖所示,主要涉及BrokerPlugin和BrokerFilter這兩個接口和類。
BrokerPlugin中的installPlugin方法用於安裝插件,在installPlugin方法中會傳入Broker對象,而BrokerFilter是Broker的實現,在BrokerFilter中包含着一個對Broker的引用next,能夠在installPlugin方法中,新建BrokerFilter對象,並將installPlugin方法傳入Broker對象賦值給next,這樣多個BrokerFilter對象就經過next引用造成鏈。這與struts中Interceptor的原理是相似的。
對於簡單驗證插件,在SimpleAuthenticationBroker類中,重寫了BrokerFilter的addConnnection方法,在新建鏈接時,若容許匿名訪問,則不進行驗證,若不容許匿名訪問,則驗證鏈接的用戶名和密碼是否與配置文件中的一致,若不一致,則拋出安全異常。
![]() |
通知信息機制是ActiveMQ服務器經過發佈特定的通知消息記錄服務器和客戶端的操做日誌,便於系統監控。另外,ActiveMQ服務器網絡之間的通訊也是基於通知消息的。
發送通知消息的操做有:
消費者、生產者和鏈接的建立和關閉;
隊列、主題的建立和銷燬;
消息的過時;
消息發送至無消費者的目的地址。
通知消息發佈至相應的主題上,通知消息的主題有兩類:
第一類是基於客戶端的主題,包括鏈接、生產者、消費者的建立和關閉,例如鏈接的建立和關閉消息發佈在Connection主題上;
第二類是基於目的地址和消息的主題,包括隊列、主題的建立和銷燬,消息的過時等,例如,隊列、主題的建立和銷燬消息發佈至Queue和Topic主題上。
![]() |
這一頁介紹一下有關排他消費者和消息組的相關概念。
對於隊列,當有多個消費者時,消息服務器將把消息平均地發送給每一個消費者,實現負載均衡,可是多個消費者接收、處理消息時並不會在線程上同步,這就致使消息在併發處理時,沒法保證消息原有的順序。
排他消費者(Exclusive Consumer)是在多消費者狀況下,消息服務器指定一個消費者接收消息,這樣能夠保證消息的有序性。其餘消費者處於等待狀態。
當原先指定的消費者沒法接收消息時,消息服務器將從等待的消費者中再指定一個消費者接收消息。
排他消費者能夠在多個消費者的狀況下,保證消息的有序性,且在單個消費者故障時,可以保證消息繼續被消費,但因爲每次只有一個消費者消費消息,形成吞吐量低,其餘消費者的資源浪費。
使用消息組(message group)能夠避免排他消費者的不足。
消息組是指經過設定消息的JMSXGroupID屬性來爲消息進行分組,而同一組消息將被髮送至同一個消費者進行處理,所以能夠保證在多消費者狀況下,消息可以有序處理。
![]() |
以前咱們討論過,對於主題,若訂閱者不鏈接,則存在消息丟失,若須要保證消息所有接收,則須要建立持久訂閱者,但對於持久訂閱者,因爲其須要指定ClientID,所以只能保證同一個ClientID只有一個消費者、一個線程訪問主題,這就致使如下兩個問題:
沒法實現消息消費的負載均衡;
消費者失敗時,不能由其餘的消費者恢復。
如何同時既能實現主題的特性,同一個消息由多個消費者消費,也能實現隊列的特性,多消費者實現負載均衡?能夠經過使用虛主題解決上述問題。
虛主題以VirtualTopic.主題名的形式命名,當配置虛主題後,ActiveMQ能夠將該主題映射到以Consumer.隊列名.VirtualTopic.主題名的形式命名的隊列上,消息生產者仍將消息發送至主題,而ActiveMQ會將消息再轉發至隊列上,消息消費者經過使用隊列接收來自主題的消息,這樣就能夠啓動多個消費者,實現負載均衡。
虛主題的配置以下所示。
![]() |
ActiveMQ支持除Java之外的多種語言,包括C/C++,.NET,Perl,PHP,Python,Ruby等,對於腳本語言,通常採用STOMP協議鏈接ActiveMQ。
STOMP是一種相似於HTTP的協議,支持命令有:SEND,SUBSCIRBE,UNSUBSCRIBE等,在使用STOMP鏈接ActiveMQ時,首先須要在ActiveMQ配置STOMP鏈接,一般通常佔用61613端口。
如下分別是Python和PHP使用STOMP鏈接消息服務器並接收主題消息的示例代碼。
對於C,ActiveMQ提供C++ API和.NET API,對於Web編程,ActiveMQ提供RESTAPI和AjaxAPI,你們有興趣能夠去嘗試一下。
![]() |
在使用消息服務器時,有時候咱們不但願ActiveMQ在單獨的JVM中運行,而是集成在已有的Java應用中。
在Java應用中嵌入ActiveMQ服務器有以下幾種方法:
建立BrokerService實例;
使用BrokerFactory方法建立BrokerService實例。
![]() |