2020-03-09

主題和隊列有什么區(qū)別

????最初的消息隊列,就是一個嚴(yán)格意義上的隊列。在計算機領(lǐng)域谎亩,“隊列(Queue)”是一種數(shù)據(jù)結(jié)構(gòu),有完整而嚴(yán)格的定義宇姚。在維基百科中匈庭,隊列的定義是這樣的:

? ??隊列是先進(jìn)先出(FIFO, First-In-First-Out)的線性表(Linear List)。在具體應(yīng)用中通常用鏈表或者數(shù)組來實現(xiàn)浑劳。隊列只允許在后端(稱為 rear)進(jìn)行插入操作阱持,在前端(稱為 front)進(jìn)行刪除操作。

????這個定義里面包含幾個關(guān)鍵點:這個定義里面包含幾個關(guān)鍵點魔熏,第一個是先進(jìn)先出衷咽,這里面隱含著的一個要求是鸽扁,在消息入隊出隊過程中,需要保證這些消息嚴(yán)格有序镶骗,按照什么順序?qū)戇M(jìn)隊列桶现,必須按照同樣的順序從隊列中讀出來。不過鼎姊,隊列是沒有“讀”這個操作的骡和,“讀”就是出隊,也就是從隊列中“刪除”這條消息相寇。

????早期的消息隊列慰于,就是按照“隊列”的數(shù)據(jù)結(jié)構(gòu)來設(shè)計的。我們一起看下這個圖唤衫,生產(chǎn)者(Producer)發(fā)消息就是入隊操作婆赠,消費者(Consumer)收消息就是出隊也就是刪除操作,服務(wù)端存放消息的容器自然就稱為“隊列”战授。這就是最初的一種消息模型:隊列模型页藻。

????如果需要將一份消息數(shù)據(jù)分發(fā)給多個消費者,要求每個消費者都能收到全量的消息植兰,例如份帐,對于一份訂單數(shù)據(jù),風(fēng)控系統(tǒng)楣导、分析系統(tǒng)废境、支付系統(tǒng)等都需要接收消息。這個時候筒繁,單個隊列就滿足不了需求噩凹,一個可行的解決方式是,為每個消費者創(chuàng)建一個單獨的隊列毡咏,讓生產(chǎn)者發(fā)送多份驮宴。顯然這是個比較蠢的做法,同樣的一份消息數(shù)據(jù)被復(fù)制到多個隊列中會浪費資源呕缭,更重要的是堵泽,生產(chǎn)者必須知道有多少個消費者。為每個消費者單獨發(fā)送一份消息恢总,這實際上違背了消息隊列“解耦”這個設(shè)計初衷迎罗。

????為了解決上述問題演化出了另外一種消息模型:“發(fā)布 - 訂閱模型(Publish-Subscribe Pattern)”。

在消息領(lǐng)域的歷史上很長的一段時間片仿,隊列模式和發(fā)布 - 訂閱模式是并存的纹安,有些消息隊列同時支持這兩種消息模型,比如 ActiveMQ。我們仔細(xì)對比一下這兩種模型厢岂,生產(chǎn)者就是發(fā)布者光督,消費者就是訂閱者,隊列就是主題塔粒,并沒有本質(zhì)的區(qū)別可帽。它們最大的區(qū)別其實就是,一份消息數(shù)據(jù)能不能被消費多次的問題窗怒。


????RabbitMQ?

RabbitMQ消息模型是基于隊列模式的映跟。通過Exchange 模塊解決多個消費者問題。在 RabbitMQ 中扬虚,Exchange 位于生產(chǎn)者和隊列之間努隙,生產(chǎn)者并不關(guān)心將消息發(fā)送給哪個隊列,而是將消息發(fā)送給 Exchange辜昵,由 Exchange 上配置的策略來決定將消息投遞到哪些隊列中荸镊。

同一份消息如果需要被多個消費者來消費,需要配置 Exchange 將消息發(fā)送到多個隊列堪置,每個隊列中都存放一份完整的消息數(shù)據(jù)躬存,可以為一個消費者提供消費服務(wù)。這也可以變相地實現(xiàn)新發(fā)布 - 訂閱模型中舀锨,“一份消息數(shù)據(jù)可以被多個訂閱者來多次消費”這樣的功能岭洲。

RocketMQ?

????RocketMQ 使用的消息模型是標(biāo)準(zhǔn)的發(fā)布 - 訂閱模型,在 RocketMQ 的術(shù)語表中坎匿,生產(chǎn)者盾剩、消費者和主題與我在上面講的發(fā)布 - 訂閱模型中的概念是完全一樣的。在 RocketMQ 也有隊列(Queue)這個概念替蔬,并且隊列在 RocketMQ 中是一個非常重要的概念告私。

????那隊列在 RocketMQ 中的作用是什么呢?這就要從消息隊列的消費機制說起承桥。幾乎所有的消息隊列產(chǎn)品都使用一種非常樸素的“請求 - 確認(rèn)”機制驻粟,確保消息不會在傳遞過程中由于網(wǎng)絡(luò)或服務(wù)器故障丟失。

