《吃透 MQ 系列1》之核心基礎(chǔ)篇

目錄:
《吃透 MQ 系列1》之核心基礎(chǔ)篇
《吃透 MQ 系列2》之扒開 Kafka 的神秘面紗
《吃透 MQ 系列3》之 Kafka 架構(gòu)設(shè)計的任督二脈
《吃透 MQ 系列4》之 Kafka 存儲選型的奧秘
《吃透 MQ 系列5》Kafka 精妙的高性能設(shè)計(上篇)
《吃透 MQ 系列6》Kafka 精妙的高性能設(shè)計(下篇)

如果讓你來設(shè)計一個 MQ颗味,該如何下手庐杨?需要考慮哪些問題蛤售?又有哪些技術(shù)挑戰(zhàn)?

對于 MQ 來說界斜,不管是 RocketMQ、Kafka 還是其他消息隊列穆趴,它們的本質(zhì)都是:一發(fā)一存一消費只泼。下面我們以這個本質(zhì)作為根,一起由淺入深地聊聊 MQ软驰。

01 從 MQ 的本質(zhì)說起

將 MQ 掰開了揉碎了來看涧窒,都是「一發(fā)一存一消費」,再直白點就是一個「轉(zhuǎn)發(fā)器」锭亏。

生產(chǎn)者先將消息投遞一個叫做「隊列」的容器中纠吴,然后再從這個容器中取出消息,最后再轉(zhuǎn)發(fā)給消費者慧瘤,僅此而已戴已。

圖片

上面這個圖便是消息隊列最原始的模型,它包含了兩個關(guān)鍵詞:消息隊列锅减。

1糖儡、消息:就是要傳輸?shù)臄?shù)據(jù),可以是最簡單的文本字符串怔匣,也可以是自定義的復(fù)雜格式(只要能按預(yù)定格式解析出來即可)握联。

2、隊列:一種先進先出數(shù)據(jù)結(jié)構(gòu)每瞒。

02 原始模型的進化

再看今天我們最常用的消息隊列產(chǎn)品(RocketMQ金闽、Kafka 等等)垂睬,你會發(fā)現(xiàn):它們都在最原始的消息模型上做了擴展乖寒,同時提出了一些新名詞,比如:主題(topic)瘸味、分區(qū)(partition)浓利、隊列(queue)等等挤庇。

要徹底理解這些五花八門的新概念,我們化繁為簡荞膘,先從消息模型的演進說起(道理好比:架構(gòu)從來不是設(shè)計出來的罚随,而是演進而來的

2.1 隊列模型

最初的消息隊列就是上一節(jié)講的原始模型玉工,它是一個嚴格意義上的隊列(Queue)羽资。消息按照什么順序?qū)戇M去,就按照什么順序讀出來遵班。不過屠升,隊列沒有 “讀” 這個操作潮改,讀就是出隊,從隊頭中 “刪除” 這個消息腹暖。

圖片

它允許多個生產(chǎn)者往同一個隊列發(fā)送消息汇在。但是,如果有多個消費者脏答,實際上是競爭的關(guān)系糕殉,也就是一條消息只能被其中一個消費者接收到,讀完即被刪除殖告。

2.2 發(fā)布-訂閱模型

如果需要將一份消息數(shù)據(jù)分發(fā)給多個消費者阿蝶,并且每個消費者都要求收到全量的消息。很顯然黄绩,隊列模型無法滿足這個需求羡洁。

一個可行的方案是:為每個消費者創(chuàng)建一個單獨的隊列,讓生產(chǎn)者發(fā)送多份爽丹。這種做法比較笨筑煮,而且同一份數(shù)據(jù)會被復(fù)制多份,也很浪費空間粤蝎。

為了解決這個問題真仲,就演化出了另外一種消息模型:發(fā)布-訂閱模型。

圖片

在發(fā)布-訂閱模型中诽里,存放消息的容器變成了 “主題”袒餐,訂閱者在接收消息之前需要先 “訂閱主題”。最終谤狡,每個訂閱者都可以收到同一個主題的全量消息灸眼。

