一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

RabbitMQ 26問(wèn),基本涵蓋了面試官必問(wèn)的面試題

 修行的嘟嘟 2024-03-08 發(fā)布于北京

最近剛學(xué)完RabbitMQ,順便整理了一下常用的面試題,用于總結(jié)跟回顧,也供各位大佬參考,如有不對(duì)的地方,歡迎指出哈!

1、為什么要使用MQ

1、流量消峰

舉個(gè)例子:如果訂單系統(tǒng)最多能處理一萬(wàn)次訂單,這個(gè)處理能力應(yīng)付正常時(shí)段的下單時(shí)綽綽有余,正常時(shí)段我們下單一秒后就能返回結(jié)果。但是在高峰期,如果有兩萬(wàn)次下單操作系統(tǒng)是處理不了的,只能限制訂單超過(guò)一萬(wàn)后不允許用戶下單。使用消息隊(duì)列做緩沖,我們可以取消這個(gè)限制,把一秒內(nèi)下的訂單分散成一段時(shí)間來(lái)處理,這時(shí)有些用戶可能在下單十幾秒后才能收到下單成功的操作,但是比不能下單的體驗(yàn)要好。

2、應(yīng)用解耦

以電商應(yīng)用為例,應(yīng)用中有訂單系統(tǒng)、庫(kù)存系統(tǒng)、物流系統(tǒng)、支付系統(tǒng)。用戶創(chuàng)建訂單后,如果耦合調(diào)用庫(kù)存系統(tǒng)、物流系統(tǒng)、支付系統(tǒng),任何一個(gè)子系統(tǒng)出了故障,都會(huì)造成下單操作異常。當(dāng)轉(zhuǎn)變成基于消息隊(duì)列的方式后,系統(tǒng)間調(diào)用的問(wèn)題會(huì)減少很多,比如物流系統(tǒng)因?yàn)榘l(fā)生故障,需要幾分鐘來(lái)修復(fù)。在這幾分鐘的時(shí)間里,物流系統(tǒng)要處理的內(nèi)存被緩存在消息隊(duì)列中,用戶的下單操作可以正常完成。當(dāng)物流系統(tǒng)恢復(fù)后,繼續(xù)處理訂單信息即可,中單用戶感受不到物流系統(tǒng)的故障,提升系統(tǒng)的可用性。

在這里插入圖片描述

3、異步處理

有些服務(wù)間調(diào)用是異步的,例如 A 調(diào)用 B,B 需要花費(fèi)很長(zhǎng)時(shí)間執(zhí)行,但是 A 需要知道 B 什么時(shí)候可以執(zhí)行完,以前一般有兩種方式:

  1. A 過(guò)一段時(shí)間去調(diào)用 B 的查詢 api 查詢

  2. A 提供一個(gè) callback api, B 執(zhí)行完之后調(diào)用 api 通知 A 服務(wù)。

這兩種方式都不是很優(yōu)雅,使用消息總線,可以很方便解決這個(gè)問(wèn)題,A 調(diào)用 B 服務(wù)后,只需要監(jiān)聽(tīng) B 處理完成的消息,當(dāng) B 處理完成后,會(huì)發(fā)送一條消息給 MQ,MQ 會(huì)將此消息轉(zhuǎn)發(fā)給 A 服務(wù)。這樣 A 服務(wù)既不用循環(huán)調(diào)用 B 的查詢 api,也不用提供 callback api。同樣 B 服務(wù)也不用做這些操作。A 服務(wù)還能及時(shí)的得到異步處理成功的消息。

在這里插入圖片描述

2、什么是RabbitMQ

RabbitMQ是一個(gè)消息中間件:它接受并轉(zhuǎn)發(fā)消息。你可以把它當(dāng)做一個(gè)快遞站點(diǎn),當(dāng)你要發(fā)送一個(gè)包裹時(shí),你把你的包裹放到快遞站,快遞員最終會(huì)把你的快遞送到收件人那里,按照這種邏輯RabbitMQ是一個(gè)快遞站,一個(gè)快遞員幫你傳遞快件。RabbitMQ與快遞站的主要區(qū)別在于,它不處理快件而是接收,存儲(chǔ)和轉(zhuǎn)發(fā)消息數(shù)據(jù)。

