面試題
- 為什么使用消息隊(duì)列?
- 消息隊(duì)列有什么優(yōu)點(diǎn)和缺點(diǎn)?
- Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么區(qū)別,以及適合哪些場(chǎng)景?
面試官心理分析
其實(shí)面試官主要是想看看:
-
第一,你知不知道你們系統(tǒng)里為什么要用消息隊(duì)列這個(gè)東西?
不少候選人,說自己項(xiàng)目里用了 Redis、MQ,但是其實(shí)他并不知道自己為什么要用這個(gè)東西。其實(shí)說白了,就是為了用而用,或者是別人設(shè)計(jì)的架構(gòu),他從頭到尾都沒思考過。
沒有對(duì)自己的架構(gòu)問過為什么的人,一定是平時(shí)沒有思考的人,面試官對(duì)這類候選人印象通常很不好。因?yàn)槊嬖嚬贀?dān)心你進(jìn)了團(tuán)隊(duì)之后只會(huì)木頭木腦的干呆活兒,不會(huì)自己思考。
-
第二,你既然用了消息隊(duì)列這個(gè)東西,你知不知道用了有什么好處&壞處?
你要是沒考慮過這個(gè),那你盲目弄個(gè) MQ 進(jìn)系統(tǒng)里,后面出了問題你是不是就自己溜了給公司留坑?你要是沒考慮過引入一個(gè)技術(shù)可能存在的弊端和風(fēng)險(xiǎn),面試官把這類候選人招進(jìn)來了,基本可能就是挖坑型選手。就怕你干 1 年挖一堆坑,自己跳槽了,給公司留下無窮后患。
-
第三,既然你用了 MQ,可能是某一種 MQ,那么你當(dāng)時(shí)做沒做過調(diào)研?
你別傻乎乎的自己拍腦袋看個(gè)人喜好就瞎用了一個(gè) MQ,比如 Kafka,甚至都從沒調(diào)研過業(yè)界流行的 MQ 到底有哪幾種。每一個(gè) MQ 的優(yōu)點(diǎn)和缺點(diǎn)是什么。每一個(gè) MQ 沒有絕對(duì)的好壞,但是就是看用在哪個(gè)場(chǎng)景可以揚(yáng)長避短,利用其優(yōu)勢(shì),規(guī)避其劣勢(shì)。
如果是一個(gè)不考慮技術(shù)選型的候選人招進(jìn)了團(tuán)隊(duì),leader 交給他一個(gè)任務(wù),去設(shè)計(jì)個(gè)什么系統(tǒng),他在里面用一些技術(shù),可能都沒考慮過選型,最后選的技術(shù)可能并不一定合適,一樣是留坑。
面試題剖析
為什么使用消息隊(duì)列
其實(shí)就是問問你消息隊(duì)列都有哪些使用場(chǎng)景,然后你項(xiàng)目里具體是什么場(chǎng)景,說說你在這個(gè)場(chǎng)景里用消息隊(duì)列是什么?
面試官問你這個(gè)問題,期望的一個(gè)回答是說,你們公司有個(gè)什么業(yè)務(wù)場(chǎng)景,這個(gè)業(yè)務(wù)場(chǎng)景有個(gè)什么技術(shù)挑戰(zhàn),如果不用 MQ 可能會(huì)很麻煩,但是你現(xiàn)在用了 MQ 之后帶給了你很多的好處。
先說一下消息隊(duì)列常見的使用場(chǎng)景吧,其實(shí)場(chǎng)景有很多,但是比較核心的有 3 個(gè):解耦、異步、削峰。
解耦
看這么個(gè)場(chǎng)景。A 系統(tǒng)發(fā)送數(shù)據(jù)到 BCD 三個(gè)系統(tǒng),通過接口調(diào)用發(fā)送。如果 E 系統(tǒng)也要這個(gè)數(shù)據(jù)呢?那如果 C 系統(tǒng)現(xiàn)在不需要了呢?A 系統(tǒng)負(fù)責(zé)人幾乎崩潰......

