<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è)計(jì)訂單超時(shí)自動(dòng)取消

          共 5202字,需瀏覽 11分鐘

           ·

          2024-04-11 08:24

          我們?cè)诿缊F(tuán) APP 下單,假如沒(méi)有立即支付,進(jìn)入訂單詳情會(huì)顯示倒計(jì)時(shí),如果超過(guò)支付時(shí)間,訂單就會(huì)被自動(dòng)取消。

          網(wǎng)上有很多八股文,很多方案其實(shí)并不太適合真實(shí)的業(yè)務(wù)場(chǎng)景。所以這篇文章,筆者想深入剖析如何設(shè)計(jì)訂單超時(shí)自動(dòng)取消的功能,希望能帶給大家一些啟發(fā)。

          eee874ac86555c0ad6c1a6db42235fb4.webp

          1 定時(shí)任務(wù)方案

          首先,我們非常自然的想到定時(shí)任務(wù)的方案。

          方案流程:

          1. 每隔 30 秒查詢數(shù)據(jù)庫(kù),取出最近的 N 條未支付的訂單。
          2. 遍歷查詢出來(lái)的訂單列表,判斷當(dāng)前時(shí)間減去訂單的創(chuàng)建時(shí)間是否超過(guò)了支付超時(shí)時(shí)間,如果超時(shí)則對(duì)該訂單執(zhí)行取消操作。

          定時(shí)任務(wù)方案工程實(shí)現(xiàn)相對(duì)簡(jiǎn)單,但這種方案會(huì)間隔對(duì)數(shù)據(jù)庫(kù)造成一定的 IO 壓力。特別是當(dāng)訂單量數(shù)據(jù)量非常高時(shí),高頻次的查詢對(duì)數(shù)據(jù)庫(kù)的性能是個(gè)不小的考驗(yàn)。

          定時(shí)任務(wù)方案從功能模塊角度來(lái)講,包含調(diào)度層業(yè)務(wù)邏輯層兩部分。

          2acd35e79425c22220e71c04da57ab39.webp

          網(wǎng)上有很多的定時(shí)任務(wù)實(shí)現(xiàn)策略,我們可以簡(jiǎn)單劃分為單機(jī)版集群版

          2 定時(shí)任務(wù)方案:?jiǎn)螜C(jī)版

          我們可以使用 Timer 、ScheduledEexcutorService、Quartz 非常容易的實(shí)現(xiàn)定時(shí)任務(wù)。

          14523903a7ce0b6676c8b13900009c6d.webp

          但筆者并不推薦使用單機(jī)版的方案,舉個(gè)簡(jiǎn)單的例子:

          435fdb8424745eb8704cbdc89883eb63.webp

          假設(shè)我們應(yīng)用 A 通過(guò) Quartz 調(diào)度三個(gè)定時(shí)任務(wù) A、B、C  ,當(dāng)集群部署時(shí),可能出現(xiàn)多臺(tái)不同機(jī)器實(shí)例同時(shí)執(zhí)行任務(wù)的風(fēng)險(xiǎn)。

          此時(shí),我們可以通過(guò)加鎖的方式適當(dāng)規(guī)避,見(jiàn)下圖:

          7bba6206b37b7fdabe881c2ded476c52.webp

          但這種方式并不優(yōu)雅,同時(shí)定時(shí)任務(wù)應(yīng)用內(nèi)調(diào)度層會(huì)經(jīng)常空跑,我們預(yù)期是希望三個(gè)定時(shí)任務(wù) A、B、C 能均勻分布應(yīng)用 A的不同實(shí)例內(nèi)。

          好,接下來(lái),筆者會(huì)介紹親身經(jīng)歷的三種集群定時(shí)任務(wù)。

          3 定時(shí)任務(wù)方案:集群版 56154874ce0f1e4a10d9839935456aa6.webp

          3.1 Quartz + JDBCJobStore

          Quartz 可以支持集群模式,集群模式需要在數(shù)據(jù)庫(kù)中添加11張表,對(duì)業(yè)務(wù)系統(tǒng)有一定的侵入性。

          75dd36e13fde232b92549b1cf6cace45.webp

          筆者曾經(jīng)服務(wù)的一家彩票公司,訂單調(diào)度中心就是使用 Quartz 的集群模式,實(shí)現(xiàn)日均百萬(wàn)訂單的調(diào)度處理。

          需要特別注意的是:

          基于底層數(shù)據(jù)庫(kù)悲觀鎖的機(jī)制,Quartz 的集群模式性能并不高,假如執(zhí)行頻率高的任務(wù)數(shù)超過(guò)達(dá)到一定數(shù)量,存在性能問(wèn)題。

          3.1 Elastic-Job

          ElasticJob 定位為輕量級(jí)無(wú)中心化解決方案,使用 jar 的形式提供分布式任務(wù)的協(xié)調(diào)服務(wù)。

          ElasticJob 從本質(zhì)上來(lái)講 ,底層任務(wù)調(diào)度還是通過(guò) Quartz ,它的優(yōu)勢(shì)在于可以依賴 Zookeeper 這個(gè)大殺器 ,將任務(wù)通過(guò)負(fù)載均衡算法分配給應(yīng)用內(nèi)的 Quartz Scheduler 容器,

          舉例:應(yīng)用A有五個(gè)任務(wù)需要執(zhí)行,分別是 A,B,C,D,E。任務(wù)E需要分成四個(gè)子任務(wù),應(yīng)用部署在兩臺(tái)機(jī)器上。

          4e1e77d84ca830def2c469a3645c8a91.webp

          圖中,應(yīng)用 A 在啟動(dòng)后, 5個(gè)任務(wù)通過(guò) Zookeeper 協(xié)調(diào)后被分配到兩臺(tái)機(jī)器上,通過(guò) Quartz Scheduler 分開(kāi)執(zhí)行不同的任務(wù)。

          相比 Quartz 集群模式,ElasticJob 的可擴(kuò)展性更高,同時(shí)因?yàn)槭潜镜貎?nèi)存存儲(chǔ) JOB,性能非常好。

          但是 ElasticJob 的控制臺(tái)非常粗糙,主要原因還是基于它的實(shí)現(xiàn)機(jī)制 (Quartz +  zookeeper)。

          通過(guò)控制 zookeeper 節(jié)點(diǎn)來(lái)間接操作應(yīng)用內(nèi)任務(wù)執(zhí)行情況,但這樣非常不靈活,所以筆者認(rèn)為 ElasticJob 更多的還是定位于框架,而不是一個(gè)調(diào)度平臺(tái)

          3.3 任務(wù)調(diào)度平臺(tái)

          筆者非常認(rèn)可任務(wù)調(diào)度平臺(tái)這種模式。XXL-JOB 是一個(gè)使用最廣泛的分布式任務(wù)調(diào)度平臺(tái)

          fc6443524d1eb74425b96c481bdf4a2d.webp d58cbcd9c262acdd1d4a02e9c63291f2.webp

          業(yè)務(wù)系統(tǒng)和調(diào)度平臺(tái)分開(kāi)部署,我們?cè)谡{(diào)度中心上配置應(yīng)用以及其定時(shí)任務(wù),當(dāng)任務(wù)需要執(zhí)行時(shí),調(diào)度平臺(tái)會(huì)觸發(fā)業(yè)務(wù)系統(tǒng)的任務(wù),業(yè)務(wù)系統(tǒng)執(zhí)行完任務(wù)之后,反饋給調(diào)度平臺(tái)任務(wù)執(zhí)行的結(jié)果。

          業(yè)務(wù)系統(tǒng)和調(diào)度平臺(tái)都可以水平擴(kuò)展實(shí)現(xiàn)高可用,同時(shí)在調(diào)度平臺(tái)可以配置靈活的調(diào)度策略(比如重試機(jī)制廣播模式等)。

          XXL-JOB  并不完美,因?yàn)榈讓右廊皇腔跀?shù)據(jù)庫(kù)悲觀鎖的機(jī)制,雖然通過(guò)時(shí)間輪的方式做了一定程度的優(yōu)化,但依然會(huì)有性能瓶頸。

          很多公司比如神州專車、美團(tuán)都有自己自研的任務(wù)調(diào)度平臺(tái)。這種模式非常適合多團(tuán)隊(duì)協(xié)作,便于大規(guī)模調(diào)度任務(wù)的統(tǒng)一管理。

          4 延時(shí)消息方案

          延時(shí)消息是一種非常優(yōu)雅的模式。訂單服務(wù)生成訂單后,發(fā)送一條延時(shí)消息到消息隊(duì)列。消息隊(duì)列在消息到達(dá)支付過(guò)期時(shí)間時(shí),將消息投遞給消費(fèi)者,消費(fèi)者收到消息之后,判斷訂單狀態(tài)是否為已支付,假如未支付,則執(zhí)行取消訂單的邏輯。

          025ef1c2a55486a5c80e7b6a0a55719e.webp

          4.1 消息隊(duì)列 RocketMQ

          RocketMQ 4.X 生產(chǎn)者發(fā)送延遲消息代碼如下:

                
                Message msg = new Message();
          msg.setTopic("TopicA");
          msg.setTags("Tag");
          msg.setBody("this is a delay message".getBytes());
          //設(shè)置延遲level為5,對(duì)應(yīng)延遲1分鐘
          msg.setDelayTimeLevel(5);
          producer.send(msg);

          RocketMQ 4.X 版本默認(rèn)支持 18 個(gè) level 的延遲消息, 通過(guò) broker 端的 messageDelayLevel 配置項(xiàng)確定的。

          12d781fe1fe010a5c6dcdabac2fe87ec.webp

          RocketMQ 5.X 版本支持任意時(shí)刻延遲消息,客戶端在構(gòu)造消息時(shí)提供了 3 個(gè) API 來(lái)指定延遲時(shí)間或定時(shí)時(shí)間。

          7e59c610d5d0d8cfd5d811fda3fa55bb.webp

          假如技術(shù)團(tuán)隊(duì)基礎(chǔ)架構(gòu)能力很強(qiáng),筆者非常推薦使用 RocketMQ 5.X 的延遲消息功能。

          4.2 自研延遲服務(wù)

          基于 RocketMQ 4 內(nèi)置的延遲消息只能支持幾個(gè)固定的延遲級(jí)別,快手、滴滴開(kāi)發(fā)了單獨(dú)的 Delay Server 來(lái)調(diào)度延遲消息。

          4932138fd8c2ecbce4041cd0053a3fee.webp

          上圖這個(gè)結(jié)構(gòu)沒(méi)有直接將延遲消息發(fā)到 Delay Server,而是更換 Topic 以后存入 RocketMQ。這樣的好處是可以復(fù)用現(xiàn)有的消息發(fā)送接口(以及上面的所有擴(kuò)展能力)。對(duì)業(yè)務(wù)來(lái)說(shuō),只需要在構(gòu)造消息的時(shí)候額外指定一個(gè)延遲時(shí)間字段即可,其它用法都不變。

          自研單獨(dú)的  Delay Server 不僅可以適配 RocketMQ 4.X , 也可以適配 Kafka ,同時(shí),也可以具有非常高的性能,說(shuō)實(shí)話,這個(gè)是一個(gè)非常實(shí)用且靈活的方案。

          如果想學(xué)Java項(xiàng)目的,強(qiáng)烈推薦我的??項(xiàng)目消息推送平臺(tái)Austin10K stars),可以用作畢業(yè)設(shè)計(jì),可以用作校招,可以看看生產(chǎn)環(huán)境是怎么推送消息的。 

          倉(cāng)庫(kù)地址(可點(diǎn)擊閱讀原文跳轉(zhuǎn)):https://gitee.com/zhongfucheng/austin

          4.3 Redis 延遲隊(duì)列

          Redis 延遲隊(duì)列是一個(gè)輕量級(jí)的解決方案,開(kāi)源成熟的實(shí)現(xiàn)是 Redission 。

          47d377036532a851be61286c322c039b.webp

          圖中,我們定義兩個(gè)集合:

          1、zset 集合

          生產(chǎn)者將任務(wù)信息發(fā)送到 zset 集合,value 是任務(wù)編號(hào),score 是任務(wù)執(zhí)行時(shí)間戳。

          2、list 集合

          守護(hù)線程檢測(cè)  zset 集合中到期的任務(wù),若任務(wù)到期,將任務(wù)編號(hào)轉(zhuǎn)移到 list 集合 , 消費(fèi)者從 list 集合彈出任務(wù),并執(zhí)行任務(wù)邏輯。

          筆者需要強(qiáng)調(diào)的是:

          Redis 雖然可以實(shí)現(xiàn)延遲消息的功能,但 Redis 并不是真正意義上的消息隊(duì)列,在使用過(guò)程中還是有小概率會(huì)丟失消息

          5 最佳實(shí)踐

          5.1 并發(fā)口訣:一鎖二判三更新

          不管我們使用定時(shí)任務(wù)還是延遲消息時(shí),不可避免的會(huì)遇到并發(fā)執(zhí)行任務(wù)的情況 (比如重復(fù)消費(fèi)、調(diào)度重試等)。

          當(dāng)我們執(zhí)行任務(wù)時(shí),我們可以按照一鎖二判三更新這個(gè)口訣來(lái)處理。

          1. 鎖定當(dāng)前需要處理的訂單。
          2. 判斷訂單是否已經(jīng)更新過(guò)對(duì)應(yīng)狀態(tài)了
          3. 如果訂單之前沒(méi)有更新過(guò)狀態(tài)了,可以更新并完成相關(guān)業(yè)務(wù)邏輯,否則本次不能更新,也不能完成業(yè)務(wù)邏輯。
          4. 釋放當(dāng)前訂單的鎖。
          87e911005475e641d6736296eb7ea68e.webp 06254c2971ed784afa888104f69f1eb3.webp偽代碼

          5.2 兜底意識(shí) + 配置監(jiān)控

          雖然我們提到了很多的實(shí)現(xiàn)策略,現(xiàn)實(shí)實(shí)戰(zhàn)時(shí)依然容易出現(xiàn)問(wèn)題,比如不合理的操作導(dǎo)致消息丟失。

          因此,我們應(yīng)該具備 兜底意識(shí)

          假如少量消息丟失,我們可以通過(guò)每天凌晨跑一次任務(wù),批量將這些未處理的訂單批量取消。這種兜底行為工程實(shí)現(xiàn)簡(jiǎn)單,同時(shí)對(duì)系統(tǒng)影響很小。

          還有一點(diǎn),就是配置監(jiān)控

          筆者曾經(jīng)自研過(guò)任務(wù)調(diào)度系統(tǒng),應(yīng)用 A 接入后,從控制臺(tái)發(fā)現(xiàn)每隔 2 個(gè)小時(shí)調(diào)度應(yīng)用 A 的任務(wù)時(shí),經(jīng)常發(fā)生超時(shí),通過(guò)分析,發(fā)現(xiàn)應(yīng)用 A 線程出現(xiàn)了死鎖。

          這種問(wèn)題出現(xiàn)的幾率非常高,因此配置監(jiān)控特別要必要。

          對(duì)業(yè)務(wù)系統(tǒng)來(lái)講,監(jiān)控分為兩個(gè)層面:系統(tǒng)監(jiān)控業(yè)務(wù)監(jiān)控

          • 系統(tǒng)監(jiān)控

          在條件允許的情況下,建議關(guān)注性能監(jiān)控,方法可用性監(jiān)控,方法調(diào)用次數(shù)監(jiān)控這三大類。

          a88836ea884d2874db5d9cae19fd2307.webp性能監(jiān)控

          上圖是性能監(jiān)控的示例圖,性能監(jiān)控不同時(shí)間段性能分布,實(shí)時(shí)統(tǒng)計(jì) TP99、TP999 、AVG 、MAX 等維度指標(biāo),這也是性能調(diào)優(yōu)的重點(diǎn)關(guān)注對(duì)象。

          • 業(yè)務(wù)監(jiān)控

          業(yè)務(wù)監(jiān)控功能是從業(yè)務(wù)角度出發(fā),各個(gè)應(yīng)用系統(tǒng)需要從業(yè)務(wù)層面進(jìn)行哪些監(jiān)控,以及提供怎樣的業(yè)務(wù)層面的監(jiān)控功能支持業(yè)務(wù)相關(guān)的應(yīng)用系統(tǒng)。

          具體就是對(duì)業(yè)務(wù)數(shù)據(jù),業(yè)務(wù)功能進(jìn)行監(jiān)控,實(shí)時(shí)收集業(yè)務(wù)流程的數(shù)據(jù),并根據(jù)設(shè)置的策略對(duì)業(yè)務(wù)流程中不符合預(yù)期的部分進(jìn)行預(yù)警和報(bào)警,并對(duì)收集到業(yè)務(wù)監(jiān)控?cái)?shù)據(jù)進(jìn)行集中統(tǒng)一的存儲(chǔ)和各種方式進(jìn)行展示。

          比如訂單系統(tǒng)中有一個(gè)定時(shí)結(jié)算的服務(wù),每?jī)煞昼妶?zhí)行一次。我們可以在定時(shí)任務(wù) JOB 中添加埋點(diǎn),并配置業(yè)務(wù)監(jiān)控,假如十分鐘該定時(shí)任務(wù)沒(méi)有執(zhí)行,則發(fā)送郵件,短信給相關(guān)負(fù)責(zé)人。

          6 總結(jié)

          這篇文章,筆者總結(jié)了訂單超時(shí)自動(dòng)取消方案的兩種流派:定時(shí)任務(wù)延遲消息

          1、定時(shí)任務(wù)

          定時(shí)任務(wù)實(shí)現(xiàn)策略,我們可以簡(jiǎn)單劃分為單機(jī)版集群版

          筆者并不認(rèn)可單機(jī)版,背八股文當(dāng)然可以,訂單自動(dòng)取消這個(gè)業(yè)務(wù)場(chǎng)景,生產(chǎn)環(huán)境還是要慎重。

          集群版有三種方式:Quartz + JDBCJobStoreElasticJobXXL-JOB

          每種方式各有優(yōu)缺點(diǎn),筆者更傾向于任務(wù)調(diào)度平臺(tái) XXL-JOB 這種方式。

          2、延遲消息

          延時(shí)消息是一種非常優(yōu)雅的模式。本文介紹了三種方式:消息隊(duì)列 RocketMQ自研延遲服務(wù)Redis 延遲隊(duì)列

          假如技術(shù)團(tuán)隊(duì)基礎(chǔ)架構(gòu)能力很強(qiáng),筆者推薦使用 RocketMQ 或者自研延遲服務(wù)。

          假如技術(shù)團(tuán)隊(duì)僅僅想用輕量級(jí)的實(shí)現(xiàn),可以選擇 Redis 延遲隊(duì)列。

          不管是使用定時(shí)任務(wù)還是延遲消息,架構(gòu)的穩(wěn)定性還需要注意如下兩點(diǎn):

          1、并發(fā)口訣:一鎖二判三更新

          2、兜底意識(shí) + 配置監(jiān)控

          Java項(xiàng)目訓(xùn)練營(yíng)

          我開(kāi)通了 項(xiàng)目股東服務(wù) ,已經(jīng)有不少消息推送平臺(tái)項(xiàng)目股東拿了阿里/vivo等大廠offer了。 我是沒(méi)找到網(wǎng)上有跟我提供相同的服務(wù),價(jià)格還比我低的

          ??一對(duì)一周到的服務(wù): 有很多人的自學(xué)能力和基礎(chǔ)確實(shí)不太行,不知道怎么開(kāi)始學(xué)習(xí),從哪開(kāi)始看起,學(xué)習(xí)項(xiàng)目的過(guò)程中會(huì)走很多彎路,很容易就迷茫了。付費(fèi)最跟自學(xué)最主要的區(qū)別就是我的服務(wù)會(huì)更周到。我會(huì)告訴你怎么開(kāi)始學(xué)這個(gè)開(kāi)源項(xiàng)目,哪些是重點(diǎn)需要掌握的,如何利用最短的時(shí)間把握整個(gè)系統(tǒng)架構(gòu)和編碼的設(shè)計(jì),把時(shí)間節(jié)省下來(lái)去做其他事情。學(xué)習(xí)經(jīng)驗(yàn)/路線/簡(jiǎn)歷編寫(xiě)/面試經(jīng)驗(yàn)知無(wú)不言

          ??本地直連遠(yuǎn)程服務(wù): 生產(chǎn)環(huán)境的應(yīng)用系統(tǒng)肯定會(huì)依賴各種中間件,我專門買了兩臺(tái)服務(wù)器已經(jīng)搭建好必要的環(huán)境??,在本地就可以直接啟動(dòng)運(yùn)行體驗(yàn)和學(xué)習(xí),無(wú)須花額外的時(shí)間自行搭建調(diào)試。

          ??細(xì)致的文檔&視頻: 巨細(xì)致的語(yǔ)雀文檔11W+ 字,共106個(gè)文檔,項(xiàng)目視頻還在持續(xù)制作更新中(20個(gè)),不怕你學(xué)不會(huì)。

          ??付費(fèi)社群 優(yōu)質(zhì)的社群里需篩選過(guò)濾,學(xué)習(xí)氛圍是很重要的,多跟同輩或前輩聊聊,會(huì)少走很多彎路??

          ??清爽干練commit: 專屬股東倉(cāng)庫(kù),一步一步從零復(fù)現(xiàn)austin,每個(gè)commit都帶著文檔&視頻學(xué)習(xí)。

          如果想獲取上面的權(quán)益,可以看看?? Java項(xiàng)目訓(xùn)練營(yíng)

          瀏覽 43
          點(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>
                  影音先锋男人站你懂的 | 岛国av在线观看网址国产 | 大香蕉大香蕉网 | 国产91白丝jk无套进入在线播放 | 樱桃香蕉网站在线观看 |