原文:http://blog.csdn.net/lifetragedy/article/details/51869032
ActiveMQ的叢集
内嵌代理所引發的問題:
消息過載
管理混亂
如何解決這些問題——叢集的兩種方式:
Master slave
Broker clusters
ActiveMQ的叢集有兩種方式:
MASTER/SLAVE模式
Cluster模式
Pure Master Slave
Pure master slave的工作方式:
當master broker失效的時候。Slave broker 做出了兩種不同的相應方式
啟動network connectors和transport connectors
slave broker停止,slave broker隻是複制了master broker的狀态
在任何情況下我們都應該先嘗試連接配接master,故在用戶端我們這樣配置:
failover://(tcp://masterhost:61616,tcp://slavehost:61616)?randomize=false
Pure Master Slave具有以下限制:
隻能有一個slave broker連接配接到master broker。
在因master broker失效後slave才接管(保證消息完全拷貝)
要想恢複master,停止slave,拷貝slave中的資料檔案到master中,然後重新開機;
Master broker不需要特殊的配置。Slave broker需要進行以下配置:
...
Shared File System Master Slave
如果你使用共享檔案系統,那麼你可以使用Shared File System Master Slave。如下圖所示:
用戶端使用failover Transport 去連接配接 broker,例如:
failover:(tcp://broker1:61616,tcp://broker2:6161 7,broker3:61618)
…
其中/sharedFileSystem是檔案共享的系統檔案目錄
JDBC Master Slave
JDBC Master Slave的工作原理跟Shared File System Master Slave類似,隻是采用了資料庫作為持久化存儲
用戶端調用:
failover:(tcp://broker1:61616,tcp://broker2:616167,broker3:61618)
Broker clusters-靜态
Broker clusters ,網絡型中介(network of brokers)
連接配接到網絡代理的兩種方式:
靜态的方法配置通路特定的網絡代理
發現中介(agents)動态的探測代理
靜态網絡代理
Static:(uri1,uri2,uri3,…)?key=value 或是Failover:(uri1, … , uriN)?key=value
下面給出一個配置執行個體:
uri=”static://(tcp://remotehost1:61616,tcp://remotehost2:61616)”/>
幾種叢集對比
broker的叢集在多個broker之前fail-over和 load-balance,master-slave能fail-over,但是不能load- balance
消息在多個broker之間轉發,但是消息隻存儲在一個broker上,一旦失效必須重新開機,而主從方式master失效,slave實時備份消息。
jdbc方式成本高,效率低
master-slave方式中pure方式管理起來麻煩
是以,我們把MASTER/SLAVE和BROKER CLUSTER兩者相結合,可以得到一個完全解決方案:即又可以做到叢集又可以做到任何一個BROKER如果發生當機節點消息也不丢失。
Master/Slave叢集搭建-傳統式
一般activemq的Master Slave是基于KAHADB的阻塞來做的,先看一下原理
注意紅色加粗的地方,這是傳統的Master Slave的一個缺陷。這樣做太不安全了!
下面給出核心配置:
master配置(不要忘了改conf目錄下的jetty.xml檔案中的端口)
slave配置(不要忘了改conf目錄下的jetty.xml檔案中的端口)
把master conf 目錄中的jetty.xml中的端口改成8161
把slave conf 目錄中的jetty.xml中的端口改成8162
此時把master和slave先後啟動,其實你也可以不用管順序,誰先啟動誰會先把
中的db lock住,它就成了mater,而此時另一個執行個體會處于“pending”狀态。
當master當機後slave會自動啟動轉變為master。
當宕掉的master再次被啟動後然後變成slave挂載在原先的slave下面變成slave’
用戶端的通路代碼如下,隻要改spring中的配置,代碼層無需發動:
Master/Slave叢集搭建-基于ZooKeeper
搭個叢集,還要共享磁盤???見了鬼去了,這種方案肯定不是最好的!
是以,從ActiveMQ5.10開始出現了使用ZooKeeper來進行Master/Slave搭建的模式。
搭建時請務必注意下面幾個問題:
參于master slave組網的配置中
ActiveMQ至少需要3個執行個體(2N+1公式),隻要不符合2N+1,master slave叢集會發生叢集崩潰
Master/Slave叢集搭建-基于ZooKeeper搭建
搭建ZooKeeper,你可以搭建3個ZooKeeper執行個體也可以隻用1個,如果出于高可用性考慮建議使用3台ZooKeeper。
下載下傳ZK,我們在這邊使用的是“zookeeper-3.4.6”,把它解壓到Linux伺服器上,在其conf目錄下生成zoo1.cfg檔案 ,内容如下:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/opt/zk/data/1
clientPort=2181
#server.1=127.0.0.1:2887:3887
#server.2=127.0.0.1:2888:3888
#server.3=127.0.0.1:2889:3889
在ZK的data目錄下建立一個目錄,名為“1”,并在其下建立一個檔案,檔案名為“myid”并使其内容為1
如果你需要在本地搭建2N+1的ZooKeeper,那你必須依次在data目錄下建立2、3兩個檔案夾并且在每個檔案夾下都有一個myid的檔案,檔案的内容依次也為2,3,然後把下面注釋掉的3行server.1 server.2 server.3前的#注釋符放開。
是以data目錄下的目錄名和myid中的内容對應的就是server.x這個名字。
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/opt/zk/data/1
clientPort=2181
server.1=127.0.0.1:2887:3887
server.2=127.0.0.1:2888:3888
server.3=127.0.0.1:2889:3889
按照2N+1,你必須至少建立3個ActiveMQ執行個體。在搭建前我們先來看一下我們的叢集規劃吧
本例中,我們隻使用一個ZK節點,即2181端口來做MQ1-3的資料檔案共享。
核心配置
以下是傳統的Master/Slave配置
基于ZK的配置
directory="${activemq.data}/leveldb"
replicas="3"
bind="tcp://0.0.0.0:0"
zkAddress="192.168.0.101:2181"
zkPassword=""
hostname="ymklinux"
sync="local_disk"
/>
不要忘了,3個MQ執行個體的brokerName必須一緻,要不然你會在叢集啟動時出現:
Not enough cluster members when using LevelDB replication
這樣的錯誤。
或者在叢集啟動後當master當機slave被promote成master時發生叢集崩潰。
依次把3台mq執行個體均配置成replicatedLevelDB即可,在此配置中有一個zkPath,筆者使用的是預設配置。你也可以自行加上如:
directory="${activemq.data}/leveldb"
replicas="3"
bind="tcp://0.0.0.0:0"
zkAddress="192.168.0.101:2181"
zkPassword=""
hostname="ymklinux"
sync="local_disk"
zkPath="/activemq/leveldb-stores"
/>
lt;/persistenceAdapter>
網上所有教程都沒有說明這個zkPath到底是一個什麼東西,害得一堆的使用者以為這是一個目錄,以為用ZK做mq的叢集也需要“共享”一塊磁盤空間。
這個zkPath代表zookeeper内的“路徑”,即你運作在2181端口的zk内的“尋址節點”,類似于JNDI。如果你沒有這個zkPath,預設它在zk内的尋址節點為“/default”。加入到某一組master slave中的mq的執行個體中的zkPath必須完全比對。
這邊還有一個replicas=“3”的設定 ,這邊的數字指的就是ActiveMQ執行個體的節點數,它需要滿足2N+1,是以你也可以5台(1拖4)。
master slave一旦啟動後,在用戶端的配置就很簡單了,如下:
你可以如此實驗:
生産和消費分成兩個程式。
生産發一條消息,注意看console會輸出如“[INFO] Successfully reconnected to tcp://192.168.0.101:61616”
手工停止61616這台執行個體,然後你會發覺61617或者 是61618中有一台被promoted to master
然後運作consumer,consumer會連上被promoted的執行個體并繼續消費剛才那3條消息
是為。。。high available。
Master/Slave叢集搭建-Broker Cluster搭建
所謂cluster即負載勻衡,它負載的是“使用者”的請求,此處的使用者就是調用端
cluster的用法就是用來分散使用者的“并發”請求的。前面説過,ActiveMQ的Cluster有兩種:
動态式(multicast)
靜态式(static)
在實際應用場景中”靜态方式“被大量使用,動态式使用的是multicast即多點傳播式,基本已經被淘汰,是以我們主要基于靜态方式來做cluster講解。
Master/Slave叢集搭建-Broker Cluster搭建方式
核心配置
請維持各cluste節點間不同的持久化方式(你也可以使用kahadb,但不要做成和master slave一樣的排它鎖方式啊。
在61616中的配置
在61617中的配置
用戶端的配置
Master/Slave叢集搭建-Broker Cluster和Master Slave對比
優點
自動分發調用端請求
流量分散
缺點
當調用端連接配接上任意一個節點發送了一條消息,比如說往NODE A發送了一條消息。
此時消費端還沒來得及消費NODE A上的消息該節點就發生當機了。此時調用端因為有failover是以它會自動連上另一個節點(NODE B)而該節點上是不存在剛才“發送的消息”的,因為剛才發送到NODE A的消息隻在NODE A上,沒有同步到NODE B上。
因為隻有Master Slave會做主從間的消息同步,這是一個緻命傷。
具體實驗步驟:
send一條消息到cluster,并觀察send時連接配接的是哪個節點
直接把該節點程序殺掉
用消費端連上叢集
觀察消費端是否拿得到消息
魚與熊掌兼得法-完美解決方案
我們知道:
master/slave模式下,消息會被逐個複制
而cluster模式下,請求會被自動派發
那麼可不可以把兩者內建起來呢?答案是有的,網上所謂的獨創。。。統統是錯的!!對,因為我全試驗過了我敢這麼説,寫得都是些個啥呀。。。一個個還COPY不走樣,全錯了而且。
我這個才叫獨創,來看原理。
MASTER SLAVE+BROKER CLUSTER的搭建
我們使用ZK搭建MASTER SLAVE
我們使用BROKER CLUSTER把兩個“組”合并在一起
先來看下面的叢集規劃
MASTER SLAVE+BROKER CLUSTER的搭建-Group1的配置
由于這涉及到兩個組6個ActiveMQ的執行個體配置,如果把6個配置全寫出來是完全沒有必要的,是以我就把配置分成兩組來寫吧。每個組的配置對于其組内各個節點都為一緻的,除去那些個端口号。Group1的配置(保持6個執行個體中brokerName全部為一緻)
可以看到這邊的broker cluster的配置是用來確定每一台都可以和Group2中的各個節點保持同步
directory="${activemq.data}/leveldb"
replicas="3"
bind="tcp://0.0.0.0:0"
zkAddress="192.168.0.101:2181"
zkPassword=""
hostname="ymklinux"
sync="local_disk"
zkPath="/activemq/leveldb-stores/group1"
/>
MASTER SLAVE+BROKER CLUSTER的搭建-Group2的配置
可以看到這邊的broker cluster的配置是用來確定每一台都可以和Group1中的各個節點保持同步
directory="${activemq.data}/leveldb"
replicas="3"
bind="tcp://0.0.0.0:0"
zkAddress="192.168.0.101:2182"
zkPassword=""
hostname="ymklinux"
sync="local_disk"
zkPath="/activemq/leveldb-stores/group2"
/>
MASTER SLAVE+BROKER CLUSTER的搭建-用戶端
用戶端:
tcp://192.168.0.101:61617,
tcp://192.168.0.101:61618,
tcp://192.168.0.101:61619,
tcp://192.168.0.101:61620,
tcp://192.168.0.101:61621)" />
把6台執行個體全部啟動起來(乖乖,好家夥)
把用戶端寫上全部6台執行個體(乖乖,好長一陀)
MASTER SLAVE+BROKER CLUSTER的搭建-實驗
使用生産端任意發送3條消息。
生産端連上了61616,發送了3條消息,然後我們把61616所屬的activemq1的程序直接殺了
然後運作消費端,消費端連上了61618,消費成功3條消息
搞定了!
哈 哈 ,不要急,再重複一遍該實驗,來:
先把所有執行個體程序全部殺掉
把6台執行個體全部啟動起來(乖乖,好家夥)
把用戶端寫上全部6台執行個體(乖乖,好長一陀)
使用生産端任意發送3條消息。
生産端連上了61616,發送了3條消息,然後我們把61616所屬的activemq1的程序直接殺了
然後運作消費端,消費端連上了61620,控台顯示無任何消息消費
哈 哈 ,死慘了。。。作者滾粗。。。
為什麼 ?WHY?
所謂的完美方案并不是真正的完美方案-情況A
是的,以上的方案存在着這一漏洞!來看原理!
對于上述情況,當61616當機後,如果此時請求被failover到了group1中任意一個節點時,此時消費端完全可以拿到因為當機而未被消費掉的消費。
所謂的完美方案并不是真正的完美方案-情況B
對于上述情況,當61616當機後,如果此時請求被failover到了group2中任意一個節點時,此時因為group2中并未儲存group1中的任何消息,是以隻要你的請求被轉發到另一個group中,消費端是決無可能去消費本不存在的消息的。這不是有可能而是一定會發生的情況。因為在生産環境中,請求是會被自由随機的派發給不同的節點的。
我為什麼要提這個缺點、要否認之前的篇章? 我就是為了讓大家感受一下網上COPY複制還是錯誤資訊的博文的嚴重性,那。。。怎麼做是真正完美的方案呢。。。
如何讓方案完美
我們來看,如果我們把兩個group間可以打通,是不是就可以在上述情況發生時做到failover到group2上時也能消費掉group1中的消息了呢?
怎麼做?很簡單,其實就是一個參數
duplex=true
什麼叫duplex=true?
它就是用于mq節點間雙向傳輸用的一個功能,看下面的例子
這就是duplex的使用方法,我很奇怪,竟然這麼多人COPY 那錯的1-2篇博文,但是就是沒有提這個duplex的值,而且都設的是false。
duplex的作用就是mq節點1收到消息後會變成一個sender把消息發給節點2。
此時客戶如果連的是節點2,也可以消息節點1中的消息,是以我給它起了一個比英譯中更有現實意義的名稱我管它叫“穿透”。
下面來看用“穿透機制”改造的真正完美方案吧。
最終完美解決方案
考慮到消費端可能會發生:
當Group1中有未消費的資料時時,消費端此時被轉派到了Group2中的任意一個節點。
是以,在配置時需要進行如下的穿透:
按照這個思路我們在各Group中的各節點中作如下配置即可:
Group1中的配置
Group2中的配置
Group2中的每一個節點都不再需要來一句以下這樣的東西了:
因為,你設的是duplex=true,它相當于下面幾行的效果:
現在知道為什麼要duplex=true了吧!
驗證
先把所有執行個體程序全部殺掉
把6台執行個體全部啟動起來(乖乖,好家夥)
把用戶端寫上全部6台執行個體(乖乖,好長一陀)
使用生産端任意發送3條消息。
生産端連上了61619(屬于Group2),發送了3條消息,然後我們把61619所屬的activemq4的程序直接殺了
然後運作消費端,消費端連上了61616,控台顯示消費成功3條消息
大功告成!!!
結束語
從生産環境的高可用性來説,如果需要使用完美解決方案的話我們至少需要以下這些實體機
2台實體機
每台虛出3個子節點來(用VM),供3個MQ執行個體運作使用,2*3共為6個
并且一台實體機必須承載一個GROUP,同一個GROUP最好不要跨實體機或虛拟
2台實體機
每台虛出3個子節點來(用VM),供3個ZK 節點使用,2*3共為6個
并且一台實體機必須承載一個ZK GROUP,同一個ZK GROUP最好不要跨實體機或虛拟
同一台實體機上不得又安裝ZK又安裝MQ
上述是ActiveMQ Master Slave + Broker Cluster的最小化配置,為了得到更高的高可用性,建議6個MQ執行個體間全部需要有實體機承載。
但是,上述情況是用于應對百萬級并發消息的生産環境而言才需要如此大動幹戈,對于正常環境筆者建議:
搞兩台高配置的VM分散在兩台不同的實體機,做MASTER SLAVE即可,當然筆者強烈建議使用ZK做ActiveMQ的Master Slave,ZK可以用3個節點,分别來自3個不同的虛機(不是指在一個VM裡啟3個不同端口的ZK執行個體,而是來自于3台虛機),至于3台虛機是否在不同實體機上,這倒不是太大要求,因為在MASTER SLAVE中的ZK隻作節點資訊、消息同步使用,不會受太多并發通路之苦。
還有一種叢集方式留給大家自己去練習,很簡單,就是幾個節點間無MASTER SLAVE也隻做static Broker Cluster, 用的就是這個“穿透原理”。
比如說,我有5個節點,其中生産連着A和B,消費連着C、D、E,然後在A上對C、D、E做穿透,B也對C、D、E做穿透,用戶端隻對A和B做failover,這就構成了一個spoker機制。它也可以制作出一個MASTER SLAVE + Broker Cluster的模型來,然後producer對a,b進行監聽,而consumer failerover至c,d,e即可,這個架構不難,動一下手就會了。