欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot整合redisson實現(xiàn)延時隊列(附倉庫地址)

 更新時間:2024年10月16日 09:28:03   作者:ゞ註﹎錠oo  
延時隊列用于管理需要定時執(zhí)行的任務(wù),對于大數(shù)據(jù)量和高實時性需求,使用延時隊列比定時掃庫更高效,Redisson提供一種高效的延時隊列實現(xiàn)方式,本文就來詳細的介紹一下,感興趣都可以了解學習

應(yīng)用場景

通常在一些需要經(jīng)歷一段時間或者到達某個指定時間節(jié)點才會執(zhí)行的功能,比如以下這些場景:

  • 訂單超時提醒
  • 收貨自動確認
  • 會議提醒
  • 代辦事項提醒

為什么使用延時隊列

對于數(shù)據(jù)量小且實時性要求不高的需求來說,最簡單的方法就是定時掃描數(shù)據(jù)庫。

但是,當數(shù)量達到數(shù)百萬、上千萬級別且時,定時掃庫就顯得非常低效且消耗資源,

甚至有些時間間隔小實時性要求高的情況,上一次掃描還沒結(jié)束,下一次就又開始了,

這時候如果使用延時隊列就會比較合適

延時隊列的幾種方式:

  • Quartz 定時任務(wù)實現(xiàn)掃庫
  • DelayQueue JDK中提供了一組實現(xiàn)延遲隊列的API
  • Redis sorted set
  • Redis 過期鍵監(jiān)聽回調(diào)
  • RabbitMQ 死信隊列
  • RabbitMQ 基于插件實現(xiàn)延遲隊列
  • Wheel 時間輪訓算法

Redisson 實現(xiàn)延時隊列

顧名思義 Redis son 就是 Redis 的兒子,舉個栗子先:

1.引入 pom

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>${lastest.version}</version>
</dependency>

2.封裝一個 RedissonQueue 類

@Service
public class RedissonQueue {

    public static final String QUEUE = "delayQueue";

    // 默認超時時間,30秒
    public static final Integer DEFAULT_TIMEOUT = 30;

    @Resource
    private RedissonClient redissonClient;

    // 加入任務(wù)并設(shè)置到期時間
    public void offer(String taskId, Integer timeout) {
        RDelayedQueue<String> delayedQueue = delayedQueue();
        delayedQueue.offer(taskId, Objects.isNull(timeout) ? DEFAULT_TIMEOUT : timeout, TimeUnit.SECONDS);
    }

    // 移除任務(wù)
    public void remove(String taskId) {
        RDelayedQueue<String> delayedQueue = delayedQueue();
        delayedQueue.removeIf(messageId -> messageId.equals(taskId));
    }

    // 任務(wù)列表
    public RDelayedQueue<String> delayedQueue() {
        RBlockingDeque<String> blockingDeque = blockingDeque();
        return redissonClient.getDelayedQueue(blockingDeque);
    }

    public RBlockingDeque<String> blockingDeque() {
        return redissonClient.getBlockingDeque(QUEUE);
    }

    public boolean isShutdown() {
        return redissonClient.isShutdown();
    }

    public void shutdown() {
        redissonClient.shutdown();
    }

}

3.交給 Spring 管理

@Slf4j
@Service
public class RedissonService implements ApplicationRunner {

    @Resource
    private RedissonQueue redissonQueue;

