消息中間件系列第3講:使用消息隊列需要考慮的幾個問題


一般情況下,我們使用消息隊列需要考慮下面幾個問題:

  • 如何保證消息的冪等性(消息重復)?
  • 如何保證消息的順序性(消息有序)?
  • 如何保證消息的可靠性(消息丟失)?

消息冪等性

冪等性其實是一個數學與計算機概念,其意思是:

在編程中一個冪等操作的特點是其任意多次執行所產生的影響均與一次執行的影響相同。

放在消息隊列中,消息冪等性的意思是:一條完全一樣的消息,它消息一次和消費無數次的結果是一樣的。

所以說消息冪等性要解決什么問題呢?消息冪等性要解決的就是消息隊列中的消息重復問題。

舉個例子:我們發送短信時,生產者將要發送的消息放入消息隊列中,消費者從隊列取出消息在將消息發送給用戶。

因為消息隊列可能存在重復消息,所以如果我們沒有對消息隊列做冪等性處理,那么可能用戶就會收到多條短信,對用戶造成騷擾。

對於消息中間件的冪等性問題,一般通用的處理方案是給消息一個唯一的ID,每次做業務處理之前判斷是否消費過。如果消費過,那么直接拋棄該消息,否則進行業務處理。

消息順序性

順序性指的是在一些具體的業務中,前后的業務操作必須有順序,否則會導致業務處理錯誤。例如在電商系統中,訂單和支付通常是兩個不同的業務邏輯,我們通常會將其分拆開來處理。這兩個業務邏輯之間存在非常清晰的依賴關系:需要先生成訂單,然后才能支付訂單。對於這種情況,我們就說訂單消息和支付消息是有順序性的。

對於消息中間件的消息順序性問題,一般通用的處理方案是保證局部的消息有序。例如對於 Kafka 來說,我們會保證 Partition 區域的消息有序性。對於上面所說的訂單消息、支付消息的例子,我們一般會將訂單消息和支付消息里的用戶ID作為key,將其分配到同一個 partition 中,這樣它們就是有序的。

消息可靠性

消息可靠性其實說的就是消息丟失,我們如何去防止消息發生丟失,或者說消息丟失之后,我們應該如何補救?

對於 Kafka 來說,可能發生消息丟失的幾個節點分別是:

  • 生產者丟失消息

生產者有一個參數request.required.acks,可以設置生產者的數據一致性級別。

當其值為0時,表示生產者不需要等待 broker 的回復,直接發送下一條消息。這種情況下如果 broker 宕機,而生產者還是一直發送消息,那么這些數據就會全部丟失。

當其值為1時,表示生產者需要等待 broker 的 ack 響應后,才發送下一條消息。在這種情況下,broker 接收到消息,寫入內存后便會發送 ack 響應,但並不會立刻寫入內存。這時候如果在寫入磁盤前 broker 發生宕機,那么這條消息就丟失了。

當其值為-1時,表示生產者需要等待所有 broker(副本)寫入內存后,發發送下一條消息。這種情況下,其實還是有可能發生宕機,因為數據還是沒有寫入磁盤,沒有持久化。生產者接收到 ack 響應,只能表明數據寫入所有主、備broker的內存中而已。不過對比起上一種,這種丟失數據的可能性降低了一些。

  • broker丟失消息

當生產者將消息發送到 broker 之后,其實只是將消息緩存到內存中,再由一個線程定時刷入磁盤。這時候如果 broker 宕機,那么這部分存在內存中的數據就丟失了。要杜絕這種情況的發生,我們可以設置log.flush.interval.messages參數為1,這樣每有一條消息,broker 就會立刻將消息刷入磁盤,這樣就不會發生消息丟失。但是這種方式非常消耗磁盤性能,如果這么做了,那么基本上 Kafka 就沒有任何吞吐量優勢了。

  • 消費者丟失消息

消費者從 broker 獲取到消息后,offset 如果設置為自動提交,那么 offset 就會提交到 zk 中。此時如果 consumer 線程被 kill 掉,那么這條消息就丟失了。

參考:http://www.voidcn.com/article/p-rwskpkmq-bpz.html

那么如何解決數據丟失的問題呢?目前來說有兩種方式,一種是在消息中間件層面解決,另一方面是在業務層面通過消息補償解決。

消息中間件層面。選擇不會丟失的消息中間件,例如 RocketMQ 對於消息的確認機制比較嚴格,可以保證消息不丟失(TODO 為什么 RocketMQ 能保證消息不丟失,而 Kafka 不行呢?)。而 Kafka 則無法保證消息不丟失。

業務層面(消息補償)。意思是允許中間件出現消息丟失,但是通過業務層面來做消息補償。不同的業務場景,消息補償的形式不一樣,需要具體情況具體分析。

總結

消息的冪等性、順序性、可靠性可以說是消息中間件需要考慮的三個基本問題,在應用到具體系統之前都必須考慮清楚它們造成的影響,以及解決方案。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM