消息中間件
應(yīng)用場(chǎng)景
- 異步通信
??有些業(yè)務(wù)不想也不需要立即處理消息芯侥。消息隊(duì)列提供了異步處理機(jī)制缠犀,允許用戶把一個(gè)消息放入隊(duì)列,但并不立即處理它臭觉。想向隊(duì)列中放入多少消息就放多少昆雀,然后在需要的時(shí)候再去處理它們。 - 解耦
??降低工程間的強(qiáng)依賴程度蝠筑,針對(duì)異構(gòu)系統(tǒng)進(jìn)行適配狞膘。在項(xiàng)目啟動(dòng)之初來預(yù)測(cè)將來項(xiàng)目會(huì)碰到什么需求,是極其困難的什乙。通過消息系統(tǒng)在處理過程中間插入了一個(gè)隱含的挽封、基于數(shù)據(jù)的接口層,兩邊的處理過程都要實(shí)現(xiàn)這一接口臣镣,當(dāng)應(yīng)用發(fā)生變化時(shí)辅愿,可以獨(dú)立的擴(kuò)展或修改兩邊的處理過程,只要確保它們遵守同樣的接口約束忆某。 - 過載保護(hù)
??在訪問量劇增的情況下点待,應(yīng)用仍然需要繼續(xù)發(fā)揮作用,但是這樣的突發(fā)流量無法提取預(yù)知弃舒;如果以為了能處理這類瞬間峰值訪問為標(biāo)準(zhǔn)來投入資源隨時(shí)待命無疑是巨大的浪費(fèi)癞埠。使用消息隊(duì)列能夠使關(guān)鍵組件頂住突發(fā)的訪問壓力状原,而不會(huì)因?yàn)橥话l(fā)的超負(fù)荷的請(qǐng)求而完全崩潰。 - 可恢復(fù)性
??系統(tǒng)的一部分組件失效時(shí)苗踪,不會(huì)影響到整個(gè)系統(tǒng)颠区。消息隊(duì)列降低了進(jìn)程間的耦合度,所以即使一個(gè)處理消息的進(jìn)程掛掉通铲,加入隊(duì)列中的消息仍然可以在系統(tǒng)恢復(fù)后被處理毕莱。 - 順序保證
??在大多使用場(chǎng)景下,數(shù)據(jù)處理的順序都很重要测暗。大部分消息隊(duì)列本來就是排序的央串,并且能保證數(shù)據(jù)會(huì)按照特定的順序來處理。 - 緩沖
??在任何重要的系統(tǒng)中碗啄,都會(huì)有需要不同的處理時(shí)間的元素质和。消息隊(duì)列通過一個(gè)緩沖層來幫助任務(wù)最高效率的執(zhí)行,該緩沖有助于控制和優(yōu)化數(shù)據(jù)流經(jīng)過系統(tǒng)的速度稚字。以調(diào)節(jié)系統(tǒng)響應(yīng)時(shí)間饲宿。 - 數(shù)據(jù)流處理
??分布式系統(tǒng)產(chǎn)生的海量數(shù)據(jù)流,如:業(yè)務(wù)日志胆描、監(jiān)控?cái)?shù)據(jù)瘫想、用戶行為等,針對(duì)這些數(shù)據(jù)流進(jìn)行實(shí)時(shí)或批量采集匯總,然后進(jìn)行大數(shù)據(jù)分析是當(dāng)前互聯(lián)網(wǎng)的必備技術(shù),通過消息隊(duì)列完成此類數(shù)據(jù)收集是最好的選擇警儒。
常用協(xié)議
- AMQP協(xié)議
- MQTT協(xié)議
- STOMP協(xié)議
- XMPP協(xié)議
- 其他基于TCP/IP自定義的協(xié)議
常用消息中間件
Kafka
??Apache下的一個(gè)子項(xiàng)目蠕啄,使用scala實(shí)現(xiàn)的一個(gè)高性能分布式Publish/Subscribe消息隊(duì)列系統(tǒng),具有以下特性:
- 快速持久化:通過磁盤順序讀寫與零拷貝機(jī)制,可以在O(1)的系統(tǒng)開銷下進(jìn)行消息持久化;
- 高吞吐:在一臺(tái)普通的服務(wù)器上既可以達(dá)到10W/s的吞吐速率;
- 高堆積:支持topic下消費(fèi)者較長(zhǎng)時(shí)間離線窄驹,消息堆積量大;
- 完全的分布式系統(tǒng):Broker证逻、Producer乐埠、Consumer都原生自動(dòng)支持分布式,依賴zookeeper自動(dòng)實(shí)現(xiàn)復(fù)雜均衡囚企;
- 支持Hadoop數(shù)據(jù)并行加載:對(duì)于像Hadoop的一樣的日志數(shù)據(jù)和離線分析系統(tǒng)丈咐,但又要求實(shí)時(shí)處理的限制,這是一個(gè)可行的解決方案洞拨。
RocketMQ
??阿里巴巴的MQ中間件扯罐,在其多個(gè)產(chǎn)品下使用,并能夠撐住雙十一的大流量烦衣,他并沒有實(shí)現(xiàn)JMS規(guī)范歹河,使用起來很簡(jiǎn)單掩浙。部署由一個(gè) 命名服務(wù)(nameserver)和一個(gè)代理(broker)組成,nameserver和broker以及producer都支持集群秸歧,隊(duì)列的容量受機(jī)器硬盤的限制厨姚,隊(duì)列滿后可以支持持久化到硬盤(也可以自己適配代碼,將其持久化到NOSQL數(shù)據(jù)庫(kù)中)键菱,隊(duì)列滿后會(huì)影響吞吐量谬墙,可以采用主備來保證穩(wěn)定性,支持回溯消費(fèi)经备,可以在broker端進(jìn)行消息過濾.
RabbitMQ
??使用Erlang編寫的一個(gè)開源的消息隊(duì)列拭抬,本身支持很多的協(xié)議:AMQP,XMPP, SMTP,STOMP侵蒙,也正是如此造虎,使的它變的非常重量級(jí),更適合于企業(yè)級(jí)的開發(fā)纷闺。同時(shí)實(shí)現(xiàn)了Broker架構(gòu)算凿,核心思想是生產(chǎn)者不會(huì)將消息直接發(fā)送給隊(duì)列,消息在發(fā)送給客戶端時(shí)先在中心隊(duì)列排隊(duì)犁功。對(duì)路由(Routing)氓轰,負(fù)載均衡(Load balance)、數(shù)據(jù)持久化都有很好的支持浸卦。多用于進(jìn)行企業(yè)級(jí)的ESB整合署鸡。結(jié)合erlang語(yǔ)言本身的并發(fā)優(yōu)勢(shì),性能較好限嫌,但是不利于做二次開發(fā)和維護(hù)储玫。
ActiveMQ
??Apache下的一個(gè)子項(xiàng)目。使用Java完全支持JMS1.1和J2EE 1.4規(guī)范的 JMS Provider實(shí)現(xiàn)萤皂,少量代碼就可以高效地實(shí)現(xiàn)高級(jí)應(yīng)用場(chǎng)景∠灰可插拔的傳輸協(xié)議支持裆熙,比如:in-VM, TCP, SSL, NIO, UDP, multicast, JGroups and JXTA transports。RabbitMQ禽笑、ZeroMQ入录、ActiveMQ均支持常用的多種語(yǔ)言客戶端 C++、Java佳镜、.Net,僚稿、Python、 Php蟀伸、 Ruby等蚀同。
Redis
??使用C語(yǔ)言開發(fā)的一個(gè)Key-Value的NoSQL數(shù)據(jù)庫(kù)缅刽,開發(fā)維護(hù)很活躍,雖然它是一個(gè)Key-Value數(shù)據(jù)庫(kù)存儲(chǔ)系統(tǒng)蠢络,但它本身支持MQ功能衰猛,所以完全可以當(dāng)做一個(gè)輕量級(jí)的隊(duì)列服務(wù)來使用。對(duì)于RabbitMQ和Redis的入隊(duì)和出隊(duì)操作刹孔,各執(zhí)行100萬次啡省,每10萬次記錄一次執(zhí)行時(shí)間。測(cè)試數(shù)據(jù)分為128Bytes髓霞、512Bytes卦睹、1K和10K四個(gè)不同大小的數(shù)據(jù)。實(shí)驗(yàn)表明:入隊(duì)時(shí)方库,當(dāng)數(shù)據(jù)比較小時(shí)Redis的性能要高于RabbitMQ结序,而如果數(shù)據(jù)大小超過了10K,Redis則慢的無法忍受薪捍;出隊(duì)時(shí)笼痹,無論數(shù)據(jù)大小,Redis都表現(xiàn)出非常好的性能酪穿,而RabbitMQ的出隊(duì)性能則遠(yuǎn)低于Redis凳干。
ZeroMQ
??擴(kuò)展性好,開發(fā)比較靈活被济,采用C語(yǔ)言實(shí)現(xiàn)救赐,實(shí)際上他只是一個(gè)socket庫(kù)的重新封裝,如果我們做為消息隊(duì)列使用只磷,需要開發(fā)大量的代碼经磅,非持久隊(duì)列。
RocketMQ
簡(jiǎn)介
- 能夠保證嚴(yán)格的消息順序
- 提供豐富的消息拉取模式
- 高效的訂閱者水平擴(kuò)展能力
- 實(shí)時(shí)的消息訂閱機(jī)制
- 億級(jí)消息堆積能力
網(wǎng)絡(luò)架構(gòu)圖
組件特性
nameserver
- nameserver互相獨(dú)立钮追,彼此沒有通信關(guān)系预厌,單臺(tái)nameserver掛掉,不影響其他nameserver元媚,即使全部掛掉轧叽,也不影響業(yè)務(wù)系統(tǒng)使用。
- nameserver不會(huì)有頻繁的讀寫刊棕,所以性能開銷非常小炭晒,穩(wěn)定性很高。
- 集群之間互不通信甥角,降低了nameserver的復(fù)雜程度网严,對(duì)網(wǎng)絡(luò)的要求也降低了不少,topic路由信息無須在集群之間保持強(qiáng)一致嗤无,追求最終一致震束。
broker
與nameserver關(guān)系
連接
- 單個(gè)broker和所有nameserver保持長(zhǎng)連接
心跳
- 心跳間隔:每隔30秒(此時(shí)間無法更改)向所有nameserver發(fā)送心跳怜庸,心跳包含了自身的topic配置信息
- 心跳超時(shí):nameserver每隔10秒鐘(此時(shí)間無法更改),掃描所有還存活的broker連接驴一,若某個(gè)連接2分鐘內(nèi)(當(dāng)前時(shí)間與最后更新時(shí)間差值超過2分鐘休雌,此時(shí)間無法更改)沒有發(fā)送心跳數(shù)據(jù),則斷開連接
斷開
- 時(shí)機(jī):broker掛掉肝断;心跳超時(shí)導(dǎo)致nameserver主動(dòng)關(guān)閉連接
- 動(dòng)作:一旦連接斷開杈曲,nameserver會(huì)立即感知,更新topc與隊(duì)列的對(duì)應(yīng)關(guān)系胸懈,但不會(huì)通知生產(chǎn)者和消費(fèi)者
負(fù)載均衡
- 一個(gè)topic分布在多個(gè)broker上担扑,一個(gè)broker可以配置多個(gè)topic,它們是多對(duì)多的關(guān)系
- 如果某個(gè)topic消息量很大趣钱,應(yīng)該給它多配置幾個(gè)隊(duì)列涌献,并且盡量多分布在不同broker上,減輕某個(gè)broker的壓力
- topic消息量都比較均勻的情況下首有,如果某個(gè)broker上的隊(duì)列越多燕垃,則該broker壓力越大
可用性
?? 由于消息分布在各個(gè)broker上,一旦某個(gè)broker宕機(jī)井联,則該broker上的消息讀寫都會(huì)受到影響卜壕。所以rocketmq提供了master/slave的結(jié)構(gòu),salve定時(shí)從master同步數(shù)據(jù)烙常,如果master宕機(jī)轴捎,則slave提供消費(fèi)服務(wù),但是不能寫入消息蚕脏,此過程對(duì)應(yīng)用透明侦副,由rocketmq內(nèi)部解決。
- 一旦某個(gè)broker master宕機(jī)驼鞭,生產(chǎn)者和消費(fèi)者多久才能發(fā)現(xiàn)秦驯?受限于rocketmq的網(wǎng)絡(luò)連接機(jī)制,默認(rèn)情況下挣棕,最多需要30秒汇竭,但這個(gè)時(shí)間可由應(yīng)用設(shè)定參數(shù)來縮短時(shí)間。這個(gè)時(shí)間段內(nèi)穴张,發(fā)往該broker的消息都是失敗的,而且該broker的消息無法消費(fèi)两曼,因?yàn)榇藭r(shí)消費(fèi)者不知道該broker已經(jīng)掛掉皂甘。
- 消費(fèi)者得到master宕機(jī)通知后,轉(zhuǎn)向slave消費(fèi)悼凑,但是slave不能保證master的消息100%都同步過來了偿枕,因此會(huì)有少量的消息丟失璧瞬。但是消息最終不會(huì)丟的,一旦master恢復(fù)渐夸,未同步過去的消息會(huì)被消費(fèi)掉嗤锉。
可用性
可靠性
消息清理
讀寫性能
系統(tǒng)特性
消費(fèi)者
Consumer Group
??用來表示一個(gè)消費(fèi)消息應(yīng)用,一個(gè)Consumer Group下包含多個(gè)Consumer實(shí)例墓塌,可以是多臺(tái)機(jī)器瘟忱,也可以是多個(gè)進(jìn)程,或者是一個(gè)進(jìn)程的多個(gè)Consumer對(duì)象苫幢。一個(gè)Consumer Group下的多個(gè)Consumer以均攤方式消費(fèi)消息访诱,如果設(shè)置為廣播方式,那么這個(gè)Consumer Group下的每個(gè)實(shí)例都消費(fèi)全量數(shù)據(jù)韩肝。
與nameserver關(guān)系
連接
??單個(gè)消費(fèi)者和一臺(tái)nameserver保持長(zhǎng)連接触菜,定時(shí)查詢topic配置信息,如果該nameserver掛掉哀峻,消費(fèi)者會(huì)自動(dòng)連接下一個(gè)nameserver涡相,直到有可用連接為止,并能自動(dòng)重連剩蟀。
輪詢時(shí)間
??默認(rèn)情況下催蝗,消費(fèi)者每隔30秒從nameserver獲取所有topic的最新隊(duì)列情況,這意味著某個(gè)broker如果宕機(jī)喻旷,客戶端最多要30秒才能感知生逸。該時(shí)間由DefaultMQPushConsumer的pollNameServerInteval參數(shù)決定,可手動(dòng)配置且预。
與broker關(guān)系
連接
心跳
斷開
負(fù)載均衡
消費(fèi)機(jī)制
消費(fèi)進(jìn)度存儲(chǔ)
生產(chǎn)者
Producer Group
??用來表示一個(gè)發(fā)送消息應(yīng)用槽袄,一個(gè)Producer Group下包含多個(gè)Producer實(shí)例,可以是多臺(tái)機(jī)器锋谐,也可以是一臺(tái)機(jī)器的多個(gè)進(jìn)程遍尺,或者一個(gè)進(jìn)程的多個(gè)Producer對(duì)象。一個(gè)Producer Group可以發(fā)送多個(gè)Topic消息涮拗,Producer Group作用如下:
- 標(biāo)識(shí)一類Producer
- 可以通過運(yùn)維工具查詢這個(gè)發(fā)送消息應(yīng)用下有多個(gè)Producer實(shí)例
- 發(fā)送分布式事務(wù)消息時(shí)乾戏,如果Producer中途意外宕機(jī),Broker會(huì)主動(dòng)回調(diào)Producer Group內(nèi)的任意一臺(tái)機(jī)器來確認(rèn)事務(wù)狀態(tài)三热。
與nameserver關(guān)系
連接
心跳
輪詢時(shí)間
與broker關(guān)系
連接
心跳
斷開連接
負(fù)載均衡
Broker集群配置方式及優(yōu)缺點(diǎn)
單個(gè) Master
多個(gè) Master
多 Master 多 Slave 模式鼓择,異步復(fù)制
多 Master 多 Slave 模式,同步雙寫
演示
單機(jī)演示
啟動(dòng)nameserver
- 配置jvm參數(shù)
啟動(dòng)broker
- 配置jvm參數(shù)
- 配置自動(dòng)創(chuàng)建主題參數(shù)(僅使用測(cè)試環(huán)境就漾,生產(chǎn)環(huán)境不建議)
- 手動(dòng)創(chuàng)建主體(命令或者直接修改store的配置文件呐能,需要重啟)
啟動(dòng)生產(chǎn)者
啟動(dòng)消費(fèi)者
管控臺(tái)演示
集群搭建及演示
源碼構(gòu)建
構(gòu)建rocketmq
git clone https://github.com/apache/rocketmq.git
mvn -Prelease-all -DskipTests clean install -U
cd distribution/target/apache-rocketmq
nohup sh bin/mqbroker -n localhost:9876 autoCreateTopicEnable=true &
構(gòu)建管控臺(tái):
注意:pom文件中,把<rocketmq.version>4.4.0</rocketmq.version>修改,4.4.0在maven中心倉(cāng)庫(kù)中有摆出,自己本地可以安裝rocketmq最新代碼的快照版本朗徊,但是仍然會(huì)有問題
git clone https://github.com/apache/rocketmq-externals.git
cd rocketmq-console
mvn clean package -Dmaven.test.skip=true
java -jar target/rocketmq-console-ng-1.0.0.jar