概要:我們使用消息隊列,就需要知道為什么要用消息隊列,什么場景需要用消息隊列,使用消息隊列能帶來哪些好處和消息隊列會帶來哪些問題?如何去避免這些問題。
一、MQ的好處
解耦:在某些場景下,A服務訂單達到某個狀態(tài)之后,需要發(fā)生一份消息到好幾個服務,但是對于A服務來說,它并不關心其他服務如何什么時候、如何處理這個消息。那么就可以利用MQ解耦。A服務只管將消息發(fā)出去,其他服務想要用這個數(shù)據(jù),就可以開啟消費者組,這樣就可以保證每個服務能消費到所有的數(shù)據(jù)了。
異步:使用異步可以提高接口響應速度,如果要跟其他系統(tǒng)交互的話,時間大概是幾百ms,而投遞到MQ時間在幾ms,而且在不同場景下調節(jié)參數(shù)可以提高消息投遞的速度。(ack的值)
削峰:在流量比較高的時候,為了較少對MySQL的壓力,使用緩存主要是解決查詢的壓力,而對于寫入則可以用MQ來削峰,在高峰期時候流量進入MQ,會造成暫時的積壓,等流量降低之后,積壓的數(shù)據(jù)很快就會被消費完。
MQ的好處這么多,但是也無可避免地會帶來一些問題。主要是以下兩個方面1. 系統(tǒng)的可用性降低,引入了中間件,如果中間件掛了,那么數(shù)據(jù)有丟失風險2. 復雜度上升,正常的系統(tǒng)間交互,我們通常不需要考慮重復消費問題,只要從HTTP請求來解決冪等性就可以。還有就是消息積壓的解決,對于MQ的監(jiān)控等問題,都要加以考慮。接下來我們就逐一看看對于常見的MQ問題。
二、消息丟失問題
Kafka消息丟失可以分為三種情況:生產者發(fā)送過程丟失,Kafka丟失和消費端丟失。
- 生產者丟失:Producer端的ack表示什么情況下Kafka才認為數(shù)據(jù)成功成功發(fā)送。ack=0表示生產者不需要等待broker的同步確認,就可以處理下一批數(shù)據(jù)了,那么如果由于網(wǎng)絡原因或者leader掛了,消息丟失了,也很難發(fā)現(xiàn)。ack=1表示生產者需要確認leader成功寫入就可以成功返回給生產者客戶端,這種配置下如果leader掛了,那么消息也會丟失。另一種比較可靠的配置是ack=-1,表示消息成功寫入leader和ISR副本之后就可以返回了,如果leader掛了,Kafka還可以從ISR中選舉出新的leader,如果這時候ISR為空,那么根據(jù)其他參數(shù)看是否選舉其他副本,這其實就是在高可用和消息不丟失之間的權衡了。另外retires重試次數(shù)設置大一些可以保證在生產過程消息不會丟失。
- Kafka丟失消息:這里需要關注的主要就是Kafka的刪除策略,如果文件過大,或者是超過一段時間,會被Kafka刪除。還有Kafka的持久化 方式,Kafka其實是充分利用了磁盤的頁緩存的,那么如果寫入頁緩存,沒寫入磁盤的時候ack是否會返回?(這塊需要再查一下相關書籍)。
- 消費者丟失消息:這個其實也比較常見,如果設置Kafka自動提交偏移量,那么可能消息偏移量提交之后,消費者掛了,消息還沒處理完,那么這部分數(shù)據(jù)就丟失了。在消費者端解決的方式就是由消費端決定何時提交偏移量,設置enable.auto.commit為false
三、重復消費問題
這個方案有Kafka的內置冪等性保證和事務,但是對性能有損,雖好還是結合業(yè)務情況來保證冪等性。
比如你拿個數(shù)據(jù)要寫庫,你先根據(jù)主鍵查一下,如果這數(shù)據(jù)都有了,你就別插入了,update 一下好吧。
比如你是寫 Redis,那沒問題了,反正每次都是 set,天然冪等性。
比如你不是上面兩個場景,那做的稍微復雜一點,你需要讓生產者發(fā)送每條數(shù)據(jù)的時候,里面加一個全局唯一的 id,類似訂單 id 之類的東西,然后你這里消費到了之后,先根據(jù)這個 id 去比如 Redis 里查一下,之前消費過嗎?如果沒有消費過,你就處理,然后這個 id 寫 Redis。如果消費過了,那你就別處理了,保證別重復處理相同的消息即可。
比如基于數(shù)據(jù)庫的唯一鍵來保證重復數(shù)據(jù)不會重復插入多條。因為有唯一鍵約束了,重復數(shù)據(jù)插入只會報錯,不會導致數(shù)據(jù)庫中出現(xiàn)臟數(shù)據(jù)。
四、消息積壓問題
消息積壓主要有以下原因:
消費者速度跟不上生產者的速度:這個時候,可以先看批次拉取的大小是否合理,以及消費者的消費邏輯是否已經使用多線程消費了。如果還是跟不上消費速度,那么可以考慮同時增加partition和消費者大小。
消費者掛了:先把消費者恢復。
瞬時流量過大:如果是這個原因的話,如果積壓的不是特別多的話,等流量低的時候消費者自然會把積壓的數(shù)據(jù)消費完。
五、高可用問題
Kafka架構可以保證高可用

六、順序性問題
對于Kafka來說,以topic為邏輯單位存儲,物理存儲結構單位是partition,而topic切分成partition無法保證有序,但是partition是順序寫的,可以保證有序。如果我們需要按照某個維度保持有序的話,可以設置消息的key