    @Resource(name = "threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor executor;

    @Override
    public void run(ApplicationArguments args) {
        RBlockingDeque<String> blockingDeque = redissonQueue.blockingDeque();
        executor.execute(() -> {
            while (true) {
                if (redissonQueue.isShutdown()) {
                    return;
                } else {
                    String messageId = null;
                    try {
                        messageId = blockingDeque.take();
                    } catch (InterruptedException e) {
                        log.warn("RedissonConsumer error:{}", e.getMessage());
                    }
                    if (!Objects.isNull(messageId) && !messageId.isEmpty()) {
                        log.warn("timeout messageId : {}", messageId);
                    }
                }
            }
        });

    }

    // 初始化,啟動服務(wù)就執(zhí)行一次
    @PostConstruct
    public void init() {
        redissonQueue.delayedQueue();
    }

    @PreDestroy
    public void shutdown() {
        redissonQueue.shutdown();
    }

}

4.測試接口

@Operation(summary = "添加任務(wù)", description = "添加任務(wù)")
@PostMapping
public ResponseEntity<?> add(@RequestParam(value = "taskId", required = false) String taskId,
                             @RequestParam(value = "timeout", required = false) Integer timeout) {
    taskId = StringUtils.isEmpty(taskId) ? String.valueOf(snowflake.nextId()) : taskId;
    redissonQueue.offer(taskId, timeout);
    return ResponseEntity.ok().body(redissonQueue.delayedQueue());
}

@Operation(summary = "移除任務(wù)", description = "移除任務(wù)")
@DeleteMapping(value = "/{taskId}")
public ResponseEntity<?> remove(@PathVariable("taskId") String taskId) {
    redissonQueue.remove(taskId);
    return ResponseEntity.ok().body(redissonQueue.delayedQueue());
}

5.測試結(jié)果

添加10個任務(wù)

在這里插入圖片描述

刪除第1個任務(wù)

在這里插入圖片描述

可以看到第一個任務(wù)刪除后沒有被執(zhí)行(沒有設(shè)置到期時間,默認為30秒到期)

在這里插入圖片描述

實現(xiàn)原理

  • redisson_delay_queue_timeout:delayQueue,sorted set 數(shù)據(jù)類型,存放所有延遲任務(wù),按延遲任務(wù)的到期時間戳(提交任務(wù)時間戳 +
    延遲時間)排序,所以列表最前面第一個元素就是整個延遲隊列中最早被執(zhí)行的任務(wù)。
  • redisson_delay_queue:delayQueue,list 數(shù)據(jù)類型,也是存放所有任務(wù)。
  • delayQueue,list 數(shù)據(jù)類型,被稱為目標隊列,這個里面存放的任務(wù)都是已經(jīng)到延遲時間的,可以被消費者獲取的任務(wù),所以上面示例中
    RBlockingQueue 的 take 方法是從此目標隊列中獲取任務(wù)的。
  • redisson_delay_queue_channel:delayQueue,是一個 channel,用來通知客戶端開啟一個延遲任務(wù)
  • 生產(chǎn)者提交任務(wù)時將任務(wù)放到 redisson_delay_queue_timeout:delayQueue 中,提交任務(wù)的時間戳+延遲時間
  • 客戶端會有一個延遲任務(wù),這個延遲任務(wù)會向 Redis Server 發(fā)送一段 lua 腳本,Redis 執(zhí)行 lua 腳本中的命令,此操作是原子性的

lua 腳本主要干兩件事

  • 將到了延遲時間的任務(wù)從 redisson_delay_queue_timeout:delayQueue 中移除,存到 delayQueue 這個目標隊列
  • 獲取到 redisson_delay_queue_timeout:delayQueue 中最早到期時間的任務(wù)的到期時間戳,發(fā)布到 redisson_delay_queue_channel:
    delayQueue channel 中

當客戶端監(jiān)聽到 redisson_delay_queue_channel:delayQueue 這個 channel 的消息時,會再次提交一個客戶端延遲任務(wù),延遲時間就是消息(最早到期時間任務(wù)的到期時間戳)當前時間戳
這個時間其實也就是 redisson_delay_queue_channel:delayQueue 中最早到期時間的任務(wù)的剩余的延遲時間。
一旦時間來到最早到期時間任務(wù)的到期時間戳,redisson_delay_queue_timeout:delayQueue 中最早到期時間的任務(wù)已經(jīng)到期,客戶端的延遲任務(wù)也同時到期,
于是開始執(zhí)行 lua 腳本操作,及時將到期任務(wù)放到目標隊列中。然后再次發(fā)布剩余的延遲任務(wù)中最早到期任務(wù)的到期時間戳到 channel
中,
如此循環(huán)運行下去,保證 redisson_delay_queue_timeout:delayQueue 中到期數(shù)據(jù)能及時放到目標隊列中。
這里存在一個特殊情況,需要項目啟動時就執(zhí)行一次延時隊列。因為由于沒有客戶端延遲任務(wù)的執(zhí)行,
可能會出現(xiàn) redisson_delay_queue_timeout:delayQueue 隊列中有到期但是沒有被放到目標隊列的可能,啟動就執(zhí)行一次是為了保證到期的數(shù)據(jù)能被及時放到目標隊列中。

結(jié)論

