RabbitMQ面試題解析


1.消息隊列的作用與使用場景?

異步:批量數據異步處理。例:批量上傳文件,比如代發代扣文件

削峰:高負載任務負載均衡。例:電商秒殺搶購

解耦:串行任務並行化。例:退貨流程解耦。

廣播:基於Pub/Sub實現一對多通信

2.多個消費者監聽一個隊列時,消息如何分發?

1.Round-Robin(輪詢)

默認的策略,消費者輪流,平均地收到消息。

2.Fair dispatch(公平分發)

如果要實現根據消費者的處理能力來分發消息,給空閑的消費者發送更多消息,可以用basicQos(int prefetch_count)來設置。prefetch_count的含義:當消費者有多少條消息沒有響應ACK時,不再給這個消費者發送消息。

3.無法被路由的消息,去了哪里?

如果沒有任何設置,無法路由的消息會被直接丟棄。

無法路由的情況:Routing key不正確

解決方案:

1.使用mandatory = true配合ReturnListener,實現消息回發

2.聲明交換機時,指定備份交換機。

4.消息在什么時候會變成Dead Letter(死信)?

1.消息被拒絕並且沒有設置重新入隊:(NACK || Reject)&&requeue == false

2.消息過期(消息或者隊列的TTL設置)

3.消息堆積,並且隊列達到最大長度,先入隊的消息會變成DL。

可以在聲明隊列的時候,指定一個Dead Letter Exchange,來實現Dead Letter的轉發。

5.RabbitMQ如何實現延時隊列?

利用TTL(隊列的消息存活時間或消息的存活時間),加上死信交換機。

當然還有一種方式就是先保存到數據庫,用調度器掃描發送(時間不夠精准)

6.如何保證消息的可靠性傳遞?

1.確保投遞到服務端Broker

有兩種解決方案,第一種是Transaction(事務)模式,第二種Confirm(確認)模式。 在通過channel.txSelect方法開啟事務之后,我們便可以發布消息給RabbitMQ了,如果事務提交成功,則消息一定 到達了RabbitMQ中,如果在事務提交執行之前由於RabbitMQ異常崩潰或者其他原因拋出異常,這個時候我們便 可以將其捕獲,進而通過執行channel.txRollback方法來實現事務回滾。使用事務機制的話會“吸干”RabbitMQ的性 能,一般不建議使用。
生產者通過調用channel.confirmSelect方法(即Confirm.Select命令)將信道設置為confirm模式。一旦消息被投 遞到所有匹配的隊列之后,RabbitMQ就會發送一個確認(Basic.Ack)給生產者(包含消息的唯一ID),這就使得 生產者知曉消息已經正確到達了目的地了。

2.保證正確的路由

使用mandatory參數和ReturnListener,可以實現消息無法路由的時候返回給生產者。
另一種方式就是使用備份交換機(alternate-exchange),無法路由的消息會發送到這個交換機上。

3.消息的持久化存儲

 

 

4.消費者應答ACK

為了保證消息從隊列可靠地達到消費者,RabbitMQ提供了消息確認機制(message acknowledgement)。消費 者在訂閱隊列時,可以指定autoAck參數,當autoAck等於false時,RabbitMQ會等待消費者顯式地回復確認信號 后才從隊列中移去消息。
如果消息消費失敗,也可以調用Basic.Reject或者Basic.Nack來拒絕當前消息而不是確認。如果requeue參數設置為 true,可以把這條消息重新存入隊列,以便發給下一個消費者(當然,只有一個消費者的時候,這種方式可能會出 現無限循環重復消費的情況,可以投遞到新的隊列中,或者只打印異常日志)

5.消費者回調

消費者處理消息以后,可以再發送一條消息給生產者,或者調用生產者的API,告知消息處理完畢。 

6.補償機制

對於一定時間沒有得到響應的消息,可以設置一個定時重發的機制,但要控制次數,比如最多重發3次,否則會造 成消息堆積。

 

7.消息冪等性是什么?

Broker本身沒有消息重復過濾的機制

1.生產者方面,可以對每條消息生成一個msgId,以此控制消息重復投遞。

//消息屬性
AMQP.BasicProperties properties = new AMQP.BasicProperties.builder()
            .messageId(String.valueOf(UUID.randomUUID()))
            .build();
//發送消息
channel.basicPublish("",QUEUE_NAME,properties,msg.getBytes());

2.消費者方面,消息體(比如json報文)中必須攜帶一個業務ID,比如銀行得到交易流水號,消費者可以根據業務ID去重,避免重復消費。

8.如何在服務端和消費端做限流?

網關/接入層:其他限流方式。

服務端(Broker):配置文件中內存和磁盤的控制;(隊列長度無法實現限流)。

消費端:prefetch_count.

9 如何保證消息的順序性?

比如新增門店,綁定產品,激活門店這種對消息順序要求嚴格的場景。

一個隊列只有一個消費者的情況下才能保證順序。

否則只能通過全局ID來實現。

1.每條消息有一個msgId,關聯的消息擁有同一個parentMsgId。

2.可以在消費端實現前一條消息未消費,不處理下一條消息;也可以在生產端實現前一條消息未處理完畢,不發布下一條消息。

10.SpringBoot中,bean還沒有初始化好,消費者就開始監聽取消息,導致空指針異常,怎么讓消費者在容器啟動完畢后才開始監聽?

RabbitMQ中有一個auto_startup參數,可以控制是否在容器啟動時就監聽啟動

全局參數:

spring.rabbitmq.listener.auto-startup=true   ##默認是true

自定義容器,容器可以應用到消費者:

// 默認是true 
factory.setAutoStartup(true);

消費者單獨設置

@RabbitListener( queues = "${com.gupaoedu.thirdqueue}" ,autoStartup = "false")


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM