面試題面試
爲何使用消息隊列? 消息隊列有什麼優勢和缺點? Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什麼區別,以及適合哪些場景?
面試官心理分析redis
其實面試官主要是想看看:數據庫
第一,你知不知道大家系統裏爲何要用消息隊列這個東西? 很多候選人,說本身項目裏用了 Redis、MQ,可是其實他並不知道本身爲何要用這個東西。其實說白了,就是爲了用而用,或者是別人設計的架構,他從頭至尾都沒思考過。 沒有對本身的架構問過爲何的人,必定是平時沒有思考的人,面試官對這類候選人印象一般很很差。由於面試官擔憂你進了團隊以後只會木頭木腦的幹呆活兒,不會本身思考。 第二,你既然用了消息隊列這個東西,你知不知道用了有什麼好處&壞處? 你要是沒考慮過這個,那你盲目弄個 MQ 進系統裏,後面出了問題你是否是就本身溜了給公司留坑?你要是沒考慮過引入一個技術可能存在的弊端和風險,面試官把這類候選人招進來了,基本可能就是挖坑型選手。就怕你幹 1 年挖一堆坑,本身跳槽了,給公司留下無窮後患。 第三,既然你用了 MQ,多是某一種 MQ,那麼你當時作沒作過調研? 你別傻乎乎的本身拍腦殼看我的喜愛就瞎用了一個 MQ,好比 Kafka,甚至都從沒調研過業界流行的 MQ 到底有哪幾種。每個 MQ 的優勢和缺點是什麼。每個 MQ 沒有絕對的好壞,可是就是看用在哪一個場景能夠揚長避短,利用其優點,規避其劣勢。 若是是一個不考慮技術選型的候選人招進了團隊,leader 交給他一個任務,去設計個什麼系統,他在裏面用一些技術,可能都沒考慮過選型,最後選的技術可能並不必定合適,同樣是留坑。
面試題剖析
爲何使用消息隊列瀏覽器
其實就是問問你消息隊列都有哪些使用場景,而後你項目裏具體是什麼場景,說說你在這個場景裏用消息隊列是什麼?架構
面試官問你這個問題,指望的一個回答是說,大家公司有個什麼業務場景,這個業務場景有個什麼技術挑戰,若是不用 MQ 可能會很麻煩,可是你如今用了 MQ 以後帶給了你不少的好處。併發
先說一下消息隊列常見的使用場景吧,其實場景有不少,可是比較核心的有 3 個:解耦、異步、削峯。
解耦異步
看這麼個場景。A 系統發送數據到 BCD 三個系統,經過接口調用發送。若是 E 系統也要這個數據呢?那若是 C 系統如今不須要了呢?A 系統負責人幾乎崩潰......大數據
mq-1網站
在這個場景中,A 系統跟其它各類亂七八糟的系統嚴重耦合,A 系統產生一條比較關鍵的數據,不少系統都須要 A 系統將這個數據發送過來。A 系統要時時刻刻考慮 BCDE 四個系統若是掛了該咋辦?要不要重發,要不要把消息存起來?頭髮都白了啊!設計
若是使用 MQ,A 系統產生一條數據,發送到 MQ 裏面去,哪一個系統須要數據本身去 MQ 裏面消費。若是新系統須要數據,直接從 MQ 裏消費便可;若是某個系統不須要這條數據了,就取消對 MQ 消息的消費便可。這樣下來,A 系統壓根兒不須要去考慮要給誰發送數據,不須要維護這個代碼,也不須要考慮人家是否調用成功、失敗超時等狀況。
mq-2
總結:經過一個 MQ,Pub/Sub 發佈訂閱消息這麼一個模型,A 系統就跟其它系統完全解耦了。
面試技巧:你須要去考慮一下你負責的系統中是否有相似的場景,就是一個系統或者一個模塊,調用了多個系統或者模塊,互相之間的調用很複雜,維護起來很麻煩。可是其實這個調用是不須要直接同步調用接口的,若是用 MQ 給它異步化解耦,也是能夠的,你就須要去考慮在你的項目裏,是否是能夠運用這個 MQ 去進行系統的解耦。在簡歷中體現出來這塊東西,用 MQ 做解耦。
異步
再來看一個場景,A 系統接收一個請求,須要在本身本地寫庫,還須要在 BCD 三個系統寫庫,本身本地寫庫要 3ms,BCD 三個系統分別寫庫要 300ms、450ms、200ms。最終請求總延時是 3 + 300 + 450 + 200 = 953ms,接近 1s,用戶感受搞個什麼東西,慢死了慢死了。用戶經過瀏覽器發起請求,等待個 1s,這幾乎是不可接受的。
mq-3
通常互聯網類的企業,對於用戶直接的操做,通常要求是每一個請求都必須在 200 ms 之內完成,對用戶幾乎是無感知的。
若是使用 MQ,那麼 A 系統連續發送 3 條消息到 MQ 隊列中,假如耗時 5ms,A 系統從接受一個請求到返回響應給用戶,總時長是 3 + 5 = 8ms,對於用戶而言,其實感受上就是點個按鈕,8ms 之後就直接返回了,爽!網站作得真好,真快!
mq-4
削峯
天天 0:00 到 12:00,A 系統風平浪靜,每秒併發請求數量就 50 個。結果每次一到 12:00 ~ 13:00 ,每秒併發請求數量忽然會暴增到 5k+ 條。可是系統是直接基於 MySQL 的,大量的請求涌入 MySQL,每秒鐘對 MySQL 執行約 5k 條 SQL。
通常的 MySQL,扛到每秒 2k 個請求就差很少了,若是每秒請求到 5k 的話,可能就直接把 MySQL 給打死了,致使系統崩潰,用戶也就無法再使用系統了。
可是高峯期一過,到了下午的時候,就成了低峯期,可能也就 1w 的用戶同時在網站上操做,每秒中的請求數量可能也就 50 個請求,對整個系統幾乎沒有任何的壓力。
mq-5
若是使用 MQ,每秒 5k 個請求寫入 MQ,A 系統每秒鐘最多處理 2k 個請求,由於 MySQL 每秒鐘最多處理 2k 個。A 系統從 MQ 中慢慢拉取請求,每秒鐘就拉取 2k 個請求,不要超過本身每秒能處理的最大請求數量就 ok,這樣下來,哪怕是高峯期的時候,A 系統也絕對不會掛掉。而 MQ 每秒鐘 5k 個請求進來,就 2k 個請求出去,結果就致使在中午高峯期(1 個小時),可能有幾十萬甚至幾百萬的請求積壓在 MQ 中。
mq-6
這個短暫的高峯期積壓是 ok 的,由於高峯期過了以後,每秒鐘就 50 個請求進 MQ,可是 A 系統依然會按照每秒 2k 個請求的速度在處理。因此說,只要高峯期一過,A 系統就會快速將積壓的消息給解決掉。
消息隊列有什麼優缺點
優勢上面已經說了,就是在特殊場景下有其對應的好處,解耦、異步、削峯。
缺點有如下幾個:
系統可用性下降 系統引入的外部依賴越多,越容易掛掉。原本你就是 A 系統調用 BCD 三個系統的接口就行了,人 ABCD 四個系統好好的,沒啥問題,你偏加個 MQ 進來,萬一 MQ 掛了咋整,MQ 一掛,整套系統崩潰的,你不就完了?如何保證消息隊列的高可用,能夠點擊這裏查看。 系統複雜度提升 硬生生加個 MQ 進來,你怎麼保證消息沒有重複消費?怎麼處理消息丟失的狀況?怎麼保證消息傳遞的順序性?頭大頭大,問題一大堆,痛苦不已。 一致性問題 A 系統處理完了直接返回成功了,人都覺得你這個請求就成功了;可是問題是,要是 BCD 三個系統那裏,BD 兩個系統寫庫成功了,結果 C 系統寫庫失敗了,咋整?你這數據就不一致了。
因此消息隊列實際是一種很是複雜的架構,你引入它有不少好處,可是也得針對它帶來的壞處作各類額外的技術方案和架構來規避掉,作好以後,你會發現,媽呀,系統複雜度提高了一個數量級,也許是複雜了 10 倍。可是關鍵時刻,用,仍是得用的。
如何選擇MQ
通常的業務系統要引入 MQ,最先你們都用 ActiveMQ,可是如今確實你們用的很少了,沒通過大規模吞吐量場景的驗證,社區也不是很活躍,因此你們仍是算了吧,我我的不推薦用這個了;
後來你們開始用 RabbitMQ,可是確實 erlang 語言阻止了大量的 Java 工程師去深刻研究和掌控它,對公司而言,幾乎處於不可控的狀態,可是確實人家是開源的,比較穩定的支持,活躍度也高;
不過如今確實愈來愈多的公司會去用 RocketMQ,確實很不錯,畢竟是阿里出品,但社區可能有忽然黃掉的風險(目前 RocketMQ 已捐給 Apache,但 GitHub 上的活躍度其實不算高)對本身公司技術實力有絕對自信的,推薦用 RocketMQ,不然回去老老實實用 RabbitMQ 吧,人家有活躍的開源社區,絕對不會黃。
因此中小型公司,技術實力較爲通常,技術挑戰不是特別高,用 RabbitMQ 是不錯的選擇;大型公司,基礎架構研發實力較強,用 RocketMQ 是很好的選擇。
若是是大數據領域的實時計算、日誌採集等場景,用 Kafka 是業內標準的,絕對沒問題,社區活躍度很高,絕對不會黃,況且幾乎是全世界這個領域的事實性規範。
怎麼保證消息沒有重複消費
1.若是是拿這個消息作數據庫insert操做(事實上update和delete重複也不影響)給這個消息作一個惟一主鍵,那麼就算出現重複消費的狀況,就會致使主鍵衝突,避免數據庫出現髒數據。 2.當拿到這個消息作redis的set的操做,那就容易了,不用解決,由於你不管set幾回結果都是同樣的,set操做原本就算冪等操做。 3.若是上面兩種狀況還不行,準備一個第三方存儲,來作消費記錄。以redis爲例,給消息分配一個全局id,只要消費過該消息,將<id,message>以K-V形式寫入redis。那消費者開始消費前,先去redis中查詢有沒消費記錄便可。
怎麼處理消息丟失的狀況
怎麼保證消息傳遞的順序性
怎麼保證多系統消息一致性