深入理解消息队列(场景,对比,原理和设计思想)
導(dǎo)語(yǔ)?|?消息隊(duì)列也通常稱(chēng)為消息中間件,提到消息隊(duì)列,大部分互聯(lián)網(wǎng)人或多或少都聽(tīng)過(guò)該名詞。對(duì)于后端工程師而言,更是日常開(kāi)發(fā)中必備的一項(xiàng)技能。隨著大數(shù)據(jù)時(shí)代的到來(lái),apache旗下的Kafka一度成為消息隊(duì)列的代名詞,提起消息隊(duì)列大家自然而然就想到了Kafka。然而消息隊(duì)列本身是工程領(lǐng)域內(nèi)一種解決問(wèn)題的通用方案。它的背后有著一些通用的設(shè)計(jì)思想和經(jīng)典模型,這些是消息隊(duì)列的精髓和靈魂。它們獨(dú)立于任何一種消息隊(duì)列的具體實(shí)現(xiàn)(例如Kafka),但每種消息隊(duì)列(除了Kafka外,還有RocketMQ、Pulsar等)的實(shí)現(xiàn)中到處體現(xiàn)著這些設(shè)計(jì)思想。本文騰訊Cloud9項(xiàng)目組后臺(tái)開(kāi)發(fā)工程師文小飛(Jaydenwen)主要從抽象層面來(lái)簡(jiǎn)單談?wù)勏㈥?duì)列背后的一些設(shè)計(jì)思想,輔助理解消息隊(duì)列這一類(lèi)組件。
本文主要解決三個(gè)問(wèn)題:
1. 消息隊(duì)列適合什么場(chǎng)景?
2. 消息隊(duì)列有哪些主流產(chǎn)品、各自的優(yōu)缺點(diǎn)?
3.?消息隊(duì)列背后的設(shè)計(jì)思想(整體核心模型、數(shù)據(jù)存儲(chǔ)考量、數(shù)據(jù)獲取方案對(duì)比、消費(fèi)者消費(fèi)模型)
一、消息隊(duì)列適合哪些場(chǎng)景
消息隊(duì)列:它主要用來(lái)暫存生產(chǎn)者生產(chǎn)的消息,供后續(xù)其他消費(fèi)者來(lái)消費(fèi)。它的功能主要有兩個(gè):a.暫存(存儲(chǔ))、b.隊(duì)列(有序:先進(jìn)先出)。其他大部分場(chǎng)景對(duì)數(shù)據(jù)的消費(fèi)沒(méi)有順序要求,主要用它的暫存能力?。從目前互聯(lián)網(wǎng)應(yīng)用中使用消息隊(duì)列的場(chǎng)景來(lái)看,主要有以下三個(gè):
異步處理數(shù)據(jù)
系統(tǒng)應(yīng)用解耦
業(yè)務(wù)流量削峰
下面對(duì)上述每一種場(chǎng)景進(jìn)行簡(jiǎn)單描述。
(一)異步處理數(shù)據(jù)
第一個(gè)例子我們以現(xiàn)實(shí)生活中送快遞來(lái)類(lèi)比,在該例子中我們把暫存快遞的快遞柜比作暫存數(shù)據(jù)的消息隊(duì)列。我們來(lái)看一下在現(xiàn)實(shí)生活中,沒(méi)有快遞柜時(shí),快遞員把快遞送到目的地后,一般需要聯(lián)系收貨人來(lái)簽收快遞,如果收貨人此時(shí)有空,那一切都很順利。但如果收貨人此時(shí)不方便(開(kāi)會(huì)、正在吃午飯、外出出差……)。那對(duì)于快遞員而言,就很尷尬,需要一直等待(開(kāi)會(huì)or吃午飯)或者將快遞拿回去(外出出差),導(dǎo)致白跑一趟。這對(duì)于快遞員而言簡(jiǎn)直太不友好。
從這兒可以看出,當(dāng)快遞員送貨時(shí),是一個(gè)同步狀態(tài),即需要等待收貨人簽收后才能去送下一趟單子,對(duì)快遞員而言效率太低。上述例子雖然有點(diǎn)牽強(qiáng),大家湊合理解,意思能大概理解到位就ok。
接著我們?cè)賮?lái)看一下,當(dāng)有了快遞柜后,對(duì)于快遞員而言,每次需要送快遞時(shí),只需要將快遞投擲到快遞柜,然后再通過(guò)短信或者電話(huà)通知收貨人具體的快遞信息即可。他就可以繼續(xù)去派送下一單。而對(duì)于收獲人而言,也可以根據(jù)具體方便的時(shí)間來(lái)取件。這樣一來(lái),二者完全異步了,不用相互等待了。
在這個(gè)例子中,如果把快遞員比作生產(chǎn)者,收貨人比作是消費(fèi)者,則快遞柜就類(lèi)似于消息隊(duì)列。我們可以通過(guò)采用消息隊(duì)列來(lái)實(shí)現(xiàn)異步數(shù)據(jù)的處理。
(二)系統(tǒng)應(yīng)用解耦
案例二,我們以目前最主流的推薦系統(tǒng)中內(nèi)容的流轉(zhuǎn)來(lái)舉例。在推薦系統(tǒng)中當(dāng)創(chuàng)作者發(fā)布了一條內(nèi)容后,該內(nèi)容會(huì)首先經(jīng)過(guò)安全部分的相關(guān)審核,通過(guò)審核后的內(nèi)容,通常需要進(jìn)行內(nèi)容入庫(kù)存儲(chǔ)、送入模型進(jìn)行特征的計(jì)算和生成。
假如后期我們想提升推薦的效果,需要單獨(dú)構(gòu)建一份冷啟動(dòng)的推薦池,此時(shí)也需要用到這部分內(nèi)容,那問(wèn)題來(lái)了,在沒(méi)有使用消息隊(duì)列時(shí),對(duì)于上游服務(wù)而言,需要通過(guò)擴(kuò)展新的邏輯來(lái)實(shí)現(xiàn)該功能。同時(shí)在該場(chǎng)景里,會(huì)存在依賴(lài)三個(gè)下游服務(wù),如果其中一個(gè)下游服務(wù)失敗后,該如何處理,是重試還是返回失敗等這些細(xì)節(jié)的處理。如果后期這部分?jǐn)?shù)據(jù)還想在其他渠道分發(fā),那又該如何對(duì)接。明顯這種場(chǎng)景下面臨著系統(tǒng)緊耦合的問(wèn)題。
我們?cè)賮?lái)看一下,如果我們一開(kāi)始就引入了消息隊(duì)列,那問(wèn)題又會(huì)變成怎樣的呢?當(dāng)內(nèi)容審核通過(guò)后,就直接將數(shù)據(jù)生產(chǎn)出來(lái)丟到消息隊(duì)列中,下游的多個(gè)服務(wù)再?gòu)南㈥?duì)列消費(fèi)數(shù)據(jù)。當(dāng)后續(xù)這一份數(shù)據(jù)需要擴(kuò)展供其他系統(tǒng)使用時(shí),也只要通過(guò)新的消費(fèi)者來(lái)接入到消息隊(duì)列消費(fèi)就ok。上游生產(chǎn)消息的模塊不要做任何的改動(dòng)。這樣我們就通過(guò)消息隊(duì)列進(jìn)行了系統(tǒng)應(yīng)用之間的解耦。這是消息隊(duì)列的第二個(gè)用途。
(三)業(yè)務(wù)流量削峰
消息對(duì)應(yīng)的第三個(gè)使用場(chǎng)景便是削峰。在現(xiàn)如今的互聯(lián)網(wǎng)世界中,電商場(chǎng)景中每年的618秒殺活動(dòng)、雙11搶購(gòu)便是最典型的案例。這種場(chǎng)景中系統(tǒng)的峰值流量往往集中于一小段時(shí)間內(nèi),平常的流量比較可控,所以為了防止系統(tǒng)在短時(shí)間內(nèi)的峰值流量沖垮,往往采用消息隊(duì)列來(lái)削弱峰值流量,高峰值期間產(chǎn)生的訂單消息等數(shù)據(jù)首先送入到消息隊(duì)列中暫存,然后供下游系統(tǒng)根據(jù)自己的消費(fèi)能力來(lái)逐步處理。同時(shí)這類(lèi)消息往往對(duì)時(shí)延的要求不是很高,比較適合采用消息隊(duì)列暫存。
(四)小結(jié)
最后我們?cè)趯?duì)本節(jié)的內(nèi)容做一個(gè)簡(jiǎn)單的總結(jié),上面通過(guò)三個(gè)簡(jiǎn)單的實(shí)例介紹了消息隊(duì)列的典型的三個(gè)使用場(chǎng)景:異步、解耦、削峰。換個(gè)角度來(lái)理解可以看到,消息隊(duì)列主要適用于處理對(duì)消息要求不是很實(shí)時(shí),同時(shí)一份數(shù)據(jù)可能會(huì)多處使用的場(chǎng)景,不同的使用方處理速率不同。更多的消息隊(duì)列的使用場(chǎng)景讀者可以自行找資料閱讀和總結(jié)。
二、消息隊(duì)列“家族”有哪些成員
(一)消息隊(duì)列主流產(chǎn)品
上圖根據(jù)時(shí)間線(xiàn)展示了不同時(shí)間點(diǎn)產(chǎn)生的消息隊(duì)列產(chǎn)品,主要的產(chǎn)品有:ActiveMQ(2003)、RabbitMQ(2006)、Kafka(2010)、RocketMQ(2011)、Pulsar(2012)。這些消息隊(duì)列中或多或少我們都聽(tīng)過(guò)一些,部分也在項(xiàng)目中真實(shí)使用過(guò)。下面對(duì)上述幾個(gè)消息隊(duì)列做一個(gè)簡(jiǎn)單的介紹。
ActiveMQ:ActiveMQ由Apache軟件基金會(huì)基于Java語(yǔ)言開(kāi)發(fā)的一個(gè)開(kāi)源的消息代理。能夠支持多個(gè)客戶(hù)機(jī)或服務(wù)器。計(jì)算機(jī)集群等屬性支持ActiveMQ來(lái)管理通信系統(tǒng)。?
RabbitMQ:RabbitMQ是實(shí)現(xiàn)了高級(jí)消息隊(duì)列協(xié)議(AMQP)的開(kāi)源消息代理軟件(亦稱(chēng)面向消息的中間件)。RabbitMQ服務(wù)器是用Erlang語(yǔ)言編寫(xiě)的,而集群和故障轉(zhuǎn)移是構(gòu)建在開(kāi)放電信平臺(tái)框架上的。所有主要的編程語(yǔ)言均有與代理接口通訊的客戶(hù)端庫(kù)。RabbitMQ支持多種消息傳遞協(xié)議、傳遞確認(rèn)等特性。
Kafka:Apache Kafka是由Apache軟件基金會(huì)開(kāi)發(fā)的一個(gè)開(kāi)源消息系統(tǒng)項(xiàng)目,由Scala寫(xiě)成。Kafka最初是由LinkedIn開(kāi)發(fā),并于2011年初開(kāi)源。2012年10月從Apache Incubator畢業(yè)。該項(xiàng)目的目標(biāo)是為處理實(shí)時(shí)數(shù)據(jù)提供一個(gè)統(tǒng)一、高通量、低等待的平臺(tái)。Kafka是一個(gè)分布式的、分區(qū)的、多復(fù)本的日志提交服務(wù)。它通過(guò)一種獨(dú)一無(wú)二的設(shè)計(jì)提供了一個(gè)消息系統(tǒng)的功能。?
RocketMQ:Apache RocketMQ是一個(gè)分布式消息和流媒體平臺(tái),具有低延遲、強(qiáng)一致、高性能和可靠性、萬(wàn)億級(jí)容量和靈活的可擴(kuò)展性。它有借鑒Kafka的設(shè)計(jì)思想,但不是kafka的拷貝。?
Pulsar:Apache Pulsar是Apache軟件基金會(huì)頂級(jí)項(xiàng)目,是下一代云原生分布式消息流平臺(tái),集消息、存儲(chǔ)、輕量化函數(shù)式計(jì)算為一體,采用計(jì)算與存儲(chǔ)分離架構(gòu)設(shè)計(jì),支持多租戶(hù)、持久化存儲(chǔ)、多機(jī)房跨區(qū)域數(shù)據(jù)復(fù)制,具有強(qiáng)一致性、高吞吐、低延時(shí)及高可擴(kuò)展性等流數(shù)據(jù)存儲(chǔ)特性,被看作是云原生時(shí)代實(shí)時(shí)消息流傳輸、存儲(chǔ)和計(jì)算最佳解決方案。
(二)不同消息隊(duì)列對(duì)比
上圖詳細(xì)的展示了幾種消息隊(duì)列的各自功能及優(yōu)缺點(diǎn),首先,ActiveMQ和RabbitMQ二者屬于同一量級(jí),在吞吐量上比后面三者差一個(gè)量級(jí);其次,支持強(qiáng)一致性的有RocketMQ和Pulsar,在對(duì)消息一致性要求比較高的場(chǎng)景可以采用這些產(chǎn)品。同時(shí)kafka雖然會(huì)有數(shù)據(jù)丟失的風(fēng)險(xiǎn),但其吞吐量比較高同時(shí)社區(qū)非常活躍,在大數(shù)據(jù)的絕大部分場(chǎng)景里,都可以采用Kafka;最后Kafka、RocketMQ、Pulsar這幾款是基于磁盤(pán)存儲(chǔ)數(shù)據(jù)的,內(nèi)存加速訪(fǎng)問(wèn)。而ActiveMQ、RabbitMQ采用內(nèi)存存儲(chǔ)數(shù)據(jù),也支持?jǐn)?shù)據(jù)持久化到磁盤(pán)。
三、消息隊(duì)列背后的設(shè)計(jì)思想
在前面,第一節(jié)內(nèi)容中,主要介紹了為什么要使用消息隊(duì)列,消息隊(duì)列適合解決哪些問(wèn)題?在第二節(jié)內(nèi)容中,又介紹了有哪些可選擇的消息隊(duì)列,以及他們之間各自的優(yōu)缺點(diǎn)。這一節(jié)是最重要的內(nèi)容,主要會(huì)介紹一下上述消息隊(duì)列背后的通用的一些設(shè)計(jì)思想。部分思想可以擴(kuò)展到其他的業(yè)務(wù)模型或者領(lǐng)域內(nèi)。后面講到對(duì)應(yīng)內(nèi)容也會(huì)有所提及。
(一)消息隊(duì)列核心模型
上圖是幾乎所有消息隊(duì)列設(shè)計(jì)的一個(gè)核心模型。對(duì)于一個(gè)消息隊(duì)列而言,從數(shù)據(jù)流向的維度,可以拆解為三大部分:生產(chǎn)者、消息隊(duì)列集群、消費(fèi)者,數(shù)據(jù)是從生產(chǎn)者流向消息隊(duì)列集群,最終再?gòu)南㈥?duì)列集群流向消費(fèi)者,下面對(duì)這幾個(gè)概念進(jìn)行一一闡述。
生產(chǎn)者:生產(chǎn)數(shù)據(jù)的服務(wù),通常也稱(chēng)為數(shù)據(jù)的輸入提供方,這里的數(shù)據(jù)通常指我們的業(yè)務(wù)數(shù)據(jù),例如推薦場(chǎng)景中用戶(hù)對(duì)內(nèi)容的點(diǎn)擊數(shù)據(jù)、內(nèi)容曝光數(shù)據(jù)、電商中的訂單數(shù)據(jù)等等。生產(chǎn)者通常是作為客戶(hù)端的方式存在,但在支持事務(wù)消息的消息隊(duì)列中,生產(chǎn)者也被設(shè)計(jì)為服務(wù)端,實(shí)現(xiàn)事務(wù)消息這一特性。其次生產(chǎn)者通常會(huì)有多個(gè),消息隊(duì)列集群內(nèi)部也會(huì)有多個(gè)分區(qū)隊(duì)列,所以在生產(chǎn)者發(fā)送數(shù)據(jù)時(shí),通常會(huì)存在負(fù)載均衡的一些策略,常見(jiàn)的有按key hash、輪詢(xún)、隨機(jī)等方式。其本質(zhì)是一條數(shù)據(jù),被消息隊(duì)列封裝后也被稱(chēng)為一條消息,該條消息只能發(fā)送到其消息隊(duì)列集群內(nèi)部的一個(gè)分區(qū)隊(duì)列中。因此只需按照一定的策略從多個(gè)隊(duì)列中選擇一個(gè)隊(duì)列即可。
消息隊(duì)列集群:?消息隊(duì)列集群是消息隊(duì)列這種組件實(shí)現(xiàn)中的核心中的核心,它的主要功能是存儲(chǔ)消息、過(guò)濾消息、分發(fā)消息。
其中存儲(chǔ)消息主要指生產(chǎn)者生產(chǎn)的數(shù)據(jù)需要存儲(chǔ)到消息隊(duì)列內(nèi)部;存儲(chǔ)消息可以說(shuō)是消息隊(duì)列的核心,一個(gè)消息隊(duì)列吞吐量的高低、性能優(yōu)劣都和它的存儲(chǔ)模型脫不開(kāi)關(guān)系。這部分內(nèi)容會(huì)在下一部分(3.2)進(jìn)行介紹。?
過(guò)濾消息只指消息隊(duì)列可以通過(guò)一定的規(guī)則或者策略進(jìn)行消息的過(guò)濾,該項(xiàng)能力通常也被稱(chēng)為消息路由;過(guò)濾消息屬于高階的特性功能,AMQP協(xié)議對(duì)這些能力抽象的比較完備,部分消息隊(duì)列可以選擇性的實(shí)現(xiàn)該協(xié)議來(lái)達(dá)到該功能,關(guān)于AMQP協(xié)議內(nèi)容讀者可以自行搜索資料閱讀,此處不再展開(kāi)。
分發(fā)消息是指消息隊(duì)列通常需要將消息分發(fā)給處理同一邏輯的多個(gè)消費(fèi)者處理或者處理不同邏輯的不同消費(fèi)者處理。分發(fā)消息可以說(shuō)和消費(fèi)者模型想掛鉤,這塊會(huì)涉及到不同的數(shù)據(jù)獲取方式,也會(huì)涉及到消費(fèi)者消費(fèi)消息的模型。
此外絕大部分的消息隊(duì)列也都支持對(duì)消息進(jìn)行分類(lèi),分類(lèi)的標(biāo)簽稱(chēng)為topic(主題),一個(gè)topic中存放的是同一類(lèi)消息。
消費(fèi)者:最終消息隊(duì)列存儲(chǔ)的消息會(huì)被消費(fèi)者消費(fèi)使用,消費(fèi)者也可以看做消息隊(duì)列中數(shù)據(jù)的輸出方。消費(fèi)者通常有兩種方式從消息隊(duì)列中獲取數(shù)據(jù):推送(push)數(shù)據(jù)、拉取(pull)數(shù)據(jù)。其次消費(fèi)者也經(jīng)常是作為客戶(hù)端的角色出現(xiàn)在在消息隊(duì)列這種組件中。
(二)消息隊(duì)列數(shù)據(jù)組織方式
在這一節(jié)中,我們?cè)敿?xì)看看消息隊(duì)列存儲(chǔ)消息這個(gè)環(huán)節(jié)的一些權(quán)衡考量,通常數(shù)據(jù)的存儲(chǔ)無(wú)外乎就是兩種,一種是存儲(chǔ)在非易失性存儲(chǔ)中,例如磁盤(pán)這種介質(zhì);另一種是選擇存儲(chǔ)在易失性存儲(chǔ)中,典型的就是內(nèi)存。關(guān)于二者的對(duì)比大家可以參考下表,此處就不再贅述。
通常在大部分組件設(shè)計(jì)時(shí),往往會(huì)選擇一種主要介質(zhì)來(lái)存儲(chǔ)、另一種介質(zhì)作為輔助使用。就拿redis來(lái)說(shuō),它主要采用內(nèi)存存儲(chǔ)數(shù)據(jù),磁盤(pán)用來(lái)做輔助的持久化。拿RabbitMQ舉例,它也是主要采用內(nèi)存存儲(chǔ)消息,但也支持將消息持久化到磁盤(pán)。而RocketMQ、Kafka、Pulsar這種,則是數(shù)據(jù)主要存儲(chǔ)在磁盤(pán),通過(guò)內(nèi)存來(lái)助力提升系統(tǒng)的性能。關(guān)系型數(shù)據(jù)庫(kù)例如mysql這種組件也是主要采用磁盤(pán)組織數(shù)據(jù),合理利用內(nèi)存提升性能。
針對(duì)采用內(nèi)存存儲(chǔ)數(shù)據(jù)的方案而言,難點(diǎn)一方面在于如何在不降低訪(fǎng)問(wèn)效率的情況下,充分利用有限的內(nèi)存空間來(lái)存儲(chǔ)盡可能多的數(shù)據(jù),這個(gè)過(guò)程中少不了對(duì)數(shù)據(jù)結(jié)構(gòu)的選型、優(yōu)化;另一方面在于如何保證數(shù)據(jù)盡可能少的丟失,我們可以看到針對(duì)此問(wèn)題的解決方案通常是快照+廣泛意義的wal文件來(lái)解決。此類(lèi)典型的代表就是redis啦。
針對(duì)采用磁盤(pán)存儲(chǔ)數(shù)據(jù)的方案而言,難點(diǎn)一方面在于如何根據(jù)系統(tǒng)所要解決的特點(diǎn)場(chǎng)景進(jìn)行合理的對(duì)磁盤(pán)布局。讀多寫(xiě)少情況下采用b+樹(shù)方式存儲(chǔ)數(shù)據(jù);寫(xiě)多讀少情況下采用lsm tree這類(lèi)方案處理。另一方面在于如何盡可能減少對(duì)磁盤(pán)的頻繁訪(fǎng)問(wèn),一些做法是采用mmap進(jìn)行內(nèi)存映射,提升讀性能;還有一些則是采用緩存機(jī)制緩存頻繁訪(fǎng)問(wèn)的數(shù)據(jù)。還有一些則是采用巧妙的數(shù)據(jù)結(jié)構(gòu)布局,充分利用磁盤(pán)預(yù)讀特性保證系統(tǒng)性能。
總的來(lái)說(shuō),針對(duì)寫(xiě)磁盤(pán)的優(yōu)化,要不采用順序?qū)懱嵘阅堋⒁徊捎卯惒綄?xiě)磁盤(pán)提升性能(異步寫(xiě)磁盤(pán)時(shí)需要結(jié)合wal保證數(shù)據(jù)的持久化,事實(shí)上wal也主要采用順序?qū)懙奶匦?;針對(duì)讀磁盤(pán)的優(yōu)化,一方面是緩存、另一方面是mmap內(nèi)存映射加速讀。
上述這些存儲(chǔ)方案上權(quán)衡的選擇在Kafka、RocketMQ、Pulsar中都可以看到。其實(shí)拋開(kāi)消息隊(duì)列而言,這些存儲(chǔ)方案的選擇上無(wú)論是關(guān)系型數(shù)據(jù)庫(kù)還是kv型組件都是通用的。
下圖列舉了幾種磁盤(pán)上的數(shù)據(jù)組織方式,僅供大家參考。
(三)獲取數(shù)據(jù)的推、拉兩種方案對(duì)比
在前面3.1節(jié)中提到,消費(fèi)者在從消息隊(duì)列中獲取數(shù)據(jù)時(shí),主要有兩種方案:
等待推送數(shù)據(jù)
主動(dòng)拉取數(shù)據(jù)
目前的消息隊(duì)列實(shí)現(xiàn)時(shí),都會(huì)選擇支持兩種的至少一種,關(guān)于這兩種方案的對(duì)比,大家可以參考下表。
在此處,個(gè)人想拋開(kāi)消息隊(duì)列談一點(diǎn)關(guān)于這兩種方案的理解,其實(shí)推拉模型不僅僅只用于消息隊(duì)列這種組件中,更一般意義上,它解決的其實(shí)是數(shù)據(jù)傳送雙方的一個(gè)問(wèn)題。本質(zhì)是數(shù)據(jù)需要從一方流向另一方。順著這個(gè)思路來(lái)看,下面這三個(gè)例子都是遵循這個(gè)原則。
網(wǎng)絡(luò)中傳輸?shù)臄?shù)據(jù):在IO多路復(fù)用中,以epoll為例,當(dāng)內(nèi)核檢測(cè)到監(jiān)聽(tīng)的描述符有數(shù)據(jù)到來(lái)時(shí),epoll_wait()阻塞會(huì)返回,上層用戶(hù)態(tài)程序就知道有數(shù)據(jù)就緒了,然后可以通過(guò)read()系統(tǒng)調(diào)用函數(shù)讀取數(shù)據(jù)。這個(gè)過(guò)程就緒通知,類(lèi)似于推送,但推送的不是數(shù)據(jù),而是數(shù)據(jù)就緒的信號(hào)。具體的數(shù)據(jù)獲取方式還是需要通過(guò)拉取的方式來(lái)主動(dòng)讀。
feeds流系統(tǒng)用戶(hù)時(shí)間線(xiàn)后臺(tái)實(shí)現(xiàn)方案(讀擴(kuò)散、寫(xiě)擴(kuò)散):?讀擴(kuò)散和寫(xiě)擴(kuò)散更是這樣一個(gè)case。對(duì)于讀擴(kuò)散而言,主要采用拉取的方式獲取數(shù)據(jù)。而對(duì)于寫(xiě)擴(kuò)散而言,它是典型的數(shù)據(jù)推送的方式。當(dāng)然在系統(tǒng)實(shí)現(xiàn)中,更復(fù)雜的場(chǎng)景往往會(huì)選擇讀寫(xiě)結(jié)合的思路來(lái)實(shí)現(xiàn)。
生活中的點(diǎn)外賣(mài)例子:當(dāng)下單點(diǎn)外賣(mài)時(shí),通常也會(huì)有兩種方式可以選擇:外賣(mài)派送、到店自取。不過(guò)通常外賣(mài)派送比較實(shí)時(shí),我們通常就選擇這種方式了而已。可以看出外賣(mài)派送其實(shí)就是一種推的方式,而到店自取,則是拉的方式。
(四)消息隊(duì)列消費(fèi)模型
本節(jié)我們來(lái)介紹最后一部分內(nèi)容,消息隊(duì)列中消費(fèi)者的消費(fèi)模型。下圖中上半部分展示了最簡(jiǎn)單的一種消費(fèi)模型。一個(gè)生產(chǎn)者、一個(gè)消費(fèi)者。但往往我們的一份數(shù)據(jù)通常會(huì)被不同場(chǎng)景所使用。那這個(gè)時(shí)候,首先就會(huì)存在每種場(chǎng)景需要使用全量的數(shù)據(jù)、而且不同場(chǎng)景之間不會(huì)相關(guān)影響,彼此獨(dú)立。方便理解起見(jiàn),我們假設(shè)有N個(gè)場(chǎng)景需要使用這同一份數(shù)據(jù),每個(gè)場(chǎng)景需要消費(fèi)全量的數(shù)據(jù)。而在N個(gè)場(chǎng)景中的一種場(chǎng)景里,又會(huì)有多個(gè)消費(fèi)者一起分?jǐn)傁M(fèi)這些數(shù)據(jù)。我們假設(shè)一個(gè)場(chǎng)景里有M個(gè)消費(fèi)者。由于每個(gè)場(chǎng)景中包含M個(gè)消費(fèi)者,我們也將其采用消費(fèi)者組來(lái)描述。通過(guò)上面的介紹,我們可以用下面一句話(huà)總結(jié)消息隊(duì)列中的消費(fèi)模型:
消費(fèi)者消費(fèi)者模型其實(shí)是一個(gè)1:N:M的關(guān)系,一份數(shù)據(jù)被N個(gè)消費(fèi)者組獨(dú)立使用,每個(gè)消費(fèi)者組中有M個(gè)消費(fèi)者進(jìn)行分?jǐn)傁M(fèi)。
其實(shí)這種模型也稱(chēng)為發(fā)布訂閱模型,對(duì)于一條消息而言,組間廣播、組內(nèi)單播。一條消息只能被一個(gè)消費(fèi)者組中的一個(gè)消費(fèi)者使用。在消費(fèi)者組內(nèi)部也存在一些負(fù)載均衡的策略。常用的有:輪詢(xún)、隨機(jī)、hash、一致性hash等方案。
(五)小結(jié)
第三部分內(nèi)容我們重點(diǎn)介紹了關(guān)于消息隊(duì)列背后的一些設(shè)計(jì)思想,其中包括:消息隊(duì)列的核心模型、數(shù)據(jù)存儲(chǔ)模型、推拉方案獲取數(shù)據(jù)對(duì)比、消費(fèi)者消費(fèi)模型。其中數(shù)據(jù)存儲(chǔ)模型不僅僅適用于消息隊(duì)列,也同樣適用于其他數(shù)據(jù)存儲(chǔ)組件的方案選擇。同理數(shù)據(jù)獲取的推拉兩種方案也不僅僅局限于消息隊(duì)列。我們可以在很多業(yè)務(wù)場(chǎng)景里看到同類(lèi)思想的影子。
四、總結(jié)
到此,本文也就告一段落了。本文主要從理論、抽象層面泛泛的談了下關(guān)于消息隊(duì)列的一些思想和理念。主要介紹了消息隊(duì)列的使用場(chǎng)景,主流的消息隊(duì)列可選方案以及他們之間的優(yōu)缺點(diǎn)。最后介紹了一些關(guān)于消息隊(duì)列背后的設(shè)計(jì)理念。本文只是拋磚引玉,希望上述內(nèi)容能輔助大家一起重新認(rèn)識(shí)消息隊(duì)列。后面會(huì)逐步挑選上述的幾種消息隊(duì)列(kafka、RocketMQ、Pulsar),重點(diǎn)分析其內(nèi)部實(shí)現(xiàn)機(jī)制,敬請(qǐng)期待。限于個(gè)人水平有限,理解有誤之處歡迎大家批評(píng)指正。
參考資料
1. ActiveMQ與RabbitMQ的區(qū)別
2. Kafka、ActiveMQ、RabbitMQ、RocketMQ?區(qū)別以及高可用原理
3. Kafka、RabbitMQ、RocketMQ等消息中間件的對(duì)比
4. Apache?Pulsar?在騰訊計(jì)費(fèi)場(chǎng)景下的應(yīng)用
5. kafka?Push?vs.?pull
6. 消息隊(duì)列-推/拉模式學(xué)習(xí)?&?ActiveMQ及JMS學(xué)習(xí)
- END -
看完一鍵三連在看,轉(zhuǎn)發(fā),點(diǎn)贊
是對(duì)文章最大的贊賞,極客重生感謝你
推薦閱讀
深入理解Kafka的設(shè)計(jì)思想
經(jīng)典算法刷題筆記pdf
編程究竟難在哪?
Redis 多線(xiàn)程網(wǎng)絡(luò)模型全面揭秘|網(wǎng)絡(luò)硬核系列
總結(jié)
以上是生活随笔為你收集整理的深入理解消息队列(场景,对比,原理和设计思想)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 实战能力|一文看懂GDB调试底层实现
- 下一篇: 深入理解操作系统内核架构(送书)!