仔細對比下它和 “隊列模式” 的異同:生產(chǎn)者就是發(fā)布者,隊列就是主題墓懂,消費者就是訂閱者焰宣,無本質(zhì)區(qū)別。唯一的不同點在于:一份消息數(shù)據(jù)是否可以被多次消費捕仔。

2.3 小結(jié)

最后做個小結(jié)匕积,上面兩種模型說白了就是:單播和廣播的區(qū)別。而且榜跌,當發(fā)布-訂閱模型中只有 1 個訂閱者時闪唆,它和隊列模型就一樣了,因此在功能上是完全兼容隊列模型的钓葫。

這也解釋了為什么現(xiàn)代主流的 RocketMQ悄蕾、Kafka 都是直接基于發(fā)布-訂閱模型實現(xiàn)的?此外,RabbitMQ 中之所以有一個 Exchange 模塊帆调?其實也是為了解決消息的投遞問題奠骄,可以變相實現(xiàn)發(fā)布-訂閱模型。

包括大家接觸到的 “消費組”番刊、“集群消費”含鳞、“廣播消費” 這些概念,都和上面這兩種模型相關(guān)芹务,以及在應(yīng)用層面大家最常見的情形:組間廣播蝉绷、組內(nèi)單播,也屬于此范疇枣抱。

所以潜必,先掌握一些共性的理論,對于大家再去學習各個消息中間件的具體實現(xiàn)原理時沃但,其實能更好地抓住本質(zhì)磁滚,分清概念。

03 透過模型看 MQ 的應(yīng)用場景

目前宵晚,MQ 的應(yīng)用場景非常多垂攘,大家能倒背如流的是:系統(tǒng)解耦、異步通信和流量削峰淤刃。除此之外晒他,還有延遲通知、最終一致性保證逸贾、順序消息陨仅、流式處理等等。

那到底是先有消息模型铝侵,還是先有應(yīng)用場景呢灼伤?答案肯定是:先有應(yīng)用場景(也就是先有問題),再有消息模型咪鲜,因為消息模型只是解決方案的抽象而已狐赡。

MQ 經(jīng)過 30 多年的發(fā)展,能從最原始的隊列模型發(fā)展到今天百花齊放的各種消息中間件(平臺級的解決方案)疟丙,我覺得萬變不離其宗颖侄,還是得益于:消息模型的適配性很廣。

我們試著重新理解下消息隊列的模型享郊。它其實解決的是:生產(chǎn)者和消費者的通信問題览祖。那它對比 RPC 有什么聯(lián)系和區(qū)別呢?

圖片

通過對比炊琉,能很明顯地看出兩點差異:

1展蒂、解耦:引入 MQ 后,由之前的一次 RPC 變成了現(xiàn)在的兩次 RPC,而且生產(chǎn)者只跟隊列耦合玄货,它根本無需知道消費者的存在。

2悼泌、同步轉(zhuǎn)異步:多了一個中間節(jié)點「隊列」進行消息轉(zhuǎn)儲松捉,相當于將同步變成了異步。

再返過來思考 MQ 的所有應(yīng)用場景馆里,就不難理解 MQ 為什么適用了隘世?因為這些應(yīng)用場景無外乎都利用了上面兩個特性。

舉一個實際例子鸠踪,比如說電商業(yè)務(wù)中最常見的「訂單支付」場景:在訂單支付成功后丙者,需要更新訂單狀態(tài)、更新用戶積分营密、通知商家有新訂單械媒、更新推薦系統(tǒng)中的用戶畫像等等。

圖片

引入 MQ 后评汰,訂單支付現(xiàn)在只需要關(guān)注它最重要的流程:更新訂單狀態(tài)即可纷捞。其他不重要的事情全部交給 MQ 來通知。這便是 MQ 解決的最核心的問題:系統(tǒng)解耦被去。

