消息隊(duì)列 RabbitMQ核心

RabbitMQ

RabbitMQ是流行的開源消息隊(duì)列系統(tǒng),用erlang語言開發(fā)。RabbitMQ是AMQP(高級消息隊(duì)列協(xié)議)的標(biāo)準(zhǔn)實(shí)現(xiàn)。支持多種客戶端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX,持久化。用于在分布式系統(tǒng)中存儲轉(zhuǎn)發(fā)消息,在易用性、擴(kuò)展性、高可用性等方面表現(xiàn)不俗。

RabbitMQ是一個開源的AMQP實(shí)現(xiàn),服務(wù)器端用Erlang語言編寫,支持多種客戶端。用于在分布式系統(tǒng)中存儲轉(zhuǎn)發(fā)消息,在易用性、擴(kuò)展性、高可用性等方面表現(xiàn)不俗,消息隊(duì)列是一種應(yīng)用系統(tǒng)之間的通信方法,是通過讀寫出入隊(duì)列的消息來通信(RPC則是通過直接調(diào)用彼此來通信的)

AMQP(Advanced Message Queuing Protocol)高級消息隊(duì)列協(xié)議是應(yīng)用層協(xié)議的一個開放標(biāo)準(zhǔn),為面向消息的中間件設(shè)計(jì)。消息中間件主要用于組件之間的解耦,消息的發(fā)送者無需知道消息使用者的存在,反之亦然。AMQP的主要特征是面向消息、隊(duì)列、路由(包括點(diǎn)對點(diǎn)和發(fā)布/訂閱)、可靠性、安全。

rabbitmq架構(gòu)圖

幾個重要概念:

Broker:簡單來說就是消息隊(duì)列服務(wù)器實(shí)體。

  • Exchange:消息交換機(jī),它指定消息按什么規(guī)則,路由到哪個隊(duì)列。

  • Queue:消息隊(duì)列載體,每個消息都會被投入到一個或多個隊(duì)列。

  • Binding:綁定,它的作用就是把exchange和queue按照路由規(guī)則綁定起來。

  • Routing Key:路由關(guān)鍵字,exchange根據(jù)這個關(guān)鍵字進(jìn)行消息投遞。

  • vhost:虛擬主機(jī),一個broker里可以開設(shè)多個vhost,用作不同用戶的權(quán)限分離。

  • producer:消息生產(chǎn)者,就是投遞消息的程序。

  • consumer:消息消費(fèi)者,就是接受消息的程序。

  • channel:消息通道,在客戶端的每個連接里,可建立多個channel,每個channel代表一個會話任務(wù)。

消息隊(duì)列的使用過程,如下:

(1)客戶端連接到消息隊(duì)列服務(wù)器,打開一個channel。

(2)客戶端聲明一個exchange,并設(shè)置相關(guān)屬性。

(3)客戶端聲明一個queue,并設(shè)置相關(guān)屬性。

(4)客戶端使用routing key,在exchange和queue之間建立好綁定關(guān)系。

(5)客戶端投遞消息到exchange。

exchange接收到消息后,就根據(jù)消息的key和已經(jīng)設(shè)置的binding,進(jìn)行消息路由,將消息投遞到一個或多個隊(duì)列里。

  • ConnectionFactory(連接工廠): 生產(chǎn)Connection的的工廠

  • Connection(連接):是RabbitMQ的socket的長鏈接,它封裝了socket協(xié)議相關(guān)部分邏輯

  • Channel(頻道|信道): 是建立在Connection連接之上的一種輕量級的連接,我們大部分的業(yè)務(wù)操作是在-Channel這個接口中完成的,包括定義隊(duì)列的聲明queueDeclare、交換機(jī)的聲明exchangeDeclare、隊(duì)列的綁定queueBind、發(fā)布消息basicPublish、消費(fèi)消息basicConsume等。如果把Connection比作一條光纖電纜的話,那么Channel信道就比作成光纖電纜中的其中一束光纖。一個Connection上可以創(chuàng)建任意數(shù)量的Channel。

image.png

