原文地址:https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/why-mq.md
-
為什么使用消息隊列
-
消息隊列的優(yōu)缺點
-
Kafka猬腰、ActiveMQ破喻、RabbitMQ、RocketMQ 都有什么區(qū)別旭贬,以及適合哪些場景袖肥?
解析
為什么使用消息隊列
首先知道一般什么業(yè)務(wù)場景下使用消息隊列抹恳?
3個常用場景 解耦教届、異步懊亡、削峰
解耦
場景:A調(diào)用B依啰、C、D三個服務(wù)店枣,如果E也要或者D不要了速警,就得修改A系統(tǒng)的代碼。如果你是A鸯两,你會不會崩潰闷旧?
在這個系統(tǒng)中,系統(tǒng)A和其他系統(tǒng)嚴重耦合钧唐,很多系統(tǒng)都需要A的數(shù)據(jù)忙灼,但是如果某個系統(tǒng)掛了呢?要不要重發(fā)?要不要把消息存起來钝侠?A又崩潰了该园。。帅韧。爬范。
如果使用MQ,A發(fā)送一條消息弱匪,直接存到MQ里面青瀑。哪個系統(tǒng)需要就自己去MQ里面取璧亮。哪個系統(tǒng)不要了,自己取消消費就行斥难。A根本不需要考慮發(fā)給誰枝嘶,也不需要考慮人家是否成功或失敗超時等情況。
總結(jié): 通過一個 MQ哑诊,Pub/Sub 發(fā)布訂閱消息這么一個模型群扶,A 系統(tǒng)就跟其它系統(tǒng)徹底解耦了。
異步
場景:A接收到一個請求镀裤,需要在本地寫庫竞阐,并且還要在B、C暑劝、D三個服務(wù)寫庫骆莹,假如本地寫庫需要3ms,B寫庫300ms担猛,C寫庫需要450ms幕垦,D寫庫需要200ms,這時請求用時為3+300+450+200將近1s傅联。用戶覺得一個請求需要一秒鐘先改,根本接收不了。
如果使用MQ蒸走,那么A系統(tǒng)將發(fā)送3條消息到MQ,假如用時5ms仇奶,A從用戶接收到一個請求到返回才用了3 + 5 = 8ms,對于用戶而言比驻,哇!這個網(wǎng)站好快案盟荨!做的真好嫁艇。
削峰
假如一個系統(tǒng),A系統(tǒng)在0:00-12:00這個時間段內(nèi)的請求每秒并發(fā)數(shù)為50弦撩。但是一到12:00-13:00這個時間段內(nèi)步咪,A系統(tǒng)的請求每秒并發(fā)數(shù)飆升,直接飆升到5K益楼,但是系統(tǒng)是直接基于MYSQL的猾漫。就是說每秒鐘對 MySQL 執(zhí)行約 5k 條 SQL。
一般的 MySQL感凤,扛到每秒 2k 個請求就差不多了悯周,如果每秒請求到 5k 的話,可能就直接把 MySQL 給打死了陪竿,導(dǎo)致系統(tǒng)崩潰禽翼,用戶也就沒法再使用系統(tǒng)了。
但是高峰期一過,到了下午的時候闰挡,就成了低峰期锐墙,可能也就 1w 的用戶同時在網(wǎng)站上操作,每秒中的請求數(shù)量可能也就 50 個請求长酗,對整個系統(tǒng)幾乎沒有任何的壓力溪北。
如果使用 MQ,每秒 5k 個請求寫入 MQ夺脾,A 系統(tǒng)每秒鐘最多處理 2k 個請求之拨,因為 MySQL 每秒鐘最多處理 2k 個。A 系統(tǒng)從 MQ 中慢慢拉取請求咧叭,每秒鐘就拉取 2k 個請求蚀乔,不要超過自己每秒能處理的最大請求數(shù)量就 ok,這樣下來佳簸,哪怕是高峰期的時候乙墙,A 系統(tǒng)也絕對不會掛掉。而 MQ 每秒鐘 5k 個請求進來生均,就 2k 個請求出去听想,結(jié)果就導(dǎo)致在中午高峰期(1 個小時),可能有幾十萬甚至幾百萬的請求積壓在 MQ 中马胧。
這個短暫的高峰期積壓是 ok 的汉买,因為高峰期過了之后,每秒鐘就 50 個請求進 MQ佩脊,但是 A 系統(tǒng)依然會按照每秒 2k 個請求的速度在處理蛙粘。所以說,只要高峰期一過威彰,A 系統(tǒng)就會快速將積壓的消息給解決掉出牧。
為什么使用消息隊列
優(yōu)點
上面說了特殊場景下有其對應(yīng)的好處
- 解耦
- 異步
- 削峰
缺點
- 系統(tǒng)可用性降低
系統(tǒng)引入的外部依賴越多,越容易掛掉歇盼。本來你就是 A 系統(tǒng)調(diào)用 BCD 三個系統(tǒng)的接口就好了舔痕,人 ABCD 四個系統(tǒng)好好的,沒啥問題豹缀,你偏加個 MQ 進來伯复,萬一 MQ 掛了咋整,MQ 一掛邢笙,整套系統(tǒng)崩潰的啸如,你不就完了?如何保證消息隊列的高可用氮惯,可以點擊這里查看
- 系統(tǒng)復(fù)雜度提高
硬生生加個 MQ 進來叮雳,你怎么保證消息沒有重復(fù)消費想暗?怎么處理消息丟失的情況?怎么保證消息傳遞的順序性债鸡?頭大頭大江滨,問題一大堆,痛苦不已厌均。
- 一致性問題
A 系統(tǒng)處理完了直接返回成功了唬滑,人都以為你這個請求就成功了;但是問題是棺弊,要是 BCD 三個系統(tǒng)那里晶密,BD 兩個系統(tǒng)寫庫成功了,結(jié)果 C 系統(tǒng)寫庫失敗了模她,咋整稻艰?你這數(shù)據(jù)就不一致了。
所以消息隊列實際是一種非常復(fù)雜的架構(gòu)侈净,你引入它有很多好處尊勿,但是也得針對它帶來的壞處做各種額外的技術(shù)方案和架構(gòu)來規(guī)避掉,做好之后畜侦,你會發(fā)現(xiàn)元扔,媽呀,系統(tǒng)復(fù)雜度提升了一個數(shù)量級旋膳,也許是復(fù)雜了 10 倍澎语。但是關(guān)鍵時刻,用验懊,還是得用的擅羞。
Kafka、ActiveMQ义图、RabbitMQ减俏、RocketMQ 都有什么優(yōu)缺點?
特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
---|---|---|---|---|
單機吞吐量 | 萬級碱工,比 RocketMQ娃承、Kafka 低一個數(shù)量級 | 同 ActiveMQ | 10 萬級,支撐高吞吐 | 10 萬級痛垛,高吞吐草慧,一般配合大數(shù)據(jù)類的系統(tǒng)來進行實時數(shù)據(jù)計算桶蛔、日志采集等場景 |
topic 數(shù)量對吞吐量的影響 | topic 可以達到幾百/幾千的級別匙头,吞吐量會有較小幅度的下降,這是 RocketMQ 的一大優(yōu)勢仔雷,在同等機器下蹂析,可以支撐大量的 topic | topic 從幾十到幾百個時候舔示,吞吐量會大幅度下降,在同等機器下电抚,Kafka 盡量保證 topic 數(shù)量不要過多惕稻,如果要支撐大規(guī)模的 topic,需要增加更多的機器資源 | ||
時效性 | ms 級 | 微秒級蝙叛,這是 RabbitMQ 的一大特點俺祠,延遲最低 | ms 級 | 延遲在 ms 級以內(nèi) |
可用性 | 高,基于主從架構(gòu)實現(xiàn)高可用 | 同 ActiveMQ | 非常高借帘,分布式架構(gòu) | 非常高蜘渣,分布式,一個數(shù)據(jù)多個副本肺然,少數(shù)機器宕機蔫缸,不會丟失數(shù)據(jù),不會導(dǎo)致不可用 |
消息可靠性 | 有較低的概率丟失數(shù)據(jù) | 基本不丟 | 經(jīng)過參數(shù)優(yōu)化配置际起,可以做到 0 丟失 | 同 RocketMQ |
功能支持 | MQ 領(lǐng)域的功能極其完備 | 基于 erlang 開發(fā)拾碌,并發(fā)能力很強,性能極好街望,延時很低 | MQ 功能較為完善校翔,還是分布式的,擴展性好 | 功能較為簡單它匕,主要支持簡單的 MQ 功能展融,在大數(shù)據(jù)領(lǐng)域的實時計算以及日志采集被大規(guī)模使用 |
綜上,各種對比之后豫柬,有如下建議:
一般的業(yè)務(wù)系統(tǒng)要引入 MQ告希,最早大家都用 ActiveMQ,但是現(xiàn)在確實大家用的不多了烧给,沒經(jīng)過大規(guī)模吞吐量場景的驗證燕偶,社區(qū)也不是很活躍,所以大家還是算了吧础嫡,我個人不推薦用這個了指么;
后來大家開始用 RabbitMQ,但是確實 erlang 語言阻止了大量的 Java 工程師去深入研究和掌控它榴鼎,對公司而言伯诬,幾乎處于不可控的狀態(tài),但是確實人家是開源的巫财,比較穩(wěn)定的支持盗似,活躍度也高;
不過現(xiàn)在確實越來越多的公司平项,會去用 RocketMQ赫舒,確實很不錯(阿里出品)悍及,但社區(qū)可能有突然黃掉的風險,對自己公司技術(shù)實力有絕對自信的接癌,推薦用 RocketMQ心赶,否則回去老老實實用 RabbitMQ 吧,人家有活躍的開源社區(qū)缺猛,絕對不會黃缨叫。
所以中小型公司,技術(shù)實力較為一般荔燎,技術(shù)挑戰(zhàn)不是特別高弯汰,用 RabbitMQ 是不錯的選擇;大型公司湖雹,基礎(chǔ)架構(gòu)研發(fā)實力較強咏闪,用 RocketMQ 是很好的選擇。
如果是大數(shù)據(jù)領(lǐng)域的實時計算摔吏、日志采集等場景鸽嫂,用 Kafka 是業(yè)內(nèi)標準的,絕對沒問題征讲,社區(qū)活躍度很高据某,絕對不會黃,何況幾乎是全世界這個領(lǐng)域的事實性規(guī)范诗箍。