延時任務(wù)實現(xiàn)方案
1、服務(wù)端如何防止重復(fù)支付 2、五年工作經(jīng)驗總結(jié) 16 條的代碼規(guī)范 3、突發(fā)!Apache Log4j2 報核彈級漏洞 4、都在建議你不要直接使用 @Async 注解,為什么? 5、面試官:拋開Spring來說,如何自己實現(xiàn)Spring AOP?
業(yè)務(wù)場景
我們買火車票或者叫外賣的時候,下完單之后會跳轉(zhuǎn)到支付頁面,頁面里通常會有一個計時器,要求在指定時間內(nèi)完成支付,否則訂單就會被自動取消。這就是延時任務(wù)的一個典型業(yè)務(wù)場景。分析這個場景,其實最關(guān)鍵的就是如何在訂單超時的時候立即觸發(fā)取消訂單的動作。
那么如何實現(xiàn)這種延時業(yè)務(wù)呢?通常有以下4種方案。
定時任務(wù)輪詢db
用戶下單后db中會生成一條訂單記錄,記錄了訂單號、用戶ID、創(chuàng)建時間、訂單詳情、訂單狀態(tài)等信息。假設(shè)超時時間是600秒,我們后臺起一個定時任務(wù),每隔固定時間運行一次,每次掃描db中的超時訂單select * from order where createTime <= now()-600,然后取消查詢到的訂單。
這種方法實現(xiàn)簡單,但是有很多缺點。超時時間通常是秒級的,如果定時任務(wù)每秒運行一次,那么就相當(dāng)于每秒就要對訂單表做一次掃描,這是相當(dāng)消耗db資源的操作,因此定時任務(wù)一般不會設(shè)置為秒級;但是如果設(shè)置為分鐘級,又會犧牲即時性,比如600秒超時,很有可能660秒的時候訂單才被取消。
DelayQueue
JDK的DelayQueue(延遲隊列)是無界阻塞隊列,只有在延遲期滿時才能從中獲取元素。每生成一個訂單,在把訂單記錄到db的同時,要把訂單id等信息投遞到延遲隊列中去,隊列會按照超時時間進行排序,最先超時的訂單排在隊列的頭部;起一個單獨的線程不斷地從隊列中摘取元素然后去做取消訂單的動作。
這種方法最大的缺點就是沒有將超時信息持久化,服務(wù)重啟之后延遲隊列的元素不會被恢復(fù)。
redis的zset
在redis中創(chuàng)建一個key是”delayOrders”的zset,每個member就是訂單ID,member的score就是該訂單的超時時間戳。我們每次從zset中取出score最小也就是最先超時的元素,判斷其是否超時,如果超時就將其從zset中刪除并取消訂單,如果未超時就繼續(xù)執(zhí)行下一次循環(huán)。
RabbitMQ的TTL+DLX
RabbitMQ可設(shè)置消息過期時間(TTL),當(dāng)消息過期后可以將該消息投遞到隊列上設(shè)置的死信交換器(DLX)上。然后投遞到死信隊列中,重新消費。

四種方案對比
| 方案 | 優(yōu)點 | 缺點 |
|---|---|---|
| 定時任務(wù)輪詢db | 實現(xiàn)簡單、無技術(shù)難點、異?;謴?fù)、支持分布式/集群環(huán)境 | 影響數(shù)據(jù)庫性能、時效性差 |
| DelayQueue | 實現(xiàn)簡單、性能較好 | 無法異?;謴?fù)、分布式/集群實現(xiàn)困難 |
| redis的zset | 解耦、異常恢復(fù)、擴展性強、支持分布式/集群環(huán)境 | 增加redis維護、占用帶寬 |
| RabbitMQ的TTL+DLX | 解耦、異常恢復(fù)、擴展性強、支持分布式/集群環(huán)境 | 增加RabbitMQ維護、占用帶寬 |
source: //xiangxianzui.github.io/2020/02/延時任務(wù)實現(xiàn)方案
最近熱文閱讀:
1、服務(wù)端如何防止重復(fù)支付 2、五年工作經(jīng)驗總結(jié) 16 條的代碼規(guī)范 3、為什么我勸你放棄了Restful API? 4、Java8 Stream:2萬字20個實例,玩轉(zhuǎn)集合的篩選、歸約、分組、聚合 5、公司規(guī)定所有接口都用 POST請求,這是為什么? 6、為什么阿里強制 boolean 類型變量不能使用 is 開頭? 7、面試官:InnoDB中一棵B+樹可以存放多少行數(shù)據(jù)? 8、MyBatis批量插入幾千條數(shù)據(jù),請慎用foreach 9、有了 for (;;) ,為什么還需要while (true) ?到底哪個更快? 10、名企公開掛“加班真好”標(biāo)語,員工稱一年被免費“白嫖”600多小時!網(wǎng)友看不下去了,稽查部門展開調(diào)查... 關(guān)注公眾號,你想要的Java都在這里