image.png
  • Producer(生產(chǎn)者):生產(chǎn)者用于發(fā)布消息

  • Exchange(交換機(jī)):生產(chǎn)者會將消息發(fā)送到交換機(jī),然后交換機(jī)通過路由策略(規(guī)則)將消息路由到匹配的隊(duì)列中去

  • Routing Key(路由鍵):一個String值,用于定義路由規(guī)則,在隊(duì)列綁定的時候需要指定路由鍵,在生產(chǎn)者發(fā)布消息的時候需要指定路由鍵,當(dāng)消息的路由鍵和隊(duì)列綁定的路由鍵匹配時,消息就會發(fā)送到該隊(duì)列。

  • Queue(隊(duì)列):用于存儲消息的容器,可以看成一個有序的數(shù)組,生產(chǎn)者生產(chǎn)的消息會發(fā)送到交換機(jī)中,最終交換機(jī)將消息存儲到某個或某些隊(duì)列中,隊(duì)列可被消費(fèi)者訂閱,消費(fèi)者從訂閱的隊(duì)列中獲取消息。

  • Binding(綁定): Binding并不是一個概念,而是一種操作,RabbitMQ中通過綁定,以路由鍵作為橋梁將-

  • Exchange與Queue關(guān)聯(lián)起來(Exchange—>Routing Key—>Queue),這樣RabbitMQ就知道如何正確地將消息路由到指定的隊(duì)列了,通過queueBind方法將Exchange、Routing Key、Queue綁定起來

  • Consumer(消費(fèi)者):用于從隊(duì)列中獲取消息,消費(fèi)者只需關(guān)注隊(duì)列即可,不需要關(guān)注交換機(jī)和路由鍵,消費(fèi)者可以通過basicConsume(訂閱模式可以從隊(duì)列中一直持續(xù)的自動的接收消息)或者basicGet(先訂閱消息,然后獲取單條消息,再然后取消訂閱,也就是說basicGet一次只能獲取一條消息,如果還想再獲取下一條還要再次調(diào)用basicGet)來從隊(duì)列中獲取消息

  • vhost(虛擬主機(jī)): RabbitMQ 通過虛擬主機(jī)(virtual host)來分發(fā)消息, 擁有自己獨(dú)立的權(quán)限控制,不同的vhost之間是隔離的,單獨(dú)的。vhost是權(quán)限控制的基本單位,用戶只能訪問與之綁定的vhost,默認(rèn)vhost:”/” ,默認(rèn)用戶”guest” 密碼“guest”,來訪問默認(rèn)的vhost。


    image.png

ConnectionFactory、Connection、Channel

ConnectionFactory、Connection、Channel都是RabbitMQ對外提供的API中最基本的對象。Connection是RabbitMQ的socket鏈接,它封裝了socket協(xié)議相關(guān)部分邏輯。ConnectionFactory為Connection的制造工廠。 Channel是我們與RabbitMQ打交道的最重要的一個接口,我們大部分的業(yè)務(wù)操作是在Channel這個接口中完成的,包括定義Queue、定義Exchange、綁定Queue與Exchange、發(fā)布消息等。

Queue

Queue(隊(duì)列)是RabbitMQ的內(nèi)部對象,用于存儲消息,用下圖表示。

image

RabbitMQ中的消息都只能存儲在Queue中,生產(chǎn)者(下圖中的P)生產(chǎn)消息并最終投遞到Queue中,消費(fèi)者(下圖中的C)可以從Queue中獲取消息并消費(fèi)。

image

多個消費(fèi)者可以訂閱同一個Queue,這時Queue中的消息會被平均分?jǐn)偨o多個消費(fèi)者進(jìn)行處理,而不是每個消費(fèi)者都收到所有的消息并處理。

image

Message acknowledgment

在實(shí)際應(yīng)用中,可能會發(fā)生消費(fèi)者收到Queue中的消息,但沒有處理完成就宕機(jī)(或出現(xiàn)其他意外)的情況,這種情況下就可能會導(dǎo)致消息丟失。為了避免這種情況發(fā)生,我們可以要求消費(fèi)者在消費(fèi)完消息后發(fā)送一個回執(zhí)給RabbitMQ,RabbitMQ收到消息回執(zhí)(Message acknowledgment)后才將該消息從Queue中移除;如果RabbitMQ沒有收到回執(zhí)并檢測到消費(fèi)者的RabbitMQ連接斷開,則RabbitMQ會將該消息發(fā)送給其他消費(fèi)者(如果存在多個消費(fèi)者)進(jìn)行處理。這里不存在timeout概念,一個消費(fèi)者處理消息時間再長也不會導(dǎo)致該消息被發(fā)送給其他消費(fèi)者,除非它的RabbitMQ連接斷開。 這里會產(chǎn)生另外一個問題,如果我們的開發(fā)人員在處理完業(yè)務(wù)邏輯后,忘記發(fā)送回執(zhí)給RabbitMQ,這將會導(dǎo)致嚴(yán)重的bug——Queue中堆積的消息會越來越多;消費(fèi)者重啟后會重復(fù)消費(fèi)這些消息并重復(fù)執(zhí)行業(yè)務(wù)邏輯…

