關(guān)于消息隊列,面試官一般都會問哪些?
1、為什么要使用消息隊列?
解耦
看這么個場景。A 系統(tǒng)發(fā)送數(shù)據(jù)到 BCD 三個系統(tǒng),通過接口調(diào)用發(fā)送。如果 E 系統(tǒng)也要這個數(shù)據(jù)呢?那如果 C 系統(tǒng)現(xiàn)在不需要了呢?A 系統(tǒng)負(fù)責(zé)人幾乎崩潰......
在這個場景中,A 系統(tǒng)跟其它各種亂七八糟的系統(tǒng)嚴(yán)重耦合,A 系統(tǒng)產(chǎn)生一條比較關(guān)鍵的數(shù)據(jù),很多系統(tǒng)都需要 A 系統(tǒng)將這個數(shù)據(jù)發(fā)送過來。A 系統(tǒng)要時時刻刻考慮 BCDE 四個系統(tǒng)如果掛了該咋辦?要不要重發(fā),要不要把消息存起來?頭發(fā)都白了啊!
如果使用 MQ,A 系統(tǒng)產(chǎn)生一條數(shù)據(jù),發(fā)送到 MQ 里面去,哪個系統(tǒng)需要數(shù)據(jù)自己去 MQ 里面消費。如果新系統(tǒng)需要數(shù)據(jù),直接從 MQ 里消費即可;如果某個系統(tǒng)不需要這條數(shù)據(jù)了,就取消對 MQ 消息的消費即可。這樣下來,A 系統(tǒng)壓根兒不需要去考慮要給誰發(fā)送數(shù)據(jù),不需要維護(hù)這個代碼,也不需要考慮人家是否調(diào)用成功、失敗超時等情況。
總結(jié):通過一個 MQ,Pub/Sub 發(fā)布訂閱消息這么一個模型,A 系統(tǒng)就跟其它系統(tǒng)徹底解耦了。
面試技巧:你需要去考慮一下你負(fù)責(zé)的系統(tǒng)中是否有類似的場景,就是一個系統(tǒng)或者一個模塊,調(diào)用了多個系統(tǒng)或者模塊,互相之間的調(diào)用很復(fù)雜,維護(hù)起來很麻煩。但是其實這個調(diào)用是不需要直接同步調(diào)用接口的,如果用 MQ 給它異步化解耦,也是可以的,你就需要去考慮在你的項目里,是不是可以運用這個 MQ 去進(jìn)行系統(tǒng)的解耦。在簡歷中體現(xiàn)出來這塊東西,用 MQ 作解耦。
異步
再來看一個場景,A 系統(tǒng)接收一個請求,需要在自己本地寫庫,還需要在 BCD 三個系統(tǒng)寫庫,自己本地寫庫要 3ms,BCD 三個系統(tǒng)分別寫庫要 300ms、450ms、200ms。最終請求總延時是 3 + 300 + 450 + 200 = 953ms,接近 1s,用戶感覺搞個什么東西,慢死了慢死了。用戶通過瀏覽器發(fā)起請求,等待個 1s,這幾乎是不可接受的。
一般互聯(lián)網(wǎng)類的企業(yè),對于用戶直接的操作,一般要求是每個請求都必須在 200 ms 以內(nèi)完成,對用戶幾乎是無感知的。
如果使用 MQ,那么 A 系統(tǒng)連續(xù)發(fā)送 3 條消息到 MQ 隊列中,假如耗時 5ms,A 系統(tǒng)從接受一個請求到返回響應(yīng)給用戶,總時長是 3 + 5 = 8ms,對于用戶而言,其實感覺上就是點個按鈕,8ms 以后就直接返回了,爽!網(wǎng)站做得真好,真快!
削峰
每天 0:00 到 12:00,A 系統(tǒng)風(fēng)平浪靜,每秒并發(fā)請求數(shù)量就 50 個。結(jié)果每次一到 12:00 ~ 13:00 ,每秒并發(fā)請求數(shù)量突然會暴增到 5k+ 條。但是系統(tǒng)是直接基于 MySQL 的,大量的請求涌入 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 個請求進(jìn)來,就 2k 個請求出去,結(jié)果就導(dǎo)致在中午高峰期(1 個小時),可能有幾十萬甚至幾百萬的請求積壓在 MQ 中。
這個短暫的高峰期積壓是 ok 的,因為高峰期過了之后,每秒鐘就 50 個請求進(jìn) MQ,但是 A 系統(tǒng)依然會按照每秒 2k 個請求的速度在處理。所以說,只要高峰期一過,A 系統(tǒng)就會快速將積壓的消息給解決掉。
2、消息隊列有什么優(yōu)缺點?
優(yōu)點:解耦、異步、削峰。
缺點:
系統(tǒng)可用性降低。系統(tǒng)引入的外部依賴越多,越容易掛掉。本來你就是 A 系統(tǒng)調(diào)用 BCD 三個系統(tǒng)的接口就好了,人 ABCD 四個系統(tǒng)好好的,沒啥問題,你偏加個 MQ 進(jìn)來,萬一 MQ 掛了咋整,MQ 一掛,整套系統(tǒng)崩潰的,你不就完了?
系統(tǒng)復(fù)雜度提高。硬生生加個 MQ 進(jìn)來,你怎么保證消息沒有重復(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)鍵時刻,用,還是得用的。
3、如何保證消息隊列的高可用?
Kafka 一個最基本的架構(gòu)認(rèn)識:由多個 broker 組成,每個 broker 是一個節(jié)點;你創(chuàng)建一個 topic,這個 topic 可以劃分為多個 partition,每個 partition 可以存在于不同的 broker 上,每個 partition 就放一部分?jǐn)?shù)據(jù)。這就是天然的分布式消息隊列,就是說一個 topic 的數(shù)據(jù),是分散放在多個機器上的,每個機器就放一部分?jǐn)?shù)據(jù)。
實際上 RabbmitMQ 之類的,并不是分布式消息隊列,它就是傳統(tǒng)的消息隊列,只不過提供了一些集群、HA(High Availability, 高可用性) 的機制而已,因為無論怎么玩兒,RabbitMQ 一個 queue 的數(shù)據(jù)都是放在一個節(jié)點里的,鏡像集群下,也是每個節(jié)點都放這個 queue 的完整數(shù)據(jù)。
Kafka 0.8 以前,是沒有 HA 機制的,就是任何一個 broker 宕機了,那個 broker 上的 partition 就廢了,沒法寫也沒法讀,沒有什么高可用性可言。比如說,我們假設(shè)創(chuàng)建了一個 topic,指定其 partition 數(shù)量是 3 個,分別在三臺機器上。但是,如果第二臺機器宕機了,會導(dǎo)致這個 topic 的 1/3 的數(shù)據(jù)就丟了,因此這個是做不到高可用的。
Kafka 0.8 以后,提供了 HA 機制,就是 replica(復(fù)制品) 副本機制。每個 partition 的數(shù)據(jù)都會同步到其它機器上,形成自己的多個 replica 副本。所有 replica 會選舉一個 leader 出來,那么生產(chǎn)和消費都跟這個 leader 打交道,然后其他 replica 就是 follower。寫的時候,leader 會負(fù)責(zé)把數(shù)據(jù)同步到所有 follower 上去,讀的時候就直接讀 leader 上的數(shù)據(jù)即可。只能讀寫 leader?很簡單,要是你可以隨意讀寫每個 follower,那么就要 care 數(shù)據(jù)一致性的問題,系統(tǒng)復(fù)雜度太高,很容易出問題。Kafka 會均勻地將一個 partition 的所有 replica 分布在不同的機器上,這樣才可以提高容錯性。
這么搞,就有所謂的高可用性了,因為如果某個 broker 宕機了,沒事兒,那個 broker 上面的 partition 在其他機器上都有副本的。如果這個宕機的 broker 上面有某個 partition 的 leader,那么此時會從 follower 中重新選舉一個新的 leader 出來,大家繼續(xù)讀寫那個新的 leader 即可。這就有所謂的高可用性了。
寫數(shù)據(jù)的時候,生產(chǎn)者就寫 leader,然后 leader 將數(shù)據(jù)落地寫本地磁盤,接著其他 follower 自己主動從 leader 來 pull 數(shù)據(jù)。一旦所有 follower 同步好數(shù)據(jù)了,就會發(fā)送 ack 給 leader,leader 收到所有 follower 的 ack 之后,就會返回寫成功的消息給生產(chǎn)者。(當(dāng)然,這只是其中一種模式,還可以適當(dāng)調(diào)整這個行為)
消費的時候,只會從 leader 去讀,但是只有當(dāng)一個消息已經(jīng)被所有 follower 都同步成功返回 ack 的時候,這個消息才會被消費者讀到。
4、如何保證消息消費的冪等性?
首先,比如 RabbitMQ、RocketMQ、Kafka,都有可能會出現(xiàn)消息重復(fù)消費的問題,正常。因為這問題通常不是 MQ 自己保證的,是由我們開發(fā)來保證的。挑一個 Kafka 來舉個例子,說說怎么重復(fù)消費吧。
Kafka 實際上有個 offset 的概念,就是每個消息寫進(jìn)去,都有一個 offset,代表消息的序號,然后 consumer 消費了數(shù)據(jù)之后,每隔一段時間(定時定期),會把自己消費過的消息的 offset 提交一下,表示“我已經(jīng)消費過了,下次我要是重啟啥的,你就讓我繼續(xù)從上次消費到的 offset 來繼續(xù)消費吧”。
但是凡事總有意外,比如我們之前生產(chǎn)經(jīng)常遇到的,就是你有時候重啟系統(tǒng),看你怎么重啟了,如果碰到點著急的,直接 kill 進(jìn)程了,再重啟。這會導(dǎo)致 consumer 有些消息處理了,但是沒來得及提交 offset,尷尬了。重啟之后,少數(shù)消息會再次消費一次。
舉個栗子。有這么個場景。數(shù)據(jù) 1/2/3 依次進(jìn)入 kafka,kafka 會給這三條數(shù)據(jù)每條分配一個 offset,代表這條數(shù)據(jù)的序號,我們就假設(shè)分配的 offset 依次是 152/153/154。消費者從 kafka 去消費的時候,也是按照這個順序去消費。假如當(dāng)消費者消費了 offset=153 的這條數(shù)據(jù),剛準(zhǔn)備去提交 offset 到 zookeeper,此時消費者進(jìn)程被重啟了。那么此時消費過的數(shù)據(jù) 1/2 的 offset 并沒有提交,kafka 也就不知道你已經(jīng)消費了 offset=153 這條數(shù)據(jù)。那么重啟之后,消費者會找 kafka 說,嘿,哥兒們,你給我接著把上次我消費到的那個地方后面的數(shù)據(jù)繼續(xù)給我傳遞過來。由于之前的 offset 沒有提交成功,那么數(shù)據(jù) 1/2 會再次傳過來,如果此時消費者沒有去重的話,那么就會導(dǎo)致重復(fù)消費。
如果消費者干的事兒是拿一條數(shù)據(jù)就往數(shù)據(jù)庫里寫一條,會導(dǎo)致說,你可能就把數(shù)據(jù) 1/2 在數(shù)據(jù)庫里插入了 2 次,那么數(shù)據(jù)就錯啦。其實重復(fù)消費不可怕,可怕的是你沒考慮到重復(fù)消費之后,怎么保證冪等性。
舉個例子吧。假設(shè)你有個系統(tǒng),消費一條消息就往數(shù)據(jù)庫里插入一條數(shù)據(jù),要是你一個消息重復(fù)兩次,你不就插入了兩條,這數(shù)據(jù)不就錯了?但是你要是消費到第二次的時候,自己判斷一下是否已經(jīng)消費過了,若是就直接扔了,這樣不就保留了一條數(shù)據(jù),從而保證了數(shù)據(jù)的正確性。一條數(shù)據(jù)重復(fù)出現(xiàn)兩次,數(shù)據(jù)庫里就只有一條數(shù)據(jù),這就保證了系統(tǒng)的冪等性。
所以第二個問題來了,怎么保證消息隊列消費的冪等性?其實還是得結(jié)合業(yè)務(wù)來思考,我這里給幾個思路:
比如你拿個數(shù)據(jù)要寫庫,你先根據(jù)主鍵查一下,如果這數(shù)據(jù)都有了,你就別插入了,update 一下好吧。
比如你是寫 Redis,那沒問題了,反正每次都是 set,天然冪等性。
比如你不是上面兩個場景,那做的稍微復(fù)雜一點,你需要讓生產(chǎn)者發(fā)送每條數(shù)據(jù)的時候,里面加一個全局唯一的 id,類似訂單 id 之類的東西,然后你這里消費到了之后,先根據(jù)這個 id 去比如 Redis 里查一下,之前消費過嗎?如果沒有消費過,你就處理,然后這個 id 寫 Redis。如果消費過了,那你就別處理了,保證別重復(fù)處理相同的消息即可。
比如基于數(shù)據(jù)庫的唯一鍵來保證重復(fù)數(shù)據(jù)不會重復(fù)插入多條。因為有唯一鍵約束了,重復(fù)數(shù)據(jù)插入只會報錯,不會導(dǎo)致數(shù)據(jù)庫中出現(xiàn)臟數(shù)據(jù)。
5、如何處理消息丟失問題?
消費端弄丟了數(shù)據(jù)
唯一可能導(dǎo)致消費者弄丟數(shù)據(jù)的情況,就是說,你消費到了這個消息,然后消費者那邊自動提交了 offset,讓 Kafka 以為你已經(jīng)消費好了這個消息,但其實你才剛準(zhǔn)備處理這個消息,你還沒處理,你自己就掛了,此時這條消息就丟咯。
這不是跟 RabbitMQ 差不多嗎,大家都知道 Kafka 會自動提交 offset,那么只要關(guān)閉自動提交 offset,在處理完之后自己手動提交 offset,就可以保證數(shù)據(jù)不會丟。但是此時確實還是可能會有重復(fù)消費,比如你剛處理完,還沒提交 offset,結(jié)果自己掛了,此時肯定會重復(fù)消費一次,自己保證冪等性就好了。
生產(chǎn)環(huán)境碰到的一個問題,就是說我們的 Kafka 消費者消費到了數(shù)據(jù)之后是寫到一個內(nèi)存的 queue 里先緩沖一下,結(jié)果有的時候,你剛把消息寫入內(nèi)存 queue,然后消費者會自動提交 offset。然后此時我們重啟了系統(tǒng),就會導(dǎo)致內(nèi)存 queue 里還沒來得及處理的數(shù)據(jù)就丟失了。
Kafka 弄丟了數(shù)據(jù)
這塊比較常見的一個場景,就是 Kafka 某個 broker 宕機,然后重新選舉 partition 的 leader。大家想想,要是此時其他的 follower 剛好還有些數(shù)據(jù)沒有同步,結(jié)果此時 leader 掛了,然后選舉某個 follower 成 leader 之后,不就少了一些數(shù)據(jù)?這就丟了一些數(shù)據(jù)啊。
生產(chǎn)環(huán)境也遇到過,我們也是,之前 Kafka 的 leader 機器宕機了,將 follower 切換為 leader 之后,就會發(fā)現(xiàn)說這個數(shù)據(jù)就丟了。
所以此時一般是要求起碼設(shè)置如下 4 個參數(shù):
給 topic 設(shè)置 replication.factor 參數(shù):這個值必須大于 1,要求每個 partition 必須有至少 2 個副本。
在 Kafka 服務(wù)端設(shè)置 min.insync.replicas 參數(shù):這個值必須大于 1,這個是要求一個 leader 至少感知到有至少一個 follower 還跟自己保持聯(lián)系,沒掉隊,這樣才能確保 leader 掛了還有一個 follower 吧。
在 producer 端設(shè)置 acks=all:這個是要求每條數(shù)據(jù),必須是寫入所有 replica 之后,才能認(rèn)為是寫成功了。
在 producer 端設(shè)置 retries=MAX(很大很大很大的一個值,無限次重試的意思):這個是要求一旦寫入失敗,就無限重試,卡在這里了。
我們生產(chǎn)環(huán)境就是按照上述要求配置的,這樣配置之后,至少在 Kafka broker 端就可以保證在 leader 所在 broker 發(fā)生故障,進(jìn)行 leader 切換時,數(shù)據(jù)不會丟失。
生產(chǎn)者會不會弄丟數(shù)據(jù)?
如果按照上述的思路設(shè)置了 acks=all,一定不會丟,要求是,你的 leader 接收到消息,所有的 follower 都同步到了消息之后,才認(rèn)為本次寫成功了。如果不滿足這個條件,生產(chǎn)者會自動不斷的重試,重試無限次。
6、如何保證消息傳遞的順序性?
我舉個例子,我們以前做過一個 mysql binlog 同步的系統(tǒng),壓力還是非常大的,日同步數(shù)據(jù)要達(dá)到上億,就是說數(shù)據(jù)從一個 mysql 庫原封不動地同步到另一個 mysql 庫里面去(mysql -> mysql)。常見的一點在于說比如大數(shù)據(jù) team,就需要同步一個 mysql 庫過來,對公司的業(yè)務(wù)系統(tǒng)的數(shù)據(jù)做各種復(fù)雜的操作。
你在 mysql 里增刪改一條數(shù)據(jù),對應(yīng)出來了增刪改 3 條 binlog 日志,接著這三條 binlog 發(fā)送到 MQ 里面,再消費出來依次執(zhí)行,起碼得保證人家是按照順序來的吧?不然本來是:增加、修改、刪除;你楞是換了順序給執(zhí)行成刪除、修改、增加,不全錯了么。
本來這個數(shù)據(jù)同步過來,應(yīng)該最后這個數(shù)據(jù)被刪除了;結(jié)果你搞錯了這個順序,最后這個數(shù)據(jù)保留下來了,數(shù)據(jù)同步就出錯了。
先看看順序會錯亂的場景:
Kafka:比如說我們建了一個 topic,有三個 partition。生產(chǎn)者在寫的時候,其實可以指定一個 key,比如說我們指定了某個訂單 id 作為 key,那么這個訂單相關(guān)的數(shù)據(jù),一定會被分發(fā)到同一個 partition 中去,而且這個 partition 中的數(shù)據(jù)一定是有順序的。消費者從 partition 中拉取數(shù)據(jù)的時候,也一定是有順序的。到這里,順序還是 ok 的,沒有錯亂。接著,我們在消費者里可能會搞多個線程來并發(fā)處理消息。因為如果消費者是單線程消費處理,而處理比較耗時的話,比如處理一條消息耗時幾十 ms,那么 1 秒鐘只能處理幾十條消息,這吞吐量太低了。而多個線程并發(fā)跑的話,順序可能就亂掉了。
解決方案
Kafka
一個 topic,一個 partition,一個 consumer,內(nèi)部單線程消費,單線程吞吐量太低,一般不會用這個。
寫 N 個內(nèi)存 queue,具有相同 key 的數(shù)據(jù)都到同一個內(nèi)存 queue;然后對于 N 個線程,每個線程分別消費一個內(nèi)存 queue 即可,這樣就能保證順序性。
7、 如何解決消息隊列的延時以及過期失效問題?消息隊列滿了以后該怎么處理?有幾百萬消息持續(xù)積壓幾小時,說說怎么解決?
你看這問法,其實本質(zhì)針對的場景,都是說,可能你的消費端出了問題,不消費了;或者消費的速度極其慢。接著就坑爹了,可能你的消息隊列集群的磁盤都快寫滿了,都沒人消費,這個時候怎么辦?或者是這整個就積壓了幾個小時,你這個時候怎么辦?或者是你積壓的時間太長了,導(dǎo)致比如 RabbitMQ 設(shè)置了消息過期時間后就沒了怎么辦?
所以就這事兒,其實線上挺常見的,一般不出,一出就是大 case。一般常見于,舉個例子,消費端每次消費之后要寫 mysql,結(jié)果 mysql 掛了,消費端 hang 那兒了,不動了;或者是消費端出了個什么岔子,導(dǎo)致消費速度極其慢。
面試題剖析
關(guān)于這個事兒,我們一個一個來梳理吧,先假設(shè)一個場景,我們現(xiàn)在消費端出故障了,然后大量消息在 mq 里積壓,現(xiàn)在出事故了,慌了。
大量消息在 mq 里積壓了幾個小時了還沒解決
幾千萬條數(shù)據(jù)在 MQ 里積壓了七八個小時,從下午 4 點多,積壓到了晚上 11 點多。這個是我們真實遇到過的一個場景,確實是線上故障了,這個時候要不然就是修復(fù) consumer 的問題,讓它恢復(fù)消費速度,然后傻傻的等待幾個小時消費完畢。這個肯定不能在面試的時候說吧。
一個消費者一秒是 1000 條,一秒 3 個消費者是 3000 條,一分鐘就是 18 萬條。所以如果你積壓了幾百萬到上千萬的數(shù)據(jù),即使消費者恢復(fù)了,也需要大概 1 小時的時間才能恢復(fù)過來。
一般這個時候,只能臨時緊急擴容了,具體操作步驟和思路如下:
先修復(fù) consumer 的問題,確保其恢復(fù)消費速度,然后將現(xiàn)有 consumer 都停掉。
新建一個 topic,partition 是原來的 10 倍,臨時建立好原先 10 倍的 queue 數(shù)量。
然后寫一個臨時的分發(fā)數(shù)據(jù)的 consumer 程序,這個程序部署上去消費積壓的數(shù)據(jù),消費之后不做耗時的處理,直接均勻輪詢寫入臨時建立好的 10 倍數(shù)量的 queue。
接著臨時征用 10 倍的機器來部署 consumer,每一批 consumer 消費一個臨時 queue 的數(shù)據(jù)。這種做法相當(dāng)于是臨時將 queue 資源和 consumer 資源擴大 10 倍,以正常的 10 倍速度來消費數(shù)據(jù)。
等快速消費完積壓數(shù)據(jù)之后,得恢復(fù)原先部署的架構(gòu),重新用原先的 consumer 機器來消費消息。
mq 中的消息過期失效了
假設(shè)你用的是 RabbitMQ,RabbtiMQ 是可以設(shè)置過期時間的,也就是 TTL。如果消息在 queue 中積壓超過一定的時間就會被 RabbitMQ 給清理掉,這個數(shù)據(jù)就沒了。那這就是第二個坑了。這就不是說數(shù)據(jù)會大量積壓在 mq 里,而是大量的數(shù)據(jù)會直接搞丟。
這個情況下,就不是說要增加 consumer 消費積壓的消息,因為實際上沒啥積壓,而是丟了大量的消息。我們可以采取一個方案,就是批量重導(dǎo),這個我們之前線上也有類似的場景干過。就是大量積壓的時候,我們當(dāng)時就直接丟棄數(shù)據(jù)了,然后等過了高峰期以后,比如大家一起喝咖啡熬夜到晚上12點以后,用戶都睡覺了。這個時候我們就開始寫程序,將丟失的那批數(shù)據(jù),寫個臨時程序,一點一點的查出來,然后重新灌入 mq 里面去,把白天丟的數(shù)據(jù)給他補回來。也只能是這樣了。
假設(shè) 1 萬個訂單積壓在 mq 里面,沒有處理,其中 1000 個訂單都丟了,你只能手動寫程序把那 1000 個訂單給查出來,手動發(fā)到 mq 里去再補一次。
mq 都快寫滿了
如果消息積壓在 mq 里,你很長時間都沒有處理掉,此時導(dǎo)致 mq 都快寫滿了,咋辦?這個還有別的辦法嗎?沒有,誰讓你第一個方案執(zhí)行的太慢了,你臨時寫程序,接入數(shù)據(jù)來消費,消費一個丟棄一個,都不要了,快速消費掉所有的消息。然后走第二個方案,到了晚上再補數(shù)據(jù)吧。
8、Kafka、ActiveMQ、RabbitMQ、RocketMQ 有什么優(yōu)缺點 ?
綜上,各種對比之后,有如下建議:
一般的業(yè)務(wù)系統(tǒng)要引入 MQ,最早大家都用 ActiveMQ,但是現(xiàn)在確實大家用的不多了,沒經(jīng)過大規(guī)模吞吐量場景的驗證,社區(qū)也不是很活躍,所以大家還是算了吧,我個人不推薦用這個了;
后來大家開始用 RabbitMQ,但是確實 erlang 語言阻止了大量的 Java 工程師去深入研究和掌控它,對公司而言,幾乎處于不可控的狀態(tài),但是確實人家是開源的,比較穩(wěn)定的支持,活躍度也高;
不過現(xiàn)在確實越來越多的公司會去用 RocketMQ,確實很不錯,畢竟是阿里出品,但社區(qū)可能有突然黃掉的風(fēng)險(目前 RocketMQ 已捐給 Apache,但 GitHub 上的活躍度其實不算高)對自己公司技術(shù)實力有絕對自信的,推薦用 RocketMQ,否則回去老老實實用 RabbitMQ 吧,人家有活躍的開源社區(qū),絕對不會黃。
所以中小型公司,技術(shù)實力較為一般,技術(shù)挑戰(zhàn)不是特別高,用 RabbitMQ 是不錯的選擇;大型公司,基礎(chǔ)架構(gòu)研發(fā)實力較強,用 RocketMQ 是很好的選擇。
如果是大數(shù)據(jù)領(lǐng)域的實時計算、日志采集等場景,用 Kafka 是業(yè)內(nèi)標(biāo)準(zhǔn)的,絕對沒問題,社區(qū)活躍度很高,絕對不會黃,何況幾乎是全世界這個領(lǐng)域的事實性規(guī)范。
歡迎關(guān)注微信公眾號:互聯(lián)網(wǎng)全棧架構(gòu),收取更多有價值的信息。