3、RabbitMQ各組件的功能

  • Server:接收客戶端的連接,實(shí)現(xiàn)AMQP實(shí)體服務(wù)。

  • Connection:連接,應(yīng)用程序與Server的網(wǎng)絡(luò)連接,TCP連接。

  • Channel:信道,消息讀寫等操作在信道中進(jìn)行。客戶端可以建立多個(gè)信道,每個(gè)信道代表一個(gè)會(huì)話任務(wù)。如果每一次訪問(wèn) RabbitMQ 都建立一個(gè) Connection,在消息量大的時(shí)候建立 TCP Connection 的開(kāi)銷將是巨大的,效率也較低。Channel 是在 connection 內(nèi)部建立的邏輯連接,如果應(yīng)用程序支持多線程,通常每個(gè) thread 創(chuàng)建單獨(dú)的 channel 進(jìn)行通訊,AMQP method 包含了 channel id 幫助客戶端和 message broker 識(shí)別 channel,所以 channel 之間是完全隔離的。Channel 作為輕量級(jí)的

    Connection極大減少了操作系統(tǒng)建立TCP connection的開(kāi)銷

  • Message:消息,應(yīng)用程序和服務(wù)器之間傳送的數(shù)據(jù),消息可以非常簡(jiǎn)單,也可以很復(fù)雜。由Properties和Body組成。Properties為外包裝,可以對(duì)消息進(jìn)行修飾,比如消息的優(yōu)先級(jí)、延遲等高級(jí)特性;Body就是消息體內(nèi)容。

  • Virtual Host:虛擬主機(jī),用于邏輯隔離。一個(gè)虛擬主機(jī)里面可以有若干個(gè)Exchange和Queue,同一個(gè)虛擬主機(jī)里面不能有相同名稱的Exchange或Queue。

  • Exchange:交換器,接收消息,按照路由規(guī)則將消息路由到一個(gè)或者多個(gè)隊(duì)列。如果路由不到,或者返回給生產(chǎn)者,或者直接丟棄。RabbitMQ常用的交換器常用類型有direct、topic、fanout、headers四種,后面詳細(xì)介紹。

  • Binding:綁定,交換器和消息隊(duì)列之間的虛擬連接,綁定中可以包含一個(gè)或者多個(gè)RoutingKey,Binding 信息被保存到 exchange 中的查詢表中,用于 message 的分發(fā)依據(jù)

  • RoutingKey:路由鍵,生產(chǎn)者將消息發(fā)送給交換器的時(shí)候,會(huì)發(fā)送一個(gè)RoutingKey,用來(lái)指定路由規(guī)則,這樣交換器就知道把消息發(fā)送到哪個(gè)隊(duì)列。路由鍵通常為一個(gè)“.”分割的字符串,例如“com.rabbitmq”

  • Queue:消息隊(duì)列,用來(lái)保存消息,供消費(fèi)者消費(fèi)。

3、RabbitMQ工作原理

不得不看一下經(jīng)典的圖了,如下??

在這里插入圖片描述

AMQP 協(xié)議模型由三部分組成:生產(chǎn)者、消費(fèi)者和服務(wù)端,執(zhí)行流程如下:

  1. 生產(chǎn)者是連接到 Server,建立一個(gè)連接,開(kāi)啟一個(gè)信道。

  2. 生產(chǎn)者聲明交換器和隊(duì)列,設(shè)置相關(guān)屬性,并通過(guò)路由鍵將交換器和隊(duì)列進(jìn)行綁定。

  3. 消費(fèi)者也需要進(jìn)行建立連接,開(kāi)啟信道等操作,便于接收消息。

  4. 生產(chǎn)者發(fā)送消息,發(fā)送到服務(wù)端中的虛擬主機(jī)。

  5. 虛擬主機(jī)中的交換器根據(jù)路由鍵選擇路由規(guī)則,發(fā)送到不同的消息隊(duì)列中。

  6. 訂閱了消息隊(duì)列的消費(fèi)者就可以獲取到消息,進(jìn)行消費(fèi)。

4、RabbitMQ 上的一個(gè) queue 中存放的 message 是否有數(shù)量限制?

可以認(rèn)為是無(wú)限制,因?yàn)橄拗迫Q于機(jī)器的內(nèi)存,但是消息過(guò)多會(huì)導(dǎo)致處理效率的下降。

5、RabbitMQ 允許發(fā)送的 message 最大可達(dá)多大?

根據(jù) AMQP 協(xié)議規(guī)定,消息體的大小由 64-bit 的值來(lái)指定,所以你就可以知道到底能發(fā)多大的數(shù)據(jù)了

6、RabbitMQ的工作模式

1、simple模式(即最簡(jiǎn)單的收發(fā)模式)

在這里插入圖片描述
  1. 消息產(chǎn)生消息,將消息放入隊(duì)列

  2. 消息的消費(fèi)者(consumer) 監(jiān)聽(tīng) 消息隊(duì)列,如果隊(duì)列中有消息,就消費(fèi)掉,消息被拿走后,自動(dòng)從隊(duì)列中刪除(隱患 消息可能沒(méi)有被消費(fèi)者正確處理,已經(jīng)從隊(duì)列中消失了,造成消息的丟失,這里可以設(shè)置成手動(dòng)的ack,但如果設(shè)置成手動(dòng)ack,處理完后要及時(shí)發(fā)送ack消息給隊(duì)列,否則會(huì)造成內(nèi)存溢出)。

2、Work Queues(工作隊(duì)列)

在這里插入圖片描述