另外pub message是沒有ack的。

Message durability

如果我們希望即使在RabbitMQ服務(wù)重啟的情況下,也不會丟失消息,我們可以將Queue與Message都設(shè)置為可持久化的(durable),這樣可以保證絕大部分情況下我們的RabbitMQ消息不會丟失。但依然解決不了小概率丟失事件的發(fā)生(比如RabbitMQ服務(wù)器已經(jīng)接收到生產(chǎn)者的消息,但還沒來得及持久化該消息時RabbitMQ服務(wù)器就斷電了),如果我們需要對這種小概率事件也要管理起來,那么我們要用到事務(wù)。由于這里僅為RabbitMQ的簡單介紹,所以這里將不講解RabbitMQ相關(guān)的事務(wù)。

Prefetch count

前面我們講到如果有多個消費(fèi)者同時訂閱同一個Queue中的消息,Queue中的消息會被平攤給多個消費(fèi)者。這時如果每個消息的處理時間不同,就有可能會導(dǎo)致某些消費(fèi)者一直在忙,而另外一些消費(fèi)者很快就處理完手頭工作并一直空閑的情況。我們可以通過設(shè)置prefetchCount來限制Queue每次發(fā)送給每個消費(fèi)者的消息數(shù),比如我們設(shè)置prefetchCount=1,則Queue每次給每個消費(fèi)者發(fā)送一條消息;消費(fèi)者處理完這條消息后Queue會再給該消費(fèi)者發(fā)送一條消息。

image

Exchange

在上一節(jié)我們看到生產(chǎn)者將消息投遞到Queue中,實(shí)際上這在RabbitMQ中這種事情永遠(yuǎn)都不會發(fā)生。實(shí)際的情況是,生產(chǎn)者將消息發(fā)送到Exchange(交換器,下圖中的X),由Exchange將消息路由到一個或多個Queue中(或者丟棄)。

image

Exchange是按照什么邏輯將消息路由到Queue的?這個將在Binding一節(jié)介紹。 RabbitMQ中的Exchange有四種類型,不同的類型有著不同的路由策略,這將在Exchange Types一節(jié)介紹。

routing key

生產(chǎn)者在將消息發(fā)送給Exchange的時候,一般會指定一個routing key,來指定這個消息的路由規(guī)則,而這個routing key需要與Exchange Type及binding key聯(lián)合使用才能最終生效。 在Exchange Type與binding key固定的情況下(在正常使用時一般這些內(nèi)容都是固定配置好的),我們的生產(chǎn)者就可以在發(fā)送消息給Exchange時,通過指定routing key來決定消息流向哪里。 RabbitMQ為routing key設(shè)定的長度限制為255 bytes。

Binding

RabbitMQ中通過Binding將Exchange與Queue關(guān)聯(lián)起來,這樣RabbitMQ就知道如何正確地將消息路由到指定的Queue了。

image

Binding key

在綁定(Binding)Exchange與Queue的同時,一般會指定一個binding key;消費(fèi)者將消息發(fā)送給Exchange時,一般會指定一個routing key;當(dāng)binding key與routing key相匹配時,消息將會被路由到對應(yīng)的Queue中。這個將在Exchange Types章節(jié)會列舉實(shí)際的例子加以說明。 在綁定多個Queue到同一個Exchange的時候,這些Binding允許使用相同的binding key。 binding key 并不是在所有情況下都生效,它依賴于Exchange Type,比如fanout類型的Exchange就會無視binding key,而是將消息路由到所有綁定到該Exchange的Queue。

Exchange Types

RabbitMQ常用的Exchange Type有fanout、direct、topic、headers這四種(AMQP規(guī)范里還提到兩種Exchange Type,分別為system與自定義,這里不予以描述),下面分別進(jìn)行介紹。

