【訂單失效】rabbitmq死信隊列實作
之前做商城遇到一個關于訂單未支付逾時失效的問題,總結一下
訂單失效問題比較麻煩的地方就是如何能夠實時擷取失效的訂單。
對于這種問題一般有兩種解決方案: 定時任務處理,延時任務處理
使用者下訂單後先生成訂單資訊,然後将該訂單加入到定時任務中(30分鐘後執行),當到達指定時間後檢查訂單狀态,如果未支付則辨別該訂單失效。
定時去輪詢資料庫/緩存,看訂單的狀态。這種方式的問題很明顯,當叢集部署伺服器的時候需要做分布式鎖進行協調,而且實時性不高,對資料庫會産生壓力
當使用者下訂單後,将使用者的訂單的辨別全部發送到延時隊列中,30分鐘後進去消費隊列中被消費,消費時先檢查該訂單的狀态,如果未支付則辨別該訂單失效。
有以下幾種延時任務處理方式
java自帶的delayedquene隊列
這是java本身提供的一種延時隊列,如果項目業務複雜性不高可以考慮這種方式。它是使用jvm記憶體來實作的,停機會丢失資料,擴充性不強
使用redis監聽key的過期來實作
當使用者下訂單後把訂單資訊設定為redis的key,30分鐘失效,程式編寫監聽redis的key失效,然後處理訂單(我也嘗試過這種方式)。這種方式最大的弊端就是隻能監聽一台redis的key失效,叢集下将無法實作,也有人監聽叢集下的每個redis節點的key,但我認為這樣做很不合适。如果項目業務複雜性不高,redis單機部署,就可以考慮這種方式
rabbitmq死信隊列實作
重點介紹這種方式
amqp協定和rabbitmq隊列本身沒有直接支援延遲隊列功能,但是可以通過以下特性模拟出延遲隊列的功能。
time to live(ttl)
rabbitmq可以針對queue設定x-expires 或者 針對message設定 x-message-ttl,來控制消息的生存時間,如果逾時(兩者同時設定以最先到期的時間為準),則消息變為dead letter(死信)
a: 通過隊列屬性設定,隊列中所有消息都有相同的過期時間。
b: 對消息進行單獨設定,每條消息ttl可以不同。
dead letter exchanges(dlx)
rabbitmq的queue可以配置x-dead-letter-exchange和x-dead-letter-routing-key(可選)兩個參數,如果隊列内出現了dead letter,則按照這兩個參數重新路由轉發到指定的隊列。
x-dead-letter-exchange:出現dead letter之後将dead letter重新發送到指定exchange
x-dead-letter-routing-key:出現dead letter之後将dead letter重新按照指定的routing-key發送
下面來做一個例子來實作訂單失效,為了效果明顯,我們把訂單的失效時間設定為10秒 (java實作)
開發工具:intellij idea 2020.2.3
springboot:2.4.1
jdk:1.8.0_211
maven: 3.6.3
rabbitmq:3.8.9
docker安裝rabbitmq可以檢視我這一篇部落格 docker 安裝rabbitmq
項目結構
最下方有完整代碼
建立項目,配置pom.xml加入依賴
配置rabbitmq的隊列和路由資訊 建立類 rabbitmqconfiuration
配置消息生産者
配置消費者
配置檔案 application.yml 加入rabbitmq的相關配置
配置啟動類
啟動成功後我們通路一下配置的接口模拟送出訂單 http://localhost:8080/order
檢視控制台,10秒後
蕪湖~起飛????️,大功告成,可以說實時性已經非常高了,可以試着多送出幾次訂單
打開rabbitmq的控制台看一下,發現多出來兩個隊列
使用這種方式不止可以做訂單失效,比如說優惠券過期啊等等延時失效問題。可以叢集部署rabbitmq,開啟消息确認機制。