在這個(gè)場(chǎng)景中,A 系統(tǒng)跟其它各種亂七八糟的系統(tǒng)嚴(yán)重耦合,A 系統(tǒng)產(chǎn)生一條比較關(guān)鍵的數(shù)據(jù),很多系統(tǒng)都需要 A 系統(tǒng)將這個(gè)數(shù)據(jù)發(fā)送過來。A 系統(tǒng)要時(shí)時(shí)刻刻考慮 BCDE 四個(gè)系統(tǒng)如果掛了該咋辦?要不要重發(fā),要不要把消息存起來?頭發(fā)都白了啊!
如果使用 MQ,A 系統(tǒng)產(chǎn)生一條數(shù)據(jù),發(fā)送到 MQ 里面去,哪個(gè)系統(tǒng)需要數(shù)據(jù)自己去 MQ 里面消費(fèi)。如果新系統(tǒng)需要數(shù)據(jù),直接從 MQ 里消費(fèi)即可;如果某個(gè)系統(tǒng)不需要這條數(shù)據(jù)了,就取消對(duì) MQ 消息的消費(fèi)即可。這樣下來,A 系統(tǒng)壓根兒不需要去考慮要給誰發(fā)送數(shù)據(jù),不需要維護(hù)這個(gè)代碼,也不需要考慮人家是否調(diào)用成功、失敗超時(shí)等情況。

總結(jié):通過一個(gè) MQ,Pub/Sub 發(fā)布訂閱消息這么一個(gè)模型,A 系統(tǒng)就跟其它系統(tǒng)徹底解耦了。
面試技巧:你需要去考慮一下你負(fù)責(zé)的系統(tǒng)中是否有類似的場(chǎng)景,就是一個(gè)系統(tǒng)或者一個(gè)模塊,調(diào)用了多個(gè)系統(tǒng)或者模塊,互相之間的調(diào)用很復(fù)雜,維護(hù)起來很麻煩。但是其實(shí)這個(gè)調(diào)用是不需要直接同步調(diào)用接口的,如果用 MQ 給它異步化解耦,也是可以的,你就需要去考慮在你的項(xiàng)目里,是不是可以運(yùn)用這個(gè) MQ 去進(jìn)行系統(tǒng)的解耦。在簡歷中體現(xiàn)出來這塊東西,用 MQ 作解耦。
異步
再來看一個(gè)場(chǎng)景,A 系統(tǒng)接收一個(gè)請(qǐng)求,需要在自己本地寫庫,還需要在 BCD 三個(gè)系統(tǒng)寫庫,自己本地寫庫要 3ms,BCD 三個(gè)系統(tǒng)分別寫庫要 300ms、450ms、200ms。最終請(qǐng)求總延時(shí)是 3 + 300 + 450 + 200 = 953ms,接近 1s,用戶感覺搞個(gè)什么東西,慢死了慢死了。用戶通過瀏覽器發(fā)起請(qǐng)求,等待個(gè) 1s,這幾乎是不可接受的。

一般互聯(lián)網(wǎng)類的企業(yè),對(duì)于用戶直接的操作,一般要求是每個(gè)請(qǐng)求都必須在 200 ms 以內(nèi)完成,對(duì)用戶幾乎是無感知的。
如果使用 MQ,那么 A 系統(tǒng)連續(xù)發(fā)送 3 條消息到 MQ 隊(duì)列中,假如耗時(shí) 5ms,A 系統(tǒng)從接受一個(gè)請(qǐng)求到返回響應(yīng)給用戶,總時(shí)長是 3 + 5 = 8ms,對(duì)于用戶而言,其實(shí)感覺上就是點(diǎn)個(gè)按鈕,8ms 以后就直接返回了,爽!網(wǎng)站做得真好,真快!

削峰
每天 0:00 到 12:00,A 系統(tǒng)風(fēng)平浪靜,每秒并發(fā)請(qǐng)求數(shù)量就 50 個(gè)。結(jié)果每次一到 12:00 ~ 13:00 ,每秒并發(fā)請(qǐng)求數(shù)量突然會(huì)暴增到 5k+ 條。但是系統(tǒng)是直接基于 MySQL的,大量的請(qǐng)求涌入 MySQL,每秒鐘對(duì) MySQL 執(zhí)行約 5k 條 SQL。
一般的 MySQL,扛到每秒 2k 個(gè)請(qǐng)求就差不多了,如果每秒請(qǐng)求到 5k 的話,可能就直接把 MySQL 給打死了,導(dǎo)致系統(tǒng)崩潰,用戶也就沒法再使用系統(tǒng)了。
但是高峰期一過,到了下午的時(shí)候,就成了低峰期,可能也就 1w 的用戶同時(shí)在網(wǎng)站上操作,每秒中的請(qǐng)求數(shù)量可能也就 50 個(gè)請(qǐng)求,對(duì)整個(gè)系統(tǒng)幾乎沒有任何的壓力。