改造前訂單系統(tǒng)依賴 3 個外部系統(tǒng)主儡,改造后僅僅依賴 MQ,而且后續(xù)業(yè)務(wù)再擴展(比如:營銷系統(tǒng)打算針對支付用戶獎勵優(yōu)惠券)惨缆,也不涉及訂單系統(tǒng)的修改糜值,從而保證了核心流程的穩(wěn)定性,降低了維護成本坯墨。

這個改造還帶來了另外一個好處:因為 MQ 的引入寂汇,更新用戶積分、通知商家捣染、更新用戶畫像這些步驟全部變成了異步執(zhí)行健无,能減少訂單支付的整體耗時,提升訂單系統(tǒng)的吞吐量液斜。這便是 MQ 的另一個典型應(yīng)用場景:異步通信累贤。

除此以外,由于隊列能轉(zhuǎn)儲消息少漆,對于超出系統(tǒng)承載能力的場景臼膏,可以用 MQ 作為 “漏斗” 進行限流保護,即所謂的流量削峰示损。

我們還可以利用隊列本身的順序性渗磅,來滿足消息必須按順序投遞的場景;利用隊列 + 定時任務(wù)來實現(xiàn)消息的延時消費 ……

MQ 其他的應(yīng)用場景基本類似,都能回歸到消息模型的特性上始鱼,找到它適用的原因仔掸,這里就不一一分析了。

總之医清,就是建議大家多從復(fù)雜多變的實踐場景再回歸到理論層面進行思考和抽象起暮,這樣能吃得更透。

04 如何設(shè)計一個 MQ会烙?

到底如何設(shè)計一個 MQ负懦?

4.1 MQ 的雛形

我們還是先從簡單版的 MQ 入手,如果只是實現(xiàn)一個很粗糙的 MQ柏腻,完全不考慮生產(chǎn)環(huán)境的要求纸厉,該如何設(shè)計呢?

文章開頭說過五嫂,任何 MQ 無外乎:一發(fā)一存一消費颗品,這是 MQ 最核心的功能需求。另外沃缘,從技術(shù)維度來看 MQ 的通信模型抛猫,可以理解成:兩次 RPC + 消息轉(zhuǎn)儲。

有了這些理解孩灯,我相信只要有一定的編程基礎(chǔ)闺金,不用 1 個小時就能寫出一個 MQ 雛形:

1、直接利用成熟的 RPC 框架(Dubbo 或者 Thrift)峰档,實現(xiàn)兩個接口:發(fā)消息和讀消息败匹。

2、消息放在本地內(nèi)存中即可讥巡,數(shù)據(jù)結(jié)構(gòu)可以用 JDK 自帶的 ArrayBlockingQueue 掀亩。

4.2 寫一個適用于生產(chǎn)環(huán)境的 MQ

當然,我們的目標絕不止于一個 MQ 雛形欢顷,而是希望實現(xiàn)一個可用于生產(chǎn)環(huán)境的消息中間件槽棍,那難度肯定就不是一個量級了,具體我們該如何下手呢抬驴?

1炼七、先把握這個問題的關(guān)鍵點假如我們還是只考慮最基礎(chǔ)的功能:發(fā)消息、存消息布持、消費消息(支持發(fā)布-訂閱模式)豌拙。那在生產(chǎn)環(huán)境中,這些基礎(chǔ)功能將面臨哪些挑戰(zhàn)呢题暖?我們能很快想到下面這些:

1按傅、高并發(fā)場景下捉超,如何保證收發(fā)消息的性能?

2唯绍、如何保證消息服務(wù)的高可用和高可靠拼岳?

3、如何保證服務(wù)是可以水平任意擴展的况芒?

4惜纸、如何保證消息存儲也是水平可擴展的?

5牛柒、各種元數(shù)據(jù)(比如集群中的各個節(jié)點、主題痊乾、消費關(guān)系等)如何管理皮壁,需不需要考慮數(shù)據(jù)的一致性?

可見哪审,高并發(fā)場景下的三高問題在你設(shè)計一個 MQ 時都會遇到蛾魄,「如何滿足高性能、高可靠等非功能性需求」才是這個問題的關(guān)鍵所在湿滓。

2滴须、整體設(shè)計思路