消息產(chǎn)生者將消息放入隊(duì)列消費(fèi)者可以有多個(gè),消費(fèi)者1,消費(fèi)者2同時(shí)監(jiān)聽(tīng)同一個(gè)隊(duì)列,消息被消費(fèi)。C1 C2共同爭(zhēng)搶當(dāng)前的消息隊(duì)列內(nèi)容,誰(shuí)先拿到誰(shuí)負(fù)責(zé)消費(fèi)消息(隱患:高并發(fā)情況下,默認(rèn)會(huì)產(chǎn)生某一個(gè)消息被多個(gè)消費(fèi)者共同使用,可以設(shè)置一個(gè)開(kāi)關(guān)(syncronize) 保證一條消息只能被一個(gè)消費(fèi)者使用)。

3、publish/subscribe發(fā)布訂閱(共享資源)

在這里插入圖片描述
  1. 每個(gè)消費(fèi)者監(jiān)聽(tīng)自己的隊(duì)列;

  2. 生產(chǎn)者將消息發(fā)給broker,由交換機(jī)將消息轉(zhuǎn)發(fā)到綁定此交換機(jī)的每個(gè)隊(duì)列,每個(gè)綁定交換機(jī)的隊(duì)列都將接收到消息。

4、routing路由模式

在這里插入圖片描述
  1. 消息生產(chǎn)者將消息發(fā)送給交換機(jī)按照路由判斷,路由是字符串(info) 當(dāng)前產(chǎn)生的消息攜帶路由字符(對(duì)象的方法),交換機(jī)根據(jù)路由的key,只能匹配上路由key對(duì)應(yīng)的消息隊(duì)列,對(duì)應(yīng)的消費(fèi)者才能消費(fèi)消息;

  2. 根據(jù)業(yè)務(wù)功能定義路由字符串

  3. 從系統(tǒng)的代碼邏輯中獲取對(duì)應(yīng)的功能字符串,將消息任務(wù)扔到對(duì)應(yīng)的隊(duì)列中。

  4. 業(yè)務(wù)場(chǎng)景:error 通知;EXCEPTION;錯(cuò)誤通知的功能;傳統(tǒng)意義的錯(cuò)誤通知;客戶通知;利用key路由,可以將程序中的錯(cuò)誤封裝成消息傳入到消息隊(duì)列中,開(kāi)發(fā)者可以自定義消費(fèi)者,實(shí)時(shí)接收錯(cuò)誤;

5、topic 主題模式(路由模式的一種)

在這里插入圖片描述
  1. 星號(hào)井號(hào)代表通配符

  2. 星號(hào)代表多個(gè)單詞,井號(hào)代表一個(gè)單詞

  3. 路由功能添加模糊匹配

  4. 消息產(chǎn)生者產(chǎn)生消息,把消息交給交換機(jī)

  5. 交換機(jī)根據(jù)key的規(guī)則模糊匹配到對(duì)應(yīng)的隊(duì)列,由隊(duì)列的監(jiān)聽(tīng)消費(fèi)者接收消息消費(fèi)

PS:(在我的理解看來(lái)就是routing查詢的一種模糊匹配,就類似sql的模糊查詢方式)

7、如何保證RabbitMQ消息的順序性?

  • 拆分多個(gè) queue(消息隊(duì)列),每個(gè) queue(消息隊(duì)列) 一個(gè) consumer(消費(fèi)者),就是多一些 queue(消息隊(duì)列)而已,確實(shí)是麻煩點(diǎn);

  • 或者就一個(gè) queue (消息隊(duì)列)但是對(duì)應(yīng)一個(gè) consumer(消費(fèi)者),然后這個(gè) consumer(消費(fèi)者)內(nèi)部用內(nèi)存隊(duì)列做排隊(duì),然后分發(fā)給底層不同的 worker 來(lái)處理。

8、RabbitMQ消息丟失的情況有哪些?

  1. 生產(chǎn)者發(fā)送消息RabbitMQ Server 消息丟失

  2. RabbitMQ Server中存儲(chǔ)的消息丟失

  3. RabbitMQ Server中存儲(chǔ)的消息分發(fā)給消費(fèi)者者丟失

1、生產(chǎn)者發(fā)送消息RabbitMQ Server 消息丟失

  1. 發(fā)送過(guò)程中存在網(wǎng)絡(luò)問(wèn)題,導(dǎo)致消息沒(méi)有發(fā)送成功

  2. 代碼問(wèn)題,導(dǎo)致消息沒(méi)發(fā)送

2、RabbitMQ Server中存儲(chǔ)的消息丟失

  1. 消息沒(méi)有持久化,服務(wù)器重啟導(dǎo)致存儲(chǔ)的消息丟失

3、RabbitMQ Server到消費(fèi)者消息丟失

  1. 消費(fèi)端接收到相關(guān)消息之后,消費(fèi)端還沒(méi)來(lái)得及處理消息,消費(fèi)端機(jī)器就宕機(jī)了

  2. 處理消息存在異常

9、RabbitMQ如何保證消息不丟失?

