一.常用的一些消息隊列
1.rabbitmq erlang語言開發,時效性最高
2.rocketmq 吞吐量高,時效性高,但在大數據方面需要自己寫代碼支持
3.kafka 超高的吞吐量,消息較少時可能會有延遲(kafka是堆積一波消息後發送)
二.消息隊列模型
1.常用的是topic訂閱發佈模型
同一個topic下,不同的consumer均能收到消息,同一個consumer(group)則只能有一個消費者收到消息【默認集羣模式下,如果是廣播模式則都能消費到】
2.點對點模型
生產者發送的消息,已有一個消費者都收到
三.topic分區,如何保證消息順序消費
rocketmq、kafka等mq均有分區的概念。
分區是爲了爲了性能考慮,如果topic內的消息只存於一個broker,那這個broker會成爲瓶頸,無法做到水平擴展。所以把topic內的數據分佈到整個集羣就是一個自然而然的設計方式。broker的引入就是解決水平擴展問題的一個方案。
mq能保證topic下每個分區裏面的消息都是順序消費的
- producer對應broker,
- consumer對應broker,並且消費者只有確認一個消息消費後才能push送另外一個消息
分佈式消息隊列RocketMQ&Kafka – 消息的“順序消費”-- 一個看似簡單的複雜問題
四.消息隊列發送過程,如果保證消息隊列不丟失消息
生產者端重試
- 向broker發送消息時,如果由於網絡抖動等原因導致消息發送失敗,可以設置失敗重試次數讓消息重發
消費者端重試
-
由於網絡等原因導致消息沒法從broker發送到消費者端,此時會重試直到發送成功(可以切換broker)
-
消費者端已經正常接收到消息但是在執行後續消息處理時發生了異常,最終返回處理失敗。broker會在某個時間後(默認10秒後)重新投遞,如果一直失敗積累到一定次數(默認16)之後會將消息投遞到死信隊列,此時需要監控死信隊列處理
五.如何解決重複消費
常用的消息隊列都能確保消息到達,但是不能保證唯一性,所以可能存在重複數據
生產者成功發送消息給隊列時,隊列會返回ack給生產者,但是當網絡出現問題,隊列成功收到消息,但是ack出現問題。生產者一般會重發消息,所以會導致隊列中存在多條重複消息。
此外,如果消費者事務提交,但是返回ack網絡出現問題,導致隊列未收到ack,那麼隊列會重複發消息給消費者
保證接口的冪等性
-
樂觀鎖
-
唯一索引
-
記錄每條被消費的消息的狀態
六.消息隊列實現分佈式事務
事務消息
當生產者事務沒提交時,發送的消息爲“半消息”,消費者是收不到的。
然後生產者事務正常提交,會通知隊列,消費者纔開始收到
如果生產者事務回滾,會通知隊列,那麼消息會刪除
如果隊列未收到提交或回滾的消息,rocketmq會提供一個消息反查的功能,隊列會定時將那些未確認的半消息去數據庫查詢該數據,如果已提交,則發送給消費者,已回滾則刪除消息
具體見 https://help.aliyun.com/document_detail/43348.html?spm=5176.doc43490.6.566.Zd5Bl7
七.消息積壓
原因:
消費者消費消息的速度比不上生產者發送消息的速度
解決辦法:
1 優化代碼
2 多部署幾臺消費者機器(橫向擴展)
注:切勿使用多線程來處理消費消息,因爲如果某線程異常了不會影響主線程,到最後主線程消費者已ack給隊列,消息已被刪除,數據就無法恢復了
突然出現消息積壓的情況?
1 消費者在處理某條消息時,消費者一直報錯,然後消費者又沒有寫類似報錯幾次就跳過這條消息的代碼,導致這條消息一直沒有被消費。那麼後面的消息會積壓
2 消費者程序出現死鎖