一、消息重復現象
在 MQTT 協議中,給出了三種傳遞消息時能夠提供的服務質量標准:
At most once:最多一次,這種情況會丟失部分數據,一般日志收集這種對數據不嚴格的可以使用
At least once:最少一次,這種會導致一條消息重復發送
Exactly once:正好一次,一條消息只會被消費一次
RocketMQ,Rabbit MQ,Kafka都是使用的At least once,雖然消息會重復,但不會丟失。不使用Exactly once這種呢,是因為這種每次發送前發送都要檢查這條消息是否已成功發送了,大大降低了MQ的性能。
二、解決方案
那消息重復了,該如何解決呢?一般都是在消費端保證冪等性來解決。
冪等:f(f(x))=f(x),執行多次和執行一次的結果是相同的,這種我們稱之為冪等的。
比如現在有個需求:給賬戶A的余額增加100。
方案一:通過唯一約束控制
1.數據庫唯一索引:
流水表中交易訂單號和賬戶建立唯一索引,重復insert的時候違反唯一性,所以只會成功執行一次。
2.redis的setnx
redis中有這個key就不能重復操作
方案二:設置前提條件
1.數據庫查詢
加分布式鎖,然后查詢有沒有該訂單號的流水,沒有則可以插入。
2.數據庫版本號
查詢出當前記錄以及其中的版本號,更新的時候根據版本號來更新。
方案三:全局id
生產者給數據增加一個全局id,消費端去查詢這個id有沒有消費過,沒有則進行處理。