<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ù),你知道哪些?

          共 4981字,需瀏覽 10分鐘

           ·

          2022-03-06 13:16

          點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)

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

          # 單點(diǎn)定時(shí)任務(wù)


          JDK原生


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

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

          Spring Task


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

          @Configuration@EnableSchedulingpublic class SomeJob {    private static final Logger LOGGER = LoggerFactory.getLogger(SomeJob.class);
          /** * 每分鐘執(zhí)行一次(例:18:01:00,18:02:00) * 秒 分鐘 小時(shí) 日 月 星期 年 */ @Scheduled(cron = "0 0/1 * * * ? *") public void someTask() { //... }}

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


          基于 Redis 實(shí)現(xiàn)


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


          通過ZSet的方式


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


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

          /** * Description: 基于Redis的ZSet的定時(shí)任務(wù) .
          * * @author mxy * @Date 2020/8/25 11:54 */@Configuration@EnableSchedulingpublic 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()); }
          /** * 定時(shí)任務(wù)隊(duì)列消費(fèi) * 每分鐘消費(fèi)一次(可以縮短間隔到1s) */ @Scheduled(cron = "0 0/1 * * * ? *") public void doDelayQueue() { long nowSecond = Instant.now().getEpochSecond(); // 查詢當(dāng)前時(shí)間的所有任務(wù) Set strings = stringRedisTemplate.opsForZSet().range(JOB_KEY, 0, nowSecond); for (String task : strings) { // 開始消費(fèi) task LOGGER.info("執(zhí)行任務(wù):{}", task); } // 刪除已經(jīng)執(zhí)行的任務(wù) stringRedisTemplate.opsForZSet().remove(JOB_KEY, 0, nowSecond); }}

          適用場(chǎng)景如下:


          • 訂單下單之后15分鐘后,用戶如果沒有付錢,系統(tǒng)需要自動(dòng)取消訂單。

          • 紅包24小時(shí)未被查收,需要延遲執(zhí)退還業(yè)務(wù);

          • 某個(gè)活動(dòng)指定在某個(gè)時(shí)間內(nèi)生效&失效;


          優(yōu)勢(shì)是:


          1. 省去了MySQL的查詢操作,而使用性能更高的Redis做為代替;

          2. 不會(huì)因?yàn)橥C(jī)等原因,遺漏要執(zhí)行的任務(wù);


          鍵空間通知的方式


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


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


          開啟之后定時(shí)任務(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 你的處理 }}


          設(shè)置該監(jiān)聽器
          /** * Description: 通過訂閱Redis的過期通知來實(shí)現(xiàn)定時(shí)任務(wù) .
          * * @author mxy * @Date 2020/8/25 12:07 */@Configurationpublic 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()); }}

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

          private?static?final?Topic?TOPIC_ALL_KEYEVENTS?=?new?PatternTopic("__keyevent@*");

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


          場(chǎng)景舉例:


          • 訂單下單之后15分鐘后,用戶如果沒有付錢,系統(tǒng)需要自動(dòng)取消訂單。

          • 紅包24小時(shí)未被查收,需要延遲執(zhí)退還業(yè)務(wù);


          優(yōu)劣勢(shì)是:


          1. 被動(dòng)觸發(fā),對(duì)于服務(wù)的資源消耗更小;

          2. Redis的Pub/Sub不可靠,沒有ACK機(jī)制等,但是一般情況可以容忍;

          3. 鍵空間通知功能會(huì)耗費(fèi)一些CPU


          # 分布式定時(shí)任務(wù)


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


          將定時(shí)任務(wù)作為單獨(dú)的服務(wù),遏制了重復(fù)消費(fèi),獨(dú)立的服務(wù)也有利于擴(kuò)展和維護(hù)。


          quartz


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


          elastic-job-lite


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


          • 多種作業(yè)模式

          • 失效轉(zhuǎn)移

          • 運(yùn)行狀態(tài)收集

          • 多線程處理數(shù)據(jù)

          • 冪等性

          • 容錯(cuò)處理

          • 支持spring命名空間

          • 有圖形化管理頁面


          LTS


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


          • 業(yè)務(wù)日志記錄器

          • SPI擴(kuò)展支持

          • 故障轉(zhuǎn)移

          • 節(jié)點(diǎn)監(jiān)控

          • 多樣化任務(wù)執(zhí)行結(jié)果支持

          • FailStore容錯(cuò)

          • 動(dòng)態(tài)擴(kuò)容

          • 對(duì)spring相對(duì)友好

          • 有監(jiān)控和管理圖形化界面


          xxl-job


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


          • 彈性擴(kuò)容

          • 分片廣播

          • 故障轉(zhuǎn)移

          • Rolling實(shí)時(shí)日志

          • GLUE(支持在線編輯代碼,免發(fā)布)

          • 任務(wù)進(jìn)度監(jiān)控

          • 任務(wù)依賴

          • 數(shù)據(jù)加密

          • 郵件報(bào)警

          • 運(yùn)行報(bào)表

          • 優(yōu)雅停機(jī)

          • 國際化(中文友好)


          # 總結(jié)


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


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


          • 任務(wù)不會(huì)因?yàn)榧翰渴鸲欢啻螆?zhí)行。

          • 任務(wù)發(fā)生異常得到有效的處理

          • 任務(wù)的處理過慢導(dǎo)致大量積壓

          • 任務(wù)應(yīng)該在預(yù)期的時(shí)間點(diǎn)執(zhí)行


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

          ????

          1發(fā)SQL

          2?Chrome會(huì)個(gè)

          3個(gè)SpringBoot44Java

          4QQ個(gè)

          5SpringBoot?發(fā)

          點(diǎn)

          點(diǎn)

          點(diǎn)點(diǎn)

          點(diǎn)

          瀏覽 100
          點(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>
                  久久久久国产一区二区三区潘金莲 | 8x8x看片网站 | 欧美特黄一区二区三区 | 黄色一级视频 | 日本aa一级 |