針對(duì)上面的情況,確保消息不丟失

生產(chǎn)者發(fā)送消息RabbitMQ Server 消息丟失解決方案:

  • 常用解決方案:發(fā)送方確認(rèn)機(jī)制(publisher confirm)

  • 開(kāi)啟AMQP的事務(wù)處理(不推薦)

RabbitMQ Server中存儲(chǔ)的消息丟失解決方案:

  • 消息回退:通過(guò)設(shè)置 mandatory 參數(shù)可以在當(dāng)消息傳遞過(guò)程中不可達(dá)目的地時(shí)將消息返回給生產(chǎn)者

  • 設(shè)置持久化:保證重啟過(guò)程中,交換機(jī)和隊(duì)列也是持久化的

RabbitMQ Server到消費(fèi)者消息丟失解決方案:

  • 手動(dòng)ack確認(rèn)機(jī)制

1、生產(chǎn)者發(fā)送消息RabbitMQ Server 消息丟失解決方案

1、發(fā)布確認(rèn)機(jī)制

生產(chǎn)者將信道設(shè)置成 confirm 模式,一旦信道進(jìn)入 confirm 模式,所有在該信道上面發(fā)布的消息都將會(huì)被指派一個(gè)唯一的 ID(從 1 開(kāi)始),一旦消息被投遞到所有匹配的隊(duì)列之后,broker就會(huì)發(fā)送一個(gè)確認(rèn)給生產(chǎn)者(包含消息的唯一 ID),這就使得生產(chǎn)者知道消息已經(jīng)正確到達(dá)目的隊(duì)列了,如果消息和隊(duì)列是可持久化的,那么確認(rèn)消息會(huì)在將消息寫入磁盤之后發(fā)出,broker 回傳給生產(chǎn)者的確認(rèn)消息中 delivery-tag 域包含了確認(rèn)消息的序列號(hào),此外 broker 也可以設(shè)置basic.ack的 multiple 域,表示到這個(gè)序列號(hào)之前的所有消息都已經(jīng)得到了處理。
confirm 模式最大的好處在于它是異步的,一旦發(fā)布一條消息,生產(chǎn)者應(yīng)用程序就可以在等信道返回確認(rèn)的同時(shí)繼續(xù)發(fā)送下一條消息,當(dāng)消息最終得到確認(rèn)之后,生產(chǎn)者應(yīng)用便可以通過(guò)回調(diào)方法來(lái)處理該確認(rèn)消息,如果 RabbitMQ 因?yàn)樽陨韮?nèi)部錯(cuò)誤導(dǎo)致消息丟失,就會(huì)發(fā)送一條 nack 消息,生產(chǎn)者應(yīng)用程序同樣可以在回調(diào)方法中處理該 nack 消息。

發(fā)布確認(rèn)分為三種:

  • 單獨(dú)發(fā)布確認(rèn):這是一種簡(jiǎn)單的確認(rèn)方式,它是一種同步確認(rèn)發(fā)布的方式,也就是發(fā)布一個(gè)消息之后只有它被確認(rèn)發(fā)布,后續(xù)的消息才能繼續(xù)發(fā)布,waitForConfirmsOrDie(long)這個(gè)方法只有在消息被確認(rèn)的時(shí)候才返回,如果在指定時(shí)間范圍內(nèi)這個(gè)消息沒(méi)有被確認(rèn)那么它將拋出異常。

    這種確認(rèn)方式有一個(gè)最大的缺點(diǎn)就是:**發(fā)布速度特別的慢,**因?yàn)槿绻麤](méi)有確認(rèn)發(fā)布的消息就會(huì)阻塞所有后續(xù)消息的發(fā)布,這種方式最多提供每秒不超過(guò)數(shù)百條發(fā)布消息的吞吐量。當(dāng)然對(duì)于某些應(yīng)用程序來(lái)說(shuō)這可能已經(jīng)足夠了。

  • 批量發(fā)布確認(rèn):上面那種方式非常慢,與單個(gè)等待確認(rèn)消息相比,先發(fā)布一批消息然后一起確認(rèn)可以極大地提高吞吐量,當(dāng)然這種方式的缺點(diǎn)就是:當(dāng)發(fā)生故障導(dǎo)致發(fā)布出現(xiàn)問(wèn)題時(shí),不知道是哪個(gè)消息出現(xiàn)問(wèn)題了,我們必須將整個(gè)批處理保存在內(nèi)存中,以記錄重要的信息而后重新發(fā)布消息。當(dāng)然這種方案仍然是同步的,也一樣阻塞消息的發(fā)布。

  • 異步發(fā)布確認(rèn):異步確認(rèn)雖然編程邏輯比上兩個(gè)要復(fù)雜,但是性價(jià)比最高,無(wú)論是可靠性還是效率都沒(méi)得說(shuō),他是利用回調(diào)函數(shù)來(lái)達(dá)到消息可靠性傳遞的,這個(gè)中間件也是通過(guò)函數(shù)回調(diào)來(lái)保證是否投遞成功