fanout

fanout類型的Exchange路由規(guī)則非常簡單,它會把所有發(fā)送到該Exchange的消息路由到所有與它綁定的Queue中。

image

上圖中,生產(chǎn)者(P)發(fā)送到Exchange(X)的所有消息都會路由到圖中的兩個Queue,并最終被兩個消費(fèi)者(C1與C2)消費(fèi)。

direct

direct類型的Exchange路由規(guī)則也很簡單,它會把消息路由到那些binding key與routing key完全匹配的Queue中。

image

以上圖的配置為例,我們以routingKey=”error”發(fā)送消息到Exchange,則消息會路由到Queue1(amqp.gen-S9b…,這是由RabbitMQ自動生成的Queue名稱)和Queue2(amqp.gen-Agl…);如果我們以routingKey=”info”或routingKey=”warning”來發(fā)送消息,則消息只會路由到Queue2。如果我們以其他routingKey發(fā)送消息,則消息不會路由到這兩個Queue中。

topic

前面講到direct類型的Exchange路由規(guī)則是完全匹配binding key與routing key,但這種嚴(yán)格的匹配方式在很多情況下不能滿足實(shí)際業(yè)務(wù)需求。topic類型的Exchange在匹配規(guī)則上進(jìn)行了擴(kuò)展,它與direct類型的Exchage相似,也是將消息路由到binding key與routing key相匹配的Queue中,但這里的匹配規(guī)則有些不同,它約定:

  • routing key為一個句點(diǎn)號“. ”分隔的字符串(我們將被句點(diǎn)號“. ”分隔開的每一段獨(dú)立的字符串稱為一個單詞),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
  • binding key與routing key一樣也是句點(diǎn)號“. ”分隔的字符串
  • binding key中可以存在兩種特殊字符“”與“#”,用于做模糊匹配,其中“”用于匹配一個單詞,“#”用于匹配多個單詞(可以是零個)
image

以上圖中的配置為例,routingKey=”quick.orange.rabbit”的消息會同時路由到Q1與Q2,routingKey=”lazy.orange.fox”的消息會路由到Q1與Q2,routingKey=”lazy.brown.fox”的消息會路由到Q2,routingKey=”lazy.pink.rabbit”的消息會路由到Q2(只會投遞給Q2一次,雖然這個routingKey與Q2的兩個bindingKey都匹配);routingKey=”quick.brown.fox”、routingKey=”orange”、routingKey=”quick.orange.male.rabbit”的消息將會被丟棄,因?yàn)樗鼈儧]有匹配任何bindingKey。

headers

headers類型的Exchange不依賴于routing key與binding key的匹配規(guī)則來路由消息,而是根據(jù)發(fā)送的消息內(nèi)容中的headers屬性進(jìn)行匹配。 在綁定Queue與Exchange時指定一組鍵值對;當(dāng)消息發(fā)送到Exchange時,RabbitMQ會取到該消息的headers(也是一個鍵值對的形式),對比其中的鍵值對是否完全匹配Queue與Exchange綁定時指定的鍵值對;如果完全匹配則消息會路由到該Queue,否則不會路由到該Queue。 該類型的Exchange沒有用到過(不過也應(yīng)該很有用武之地),所以不做介紹。

RPC

MQ本身是基于異步的消息處理,前面的示例中所有的生產(chǎn)者(P)將消息發(fā)送到RabbitMQ后不會知道消費(fèi)者(C)處理成功或者失敗(甚至連有沒有消費(fèi)者來處理這條消息都不知道)。 但實(shí)際的應(yīng)用場景中,我們很可能需要一些同步處理,需要同步等待服務(wù)端將我的消息處理完成后再進(jìn)行下一步處理。這相當(dāng)于RPC(Remote Procedure Call,遠(yuǎn)程過程調(diào)用)。在RabbitMQ中也支持RPC。

image

RabbitMQ 中實(shí)現(xiàn)RPC 的機(jī)制是:

  • 客戶端發(fā)送請求(消息)時,在消息的屬性(MessageProperties ,在AMQP 協(xié)議中定義了14中properties ,這些屬性會隨著消息一起發(fā)送)中設(shè)置兩個值replyTo (一個Queue 名稱,用于告訴服務(wù)器處理完成后將通知我的消息發(fā)送到這個Queue 中)和correlationId (此次請求的標(biāo)識號,服務(wù)器處理完成后需要將此屬性返還,客戶端將根據(jù)這個id了解哪條請求被成功執(zhí)行了或執(zhí)行失敗)
  • 服務(wù)器端收到消息并處理
  • 服務(wù)器端處理完消息后,將生成一條應(yīng)答消息到replyTo 指定的Queue ,同時帶上correlationId 屬性
  • 客戶端之前已訂閱replyTo 指定的Queue ,從中收到服務(wù)器的應(yīng)答消息后,根據(jù)其中的correlationId屬性分析哪條請求被執(zhí)行了,根據(jù)執(zhí)行結(jié)果進(jìn)行后續(xù)業(yè)務(wù)處理

總結(jié)

本文介紹了RabbitMQ 中個人認(rèn)為最重要的概念,充分利用RabbitMQ 提供的這些功能就可以處理我們絕大部分的異步業(yè)務(wù)了。

RabbitMQ 選型和對比

1.從社區(qū)活躍度

按照目前網(wǎng)絡(luò)上的資料,RabbitMQactiveM 、ZeroMQ 三者中,綜合來看,RabbitMQ 是首選。

2.持久化消息比較

ZeroMq 不支持,ActiveMqRabbitMq 都支持。持久化消息主要是指我們機(jī)器在不可抗力因素等情況下掛掉了,消息不會丟失的機(jī)制。

3.綜合技術(shù)實(shí)現(xiàn)

可靠性、靈活的路由、集群、事務(wù)、高可用的隊(duì)列、消息排序、問題追蹤、可視化管理工具、插件系統(tǒng)等等。

RabbitMq / Kafka 最好,ActiveMq 次之,ZeroMq 最差。當(dāng)然ZeroMq 也可以做到,不過自己必須手動寫代碼實(shí)現(xiàn),代碼量不小。尤其是可靠性中的:持久性、投遞確認(rèn)、發(fā)布者證實(shí)和高可用性。

4.高并發(fā)

毋庸置疑,RabbitMQ 最高,原因是它的實(shí)現(xiàn)語言是天生具備高并發(fā)高可用的erlang 語言。

5.比較關(guān)注的比較, RabbitMQ 和 Kafka

RabbitMqKafka 成熟,在可用性上,穩(wěn)定性上,可靠性上, RabbitMq 勝于 Kafka (理論上)。

另外,Kafka 的定位主要在日志等方面, 因?yàn)?code>Kafka 設(shè)計(jì)的初衷就是處理日志的,可以看做是一個日志(消息)系統(tǒng)一個重要組件,針對性很強(qiáng),所以 如果業(yè)務(wù)方面還是建議選擇 RabbitMq 。

還有就是,Kafka 的性能(吞吐量、TPS )比RabbitMq 要高出來很多。

選型最后總結(jié):

如果我們系統(tǒng)中已經(jīng)有選擇 Kafka ,或者 RabbitMq ,并且完全可以滿足現(xiàn)在的業(yè)務(wù),建議就不用重復(fù)去增加和造輪子。

可以在 KafkaRabbitMq 中選擇一個適合自己團(tuán)隊(duì)和業(yè)務(wù)的,這個才是最重要的。但是毋庸置疑現(xiàn)階段,綜合考慮沒有第三選擇。

隊(duì)列聲明和隊(duì)列持久化,消息持久化

隊(duì)列聲明和隊(duì)列持久化,消息持久化

消費(fèi)者確認(rèn)ack,生產(chǎn)者消息確認(rèn) Confirm機(jī)制,事務(wù)機(jī)制

消費(fèi)者確認(rèn)ack,生產(chǎn)者消息確認(rèn) Confirm機(jī)制,事務(wù)機(jī)制

消息隊(duì)列中間件是分布式系統(tǒng)中重要的組件,主要解決應(yīng)用耦合,異步消息,流量削鋒等問題

實(shí)現(xiàn)高性能,高可用,可伸縮和最終一致性架構(gòu)

使用較多的消息隊(duì)列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ

消息隊(duì)列應(yīng)用場景

以下介紹消息隊(duì)列在實(shí)際應(yīng)用中常用的使用場景。異步處理,應(yīng)用解耦,流量削鋒和消息通訊四個場景

2.1異步處理

