前言:關(guān)于消息隊(duì)列應(yīng)該大家都不陌生,在實(shí)際的項(xiàng)目中消息隊(duì)列也無(wú)處不在,今天我和大家分享一下關(guān)于消息隊(duì)列的問(wèn)題。
1、消息隊(duì)列定義
消息隊(duì)列大家又經(jīng)常稱為MQ(message queue),從字面的含義來(lái)看就是一個(gè)存放消息的容器。
2、消息隊(duì)列應(yīng)用場(chǎng)景
2.1、異步處理

2.2、系統(tǒng)解耦

2.3、流量削峰

3、消息隊(duì)列順序性
? 提到mq那么我們必然會(huì)討論mq順序性問(wèn)題,比如生產(chǎn)者發(fā)送消息1,2,3...對(duì)于消費(fèi)者必須按照1,2,3...這樣的順序來(lái)消費(fèi),那么消息隊(duì)列應(yīng)該怎么樣去考慮這樣事情呢,有人說(shuō)了消息隊(duì)列是先進(jìn)先出不就保證了順序性,其實(shí)并非如此,而且想通過(guò)隊(duì)列來(lái)保證順序性是非常困難的,那么我們來(lái)看看為什么說(shuō)非常困難的。
對(duì)于生產(chǎn)者而言
比如生產(chǎn)者連續(xù)發(fā)送1、2、3但是不久2和3返回結(jié)果成功,唯獨(dú)1返回結(jié)果是失敗,這個(gè)時(shí)候如果我們重發(fā)1那么順序肯定就會(huì)亂了。
對(duì)于存儲(chǔ)端而言
?消息隊(duì)列不可能分區(qū)進(jìn)行存儲(chǔ),也就是一個(gè)topic的消息只能采用一個(gè)隊(duì)列存儲(chǔ),如果一個(gè)topic采用多個(gè)隊(duì)列就不可能保證順序
對(duì)于消費(fèi)者而言
對(duì)于消費(fèi)端來(lái)說(shuō)還不可以并行消費(fèi),也就是不可以開(kāi)啟多線程或者多個(gè)客戶端來(lái)進(jìn)行消費(fèi)
3.1、消息隊(duì)列順序性分析1:

假設(shè)我們現(xiàn)在想要保證s1和s2兩條消息順序被消費(fèi)可能想設(shè)計(jì)如上圖所示,假定生產(chǎn)者先發(fā)送s1然后在發(fā)送s2,如果想保證s1先被消費(fèi),那么需要s1到達(dá)消費(fèi)端后在通知mq2,然后mq2在發(fā)送消息。但是其實(shí)這是理想的模型,可能會(huì)出現(xiàn)如下2個(gè)問(wèn)題
1、s1不一定要比s2先到mq集群(比如網(wǎng)絡(luò)延遲)
2、s2到達(dá)mq集群并且已經(jīng)消費(fèi)完畢,s1還沒(méi)到達(dá)mq集群,這就會(huì)出現(xiàn)亂序
所有我們想要s1比s2先消費(fèi)最簡(jiǎn)單粗暴的方式就是s1和s2發(fā)送同一臺(tái)server上,這樣根據(jù)隊(duì)列先進(jìn)先出原則,肯定s1要比s2先消費(fèi)
3.2、消息隊(duì)列順序性分析2:

但是這種模型僅僅是理論上的可行,因?yàn)榭赡艹霈F(xiàn)網(wǎng)絡(luò)延遲,比如s2比是s1先到達(dá)消費(fèi)端,我們同樣無(wú)法保證消息的順序,這樣一來(lái)我們可能發(fā)送s1等消費(fèi)者響應(yīng)后然后在發(fā)s2。
3.3、消息隊(duì)列順序性分析3:

