日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

單點定時任務

JDK原生

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

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

Spring Task

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

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

    /**
     * 每分鐘執行一次(例:18:01:00,18:02:00)
     * 秒 分鐘 小時 日 月 星期 年
     */
    @Scheduled(cron = "0 0/1 * * * ? *")
    public void someTask() {
       //...
    }
}

單點的定時服務在目前微服務的大環境下,應用場景越來越局限,所以嘗鮮一下分布式定時任務吧。

基于 redis 實現

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

通過ZSet的方式

將定時任務存放到ZSet集合中,并且將過期時間存儲到ZSet的Score字段中,然后通過一個循環來判斷當前時間內是否有需要執行的定時任務,如果有則進行執行。

具體實現代碼如下:

/**
 * Description: 基于Redis的ZSet的定時任務 .<br>
 *
 * @author mxy
 */
@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;

    /**
     * 添加任務.
     *
     * @param task
     */
    public void addTask(String task, Instant instant) {
        stringRedisTemplate.opsForZSet().add(JOB_KEY, task, instant.getEpochSecond());
    }

    /**
     * 定時任務隊列消費
     * 每分鐘消費一次(可以縮短間隔到1s)
     */
    @Scheduled(cron = "0 0/1 * * * ? *")
    public void doDelayQueue() {
        long nowSecond = Instant.now().getEpochSecond();
        // 查詢當前時間的所有任務
        Set<String> strings = stringRedisTemplate.opsForZSet().range(JOB_KEY, 0, nowSecond);
        for (String task : strings) {
            // 開始消費 task
            LOGGER.info("執行任務:{}", task);
        }
        // 刪除已經執行的任務
        stringRedisTemplate.opsForZSet().remove(JOB_KEY, 0, nowSecond);
    }
}

適用場景如下:

  • 訂單下單之后15分鐘后,用戶如果沒有付錢,系統需要自動取消訂單。
  • 紅包24小時未被查收,需要延遲執退還業務;
  • 某個活動指定在某個時間內生效&失效;

優勢是:

  • 省去了MySQL的查詢操作,而使用性能更高的Redis做為代替;
  • 不會因為停機等原因,遺漏要執行的任務;

鍵空間通知的方式

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

默認情況下Redis是不開啟鍵空間通知的,需要我們通過config set notify-keyspace-events Ex的命令手動開啟。開啟之后定時任務的代碼如下:

自定義監聽器

 /**
  * 自定義監聽器.
  */
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 你的處理
    }
}

設置該監聽器

/**
 * Description: 通過訂閱Redis的過期通知來實現定時任務 .<br>
 *
 * @author mxy
 */
@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());
    }
}

Spring會監聽符合以下格式的Redis消息

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

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

場景舉例:

  • 訂單下單之后15分鐘后,用戶如果沒有付錢,系統需要自動取消訂單。
  • 紅包24小時未被查收,需要延遲執退還業務;

優劣勢是:

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

分布式定時任務

引入分布式定時任務組件or中間件

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

quartz

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

elastic-job-lite

依賴于Zookeeper,通過zookeeper的注冊與發現,可以動態的添加服務器。

  • 多種作業模式
  • 失效轉移
  • 運行狀態收集
  • 多線程處理數據
  • 冪等性
  • 容錯處理
  • 支持spring命名空間
  • 有圖形化管理頁面

LTS

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

  • 業務日志記錄器
  • SPI擴展支持
  • 故障轉移
  • 節點監控
  • 多樣化任務執行結果支持
  • FailStore容錯
  • 動態擴容
  • 對spring相對友好
  • 有監控和管理圖形化界面

xxl-job

國產,依賴于MySQL,基于競爭數據庫鎖保證只有一個節點執行任務,支持水平擴容。可以手動增加定時任務,啟動和暫停任務。

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

總結

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

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

  • 任務不會因為集群部署而被多次執行。
  • 任務發生異常得到有效的處理
  • 任務的處理過慢導致大量積壓
  • 任務應該在預期的時間點執行

中間件可以將服務解耦,但增加了復雜度

來源:
juejin.cn/post/6930912870058328071

分享到:
標簽:定時
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定