????具體的做法也非常簡單凶异。在生產(chǎn)端蜀撑,生產(chǎn)者先將消息發(fā)送給服務(wù)端,也就是 Broker唠帝,服務(wù)端在收到消息并將消息寫入主題或者隊列中后屯掖,會給生產(chǎn)者發(fā)送確認(rèn)的響應(yīng)玄柏。如果生產(chǎn)者沒有收到服務(wù)端的確認(rèn)或者收到失敗的響應(yīng)襟衰,則會重新發(fā)送消息;在消費端粪摘,消費者在收到消息并完成自己的消費業(yè)務(wù)邏輯(比如瀑晒,將數(shù)據(jù)保存到數(shù)據(jù)庫中)后绍坝,也會給服務(wù)端發(fā)送消費成功的確認(rèn),服務(wù)端只有收到消費確認(rèn)后苔悦,才認(rèn)為一條消息被成功消費轩褐,否則它會給消費者重新發(fā)送這條消息,直到收到對應(yīng)的消費成功確認(rèn)玖详。

????這個確認(rèn)機制很好地保證了消息傳遞過程中的可靠性把介,但是,引入這個機制在消費端帶來了一個不小的問題蟋座。為了確保消息的有序性拗踢,在某一條消息被成功消費之前,下一條消息是不能被消費的向臀,否則違背了有序性這個原則巢墅。

????也就是說,每個主題在任意時刻券膀,至多只能有一個消費者實例在進(jìn)行消費君纫,那就沒法通過水平擴展消費者的數(shù)量來提升消費端總體的消費性能。為了解決這個問題芹彬,RocketMQ 在主題下面增加了隊列的概念蓄髓。

????每個主題包含多個隊列,通過多個隊列來實現(xiàn)多實例并行生產(chǎn)和消費舒帮。需要注意的是双吆,RocketMQ 只在隊列上保證消息的有序性,主題層面是無法保證消息的嚴(yán)格順序的会前。

????RocketMQ 中好乐,訂閱者的概念是通過消費組(Consumer Group)來體現(xiàn)的。每個消費組都有消費主題中一份完整的消息瓦宜,不同消費組之間消費進(jìn)度彼此不受影響蔚万,也就是說,一條消息被 Consumer Group1 消費過临庇,也會再給 Consumer Group2 消費反璃。

? ? 每個消費組中消費者是存在競爭關(guān)系的。如果消息被消費組其中一個消費者消費了假夺,同組中其他消費者就不會收到該條消息了淮蜈。

????在 Topic 的消費過程中,由于消息需要被不同的組進(jìn)行多次消費已卷,所以消費完的消息并不會立即被刪除梧田,這就需要 RocketMQ 為每個消費組在每個隊列上維護(hù)一個消費位置(Consumer Offset),這個位置之前的消息都被消費過,之后的消息都沒有被消費過裁眯,每成功消費一條消息鹉梨,消費位置就加一。這個消費位置是非常重要的概念穿稳,我們在使用消息隊列的時候存皂,丟消息的原因大多是由于消費位置處理不當(dāng)導(dǎo)致的。


Kafka

? ? Kafka 的消息模型和 RocketMQ 是完全一樣的逢艘,我剛剛講的所有 RocketMQ 中對應(yīng)的概念旦袋,和生產(chǎn)消費過程中的確認(rèn)機制,都完全適用于 Kafka它改。唯一的區(qū)別是猜憎,在 Kafka 中,隊列這個概念的名稱不一樣搔课,Kafka 中對應(yīng)的名稱是“分區(qū)(Partition)”胰柑,含義和功能是沒有任何區(qū)別的。

總結(jié):

?????1.隊列和主題的區(qū)別爬泥,這兩個概念的背后實際上對應(yīng)著兩種不同的消息模型:隊列模型和發(fā)布 - 訂閱模型柬讨。兩種消息模型其實并沒有本質(zhì)上的區(qū)別,都可以通過一些擴展或者變化來互相替代袍啡。

????2.常用的消息隊列中踩官,RabbitMQ 采用的是隊列模型,但是它一樣可以實現(xiàn)發(fā)布 - 訂閱的功能境输。RocketMQ 和 Kafka 采用的是發(fā)布 - 訂閱模型蔗牡,并且二者的消息模型是基本一致的。

? ?3.上述所說的消息模型都是從邏輯層面考慮的嗅剖,如RabbitMQ和kafka消息模型幾乎一致辩越,但他們底層實現(xiàn)可能就千差萬別啦。

來源:(李玥-消息隊列高手)學(xué)習(xí)總結(jié)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末信粮,一起剝皮案震驚了整個濱河市黔攒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌强缘,老刑警劉巖督惰,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異旅掂,居然都是意外死亡赏胚,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門商虐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來觉阅,“玉大人崖疤,你說我怎么就攤上這事×羰埃” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵鲫尊,是天一觀的道長痴柔。 經(jīng)常有香客問我,道長疫向,這世上最難降的妖魔是什么咳蔚? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮搔驼,結(jié)果婚禮上谈火,老公的妹妹穿的比我還像新娘。我一直安慰自己舌涨,他們只是感情好糯耍,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著囊嘉,像睡著了一般温技。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上扭粱,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天舵鳞,我揣著相機與錄音,去河邊找鬼琢蛤。 笑死蜓堕,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的博其。 我是一名探鬼主播套才,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼慕淡!你這毒婦竟也來了霜旧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤儡率,失蹤者是張志新(化名)和其女友劉穎挂据,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體儿普,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡崎逃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了眉孩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片个绍。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡勒葱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出巴柿,到底是詐尸還是另有隱情凛虽,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布广恢,位于F島的核電站凯旋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏钉迷。R本人自食惡果不足惜至非,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望糠聪。 院中可真熱鬧荒椭,春花似錦、人聲如沸舰蟆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽身害。三九已至信卡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間题造,已是汗流浹背傍菇。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留界赔,地道東北人丢习。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像淮悼,于是被迫代替她去往敵國和親咐低。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容