延時任務實現方案
業務場景
那麼如何實現這種延時業務呢?通常有以下 4 種方案。
定時任務輪詢 db
用戶下單後 db 中會生成一條訂單記錄,記錄了訂單號、用戶 ID、創建時間、訂單詳情、訂單狀態等信息。假設超時時間是 600 秒,我們後臺起一個定時任務,每隔固定時間運行一次,每次掃描 db 中的超時訂單select * from order where createTime <= now()-600
,然後取消查詢到的訂單。
這種方法實現簡單,但是有很多缺點。超時時間通常是秒級的,如果定時任務每秒運行一次,那麼就相當於每秒就要對訂單表做一次掃描,這是相當消耗 db 資源的操作,因此定時任務一般不會設置爲秒級;但是如果設置爲分鐘級,又會犧牲即時性,比如 600 秒超時,很有可能 660 秒的時候訂單才被取消。
DelayQueue
JDK 的 DelayQueue(延遲隊列)是無界阻塞隊列,只有在延遲期滿時才能從中獲取元素。每生成一個訂單,在把訂單記錄到 db 的同時,要把訂單 id 等信息投遞到延遲隊列中去,隊列會按照超時時間進行排序,最先超時的訂單排在隊列的頭部;起一個單獨的線程不斷地從隊列中摘取元素然後去做取消訂單的動作。
這種方法最大的缺點就是沒有將超時信息持久化,服務重啓之後延遲隊列的元素不會被恢復。
redis 的 zset
RabbitMQ 的 TTL+DLX
RabbitMQ 可設置消息過期時間(TTL),當消息過期後可以將該消息投遞到隊列上設置的死信交換器(DLX)上。然後投遞到死信隊列中,重新消費。
四種方案對比
source: //xiangxianzui.github.io/2020/02 / 延時任務實現方案
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Vntkg1E5yq_QcOdEO0KYrQ