一、摘要
分布式消息系統(tǒng)作為實現(xiàn)分布式系統(tǒng)可擴(kuò)展、可伸縮性的關(guān)鍵組件,需要具有高吞吐量、高可用等特點。而談到消息系統(tǒng)的設(shè)計,就回避不了兩個問題:
1、消息的順序問題
2、消息的重復(fù)問題
二、關(guān)鍵特性以及其實現(xiàn)原理
2.1、順序消息
要實現(xiàn)嚴(yán)格的順序消息,簡單且可行的辦法就是:
保證生產(chǎn)者 - MQServer - 消費者是一對一對一的關(guān)系
這樣的設(shè)計雖然簡單易行,但也會存在一些很嚴(yán)重的問題,比如:
1、并行度就會成為消息系統(tǒng)的瓶頸(吞吐量不夠)
2、更多的異常處理,比如:只要消費端出現(xiàn)問題,就會導(dǎo)致整個處理流程阻塞,我們不得不花費更多的精力來解決阻塞的問題。
但我們的最終目標(biāo)是要集群的高容錯性和高吞吐量。這似乎是一對不可調(diào)和的矛盾,那么阿里是如何解決的?
有些問題,看起來很重要,但實際上我們可以通過合理的設(shè)計或者將問題分解來規(guī)避。如果硬要把時間花在解決問題本身,實際上不僅效率低下,而且也是一種浪費。從這個角度來看消息的順序問題,我們可以得出兩個結(jié)論:
1、不關(guān)注亂序的應(yīng)用實際大量存在
2、隊列無序并不意味著消息無序
2.2、消息重復(fù)
上面在解決消息順序問題時,引入了一個新的問題,就是消息重復(fù)。那么MQ是怎樣解決消息重復(fù)的問題呢?還是“恰好”不解決。
造成消息的重復(fù)的根本原因是:網(wǎng)絡(luò)不可達(dá)。只要通過網(wǎng)絡(luò)交換數(shù)據(jù),就無法避免這個問題。所以解決這個問題的辦法就是不解決,轉(zhuǎn)而繞過這個問題。那么問題就變成了:如果消費端收到兩條一樣的消息,應(yīng)該怎樣處理?
1、消費端處理消息的業(yè)務(wù)邏輯保持冪等性
2、保證每條消息都有唯一編號且保證消息處理成功與去重表的日志同時出現(xiàn)
第1條很好理解,只要保持冪等性,不管來多少條重復(fù)消息,最后處理的結(jié)果都一樣。第2條原理就是利用一張日志表來記錄已經(jīng)處理成功的消息的ID,如果新到的消息ID已經(jīng)在日志表中,那么就不再處理這條消息。
我們可以看到第1條的解決方式,很明顯應(yīng)該在消費端實現(xiàn),不屬于消息系統(tǒng)要實現(xiàn)的功能。第2條可以消息系統(tǒng)實現(xiàn),也可以業(yè)務(wù)端實現(xiàn)。正常情況下出現(xiàn)重復(fù)消息的概率不一定大,且由消息系統(tǒng)實現(xiàn)的話,肯定會對消息系統(tǒng)的吞吐量和高可用有影響,所以最好還是由業(yè)務(wù)端自己處理消息重復(fù)的問題,這也是MQ不解決消息重復(fù)的問題的原因。
MQ不保證消息不重復(fù),如果你的業(yè)務(wù)需要保證嚴(yán)格的不重復(fù)消息,需要你自己在業(yè)務(wù)端去重。