2、開(kāi)啟AMQP的事務(wù)處理(不推薦)

為什么不推薦呢,因?yàn)樗峭降?,一條消息發(fā)送之后會(huì)使發(fā)送端阻塞,以等待RabbitMQ Server的回應(yīng),之后才能繼續(xù)發(fā)送下一條消息,生產(chǎn)者生產(chǎn)消息的吞吐量和性能都會(huì)大大降低,這就跟單獨(dú)發(fā)布確認(rèn)一樣。

如何使用:在生產(chǎn)者發(fā)送消息之前,通過(guò)channel.txSelect開(kāi)啟一個(gè)事務(wù),接著發(fā)送消息, 如果消息投遞server失敗,進(jìn)行事務(wù)回滾channel.txRollback,然后重新發(fā)送, 如果server收到消息,就提交事務(wù)channel.txCommit

2、RabbitMQ Server中存儲(chǔ)的消息丟失解決方案

第一種保證消息丟失,只能夠保證發(fā)送方發(fā)送消息成功到達(dá)交換機(jī),若此時(shí)服務(wù)器存在問(wèn)題或者綁定的routingKey不正確,導(dǎo)致消息發(fā)送失敗,那么消息最終也會(huì)丟失。

  • 采用消息回退:通過(guò)設(shè)置 mandatory 參數(shù)可以在當(dāng)消息傳遞過(guò)程中不可達(dá)目的地時(shí)將消息返回給生產(chǎn)者

  • 設(shè)置持久化

1、消息回退

源碼:

mandatory參數(shù) true:交換機(jī)無(wú)法將消息進(jìn)行路由時(shí),會(huì)將該消息返回給生產(chǎn)者 false:如果發(fā)現(xiàn)消息無(wú)法進(jìn)行路由,則直接丟棄public void basicPublish(String exchange, String routingKey, boolean mandatory, BasicProperties props, byte[] body) throws IOException {    this.delegate.basicPublish(exchange, routingKey, mandatory, props, body);}

有了 mandatory 參數(shù)和回退消息,我們獲得了對(duì)無(wú)法投遞消息的感知能力,有機(jī)會(huì)在生產(chǎn)者的消息無(wú)法被投遞時(shí)發(fā)現(xiàn)并處理。但有時(shí)候,我們并不知道該如何處理這些無(wú)法路由的消息,最多打個(gè)日志,然后觸發(fā)報(bào)警,再來(lái)手動(dòng)處理。而通過(guò)日志來(lái)處理這些無(wú)法路由的消息是很不優(yōu)雅的做法,特別是當(dāng)生產(chǎn)者所在的服務(wù)有多臺(tái)機(jī)器的時(shí)候,手動(dòng)復(fù)制日志會(huì)更加麻煩而且容易出錯(cuò)。

這時(shí)需要采用備份交換機(jī)

備份交換機(jī)可以理解為 RabbitMQ 中交換機(jī)的“備胎”,當(dāng)我們?yōu)槟骋粋€(gè)交換機(jī)聲明一個(gè)對(duì)應(yīng)的備份交換機(jī)時(shí),

就是為它創(chuàng)建一個(gè)備胎,當(dāng)交換機(jī)接收到一條不可路由消息時(shí),將會(huì)把這條消息轉(zhuǎn)發(fā)到備份交換機(jī)中,由備份交換機(jī)來(lái)進(jìn)行轉(zhuǎn)發(fā)和處理,通常備份交換機(jī)的類型為 Fanout ,這樣就能把所有消息都投遞到與其綁定的隊(duì)列中,然后我們?cè)趥浞萁粨Q機(jī)下綁定一個(gè)隊(duì)列,這樣所有那些原交換機(jī)無(wú)法被路由的消息,就會(huì)都進(jìn)入這個(gè)隊(duì)列了。當(dāng)然,我們還可以建立一個(gè)報(bào)警隊(duì)列,用獨(dú)立的消費(fèi)者來(lái)進(jìn)行監(jiān)測(cè)和報(bào)警。

具體代碼請(qǐng)參考這篇:

2、設(shè)置持久化

上面我們的角度是站在生產(chǎn)者的方向,但是如果服務(wù)器重啟了,此時(shí)交換機(jī)和隊(duì)列都不存在了,消息存在也發(fā)送不了,這時(shí)需要把交換機(jī)和隊(duì)列都持久化。

/** * 生成一個(gè)隊(duì)列 * 1.隊(duì)列名稱 * 2.隊(duì)列里面的消息是否持久化 默認(rèn)消息存儲(chǔ)在內(nèi)存中 * 3.該隊(duì)列是否只供一個(gè)消費(fèi)者進(jìn)行消費(fèi) 是否進(jìn)行共享 true 可以多個(gè)消費(fèi)者消費(fèi) * 4.是否自動(dòng)刪除 最后一個(gè)消費(fèi)者端開(kāi)連接以后 該隊(duì)列是否自動(dòng)刪除 true 自動(dòng)刪除 * 5.其他參數(shù) */channel.queueDeclare(QUEUE_NAME, false, false, false, null);

