天天看點

【延時任務處理、訂單失效】RabbitMQ死信隊列實作

【訂單失效】rabbitmq死信隊列實作

之前做商城遇到一個關于訂單未支付逾時失效的問題,總結一下

訂單失效問題比較麻煩的地方就是如何能夠實時擷取失效的訂單。

對于這種問題一般有兩種解決方案: 定時任務處理,延時任務處理

使用者下訂單後先生成訂單資訊,然後将該訂單加入到定時任務中(30分鐘後執行),當到達指定時間後檢查訂單狀态,如果未支付則辨別該訂單失效。

定時去輪詢資料庫/緩存,看訂單的狀态。這種方式的問題很明顯,當叢集部署伺服器的時候需要做分布式鎖進行協調,而且實時性不高,對資料庫會産生壓力

當使用者下訂單後,将使用者的訂單的辨別全部發送到延時隊列中,30分鐘後進去消費隊列中被消費,消費時先檢查該訂單的狀态,如果未支付則辨別該訂單失效。

有以下幾種延時任務處理方式

java自帶的delayedquene隊列

這是java本身提供的一種延時隊列,如果項目業務複雜性不高可以考慮這種方式。它是使用jvm記憶體來實作的,停機會丢失資料,擴充性不強

使用redis監聽key的過期來實作

當使用者下訂單後把訂單資訊設定為redis的key,30分鐘失效,程式編寫監聽redis的key失效,然後處理訂單(我也嘗試過這種方式)。這種方式最大的弊端就是隻能監聽一台redis的key失效,叢集下将無法實作,也有人監聽叢集下的每個redis節點的key,但我認為這樣做很不合适。如果項目業務複雜性不高,redis單機部署,就可以考慮這種方式

rabbitmq死信隊列實作

重點介紹這種方式

amqp協定和rabbitmq隊列本身沒有直接支援延遲隊列功能,但是可以通過以下特性模拟出延遲隊列的功能。

【延時任務處理、訂單失效】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 ​

項目結構

【延時任務處理、訂單失效】RabbitMQ死信隊列實作

最下方有完整代碼

建立項目,配置pom.xml加入依賴

配置rabbitmq的隊列和路由資訊  建立類 rabbitmqconfiuration

配置消息生産者

配置消費者 

配置檔案 application.yml 加入rabbitmq的相關配置

配置啟動類

啟動成功後我們通路一下配置的接口模拟送出訂單 ​​http://localhost:8080/order​​

【延時任務處理、訂單失效】RabbitMQ死信隊列實作

檢視控制台,10秒後

【延時任務處理、訂單失效】RabbitMQ死信隊列實作

蕪湖~起飛????️,大功告成,可以說實時性已經非常高了,可以試着多送出幾次訂單

打開rabbitmq的控制台看一下,發現多出來兩個隊列

【延時任務處理、訂單失效】RabbitMQ死信隊列實作

使用這種方式不止可以做訂單失效,比如說優惠券過期啊等等延時失效問題。可以叢集部署rabbitmq,開啟消息确認機制。