如果使用 MQ,每秒 5k 個(gè)請(qǐng)求寫入 MQ,A 系統(tǒng)每秒鐘最多處理 2k 個(gè)請(qǐng)求,因?yàn)?MySQL 每秒鐘最多處理 2k 個(gè)。A 系統(tǒng)從 MQ 中慢慢拉取請(qǐng)求,每秒鐘就拉取 2k 個(gè)請(qǐng)求,不要超過自己每秒能處理的最大請(qǐng)求數(shù)量就 ok,這樣下來,哪怕是高峰期的時(shí)候,A 系統(tǒng)也絕對(duì)不會(huì)掛掉。而 MQ 每秒鐘 5k 個(gè)請(qǐng)求進(jìn)來,就 2k 個(gè)請(qǐng)求出去,結(jié)果就導(dǎo)致在中午高峰期(1 個(gè)小時(shí)),可能有幾十萬甚至幾百萬的請(qǐng)求積壓在 MQ 中。

這個(gè)短暫的高峰期積壓是 ok 的,因?yàn)楦叻迤谶^了之后,每秒鐘就 50 個(gè)請(qǐng)求進(jìn) MQ,但是 A 系統(tǒng)依然會(huì)按照每秒 2k 個(gè)請(qǐng)求的速度在處理。所以說,只要高峰期一過,A 系統(tǒng)就會(huì)快速將積壓的消息給解決掉。
消息隊(duì)列有什么優(yōu)缺點(diǎn)
優(yōu)點(diǎn)上面已經(jīng)說了,就是在特殊場(chǎng)景下有其對(duì)應(yīng)的好處,解耦、異步、削峰。
缺點(diǎn)有以下幾個(gè):
-
系統(tǒng)可用性降低
系統(tǒng)引入的外部依賴越多,越容易掛掉。本來你就是 A 系統(tǒng)調(diào)用 BCD 三個(gè)系統(tǒng)的接口就好了,人 ABCD 四個(gè)系統(tǒng)好好的,沒啥問題,你偏加個(gè) MQ 進(jìn)來,萬一 MQ 掛了咋整,MQ 一掛,整套系統(tǒng)崩潰的,你不就完了?如何保證消息隊(duì)列的高可用,可以點(diǎn)擊這里查看。
-
系統(tǒng)復(fù)雜度提高
硬生生加個(gè) MQ 進(jìn)來,你怎么保證消息沒有重復(fù)消費(fèi)?怎么處理消息丟失的情況?怎么保證消息傳遞的順序性?頭大頭大,問題一大堆,痛苦不已。
-
一致性問題
A 系統(tǒng)處理完了直接返回成功了,人都以為你這個(gè)請(qǐng)求就成功了;但是問題是,要是 BCD 三個(gè)系統(tǒng)那里,BD 兩個(gè)系統(tǒng)寫庫成功了,結(jié)果 C 系統(tǒng)寫庫失敗了,咋整?你這數(shù)據(jù)就不一致了。
所以消息隊(duì)列實(shí)際是一種非常復(fù)雜的架構(gòu),你引入它有很多好處,但是也得針對(duì)它帶來的壞處做各種額外的技術(shù)方案和架構(gòu)來規(guī)避掉,做好之后,你會(huì)發(fā)現(xiàn),媽呀,系統(tǒng)復(fù)雜度提升了一個(gè)數(shù)量級(jí),也許是復(fù)雜了 10 倍。但是關(guān)鍵時(shí)刻,用,還是得用的。
Kafka、ActiveMQ、RabbitMQ、RocketMQ 有什么優(yōu)缺點(diǎn)?
| 特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
|---|---|---|---|---|
| 單機(jī)吞吐量 | 萬級(jí),比 RocketMQ、Kafka 低一個(gè)數(shù)量級(jí) | 同 ActiveMQ | 10 萬級(jí),支撐高吞吐 | 10 萬級(jí),高吞吐,一般配合大數(shù)據(jù)類的系統(tǒng)來進(jìn)行實(shí)時(shí)數(shù)據(jù)計(jì)算、日志采集等場(chǎng)景 |
| topic 數(shù)量對(duì)吞吐量的影響 | topic 可以達(dá)到幾百/幾千的級(jí)別,吞吐量會(huì)有較小幅度的下降,這是 RocketMQ 的一大優(yōu)勢(shì),在同等機(jī)器下,可以支撐大量的 topic | topic 從幾十到幾百個(gè)時(shí)候,吞吐量會(huì)大幅度下降,在同等機(jī)器下,Kafka 盡量保證 topic 數(shù)量不要過多,如果要支撐大規(guī)模的 topic,需要增加更多的機(jī)器資源 | ||
| 時(shí)效性 | ms 級(jí) | 微秒級(jí),這是 RabbitMQ 的一大特點(diǎn),延遲最低 | ms 級(jí) | 延遲在 ms 級(jí)以內(nèi) |
| 可用性 | 高,基于主從架構(gòu)實(shí)現(xiàn)高可用 | 同 ActiveMQ | 非常高,分布式架構(gòu) | 非常高,分布式,一個(gè)數(shù)據(jù)多個(gè)副本,少數(shù)機(jī)器宕機(jī),不會(huì)丟失數(shù)據(jù),不會(huì)導(dǎo)致不可用 |
| 消息可靠性 | 有較低的概率丟失數(shù)據(jù) | 基本不丟 | 經(jīng)過參數(shù)優(yōu)化配置,可以做到 0 丟失 | 同 RocketMQ |
| 功能支持 | MQ 領(lǐng)域的功能極其完備 | 基于 erlang 開發(fā),并發(fā)能力很強(qiáng),性能極好,延時(shí)很低 | MQ 功能較為完善,還是分布式的,擴(kuò)展性好 | 功能較為簡單,主要支持簡單的 MQ 功能,在大數(shù)據(jù)領(lǐng)域的實(shí)時(shí)計(jì)算以及日志采集被大規(guī)模使用 |
綜上,各種對(duì)比之后,有如下建議:
一般的業(yè)務(wù)系統(tǒng)要引入 MQ,最早大家都用 ActiveMQ,但是現(xiàn)在確實(shí)大家用的不多了,沒經(jīng)過大規(guī)模吞吐量場(chǎng)景的驗(yàn)證,社區(qū)也不是很活躍,所以大家還是算了吧,我個(gè)人不推薦用這個(gè)了;
后來大家開始用 RabbitMQ,但是確實(shí) erlang 語言阻止了大量的 Java 工程師去深入研究和掌控它,對(duì)公司而言,幾乎處于不可控的狀態(tài),但是確實(shí)人家是開源的,比較穩(wěn)定的支持,活躍度也高;
不過現(xiàn)在確實(shí)越來越多的公司,會(huì)去用 RocketMQ,確實(shí)很不錯(cuò)(阿里出品),但社區(qū)可能有突然黃掉的風(fēng)險(xiǎn),對(duì)自己公司技術(shù)實(shí)力有絕對(duì)自信的,推薦用 RocketMQ,否則回去老老實(shí)實(shí)用 RabbitMQ 吧,人家有活躍的開源社區(qū),絕對(duì)不會(huì)黃。
所以中小型公司,技術(shù)實(shí)力較為一般,技術(shù)挑戰(zhàn)不是特別高,用 RabbitMQ 是不錯(cuò)的選擇;大型公司,基礎(chǔ)架構(gòu)研發(fā)實(shí)力較強(qiáng),用 RocketMQ 是很好的選擇。
如果是大數(shù)據(jù)領(lǐng)域的實(shí)時(shí)計(jì)算、日志采集等場(chǎng)景,用 Kafka 是業(yè)內(nèi)標(biāo)準(zhǔn)的,絕對(duì)沒問題,社區(qū)活躍度很高,絕對(duì)不會(huì)黃,何況幾乎是全世界這個(gè)領(lǐng)域的事實(shí)性規(guī)范。
轉(zhuǎn)載自:互聯(lián)網(wǎng) Java 工程師進(jìn)階知識(shí)完全掃盲,萬分感謝。