但是我們知道消費(fèi)者可能出現(xiàn)2種情況
1、消費(fèi)者沒(méi)有響應(yīng)(可能消費(fèi)成功沒(méi)有響應(yīng),也可能消費(fèi)失敗沒(méi)有響應(yīng))
2、消費(fèi)者響應(yīng)成功
對(duì)于沒(méi)有響應(yīng)的mq集群可以進(jìn)行重發(fā)消息,如果消費(fèi)成功重發(fā)就會(huì)導(dǎo)致消息重新處理,這樣一來(lái)就會(huì)帶來(lái)新的問(wèn)題,重復(fù)問(wèn)題下面說(shuō)
綜上我們可以得出想保證消息順序性最簡(jiǎn)單可行方式就是生產(chǎn)者->mq->消費(fèi)者這樣一一對(duì)應(yīng)關(guān)系,但是同樣會(huì)帶來(lái)如下2個(gè)問(wèn)題
1、吞吐量不足
2、可用性低
3.4、消息隊(duì)列順序性分析4:
任何設(shè)計(jì)都離不開(kāi)業(yè)務(wù)的本身,我們可以從業(yè)務(wù)來(lái)考慮順序消息
1、不關(guān)注亂序的應(yīng)用實(shí)際大量存在
2、隊(duì)列無(wú)序不表示消息無(wú)序

注釋?zhuān)簩?duì)于同一種消息放入同一個(gè)隊(duì)列中,同一種消息可以通過(guò)topic主題來(lái)進(jìn)行標(biāo)記。
綜上我們可以可以總結(jié)出來(lái)為了保證消息的順序性要從生產(chǎn)者、存儲(chǔ)端、消費(fèi)者三個(gè)角度來(lái)考慮
1、生產(chǎn)端必須保證消息成功發(fā)送以后才能繼續(xù)發(fā)送第二條
2、存儲(chǔ)端必須要求同一種消息必須存放在同一個(gè)隊(duì)列中
3、消費(fèi)端不可以采用并發(fā)消費(fèi)
4、消息隊(duì)列重復(fù)性

消息重復(fù)由業(yè)務(wù)端來(lái)保證如上圖
5、消息隊(duì)列可靠性
生產(chǎn)者:ack確認(rèn)機(jī)制消息重發(fā)
消費(fèi)者:手動(dòng)ack確認(rèn),消息重新請(qǐng)求,或者重試等
消息隊(duì)列:如下圖所示
1、對(duì)于業(yè)務(wù)方進(jìn)行限流,避免惡意刷消息
2、服務(wù)器采用負(fù)載均衡避免一臺(tái)服務(wù)宕機(jī)而不可用
3、消息采用持久化,避免斷電等原因?qū)е孪G失

6、消息隊(duì)列存儲(chǔ)
消息隊(duì)列存儲(chǔ)一般采用邏輯存儲(chǔ)和物理存儲(chǔ)如下圖所示
1、邏輯存儲(chǔ)放入內(nèi)存,主要存儲(chǔ)偏移量、消息主題等,同時(shí)將存儲(chǔ)內(nèi)容刷入磁盤(pán)避免丟失
2、物理采用文件進(jìn)行存儲(chǔ),定期對(duì)文件進(jìn)行歸檔

6、消息隊(duì)列的缺點(diǎn)
6.1、服務(wù)可用性降低
加入消息隊(duì)列后,如果出現(xiàn)mq集群宕機(jī),那么就可能會(huì)導(dǎo)致服務(wù)不可用
6.2、服務(wù)復(fù)雜度增加
加入消息隊(duì)列以后就不得不考慮消息一致性、可靠性、重復(fù)性等問(wèn)題無(wú)疑加大了服務(wù)的難度
歡迎工作一到五年的Java工程師朋友們加入Java架構(gòu)開(kāi)發(fā): 854393687
群內(nèi)提供免費(fèi)的Java架構(gòu)學(xué)習(xí)資料(里面有高可用、高并發(fā)、高性能及分布式、Jvm性能調(diào)優(yōu)、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個(gè)知識(shí)點(diǎn)的架構(gòu)資料)合理利用自己每一分每一秒的時(shí)間來(lái)學(xué)習(xí)提升自己,不要再用"沒(méi)有時(shí)間“來(lái)掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來(lái)的自己一個(gè)交代!