先來看下整體架構(gòu),會涉及三類角色:

圖片

另外叽奥,將「一發(fā)一存一消費」這個核心流程進一步細化后扔水,比較完整的數(shù)據(jù)流如下:

圖片

基于上面兩個圖,我們可以很快明確出 3 類角色的作用朝氓,分別如下:

1魔市、Broker(服務(wù)端):MQ 中最核心的部分,是 MQ 的服務(wù)端赵哲,核心邏輯幾乎全在這里待德,它為生產(chǎn)者和消費者提供 RPC 接口,負責消息的存儲枫夺、備份和刪除将宪,以及消費關(guān)系的維護等。

2橡庞、Producer(生產(chǎn)者):MQ 的客戶端之一较坛,調(diào)用 Broker 提供的 RPC 接口發(fā)送消息。

3扒最、Consumer(消費者):MQ 的另外一個客戶端燎潮,調(diào)用 Broker 提供的 RPC 接口接收消息,同時完成消費確認扼倘。

3确封、詳細設(shè)計下面除呵,再展開討論下一些具體的技術(shù)難點和可行的解決方案。

難點1:RPC 通信

解決的是 Broker 與 Producer 以及 Consumer 之間的通信問題爪喘。如果不重復(fù)造輪子颜曾,直接利用成熟的 RPC 框架 Dubbo 或者 Thrift 實現(xiàn)即可,這樣不需要考慮服務(wù)注冊與發(fā)現(xiàn)秉剑、負載均衡泛豪、通信協(xié)議、序列化方式等一系列問題了侦鹏。

當然诡曙,你也可以基于 Netty 來做底層通信,用 Zookeeper略水、Euraka 等來做注冊中心价卤,然后自定義一套新的通信協(xié)議(類似 Kafka),也可以基于 AMQP 這種標準化的 MQ 協(xié)議來做實現(xiàn)(類似 RabbitMQ)渊涝。對比直接用 RPC 框架慎璧,這種方案的定制化能力和優(yōu)化空間更大。

難點2:高可用設(shè)計

高可用主要涉及兩方面:Broker 服務(wù)的高可用跨释、存儲方案的高可用胸私。可以拆開討論鳖谈。

Broker 服務(wù)的高可用岁疼,只需要保證 Broker 可水平擴展進行集群部署即可,進一步通過服務(wù)自動注冊與發(fā)現(xiàn)缆娃、負載均衡五续、超時重試機制、發(fā)送和消費消息時的 ack 機制來保證龄恋。

存儲方案的高可用有兩個思路:1)參考 Kafka 的分區(qū) + 多副本模式疙驾,但是需要考慮分布式場景下數(shù)據(jù)復(fù)制和一致性方案(類似 Zab、Raft等協(xié)議)郭毕,并實現(xiàn)自動故障轉(zhuǎn)移它碎;2)還可以用主流的 DB、分布式文件系統(tǒng)显押、帶持久化能力的 KV 系統(tǒng)扳肛,它們都有自己的高可用方案。

難點3:存儲設(shè)計

消息的存儲方案是 MQ 的核心部分乘碑,可靠性保證已經(jīng)在高可用設(shè)計中談過了挖息,可靠性要求不高的話直接用內(nèi)存或者分布式緩存也可以。這里重點說一下存儲的高性能如何保證兽肤?這個問題的決定因素在于存儲結(jié)構(gòu)的設(shè)計套腹。

目前主流的方案是:追加寫日志文件(數(shù)據(jù)部分) + 索引文件的方式(很多主流的開源 MQ 都是這種方式)绪抛,索引設(shè)計上可以考慮稠密索引或者稀疏索引,查找消息可以利用跳轉(zhuǎn)表电禀、二分查找等幢码,還可以通過操作系統(tǒng)的頁緩存、零拷貝等技術(shù)來提升磁盤文件的讀寫性能尖飞。

如果不追求很高的性能症副,也可以考慮現(xiàn)成的分布式文件系統(tǒng)、KV 存儲或者數(shù)據(jù)庫方案政基。

難點4:消費關(guān)系管理

