<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          延時(shí)任務(wù)實(shí)現(xiàn)方案

          共 395字,需瀏覽 1分鐘

           ·

          2021-12-25 07:46

          業(yè)務(wù)場(chǎng)景

          我們買(mǎi)火車(chē)票或者叫外賣(mài)的時(shí)候,下完單之后會(huì)跳轉(zhuǎn)到支付頁(yè)面,頁(yè)面里通常會(huì)有一個(gè)計(jì)時(shí)器,要求在指定時(shí)間內(nèi)完成支付,否則訂單就會(huì)被自動(dòng)取消。這就是延時(shí)任務(wù)的一個(gè)典型業(yè)務(wù)場(chǎng)景。分析這個(gè)場(chǎng)景,其實(shí)最關(guān)鍵的就是如何在訂單超時(shí)的時(shí)候立即觸發(fā)取消訂單的動(dòng)作。

          那么如何實(shí)現(xiàn)這種延時(shí)業(yè)務(wù)呢?通常有以下4種方案。

          定時(shí)任務(wù)輪詢(xún)db

          用戶下單后db中會(huì)生成一條訂單記錄,記錄了訂單號(hào)、用戶ID、創(chuàng)建時(shí)間、訂單詳情、訂單狀態(tài)等信息。假設(shè)超時(shí)時(shí)間是600秒,我們后臺(tái)起一個(gè)定時(shí)任務(wù),每隔固定時(shí)間運(yùn)行一次,每次掃描db中的超時(shí)訂單select * from order where createTime <= now()-600,然后取消查詢(xún)到的訂單。

          這種方法實(shí)現(xiàn)簡(jiǎn)單,但是有很多缺點(diǎn)。超時(shí)時(shí)間通常是秒級(jí)的,如果定時(shí)任務(wù)每秒運(yùn)行一次,那么就相當(dāng)于每秒就要對(duì)訂單表做一次掃描,這是相當(dāng)消耗db資源的操作,因此定時(shí)任務(wù)一般不會(huì)設(shè)置為秒級(jí);但是如果設(shè)置為分鐘級(jí),又會(huì)犧牲即時(shí)性,比如600秒超時(shí),很有可能660秒的時(shí)候訂單才被取消。

          DelayQueue

          JDK的DelayQueue(延遲隊(duì)列)是無(wú)界阻塞隊(duì)列,只有在延遲期滿時(shí)才能從中獲取元素。每生成一個(gè)訂單,在把訂單記錄到db的同時(shí),要把訂單id等信息投遞到延遲隊(duì)列中去,隊(duì)列會(huì)按照超時(shí)時(shí)間進(jìn)行排序,最先超時(shí)的訂單排在隊(duì)列的頭部;起一個(gè)單獨(dú)的線程不斷地從隊(duì)列中摘取元素然后去做取消訂單的動(dòng)作。

          這種方法最大的缺點(diǎn)就是沒(méi)有將超時(shí)信息持久化,服務(wù)重啟之后延遲隊(duì)列的元素不會(huì)被恢復(fù)。

          redis的zset

          在redis中創(chuàng)建一個(gè)key是”delayOrders”的zset,每個(gè)member就是訂單ID,member的score就是該訂單的超時(shí)時(shí)間戳。我們每次從zset中取出score最小也就是最先超時(shí)的元素,判斷其是否超時(shí),如果超時(shí)就將其從zset中刪除并取消訂單,如果未超時(shí)就繼續(xù)執(zhí)行下一次循環(huán)。

          RabbitMQ的TTL+DLX

          RabbitMQ可設(shè)置消息過(guò)期時(shí)間(TTL),當(dāng)消息過(guò)期后可以將該消息投遞到隊(duì)列上設(shè)置的死信交換器(DLX)上。然后投遞到死信隊(duì)列中,重新消費(fèi)。

          四種方案對(duì)比

          方案優(yōu)點(diǎn)缺點(diǎn)
          定時(shí)任務(wù)輪詢(xún)db實(shí)現(xiàn)簡(jiǎn)單、無(wú)技術(shù)難點(diǎn)、異?;謴?fù)、支持分布式/集群環(huán)境影響數(shù)據(jù)庫(kù)性能、時(shí)效性差
          DelayQueue實(shí)現(xiàn)簡(jiǎn)單、性能較好無(wú)法異常恢復(fù)、分布式/集群實(shí)現(xiàn)困難
          redis的zset解耦、異?;謴?fù)、擴(kuò)展性強(qiáng)、支持分布式/集群環(huán)境增加redis維護(hù)、占用帶寬
          RabbitMQ的TTL+DLX解耦、異常恢復(fù)、擴(kuò)展性強(qiáng)、支持分布式/集群環(huán)境增加RabbitMQ維護(hù)、占用帶寬


          source: //xiangxianzui.github.io/2020/02/延時(shí)任務(wù)實(shí)現(xiàn)方案

          喜歡,在看

          瀏覽 36
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲无码高清黄色视频网站 | 日本做爰乱高潮A片分手的决心 | 国产女孩骚逼AV重口免费大全 | 欧美精品久久久免费观看 | 天天看夜夜操 |