  • Redisson 方案理論上沒有延遲,但當消息數(shù)量劇增,消費者消費緩慢這種情況下,可能會導致延遲任務(wù)消費的延遲。

  • 消息丟失問題 Redisson 方案最大程度上減輕消息丟失的可能性,因為所有任務(wù)都是存在 list 和 sorted set 兩種數(shù)據(jù)類型中,Redis
    有持久化機制。除非整個 redis 集群宕機,可能丟失一小部分數(shù)據(jù)。

  • 廣播任務(wù)問題,是不會出現(xiàn)的,因為每個客戶端都是從同一個目標隊列中獲取任務(wù)。

Redisson 這種實現(xiàn)方案是比較合適且靠譜的,一般中小型項目建議用 Redisson 實現(xiàn)延遲隊列,規(guī)模較大的項目直接上 MQ。

整合DEMO倉庫地址

到此這篇關(guān)于springboot整合redisson實現(xiàn)延時隊列(附倉庫地址)的文章就介紹到這了,更多相關(guān)springboot redisson延時隊列內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • HttpClient實現(xiàn)遠程調(diào)用

    HttpClient實現(xiàn)遠程調(diào)用

    這篇文章主要為大家詳細介紹了HttpClient實現(xiàn)遠程調(diào)用的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • Java實現(xiàn)二分查找BinarySearch算法

    Java實現(xiàn)二分查找BinarySearch算法

    這篇文章主要介紹了Java實現(xiàn)二分查找BinarySearch算法,二分查找針對的是一個有序的數(shù)據(jù)集合,每次都通過跟區(qū)間的中間元素對比,將待查找的區(qū)間縮小為之前的一半,直到找到要查找的元素,或者區(qū)間被縮小為 0,需要的朋友可以參考下
    2023-12-12
  • 運行時常量池和字符串常量池的區(qū)別及說明

    運行時常量池和字符串常量池的區(qū)別及說明

    這篇文章主要介紹了運行時常量池和字符串常量池的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • java處理轉(zhuǎn)義字符↑ → ↓ 保存后的展示還原操作

    java處理轉(zhuǎn)義字符↑ → ↓ 保存后的展示還原操作

    這篇文章主要介紹了java處理轉(zhuǎn)義字符↑ → ↓ 保存后的展示還原操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • SpringMVC基于注解方式實現(xiàn)上傳下載

    SpringMVC基于注解方式實現(xiàn)上傳下載

    本文主要介紹了SpringMVC基于注解方式實現(xiàn)上傳下載,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-04-04
  • 使用SpringBoot整合Jpa的過程詳解

    使用SpringBoot整合Jpa的過程詳解

    SpringBoot是一種快速開發(fā)框架,它簡化了Java應(yīng)用程序的開發(fā)過程,而Jpa是Java持久化規(guī)范的一種實現(xiàn),將SpringBoot與Jpa整合可以更加方便地進行數(shù)據(jù)庫操作,提高開發(fā)效率,本文將介紹如何使用Spring Boot整合Jpa,幫助讀者快速上手并應(yīng)用于實際項目中
    2023-12-12
  • Java創(chuàng)建子線程的兩種方法

    Java創(chuàng)建子線程的兩種方法

    這篇文章主要介紹了Java創(chuàng)建子線程的兩種方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-05-05
  • Java自定義異常類的實例詳解

    Java自定義異常類的實例詳解

    這篇文章主要介紹了Java自定義異常類的實例詳解的相關(guān)資料,希望通過本文能幫助到大家,讓大家學習理解掌握這部分內(nèi)容,需要的朋友可以參考下
    2017-09-09
  • Springmvc自定義參數(shù)轉(zhuǎn)換實現(xiàn)代碼解析

    Springmvc自定義參數(shù)轉(zhuǎn)換實現(xiàn)代碼解析

    這篇文章主要介紹了Springmvc自定義參數(shù)轉(zhuǎn)換實現(xiàn)代碼解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07
  • SpringBoot如何實現(xiàn)緩存預(yù)熱

    SpringBoot如何實現(xiàn)緩存預(yù)熱

    緩存預(yù)熱是指在 Spring Boot 項目啟動時,預(yù)先將數(shù)據(jù)加載到緩存系統(tǒng)(如 Redis)中的一種機制,本文主要介紹了SpringBoot如何實現(xiàn)緩存預(yù)熱,感興趣的可以了解下
    2024-12-12

最新評論