MQ相關面試題


如果你的簡歷中有寫到MQ,那么面試官一般會問到如下幾個問題,至少我在面試中經常常被問到,所以今天總結一下,有不對的地方還望多多包涵:

首先第一個問題,為什么要用MQ?

如果這個問題你都沒考慮過,那么說明你只是一個單純會用MQ技術的一個coder,而不是一個會獨立思考的程序員,如果被面試官問到這個問題,你都沒有回答上來,那么你的第一印象肯定會很差。

一、為什么要用MQ?

(1)解耦:如果多個模塊或者系統中,互相調用很復雜,維護起來比較麻煩,但是這個調用又不是同步調用,就可以運用MQ到這個業務中。

(2)異步:這個很好理解,比如用戶的操作日志的維護,可以不用同步處理,節約響應時間。

(3)削峰:在高峰期的時候,系統每秒的請求量達到 5000,那么調用 MySQL 的請求也是 5000,一般情況下 MySQL 的請求大概在 2000 左右,那么在高峰期的時候,數據庫就被打垮了,那系統就不可用了。此時引入MQ,在系統 A 前面加個 MQ,用戶請求先到 MQ,系統 A 從 MQ 中每秒消費 2000 條數據,這樣就把本來 5000 的請求變為 MySQL 可以接受的請求數量了,可以保證系統不掛掉,可以繼續提供服務。MQ 里的數據可以慢慢的把它消費掉。

二、使用了MQ會有什么問題?

這個問題記住一個降低一個增加即可。

(1)降低了系統可用性 (2)增加了系統的復雜性

三、怎樣選型MQ?

如果你被問及這個問題,面試官主要是想看你選型的時候是否會比較架構的區別,是否滿足業務需求。

特性 ActiveMQ RabbitMQ RocketMQ Kafka
單機吞吐量 萬級 萬級 十萬級 十萬級
topic 數量對吞吐量的影響  -  -  topic 可以達到幾百,幾千個的級別,吞吐量會有較小幅度的下降  topic 從幾十個到幾百個的時候,吞吐量會大幅度下降
 時效性  毫秒級  微妙級  毫秒級  毫秒級
 可用性  高  高  非常高,分布式架構  非常高,分布式架構
 消息可靠性  有較低的概率丟失數據  -  經過參數優化配置,可以做到 0 丟失  經過參數優化配置,消息可以做到 0 丟失
 功能支持  完善  並發能力很強,性能極其好,延時很低  MQ 功能較為完善,還是分布式的,擴展性好  功能較為簡單,主要支持簡單的 MQ 功能,在大數據領域的實時計算以及日志采集被大規模使用,是事實上的標准
 優劣勢總結  非常成熟,功能強大;偶爾會有較低概率丟失消息;社區不活躍了  性能極其好,延時很低;功能完善;提供管理界面;社區比較活躍;吞吐量較低;使用 erlang 開發源碼閱讀不方便;  接口簡單易用;吞吐量高;分布式擴展方便;社區還算活躍;經過雙 11 的考驗  MQ 功能比較少;吞吐量高;分布式架構;可能存在消息重復消費問題;主要適用大數據實時計算以及日志收集;

 個人建議:

中小型公司,技術一般,可以考慮用 RabbitMQ;
大型公司,基礎架構研發實力較強,用 RocketMQ 是很好的選擇
實時計算、日志采集:使用 kafka;

四、怎樣保證MQ的高可用?

RabbitMQ是比較有代表性的,因為是基於主從做高可用性的。以他為例,自行查閱以下模式。

rabbitmq有三種模式:單機模式、普通集群模式、鏡像集群模式

五、如何保證不被重復消費?

不通的消費隊列都會有一個消費通知的機制,如:

RabbitMQ提供了一個ACK確認消息機制,

rocketMQ返回一個CONSUME_SUCCESS成功標志

 (1)比如,你拿到這個消息做數據庫的insert操作。那就容易了,給這個消息做一個唯一主鍵,那么就算出現重復消費的情況,就會導致主鍵沖突,避免數據庫出現臟數據。
 (2)再比如,你拿到這個消息做redis的set的操作,那就容易了,不用解決,因為你無論set幾次結果都是一樣的,set操作本來就算冪等操作。
 (3)如果上面兩種情況還不行,上大招。准備一個第三方介質,來做消費記錄。以redis為例,給消息分配一個全局id,只要消費過該消息,將<id,message>以K-V形式寫入redis。那消費者開始消費前,先去redis中查詢有沒消費記錄即可。

六、如何保證消費的可靠傳輸性?

 

每個MQ都要從生產者丟失數據、消費隊列丟失數據、消費丟失數據三個層面回答

(1) 生產者丟失數據

以rabbitMQ為例,rabbitMQ提供了transaction和confirm模式來確保生產者不丟失數據,事務機制,發送消息前,開啟事務(channel.txSelect()),發送消息后出現異常,事務回滾(channel.txRollback()),發送成功提交事務(channel.txCommit())。

上面這種方式吞吐量會下降,因此生產上應該使用confirm模式居多。

一旦channel進入confirm模式,所有在該通道發布上的消息都會被指派一個唯一的ID(從1開始),消息進來如隊列后,rabbitMq會立即發送一個ACK給生產者,其中包含了消息的唯一ID,這就使得生產者知道消息已經到達了消息隊列里。如果消息隊列沒能處理該消息,則會發送一個NACK給生產者進行重試操作。

channel.addConfirmListener(new ConfirmListener() {

    @Override
    public void handleNack(long deliveryTag, boolean multiple) throws IOException {
        System.out.println("nack: deliveryTag = "+deliveryTag+" multiple: "+multiple);
    }

    @Override
    public void handleAck(long deliveryTag, boolean multiple) throws IOException {
        System.out.println("ack: deliveryTag = "+deliveryTag+" multiple: "+multiple);
    }
});

(2) 消息隊列丟失數據

消息隊列丟失的情況一般是開啟持久化硬盤配置,這個持久化配置可以和confirm機制配合使用,可以在持久化硬盤之后,發送一個ack給生產者,如果生產者收不到ack信息,會重發信息。

如何持久化硬盤:

①將queue的持久化標識durable設置為true,

②發送消息的時候將deliveryMode=2

這樣設置就算rabbitMQ掛了,重啟后也能恢復數據

(3) 消費者丟失數據

消費者丟失數據一般都是以為采用了自動確認消息模式。消費者收到消息后,rabbitMQ會立即從隊列里面刪除該消息,這是情況如果消費者出現異常而沒有及時處理該消息就會丟失數據。

解決方案:采用手動確認消息。

 七、如何保證消息的時序性?

先進先出隊列,比如linkedBlockingQueue。


免責聲明!

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



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