您好,登錄后才能下訂單哦!
目前很多互聯網公司的系統都在朝著微服務化、分布式化系統的方向在演進,這帶來了很多好處,也帶來了一些棘手的問題,其中最棘手的莫過于數據一致性問題了。早期我們的軟件功能都在一個進程中,數據的一致性可以通過數據庫本地事務來加以控制。而在分布式架構下,原本比較完整的本地功能可能被拆分成了多個獨立的服務進程。與之前相比,同樣一筆業務訂單此時可能會經歷很多服務模塊的處理,調用鏈路會變得很長,例如某電商平臺,一筆購物訂單可能會經過:商品中心、訂單、支付、物流等多個服務的調用,而這可能還只是比較粗粒度的劃分,某些比較大型的服務,如支付系統,可能本身又會按照分布式的架構拆分成多個微服務,所以整個業務的調用鏈路會變得更加冗長。
而這不可避免的就會產生數據不一致的問題,為了實現業務上的最終一致性,然后功能比較獨立的系統,如訂單系統與支付系統就會通過額外的業務邏輯設計來確保彼此之間的最終一致性,如訂單系統會通過訂單的支付狀態來保持與支付系統的數據一致,而支付系統則會提供支付狀態查詢接口,或者實現最大可能的主動回調功能,來確保二者數據狀態的最終一致。此外可能還會通過日終的訂單對賬來發現不一致的數據,并進行數據校正。
但是這些都只是業務邏輯上的手段,對于某些內部服務之間的調用,如果可以通過分布式事務解決方案來加以保證的話,其實是可以大大減少一些不必要的復雜業務邏輯的。實際上,目前市面上能夠提供分布式事務解決方案、又比較成熟的開源技術框架比較少,而RocketMQ在4.3.0之后的版本提供了事務消息的功能,因為RocketMQ本身擁有比較多的生產實踐的關系,所以這一功能備受關注,作者所在的公司也有一些實踐。
以此為契機,為了給大家關于分布式事務一個比較清晰的認識,這里我打算以RocketMQ的事務消息功能為示例,來相對全面的總結下分布式事務的內容。本篇文章的主要內容,是先介紹如何搭建一套生產級的RocketMQ消息集群,以此準備下試驗環境。
RocketMQ是阿里開源的并貢獻給Apache基金會的一款分布式消息平臺,它具有低延遲、高性能和可靠性、萬億級容量和靈活的可伸縮性的特點,單機也可以支持億級的消息堆積能力、單機寫入TPS單實例約7萬條/秒,單機部署3個Broker,可以跑到最高12萬條/秒。
基于以上強大的性能,以及阿里的技術影響力,RocketMQ目前在國內互聯網公司中被使用得比較廣泛。那么,我們先大概來了解一下RocketMQ的整體結構吧!
整個RocketMQ消息系統主要由如下4個部分組成:
從中間件服務角度來看整個RocketMQ消息系統(服務端)主要分為:NameSrv和Broker兩個部分。
NameSrv:在RocketMQ分布式消息系統中,NameSrv主要提供兩個功能:
提供服務發現和注冊,這里主要是管理Broker,NameSrv接受來自Broker的注冊,并通過心跳機制來檢測Broker服務的健康性;
提供路由功能,集群(這里是指以集群方式部署的NameSrv)中的每個NameSrv都保存了Broker集群(這里是指以集群方式部署的Broker)中整個的路由信息和隊列信息。這里需要注意,在NameSrv集群中,每個NameSrv都是相互獨立的,所以每個Broker需要連接所有的NameSrv,每創建一個新的topic都要同步到所有的NameSrv上。
Broker:主要是負責消息的存儲、傳遞、查詢以及高可用(HA)保證等。其由如下幾個子模塊(源碼總體上也是這么拆分的)構成:
而從客戶端的角度看主要有:Producer、Consumer兩個部分。
*Producer:消息的生產者,由用戶進行分布式部署,消息由Producer通過多種負載均衡模式發送到Broker集群,發送低延時,支持快速失敗。
Consumer:消息的消費者,也由用戶部署,支持PUSH和PULL兩種消費模式,支持集群消費和廣播消息,提供實時的消息訂閱機制,滿足大多數消費場景。
來總結下,整個RocketMQ消息集群就是由NameSrv/Broker、Producer/Consumer組成的。為了讓大家更清晰的理解它們之間的關系,我們以一條完整的信息流轉為例,來看看RocketMQ消息系統是如何運轉的,如下圖所示:
看到這里相信大家應該對RocketMQ有一個大致的了解了,那么下面我們就具體看看,如何搭建一套生產級的RocketMQ消息集群系統吧!
RocketMQ集群部署有多種模式,對于NameSrv來說可以同時部署多個節點,并且這些節點間也不需要有任何的信息同步,這里因為每個NameSrv節點都會存儲全量路由信息,在NameSrv集群模式下,每個Broker都需要同時向集群中的每個NameSrv節點發送注冊信息,所以這里對于NameSrv的集群部署來說并不需要做什么額外的設置。
而對于Broker集群來說就有多種模式了,這里我先給大家介紹下這幾種模式,然后我們再來看看生產級的部署方式是什么:
1)、單個Master模式
一個Broker作為主服務,不設置任何Slave,很顯然這種方式風險比較大,存在單節點故障會導致整個基于消息的服務掛掉,所以生產環境不可能采用這種模式。
2)、多Master模式
這種模式的Broker集群,全是Master,沒有Slave節點。這種方式的優缺點如下:
優點:配置會比較簡單一些,如果單個Master掛掉或重啟維護的話對應用是沒有什么影響的。如果磁盤配置為RAID10(服務器的磁盤陣列模式,遺忘的同學可以自己查下資料)的話,即使在機器宕機不可恢復的情況下,由于RAID10磁盤本身的可靠性,消息也不會丟失(異步刷盤丟失少量消息,同步刷盤一條不丟),這種Broker的集群模式性能相對來說是最高的。
缺點:就是在單臺機器宕機期間,這臺機器上未被消費的消息在機器恢復之前是不可以進行消息訂閱的,這對消息的實時性會有一些影響。
3)、多Master多Slave模式(異步復制)
在這種模式下Broker集群存在多個Master節點,并且每個Master節點都會對應一個Slave節點,有多對Master-Slave,HA(高可用)之間采用異步復制的方式進行信息同步,在這種方式下主從之間會有短暫的毫秒級的消息延遲。
優點:在這種模式下即便磁盤損壞了,消息丟失的情況也非常少,因為主從之間有信息備份;并且,在這種模式下消息的實時性也不會受影響,因為Master宕機后Slave可以自動切換為Master模式,這樣Consumer仍然可以通過Slave進行消息消費,而這個過程對應用來說則是完全透明的,并不需要人工干預;另外,這種模式的性能與多Master模式幾乎差不多。
缺點:如果Master宕機,并且在磁盤損壞的情況下,會丟失少量的消息。
4)、多Master多Slave模式(同步復制)
這種模式與3)差不多,只是HA采用的是同步雙寫的方式,即主備都寫成功后,才會向應用返回成功。
優點:在這種模式下數據與服務都不存在單點的情況,在Master宕機的情況下,消息也沒有延遲,服務的可用性以及數據的可用性都非常高。
缺點:性能相比于異步復制來說略低一些(大約10%);另外一個缺點就是相比于異步復制,目前Slave備機還暫時不能實現自動切換為Master,可能后續的版本會支持Master-Slave的自動切換功能。
綜合考慮以上集群模式的優缺點,在實際生產環境中目前基于RocketMQ消息集群的部署方式基本都是采用多Master多Slave(異步復制)這種模式,作者目前所在公司的生產環境的Rocket消息系統也是采用這種模式進行部署的。
以下為目前作者所在公司的實際部署結構:
在以上實踐中,部署了3個NameSrv節點,Broker采用2主2從的異步復制模式進行集群部署。
為了更好地理解RocketMQ的集群運行原理,接下來我們以4臺虛擬機來模擬上述集群的搭建過程,假設這4臺機器的IP分別為:
10.211.55.4
10.211.55.5
10.211.55.6
10.211.55.7
首先確保幾臺虛擬機上安裝了JDK1.8+:
wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" https://download.oracle.com/otn-pub/java/jdk/8u191-b12/2787e4a523244c269598db4e85c51e0c/jdk-8u191-linux-x64.tar.gz
JAVA_HOME=/opt/java/jdk1.8.0_191
CLASSPATH=$JAVA_HOME/lib/
PATH=$PATH:$JAVA_HOME/bin
export PATH JAVA_HOME CLASSPATH
其次我們打算通過RocketMQ的源碼進行編譯,因為源碼是基于Maven開發的Java工程,所以我們需要安裝下Maven環境:
wget https://archive.apache.org/dist/maven/binaries/apache-maven-3.2.1-bin.tar.gz
export MAVEN_HOME=/opt/apache-maven-3.2.1
export PATH=${PATH}:${MAVEN_HOME}/bin
#配置阿里云鏡像
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
如果多臺機器,沒有必要依次下載,可以通過遠程復制命令完成機器間的拷貝:
scp -r /opt/apache-maven-3.2.1/ root@10.211.55.6:/opt/
完成后,我們就可以在主機的指定目錄下載RocketMQ的源碼發布包(這里為4.3.2版本)進行編譯了:
#download-4.3.2源碼準備編譯
wget http://mirror.bit.edu.cn/apache/rocketmq/4.3.2/rocketmq-all-4.3.2-source-release.zip
mvn -Prelease-all -DskipTests clean install -U
cd /opt/rocketmq-all-4.3.2/distribution/target/apache-rocketmq
以上動作需要在各個機器節點也同步操作!編譯完成后,我們來規劃下如何利用這4臺虛擬機來實現“3個NameSrv節點、2組Master-Slave Broker集群”的效果。
因為本地機器資源原因,我們通過虛擬機混部的方式來實現上述集群的效果,4臺機器的3臺會分別作為NameSrv節點,而對于Broker集群則兩兩組合,如上表所示!
按照上述規劃,接下來我們就來看下具體的配置方式:
1)Master-Broker-a的配置
創建數據存儲目錄
[root@bogon local]# mkdir -p /usr/local/rocketmq/data/store
[root@bogon local]# mkdir -p /usr/local/rocketmq/data/store/commitlog
[root@bogon local]# mkdir -p /usr/local/rocketmq/data/store/consumequeue
[root@bogon local]# mkdir -p /usr/local/rocketmq/data/store/index
[root@bogon local]# mkdir -p /usr/local/rocketmq/data/store/checkpoint
[root@bogon local]# mkdir -p /usr/local/rocketmq/data/store/abort
切換服務器目錄為對應的配置文件目錄
cd /opt/rocketmq-all-4.3.2/distribution/target/apache-rocketmq/conf
cd 2m-2s-async //這里因為我們采用的是異步復制模式,所以需要編輯2m-2s-async中的配置文件
編輯Broker集群配置文件
[root@bogon 2m-2s-async]# vim broker-a.properties
#broker所屬哪個集群,默認【DefaultCluster】
brokerClusterName=DefaultCluster
#broker 實列名稱,主從關系的需要保持名稱一致
brokerName=broker-a
#brokerId,必須是大等于0的整數,0表示Master,>0表示Slave
brokerId=0
#刪除文件的時間點,默認為凌晨4點
deleteWhen=04
#文件保留時間,默認為48小時
fileReservedTime=48
#-ASYNC_MASTER 異步復制Master
#-SYNC_MASTER 同步雙寫Master
#-SLAVE
brokerRole=ASYNC_MASTER
#刷盤方式
#-ASYNC_FLUSH 異步刷盤
#-SYNC_FLUSH 同步刷盤
flushDiskType=ASYNC_FLUSH
#NameSrv集群地址
namesrvAddr=10.211.55.4:9876;10.211.55.5:9876;10.211.55.6:9876
#broker對外服務的監聽端口
listenPort=10911
defaultTopicQueueNums=4
#是否允許broker自動創建Topic,建議線下開啟,線上關閉,默認【true】
autoCreateTopicEnable=false
#是否允許broker自動創建訂閱組,建議線下開啟,線上關閉,默認【true】
autoCreateSubscriptionGroup=false
mapedFileSizeCommitLog=1073741824
mapedFileSizeConsumeQueue=50000000
destroyMapedFileIntervalForcibly=120000
redeleteHangedFileInterval=120000
diskMaxUsedSpaceRatio=88
storePathRootDir=/usr/local/rocketmq/data/store
storePathCommitLog=/usr/local/rocketmq/data/store/commitlog
#消費隊列存儲路徑
storePathConsumeQueue=/usr/local/rocketmq/data/store/consumequeue
#消息索引存儲路徑
storePathIndex=/usr/local/rocketmq/data/store/index
#checkpoint文件存儲路徑
storeCheckpoint=/usr/local/rocketmq/data/store/checkpoint
#abort文件存儲路徑
abortFile=/usr/local/rocketmq/data/store/abort
maxMessageSize=65536
flushCommitLogLeastPages=4
flushConsumeQueueLeastPages=2
flushCommitLogThoroughInterval=10000
flushConsumeQueueThoroughInterval=60000
checkTransactionMessageEnable=false
sendMessageThreadPoolNums=128
pullMessageThreadPoolNums=128
2)、Slave-Broker-a的配置
創建數據存儲目錄
[root@bogon local]# mkdir -p /usr/local/rocketmq/data/store
[root@bogon local]# mkdir -p /usr/local/rocketmq/data/store/commitlog
[root@bogon local]# mkdir -p /usr/local/rocketmq/data/store/consumequeue
[root@bogon local]# mkdir -p /usr/local/rocketmq/data/store/index
[root@bogon local]# mkdir -p /usr/local/rocketmq/data/store/checkpoint
[root@bogon local]# mkdir -p /usr/local/rocketmq/data/store/abort
切換服務器目錄為對應的配置文件目錄
cd /opt/rocketmq-all-4.3.2/distribution/target/apache-rocketmq/conf
cd 2m-2s-async //這里因為我們采用的是異步復制模式,所以需要編輯2m-2s-async中的配置文件
3)、Master-Broker-b的配置
參考Master-Broker-a的配置方式,只需要改下“brokerName=broker-b”即可,其他一樣!
4)、Slave-Broker-b的配置
參考Slave-Broker-a的配置,只需要改下“brokerName=broker-b”即可,其他一樣!
至此,我們就完成了整個RocketMQ集群的配置了!接下來我們啟動整個集群。
首先我們需要關閉各個節點的防火墻(很重要)
service iptables stop
#CentOs7
systemctl stop firewalld
先分別啟動三個NameSrv節點
cd /opt/rocketmq-all-4.3.2/distribution/target/apache-rocketmq
nohup sh bin/mqnamesrv &
tail -f ~/logs/rocketmqlogs/namesrv.log
啟動Broker集群
#啟動Master broker-a服務(10.211.55.4)
cd /opt/rocketmq-all-4.3.2/distribution/target/apache-rocketmq/bin/
[root@bogon bin]#
nohup sh mqbroker -c /opt/rocketmq-all-4.3.2/distribution/target/apache-rocketmq/conf/2m-2s-sync/broker-a.properties >/dev/null 2>&1 &
#啟動Slave broker-a-s服務
cd /opt/rocketmq-all-4.3.2/distribution/target/apache-rocketmq/bin/
nohup sh mqbroker -c /opt/rocketmq-all-4.3.2/distribution/target/apache-rocketmq/conf/2m-2s-sync/broker-a-s.properties >/dev/null 2>&1 &
#啟動Master broker-b服務(10.211.55.6)
cd /opt/rocketmq-all-4.3.2/distribution/target/apache-rocketmq/bin/
nohup sh mqbroker -c /opt/rocketmq-all-4.3.2/distribution/target/apache-rocketmq/conf/2m-2s-sync/broker-b.properties >/dev/null 2>&1 &
#啟動Slave broker-b-s服務(10.211.55.7)
cd /opt/rocketmq-all-4.3.2/distribution/target/apache-rocketmq/bin
nohup sh mqbroker -c /opt/rocketmq-all-4.3.2/distribution/target/apache-rocketmq/conf/2m-2s-sync/broker-b-s.properties >/dev/null 2>&1 &
到這里,我們就完成了RocketMQ生產級集群的模擬搭建,可以通過jps命令檢查各節點NameSrv&Broker進程是否啟動成功。
集群啟動成功后,可以通過常用命令來進行查看!如:
查看所有消費組group
[root@bogon bin]# sh mqadmin consumerProgress -n 10.211.55.6:9876
查看集群消息
[root@bogon bin]# sh mqadmin clusterList -n 10.211.55.5:9876
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。