3、RabbitMQ Server到消費(fèi)者消息丟失解決方案

默認(rèn)消息采用的是自動(dòng)應(yīng)答,所以我們要想實(shí)現(xiàn)消息消費(fèi)過(guò)程中不丟失,需要把自動(dòng)應(yīng)答改為手動(dòng)應(yīng)答

//將自動(dòng)應(yīng)答關(guān)閉boolean autoAck = false;channel.basicConsume(TASK_QUEUE_NAME, autoAck, deliverCallback, consumerTag -> { });

10、RabbitMQ消息基于什么傳輸?

由于 TCP 連接的創(chuàng)建和銷毀開(kāi)銷較大,且并發(fā)數(shù)受系統(tǒng)資源限制,會(huì)造成性能瓶頸。RabbitMQ 使用信道的方式來(lái)傳輸數(shù)據(jù)。信道是建立在真實(shí)的 TCP 連接內(nèi)的虛擬連接,且每條 TCP 連接上的信道數(shù)量沒(méi)有限制。

11、RabbitMQ支持消息的冪等性嗎?

支持。在消息生產(chǎn)時(shí),MQ 內(nèi)部針對(duì)每條生產(chǎn)者發(fā)送的消息生成一個(gè) inner-msg-id,作為去重的依據(jù)(消息投遞失敗并重傳),避免重復(fù)的消息進(jìn)入隊(duì)列。

在消息消費(fèi)時(shí),要求消息體中必須要有一個(gè) bizId(對(duì)于同一業(yè)務(wù)全局唯一,如支付 ID、訂單 ID、帖子 ID 等)作為去重的依據(jù),避免同一條消息被重復(fù)消費(fèi)。

12、RabbitMQ怎么確保消息已被消費(fèi)?

  • 消費(fèi)端配置手動(dòng)ACK確認(rèn)機(jī)制

  • 結(jié)合數(shù)據(jù)庫(kù)進(jìn)行狀態(tài)標(biāo)記處理

13、RabbitMQ支持事務(wù)消息嗎?

支持事務(wù)消息。前面在第9題中保證生產(chǎn)者不丟失消息,提到可以使用AMQP的事務(wù),但是它是同步的,所以不怎么推薦使用

事務(wù)的實(shí)現(xiàn)主要是對(duì)信道(Channel)的設(shè)置,主要方法如下:1. channel.txSelect()  聲明啟動(dòng)事務(wù)模式2.channel.txCommit() 提交事務(wù)3.channel.txRollback()回滾事務(wù)

14、RabbitMQ消息持久化的條件?

消息持久化,當(dāng)然前提是隊(duì)列必須持久化

  • 聲明隊(duì)列必須設(shè)置持久化 durable 設(shè)置為 true.

  • 消息推送投遞模式必須設(shè)置持久化,deliveryMode 設(shè)置為 2(持久)。

  • 消息已經(jīng)到達(dá)持久化交換器。

  • 消息已經(jīng)到達(dá)持久化隊(duì)列。

15、RabiitMQ消息什么情況下會(huì)變成死信消息?

由于特定的原因?qū)е?/strong>queue中的某些消息無(wú)法被消費(fèi),這樣的消息如果沒(méi)有后續(xù)的處理,就變成了死信消息

16、RabbitMQ死信消息的來(lái)源?

  • 消息 TTL 過(guò)期

  • 隊(duì)列達(dá)到最大長(zhǎng)度(隊(duì)列滿了,無(wú)法再添加數(shù)據(jù)到 mq 中)

  • 消息被拒絕(basic.reject 或 basic.nack)并且 requeue=false.

17、RabbitMQ死信隊(duì)列的用處?

  • 可以用于實(shí)現(xiàn)延遲隊(duì)列

18、RabbitMQ支持延遲隊(duì)列嗎?

支持。延時(shí)隊(duì)列,隊(duì)列內(nèi)部是有序的,最重要的特性就體現(xiàn)在它的延時(shí)屬性上,延時(shí)隊(duì)列中的元素是希望在指定時(shí)間到了以后或之前取出和處理,簡(jiǎn)單來(lái)說(shuō),延時(shí)隊(duì)列就是用來(lái)存放需要在指定時(shí)間被處理的元素的隊(duì)列。

19、RabbitMQ延遲隊(duì)列的使用場(chǎng)景

  • 訂單在十分鐘之內(nèi)未支付則自動(dòng)取消

  • 新創(chuàng)建的店鋪,如果在十天內(nèi)都沒(méi)有上傳過(guò)商品,則自動(dòng)發(fā)送消息提醒

  • 用戶注冊(cè)成功后,如果三天內(nèi)沒(méi)有登陸則進(jìn)行短信提醒

  • 用戶發(fā)起退款,如果三天內(nèi)沒(méi)有得到處理則通知相關(guān)運(yùn)營(yíng)人員

  • 預(yù)定會(huì)議后,需要在預(yù)定的時(shí)間點(diǎn)前十分鐘通知各個(gè)與會(huì)人員參加會(huì)議