為了支持發(fā)布-訂閱的廣播模式贞铣,Broker 需要知道每個主題都有哪些 Consumer 訂閱了,基于這個關(guān)系進行消息投遞沮明。

由于 Broker 是集群部署的辕坝,所以消費關(guān)系通常維護在公共存儲上,可以基于 Zookeeper珊擂、Apollo 等配置中心來管理以及進行變更通知圣勒。

難點5:高性能設(shè)計

存儲的高性能前面已經(jīng)談過了费变,當然還可以從其他方面進一步優(yōu)化性能摧扇。

比如 Reactor 網(wǎng)絡(luò) IO 模型、業(yè)務(wù)線程池的設(shè)計挚歧、生產(chǎn)端的批量發(fā)送扛稽、Broker 端的異步刷盤、消費端的批量拉取等等滑负。

4.3 小結(jié)

再總結(jié)下在张,要回答好:如何設(shè)計一個 MQ?

1矮慕、需要從功能性需求(收發(fā)消息)和非功能性需求(高性能帮匾、高可用、高擴展等)兩方面入手痴鳄。

2瘟斜、功能性需求不是重點,能覆蓋 MQ 最基礎(chǔ)的功能即可痪寻,至于延時消息螺句、事務(wù)消息、重試隊列等高級特性只是錦上添花的東西橡类。

3蛇尚、最核心的是:能結(jié)合功能性需求,理清楚整體的數(shù)據(jù)流顾画,然后順著這個思路去考慮非功能性的訴求如何滿足取劫,這才是技術(shù)難點所在匆笤。

05 寫在最后

這篇文章從 MQ 一發(fā)一存一消費這個本質(zhì)出發(fā),講解了消息模型的演進過程勇凭,這是 MQ 最核心的理論基礎(chǔ)疚膊。基于此虾标,大家也能更容易理解 MQ 的各種新名詞以及應(yīng)用場景寓盗。

最后通過回答:如何設(shè)計一個 MQ?目的是讓大家對 MQ 的核心組件和技術(shù)難點有一個清晰的認識璧函。另外傀蚌,帶著這個問題的答案再去學習 Kafka、RocketMQ 等具體的消息中間件時蘸吓,也會更有側(cè)重點善炫。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市库继,隨后出現(xiàn)的幾起案子箩艺,更是在濱河造成了極大的恐慌,老刑警劉巖宪萄,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件艺谆,死亡現(xiàn)場離奇詭異,居然都是意外死亡拜英,警方通過查閱死者的電腦和手機静汤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來居凶,“玉大人虫给,你說我怎么就攤上這事∠辣蹋” “怎么了抹估?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長弄兜。 經(jīng)常有香客問我药蜻,道長,這世上最難降的妖魔是什么挨队? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任谷暮,我火速辦了婚禮,結(jié)果婚禮上盛垦,老公的妹妹穿的比我還像新娘湿弦。我一直安慰自己,他們只是感情好腾夯,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布颊埃。 她就那樣靜靜地躺著蔬充,像睡著了一般。 火紅的嫁衣襯著肌膚如雪班利。 梳的紋絲不亂的頭發(fā)上饥漫,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機與錄音罗标,去河邊找鬼庸队。 笑死,一個胖子當著我的面吹牛闯割,可吹牛的內(nèi)容都是我干的彻消。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼宙拉,長吁一口氣:“原來是場噩夢啊……” “哼宾尚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起谢澈,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤煌贴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后锥忿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牛郑,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年缎谷,在試婚紗的時候發(fā)現(xiàn)自己被綠了井濒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灶似。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡列林,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出酪惭,到底是詐尸還是另有隱情希痴,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布春感,位于F島的核電站砌创,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鲫懒。R本人自食惡果不足惜嫩实,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望窥岩。 院中可真熱鬧甲献,春花似錦、人聲如沸颂翼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至球及,卻和暖如春氧骤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吃引。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工筹陵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人镊尺。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓惶翻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鹅心。 傳聞我的和親對象是個殘疾皇子吕粗,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

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