<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>

          幾種主流的分布式定時任務(wù),你知道哪些?

          共 5437字,需瀏覽 11分鐘

           ·

          2022-04-18 01:04

          單點定時任務(wù)

          JDK原生

          自從JDK1.5之后,提供了ScheduledExecutorService代替TimerTask來執(zhí)行定時任務(wù),提供了不錯的可靠性。

          public?class?SomeScheduledExecutorService?{
          ????public?static?void?main(String[]?args)?{
          ????????//?創(chuàng)建任務(wù)隊列,共?10?個線程
          ????????ScheduledExecutorService?scheduledExecutorService?=
          ????????????????Executors.newScheduledThreadPool(10);
          ????????//?執(zhí)行任務(wù):?1秒?后開始執(zhí)行,每?30秒?執(zhí)行一次
          ????????scheduledExecutorService.scheduleAtFixedRate(()?->?{
          ????????????System.out.println("執(zhí)行任務(wù):"?+?new?Date());
          ????????},?10,?30,?TimeUnit.SECONDS);
          ????}
          }
          復(fù)制代碼

          Spring Task

          Spring Framework自帶定時任務(wù),提供了cron表達式來實現(xiàn)豐富定時任務(wù)配置。新手推薦使用https://cron.qqe2.com/這個網(wǎng)站來匹配你的cron表達式

          @Configuration
          @EnableScheduling
          public?class?SomeJob?{
          ????private?static?final?Logger?LOGGER?=?LoggerFactory.getLogger(SomeJob.class);

          ????/**
          ?????*?每分鐘執(zhí)行一次(例:18:01:00,18:02:00)
          ?????*?秒?分鐘?小時?日?月?星期?年
          ?????*/

          ????@Scheduled(cron?=?"0?0/1?*?*?*???*")
          ????public?void?someTask()?{
          ???????//...
          ????}
          }
          復(fù)制代碼

          單點的定時服務(wù)在目前微服務(wù)的大環(huán)境下,應(yīng)用場景越來越局限,所以嘗鮮一下分布式定時任務(wù)吧。

          關(guān)于該功能的使用,DD的Spring Boot教程中也有介紹,感興趣的小伙伴可以通過這個鏈接查看:https://blog.didispace.com/spring-boot-learning-2-7-1/

          基于 Redis 實現(xiàn)

          相較于之前兩種方式,這種基于Redis的實現(xiàn)可以通過多點來增加定時任務(wù),多點消費。但是要做好防范重復(fù)消費的準備。

          通過ZSet的方式

          將定時任務(wù)存放到ZSet集合中,并且將過期時間存儲到ZSetScore字段中,然后通過一個循環(huán)來判斷當(dāng)前時間內(nèi)是否有需要執(zhí)行的定時任務(wù),如果有則進行執(zhí)行。

          具體實現(xiàn)代碼如下:

          /**
          ?*?Description:?基于Redis的ZSet的定時任務(wù)?.

          ?*
          ?*?@author?mxy
          ?*?@Date?2020/8/25?11:54
          ?*/

          @Configuration
          @EnableScheduling
          public?class?RedisJob?{
          ????public?static?final?String?JOB_KEY?=?"redis.job.task";
          ????private?static?final?Logger?LOGGER?=?LoggerFactory.getLogger(RedisJob.class);
          ????@Autowired?private?StringRedisTemplate?stringRedisTemplate;

          ????/**
          ?????*?添加任務(wù).
          ?????*
          ?????*?@param?task
          ?????*/

          ????public?void?addTask(String?task,?Instant?instant)?{
          ????????stringRedisTemplate.opsForZSet().add(JOB_KEY,?task,?instant.getEpochSecond());
          ????}

          ????/**
          ?????*?定時任務(wù)隊列消費
          ?????*?每分鐘消費一次(可以縮短間隔到1s)
          ?????*/

          ????@Scheduled(cron?=?"0?0/1?*?*?*???*")
          ????public?void?doDelayQueue()?{
          ????????long?nowSecond?=?Instant.now().getEpochSecond();
          ????????//?查詢當(dāng)前時間的所有任務(wù)
          ????????Set?strings?=?stringRedisTemplate.opsForZSet().range(JOB_KEY,?0,?nowSecond);
          ????????for?(String?task?:?strings)?{
          ????????????//?開始消費?task
          ????????????LOGGER.info("執(zhí)行任務(wù):{}",?task);
          ????????}
          ????????//?刪除已經(jīng)執(zhí)行的任務(wù)
          ????????stringRedisTemplate.opsForZSet().remove(JOB_KEY,?0,?nowSecond);
          ????}
          }
          復(fù)制代碼

          適用場景如下:

          • 訂單下單之后15分鐘后,用戶如果沒有付錢,系統(tǒng)需要自動取消訂單
          • 紅包24小時未被查收,需要延遲執(zhí)退還業(yè)務(wù);
          • 某個活動指定在某個時間內(nèi)生效&失效

          優(yōu)勢是:

          1. 省去了MySQL的查詢操作,而使用性能更高的Redis做為代替;
          2. 不會因為停機等原因,遺漏要執(zhí)行的任務(wù);

          鍵空間通知的方式

          我們可以通過Redis的鍵空間通知來實現(xiàn)定時任務(wù),它的實現(xiàn)思路是給所有的定時任務(wù)設(shè)置一個過期時間,等到了過期之后,我們通過訂閱過期消息就能感知到定時任務(wù)需要被執(zhí)行了,此時我們執(zhí)行定時任務(wù)即可。

          默認情況下Redis是不開啟鍵空間通知的,需要我們通過config set notify-keyspace-events Ex的命令手動開啟。

          開啟之后定時任務(wù)的代碼如下:

          自定義監(jiān)聽器
          ?/**
          ??*?自定義監(jiān)聽器.
          ??*/

          public?class?KeyExpiredListener?extends?KeyExpirationEventMessageListener?{
          ????public?KeyExpiredListener(RedisMessageListenerContainer?listenerContainer)?{
          ????????super(listenerContainer);
          ????}

          ????@Override
          ????public?void?onMessage(Message?message,?byte[]?pattern)?{
          ????????//?channel
          ????????String?channel?=?new?String(message.getChannel(),?StandardCharsets.UTF_8);
          ????????//?過期的key
          ????????String?key?=?new?String(message.getBody(),?StandardCharsets.UTF_8);
          ????????//?todo?你的處理
          ????}
          }
          復(fù)制代碼
          設(shè)置該監(jiān)聽器
          /**
          ?*?Description:?通過訂閱Redis的過期通知來實現(xiàn)定時任務(wù)?.

          ?*
          ?*?@author?mxy
          ?*?@Date?2020/8/25?12:07
          ?*/

          @Configuration
          public?class?RedisExJob?{
          ????@Autowired?private?RedisConnectionFactory?redisConnectionFactory;
          ????@Bean
          ????public?RedisMessageListenerContainer?redisMessageListenerContainer()?{
          ????????RedisMessageListenerContainer?redisMessageListenerContainer?=?new?RedisMessageListenerContainer();
          ????????redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
          ????????return?redisMessageListenerContainer;
          ????}

          ????@Bean
          ????public?KeyExpiredListener?keyExpiredListener()?{
          ????????return?new?KeyExpiredListener(this.redisMessageListenerContainer());
          ????}
          }
          復(fù)制代碼

          Spring會監(jiān)聽符合以下格式的Redis消息

          private?static?final?Topic?TOPIC_ALL_KEYEVENTS?=?new?PatternTopic("__keyevent@*");
          復(fù)制代碼

          基于Redis的定時任務(wù)能夠適用的場景也比較有限,但實現(xiàn)上相對簡單,但對于功能冪等有很大要求。從使用場景上來說,更應(yīng)該叫做延時任務(wù)

          場景舉例:

          • 訂單下單之后15分鐘后,用戶如果沒有付錢,系統(tǒng)需要自動取消訂單
          • 紅包24小時未被查收,需要延遲執(zhí)退還業(yè)務(wù);

          優(yōu)劣勢是:

          1. 被動觸發(fā),對于服務(wù)的資源消耗更小;
          2. Redis的Pub/Sub不可靠,沒有ACK機制等,但是一般情況可以容忍;
          3. 鍵空間通知功能會耗費一些CPU

          分布式定時任務(wù)

          引入分布式定時任務(wù)組件or中間件

          將定時任務(wù)作為單獨的服務(wù),遏制了重復(fù)消費,獨立的服務(wù)也有利于擴展和維護。

          quartz

          依賴于MySQL,使用相對簡單,可多節(jié)點部署,通過競爭數(shù)據(jù)庫鎖來保證只有一個節(jié)點執(zhí)行任務(wù)。沒有圖形化管理頁面,使用相對麻煩。

          elastic-job-lite

          依賴于Zookeeper,通過zookeeper的注冊與發(fā)現(xiàn),可以動態(tài)的添加服務(wù)器。

          • 多種作業(yè)模式
          • 失效轉(zhuǎn)移
          • 運行狀態(tài)收集
          • 多線程處理數(shù)據(jù)
          • 冪等性
          • 容錯處理
          • 支持spring命名空間
          • 有圖形化管理頁面

          關(guān)于該框架的實用,DD在博客也連載過,通過這個鏈接可以直接看詳細教程:https://blog.didispace.com/tags/Elastic-Job/


          LTS

          依賴于Zookeeper,集群部署,可以動態(tài)的添加服務(wù)器。可以手動增加定時任務(wù),啟動和暫停任務(wù)。

          • 業(yè)務(wù)日志記錄器
          • SPI擴展支持
          • 故障轉(zhuǎn)移
          • 節(jié)點監(jiān)控
          • 多樣化任務(wù)執(zhí)行結(jié)果支持
          • FailStore容錯
          • 動態(tài)擴容
          • 對spring相對友好
          • 有監(jiān)控和管理圖形化界面

          xxl-job

          國產(chǎn),依賴于MySQL,基于競爭數(shù)據(jù)庫鎖保證只有一個節(jié)點執(zhí)行任務(wù),支持水平擴容。可以手動增加定時任務(wù),啟動和暫停任務(wù)。

          • 彈性擴容
          • 分片廣播
          • 故障轉(zhuǎn)移
          • Rolling實時日志
          • GLUE(支持在線編輯代碼,免發(fā)布)
          • 任務(wù)進度監(jiān)控
          • 任務(wù)依賴
          • 數(shù)據(jù)加密
          • 郵件報警
          • 運行報表
          • 優(yōu)雅停機
          • 國際化(中文友好)

          總結(jié)

          微服務(wù)下,推薦使用xxl-job這一類組件服務(wù)將定時任務(wù)合理有效的管理起來。而單點的定時任務(wù)有其局限性,適用于規(guī)模較小、對未來擴展要求不高的服務(wù)。

          相對而言,基于spring task的定時任務(wù)最簡單快捷,而xxl-job的難度主要體現(xiàn)在集成和調(diào)試上。無論是什么樣的定時任務(wù),你都需要確保:

          • 任務(wù)不會因為集群部署而被多次執(zhí)行。
          • 任務(wù)發(fā)生異常得到有效的處理
          • 任務(wù)的處理過慢導(dǎo)致大量積壓
          • 任務(wù)應(yīng)該在預(yù)期的時間點執(zhí)行

          中間件可以將服務(wù)解耦,但增加了復(fù)雜度

          作者:襄垣來源:https://juejin.cn/post/6930912870058328071?

          ------
          我們創(chuàng)建了一個高質(zhì)量的技術(shù)交流群,與優(yōu)秀的人在一起,自己也會優(yōu)秀起來,趕緊點擊加群,享受一起成長的快樂。另外,如果你最近想跳槽的話,年前我花了2周時間收集了一波大廠面經(jīng),節(jié)后準備跳槽的可以點擊這里領(lǐng)取

          推薦閱讀

          ··································

          你好,我是程序猿DD,10年開發(fā)老司機、阿里云MVP、騰訊云TVP、出過書、創(chuàng)過業(yè)、國企4年互聯(lián)網(wǎng)6年10年前畢業(yè)加入宇宙行,工資不高、也不算太忙,業(yè)余堅持研究技術(shù)和做自己想做的東西。4年后離開國企,加入永輝互聯(lián)網(wǎng)板塊的創(chuàng)業(yè)團隊,從開發(fā)、到架構(gòu)、到合伙人。一路過來,給我最深的感受就是一定要不斷學(xué)習(xí)并關(guān)注前沿。只要你能堅持下來,多思考、少抱怨、勤動手,就很容易實現(xiàn)彎道超車!所以,不要問我現(xiàn)在干什么是否來得及。如果你看好一個事情,一定是堅持了才能看到希望,而不是看到希望才去堅持。相信我,只要堅持下來,你一定比現(xiàn)在更好!如果你還沒什么方向,可以先關(guān)注我,這里會經(jīng)常分享一些前沿資訊,幫你積累彎道超車的資本。

          點擊領(lǐng)取2022最新10000T學(xué)習(xí)資料
          瀏覽 42
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  婷婷毛片 | 天天日女人 | 亚州高清免费播放 | 99久久精品国产一区色 | 日产精品高潮呻吟AV久久 |