場景說明:用戶注冊后,需要發(fā)注冊郵件和注冊短信。傳統(tǒng)的做法有兩種 1.串行的方式;2.并行方式

(1)串行方式:將注冊信息寫入數(shù)據(jù)庫成功后,發(fā)送注冊郵件,再發(fā)送注冊短信。以上三個任務(wù)全部完成后,返回給客戶端

image

(2)并行方式:將注冊信息寫入數(shù)據(jù)庫成功后,發(fā)送注冊郵件的同時,發(fā)送注冊短信。以上三個任務(wù)完成后,返回給客戶端。與串行的差別是,并行的方式可以提高處理的時間

image

假設(shè)三個業(yè)務(wù)節(jié)點(diǎn)每個使用50毫秒鐘,不考慮網(wǎng)絡(luò)等其他開銷,則串行方式的時間是150毫秒,并行的時間可能是100毫秒。

因?yàn)镃PU在單位時間內(nèi)處理的請求數(shù)是一定的,假設(shè)CPU1秒內(nèi)吞吐量是100次。則串行方式1秒內(nèi)CPU可處理的請求量是7次(1000/150)。并行方式處理的請求量是10次(1000/100)

小結(jié):如以上案例描述,傳統(tǒng)的方式系統(tǒng)的性能(并發(fā)量,吞吐量,響應(yīng)時間)會有瓶頸。如何解決這個問題呢?

引入消息隊(duì)列,將不是必須的業(yè)務(wù)邏輯,異步處理。改造后的架構(gòu)如下:

image

按照以上約定,用戶的響應(yīng)時間相當(dāng)于是注冊信息寫入數(shù)據(jù)庫的時間,也就是50毫秒。注冊郵件,發(fā)送短信寫入消息隊(duì)列后,直接返回,因此寫入消息隊(duì)列的速度很快,基本可以忽略,因此用戶的響應(yīng)時間可能是50毫秒。因此架構(gòu)改變后,系統(tǒng)的吞吐量提高到每秒20 QPS。比串行提高了3倍,比并行提高了兩倍

2.2應(yīng)用解耦

場景說明:用戶下單后,訂單系統(tǒng)需要通知庫存系統(tǒng)。傳統(tǒng)的做法是,訂單系統(tǒng)調(diào)用庫存系統(tǒng)的接口。如下圖

image

傳統(tǒng)模式的缺點(diǎn):

  • 假如庫存系統(tǒng)無法訪問,則訂單減庫存將失敗,從而導(dǎo)致訂單失敗

  • 訂單系統(tǒng)與庫存系統(tǒng)耦合

如何解決以上問題呢?引入應(yīng)用消息隊(duì)列后的方案,如下圖:

image
  • 訂單系統(tǒng):用戶下單后,訂單系統(tǒng)完成持久化處理,將消息寫入消息隊(duì)列,返回用戶訂單下單成功

  • 庫存系統(tǒng):訂閱下單的消息,采用拉/推的方式,獲取下單信息,庫存系統(tǒng)根據(jù)下單信息,進(jìn)行庫存操作

  • 假如:在下單時庫存系統(tǒng)不能正常使用。也不影響正常下單,因?yàn)橄聠魏?,訂單系統(tǒng)寫入消息隊(duì)列就不再關(guān)心其他的后續(xù)操作了。實(shí)現(xiàn)訂單系統(tǒng)與庫存系統(tǒng)的應(yīng)用解耦

2.3流量削鋒

流量削鋒也是消息隊(duì)列中的常用場景,一般在秒殺或團(tuán)搶活動中使用廣泛

應(yīng)用場景:秒殺活動,一般會因?yàn)榱髁窟^大,導(dǎo)致流量暴增,應(yīng)用掛掉。為解決這個問題,一般需要在應(yīng)用前端加入消息隊(duì)列。

  • 可以控制活動的人數(shù)

  • 可以緩解短時間內(nèi)高流量壓垮應(yīng)用

image
  • 用戶的請求,服務(wù)器接收后,首先寫入消息隊(duì)列。假如消息隊(duì)列長度超過最大數(shù)量,則直接拋棄用戶請求或跳轉(zhuǎn)到錯誤頁面

  • 秒殺業(yè)務(wù)根據(jù)消息隊(duì)列中的請求信息,再做后續(xù)處理

2.4日志處理