20、RabbitMQ實(shí)現(xiàn)延遲隊(duì)列的有什么條件?

  • 消息設(shè)置TTL

  • 配置了死信隊(duì)列

21、RabbitMQ怎么實(shí)現(xiàn)優(yōu)先級(jí)隊(duì)列?

  1. 控制臺(tái)頁(yè)面:添加一個(gè)x-max-priority

在這里插入圖片描述
  1. 生產(chǎn)者添加優(yōu)先級(jí),案例代碼

    public class Product {    private static final String QUEUE_NAME = 'hello';    public static void main(String[] args) throws Exception {        try(Channel channel = RabbitMQConfig.getChannel()){            //給消息賦予一個(gè) priority 屬性            AMQP.BasicProperties basicProperties = new AMQP.BasicProperties().builder().priority(5).build();            for (int i = 1; i < 11; i ) {                String msg = 'info' i;                if(i==5){                    channel.basicPublish('', QUEUE_NAME, basicProperties, msg.getBytes());                }else{                    channel.basicPublish('', QUEUE_NAME, null, msg.getBytes());                }                System.out.println('發(fā)送消息完成:' msg);            }        }    }}

  2. 消費(fèi)者隊(duì)列中代碼添加優(yōu)先級(jí)

    public class Consumer {    private static final String QUEUE_NAME = 'hello';    public static void main(String[] args) throws Exception {        Channel channel = RabbitMQConfig.getChannel();        //設(shè)置隊(duì)列的最大優(yōu)先級(jí) 最大可以設(shè)置到 255 官網(wǎng)推薦 1-10 如果設(shè)置太高比較吃內(nèi)存和 CPU        Map<String, Object> map = new HashMap<>();        map.put('x-max-priority', 10);        channel.queueDeclare(QUEUE_NAME, true, false, false, map);        System.out.println('消費(fèi)者等待啟動(dòng)接收消息......');        DeliverCallback deliverCallback = (consumerTag, delivery) ->{            String receivedMessage = new String(delivery.getBody());            System.out.println('接收到消息:' receivedMessage);        };        channel.basicConsume(QUEUE_NAME, true, deliverCallback, (consumerTag) ->{            System.out.println('消費(fèi)者無(wú)法消費(fèi)消息時(shí)調(diào)用,如隊(duì)列被刪除');        });    }}

22、哪些情況下推薦使用RabbitMQ的惰性隊(duì)列

  • 隊(duì)列可能會(huì)產(chǎn)生消息堆積

  • 隊(duì)列對(duì)性能(吞吐量)的要求不是非常高,例如TPS 1萬(wàn)以下的場(chǎng)景

  • 希望隊(duì)列有穩(wěn)定的生產(chǎn)消費(fèi)性能,不受內(nèi)存影響而波動(dòng)

23、RabbitMQ如何處理消息堆積情況?

方法:臨時(shí)擴(kuò)容,快速處理積壓的消息

  • 先修復(fù) consumer 的問(wèn)題,確保其恢復(fù)消費(fèi)速度,然后將現(xiàn)有的 consumer 都停掉;

  • 臨時(shí)創(chuàng)建原先 N 倍數(shù)量的 queue ,然后寫一個(gè)臨時(shí)分發(fā)數(shù)據(jù)的消費(fèi)者程序,將該程序部署上去消費(fèi)隊(duì)列中積壓的數(shù)據(jù),消費(fèi)之后不做任何耗時(shí)處理,直接均勻輪詢寫入臨時(shí)建立好的 N 倍數(shù)量的 queue 中;

  • 接著,臨時(shí)征用 N 倍的機(jī)器來(lái)部署 consumer,每個(gè) consumer 消費(fèi)一個(gè)臨時(shí) queue 的數(shù)據(jù)

  • 等快速消費(fèi)完積壓數(shù)據(jù)之后,恢復(fù)原先部署架構(gòu) ,重新用原先的 consumer 機(jī)器消費(fèi)消息。

這種做法相當(dāng)于臨時(shí)將 queue 資源和 consumer 資源擴(kuò)大 N 倍,以正常 N 倍速度消費(fèi)。

24、RabbitMQ如何處理消息堆積過(guò)程中丟失的數(shù)據(jù)?

采用**“批量重導(dǎo)”**的方式,在流量低峰期,寫一個(gè)程序,手動(dòng)去查詢丟失的那部分?jǐn)?shù)據(jù),然后將消息重新發(fā)送到mq里面,把丟失的數(shù)據(jù)重新補(bǔ)回來(lái)。

25、RabbitMQ如何處理長(zhǎng)時(shí)間未處理導(dǎo)致寫滿的情況?

如果消息積壓在RabbitMQ里,并且長(zhǎng)時(shí)間都沒(méi)處理掉,導(dǎo)致RabbitMQ都快寫滿了,這種情況肯定是臨時(shí)擴(kuò)容方案執(zhí)行太慢;這種時(shí)候只好采用 “丟棄 批量重導(dǎo)”的方式來(lái)解決了。首先,臨時(shí)寫個(gè)程序,連接到RabbitMQ里面消費(fèi)數(shù)據(jù),消費(fèi)一個(gè)丟棄一個(gè),快速消費(fèi)掉積壓的消息,降低RabbitMQ的壓力,然后在流量低峰期時(shí)去手動(dòng)查詢重導(dǎo)丟失的這部分?jǐn)?shù)據(jù)。

26、如何設(shè)計(jì)一個(gè)消息隊(duì)列?

要考慮三點(diǎn):伸縮性、持久化、可用性

  1. 伸縮性:需要擴(kuò)容的時(shí)候可以快速擴(kuò)容,增加吞吐量和容量;可以參考kafaka的設(shè)計(jì)理念,broker -> topic -> partition,每個(gè)partition放一個(gè)機(jī)器,就存一部分?jǐn)?shù)據(jù);資源不夠了,給topic增加partition,然后做數(shù)據(jù)遷移,增加機(jī)器;

  2. 持久化:也就是數(shù)據(jù)要不要寫入磁盤,不寫入吧,進(jìn)程掛了,數(shù)據(jù)就丟失了,寫入磁盤該如何高效寫入呢?kafaka的思路:順序讀寫,采用磁盤緩存(Page Cache)的策略,操作系統(tǒng)采用預(yù)讀和后寫的方式,對(duì)磁盤進(jìn)行優(yōu)化。

    • 預(yù)讀:磁盤順序讀取的效率是很高的(不需要尋道時(shí)間,只需要很少的旋轉(zhuǎn)時(shí)間)。而在讀取磁盤某塊數(shù)據(jù)時(shí),同時(shí)會(huì)順序讀取相鄰地址的數(shù)據(jù)加載到PageCache,這樣在讀取后續(xù)連續(xù)數(shù)據(jù)時(shí),只需要從PageCache中讀取數(shù)據(jù),相當(dāng)于內(nèi)存讀寫,速度會(huì)特別快

    • 后寫:數(shù)據(jù)并不是直接寫入到磁盤,而是默認(rèn)先寫入到Page Cache,再由Page Cache刷新到磁盤,刷新頻率是由操作系統(tǒng)周期性的sync觸發(fā)的(用戶也可以手動(dòng)調(diào)用sync觸發(fā)刷新操作)。后寫的方式大大減少對(duì)磁盤的總寫入次數(shù),提高寫入效率

  3. 可用性:分布式系統(tǒng)的高可用幾乎都是通過(guò)冗余實(shí)現(xiàn)的,Kafka同樣如此。Kafka的消息存儲(chǔ)到partition中,每個(gè)partition在其他的broker中都存在多個(gè)副本。對(duì)外通過(guò)主partition提供讀寫服務(wù),當(dāng)主partition所在的broker故障時(shí),通過(guò)HA機(jī)制,將其他Broker上的某個(gè)副本partition會(huì)重新選舉成主partition,繼續(xù)對(duì)外提供服務(wù)。

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    免费观看日韩一级黄色大片| 人妻露脸一区二区三区| 日本人妻中出在线观看| 日韩欧美三级中文字幕| 在线中文字幕亚洲欧美一区| 国产一区二区三区av在线| 国产在线视频好看不卡| 日韩精品少妇人妻一区二区| 国产又粗又爽又猛又黄的| 久热青青草视频在线观看| 国产成人精品一区二三区在线观看 | 激情亚洲内射一区二区三区| 中文字幕乱子论一区二区三区| 欧美大粗爽一区二区三区| 国产精品第一香蕉视频| 欧美精品亚洲精品日韩精品| 欧美日韩国产综合在线| 久久亚洲精品成人国产| 国产对白老熟女正在播放| 午夜直播免费福利平台| 日本高清不卡在线一区| 欧美中文日韩一区久久| 激情内射亚洲一区二区三区| 国产成人亚洲精品青草天美 | 女人高潮被爽到呻吟在线观看| 欧美熟妇喷浆一区二区| 亚洲一区二区三区国产| 亚洲一区二区三区中文久久| 欧美日韩在线第一页日韩| 午夜久久精品福利视频| 精品日韩视频在线观看| 在线免费观看黄色美女| 亚洲国产精品av在线观看| 亚洲中文字幕有码在线观看| 亚洲少妇人妻一区二区| 日韩一区二区三区在线欧洲| 国产一区二区三区香蕉av| 一区二区三区四区亚洲专区| 99久久精品久久免费| 中文字幕亚洲精品在线播放| 国产韩国日本精品视频|