日志處理是指將消息隊(duì)列用在日志處理中,比如Kafka的應(yīng)用,解決大量日志傳輸?shù)膯栴}。架構(gòu)簡化如下

image
  • 日志采集客戶端,負(fù)責(zé)日志數(shù)據(jù)采集,定時寫受寫入Kafka隊(duì)列

  • Kafka消息隊(duì)列,負(fù)責(zé)日志數(shù)據(jù)的接收,存儲和轉(zhuǎn)發(fā)

  • 日志處理應(yīng)用:訂閱并消費(fèi)kafka隊(duì)列中的日志數(shù)據(jù)

以下是新浪kafka日志處理應(yīng)用案例:轉(zhuǎn)自(http://cloud.51cto.com/art/201507/484338.htm

image

(1)Kafka:接收用戶日志的消息隊(duì)列

(2)Logstash:做日志解析,統(tǒng)一成JSON輸出給Elasticsearch

(3)Elasticsearch:實(shí)時日志分析服務(wù)的核心技術(shù),一個schemaless,實(shí)時的數(shù)據(jù)存儲服務(wù),通過index組織數(shù)據(jù),兼具強(qiáng)大的搜索和統(tǒng)計(jì)功能

(4)Kibana:基于Elasticsearch的數(shù)據(jù)可視化組件,超強(qiáng)的數(shù)據(jù)可視化能力是眾多公司選擇ELK stack的重要原因

2.5消息通訊

消息通訊是指,消息隊(duì)列一般都內(nèi)置了高效的通信機(jī)制,因此也可以用在純的消息通訊。比如實(shí)現(xiàn)點(diǎn)對點(diǎn)消息隊(duì)列,或者聊天室等

點(diǎn)對點(diǎn)通訊:

image

客戶端A和客戶端B使用同一隊(duì)列,進(jìn)行消息通訊。

聊天室通訊:

image

客戶端A,客戶端B,客戶端N訂閱同一主題,進(jìn)行消息發(fā)布和接收。實(shí)現(xiàn)類似聊天室效果。

以上實(shí)際是消息隊(duì)列的兩種消息模式,點(diǎn)對點(diǎn)或發(fā)布訂閱模式。模型為示意圖,供參考。

三、消息中間件示例

3.1電商系統(tǒng)

image

消息隊(duì)列采用高可用,可持久化的消息中間件。比如Active MQ,Rabbit MQ,Rocket Mq。

(1)應(yīng)用將主干邏輯處理完成后,寫入消息隊(duì)列。消息發(fā)送是否成功可以開啟消息的確認(rèn)模式。(消息隊(duì)列返回消息接收成功狀態(tài)后,應(yīng)用再返回,這樣保障消息的完整性)

(2)擴(kuò)展流程(發(fā)短信,配送處理)訂閱隊(duì)列消息。采用推或拉的方式獲取消息并處理。

(3)消息將應(yīng)用解耦的同時,帶來了數(shù)據(jù)一致性問題,可以采用最終一致性方式解決。比如主數(shù)據(jù)寫入數(shù)據(jù)庫,擴(kuò)展應(yīng)用根據(jù)消息隊(duì)列,并結(jié)合數(shù)據(jù)庫方式實(shí)現(xiàn)基于消息隊(duì)列的后續(xù)處理。

3.2日志收集系統(tǒng)

image

分為Zookeeper注冊中心,日志收集客戶端,Kafka集群和Storm集群(OtherApp)四部分組成。

  • Zookeeper注冊中心,提出負(fù)載均衡和地址查找服務(wù)

  • 日志收集客戶端,用于采集應(yīng)用系統(tǒng)的日志,并將數(shù)據(jù)推送到kafka隊(duì)列

  • Kafka集群:接收,路由,存儲,轉(zhuǎn)發(fā)等消息處理

Storm集群:與OtherApp處于同一級別,采用拉的方式消費(fèi)隊(duì)列中的數(shù)據(jù)

參考

https://blog.csdn.net/cws1214/article/details/52922267
https://blog.csdn.net/vbirdbest/article/details/78837247
https://blog.csdn.net/vbirdbest/column/info/18247
https://www.cnblogs.com/xifengxiaoma/p/9391647.html
https://www.sojson.com/blog/48.html
https://github.com/jasonGeng88/blog/blob/master/201705/MQ.md

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容