Redis 实现延迟队列的方案及实践

什么是延迟队列?

延迟队列是一种处理任务的方式,可以在一定时间后再执行某些特定操作,通常应用于消息队列中。举个例子,在订单系统中,如果订单过期未支付,可以将订单信息放入延迟队列中,在一定的时间后检查该订单是否支付,如果没有支付,则触发将该订单关闭的操作。

为什么要用 Redis 实现延迟队列?

Redis 具有高性能、高可用性、支持分布式部署等特点,因此成为了实现延迟队列的最佳选择。

Redis 实现延迟队列的方案

基于 Redis 的 Zset

Redis 的 Zset 是有序集合,可以排序,每个元素还绑定了一个分数。在延迟队列中可以将任务作为 Zset 的元素,将执行时间作为分数,实现按照时间顺序排列。定时任务调度器每隔一段时间(比如 1 秒)去查询 Zset 中分数在当前时间范围内的任务,如果查询到任务,则将其弹出队列,执行任务。

基于 Redis 的 List

Redis 的 List 是一个双端队列,支持在队头和队尾进行插入和删除操作。在延迟队列中可以将任务作为 List 的元素,将执行时间作为任务的一个属性,如下图所示:

在每个时间单位(比如 1 秒),将队列的第一个任务弹出,判断其执行时间和当前时间的差值,如果大于零,则重新将该任务加入队列,如果小于等于零,则执行该任务。

Redis 实现延迟队列的实践

下面我们结合代码来实现一个基于 Redis 的延迟队列。

安装 Redis

首先我们需要在本地安装 Redis,可以前往官网下载对应版本:https://redis.io/download

引入依赖

接着我们需要引入 Redis 相关依赖,例如 redis.clients:jedisorg.springframework.data:spring-data-redis 等。

实现基于 Zset 的延迟队列

------
----------
------ ----- ----------------------- -

    ----------
    ------- --------- ----------

    ---
     - - ---- -----
     -
     - ------ ------- ----
     - ------ -----   -------
     - ------- ------
     --
    ------ ------- ----------------- -------- ---- ------ -
        ----- ----- - -----
        --- -
            ----- - ------------------------
            ---- ---- - -------------------------- - ----- - -----
            ------ ------------------------------ ----- -------- -- --
        - ----- ---------- -- -
            --------------------- ------ ----------- ---------- -------- ------ ---
            ------ ------
        - ------- -
            -- ------ -- ----- -
                --------------
            -
        -
    -

    ---
     - -- ---- ----
     --
    ------ ---- ---------------- -
        ----- ----- - -----
        --- -
            ----- - ------------------------
            ----- ------ -
                ----------- --- - --------------------------------------- -- --------------------------- -- ---
                -- --------------- -
                    -------------------
                    ---------
                -
                ------ ------- - ----------------------
                -- ------------------------------- -------- -- -- -
                    ----------------- -------- ---- ---------
                -
            -
        - ----- ---------- -- -
            ------------------------- ------- ---
        - ------- -
            -- ------ -- ----- -
                --------------
            -
        -
    -
-

首先我们定义了一个 RedisDelayQueueWithZset 类,该类提供了向 Zset 中添加消息的方法 addMessage 和消费 Zset 中的消息的方法 consumeMessage

addMessage 方法中,我们使用 zadd 方法将消息添加到 Zset 中,其中 delay 参数代表了延迟的时间,使用 System.currentTimeMillis() 计算了一个到期时间。在返回值中,我们通过判断插入是否成功来判断是否成功添加消息。

consumeMessage 方法中,我们使用 zrangeByScore 方法查询符合条件的消息,如果没有符合条件的消息,则等待 1 秒继续查询。如果有符合条件的消息,则使用 zrem 方法将其从 Zset 中删除,并打印出该消息。

实现基于 List 的延迟队列

------
----------
------ ----- ----------------------- -

    ----------
    ------- ------------------- --------------------

    ---
     - - ---- -----
     -
     - ------ ------- ----
     - ------ -----   -------
     - ------- ------
     --
    ------ ------- ----------------- -------- ---- ------ -
        --- -
            ---- ---- - -------------------------- - ----- - -----
            ------------------------------------------------------------- ---- - --- - ---------
            ------ -----
        - ----- ---------- -- -
            --------------------- ------ ----------- ---------- -------- ------ ---
            ------ ------
        -
    -

    ---
     - -- ---- ----
     --
    ------ ---- ---------------- -
        ----- ------ -
            ------ ----- - --------------------------------------------------------------
            -- ------ -- ----- -
                --- -
                    -------------------
                - ----- --------------------- -- -
                    ------------------------- ------- ---
                -
            - ---- -
                -------- -------- - ---------------- ---
                ---- ---- - ----------------------------
                -- ----- - --------------------------- -
                    -------------------------------------------------------------- -------
                    --- -
                        -------------------
                    - ----- --------------------- -- -
                        ------------------------- ------- ---
                    -
                - ---- -
                    ----------------- -------- ---- -------------
                -
            -
        -
    -
-

RedisDelayQueueWithZset 类似,我们定义了一个 RedisDelayQueueWithList 类,该类提供了向 List 中添加消息的方法 addMessage 和消费 List 中的消息的方法 consumeMessage

addMessage 方法中,我们将消息和有效时间拼接成一个字符串,使用 opsForList().leftPush 方法将消息存入 List 中。

consumeMessage 方法中,我们使用 opsForList().rightPop 方法获取 List 中的首位元素。如果该元素为空,说明 List 中没有任务需要执行,则等待 1 秒继续查询。如果该元素不为空,则判断该任务的有效时间和当前时间的差值,如果大于零则继续将该任务插入队列等待执行,如果小于等于零则执行该任务。

测试代码

---------------
------
----- ------------------------------- -

    ----------
    ------- ----------------------- ------------------------

    ----------
    ------- ----------------------- ------------------------

    -----
    ---- ----------------------------- ------ -------------------- -
        ----------------------------------------- ------ ---
        ----------------------------------------- ------ ----
        ----------------------------------------- ------ ---
        ----------------------------------------- ------ ---
        ----------------------------------------- ------ ---
        ----- ------ -
            -----------------------------------------
            -------------------
        -
    -

    -----
    ---- ----------------------------- ------ -------------------- -
        ----------------------------------------- ------ ---
        ----------------------------------------- ------ ----
        ----------------------------------------- ------ ---
        ----------------------------------------- ------ ---
        ----------------------------------------- ------ ---
        ----- ------ -
            -----------------------------------------
        -
    -
-

我们使用 JUnit 进行测试,在 RedisDelayQueueWithZset 中调用了 addMessage 方法添加了五个消息,在 RedisDelayQueueWithList 中调用了 addMessage 方法添加了五个消息,然后分别调用了 consumeMessage 方法。

总结

本文介绍了 Redis 实现延迟队列的方案,并通过代码示例进行了实践。Zset 和 List 都是实现延迟队列的常见方案,选取哪种方案还需要根据具体业务场景进行评估。我希望本文可以对大家理解延迟队列有所帮助,并能够帮助大家在实际业务中灵活使用 Redis 实现延迟队列。

来源:JavaScript中文网 ,转载请联系管理员! 本文地址:https://www.javascriptcn.com/post/64717db8968c7c53b0f5a75e


猜你喜欢

  • 使用 ES8 特性解决 JavaScript 闭包传参问题

    JavaScript 的闭包是一种强大的特性,可以实现数据私有化和函数参数的缓存。然而,在使用闭包的过程中,由于变量作用域的复杂性,经常会遇到传参问题。这篇文章将介绍 ES8 中的特性,来解决 Jav...

    1 年前
  • 了解 Object.freeze 和 Object.seal 的区别

    在 JavaScript 中,对象是一个重要的概念,对象属性、对象方法、对象实例都在实际场景中得到了广泛的使用。但是,对于对象的管理和保护问题,必须引入一些机制就像 Object.freeze 和 O...

    1 年前
  • PM2 自动化部署到服务器教程

    什么是 PM2? PM2 是一个 Node.js 应用的进程管理工具,它可以帮助开发者在生产环境中轻松地管理 Node.js 应用的部署、监控、日志等一系列操作。它可以通过命令行或者 Web 界面来管...

    1 年前
  • SASS 中如何调用外部函数

    在前端开发过程中,使用 SASS(Syntastically Awesome Style Sheets)可以更加方便地管理 CSS 样式。SASS 是一种 CSS 预处理器,它允许我们使用变量、嵌套规...

    1 年前
  • 用 Mongoose 对 MongoDB 进行分页

    前言 随着数据量的不断增加,数据分页成为了前后端开发中经常遇到的问题。而在 Node.js 后端开发中,MongoDB 的使用也越来越普遍。 在使用 MongoDB 进行数据查询时,我们通常会使用一些...

    1 年前
  • Redux-Saga:如何在 Redux 应用中使用

    Redux-Saga:如何在 Redux 应用中使用 Redux-Saga 是一个用于管理应用程序副作用(例如异步数据获取和不纯的操作)的 Redux 中间件。它允许您通过利用 ES6 的生成器功能创...

    1 年前
  • 深度学习 Flexbox 布局 —— 一篇极致总结

    Flexbox 布局可以说是现代前端开发中最常用的布局方式之一,它提供了一种非常便捷的方式来对于元素进行定位、分布及对齐等操作。但是,很多开发者对于 Flexbox 布局还是比较陌生的,或者只是停留在...

    1 年前
  • 深入了解 Web Components 中的 Scoped CSS

    简介 Web Components 是一组标准,用于创建可重用的组件,而 Scoped CSS 能够防止样式污染、提高组件隔离性。本文将深入探讨 Scoped CSS 在 Web Components...

    1 年前
  • Serverless 应用如何进行权限控制

    Serverless 应用的开发越来越受到关注,因为它们比传统的应用程序更灵活、更可扩展、更容易维护。但是,如何对这些应用程序进行安全的身份验证和授权是一个非常重要的问题。

    1 年前
  • 如何通过 Swagger 构建 RESTful API 文档

    在软件开发中,RESTful API 已经成为了一种常见的 Web API 形式。为了方便开发者使用 API,构建一份详细的 API 文档显得尤为重要。Swagger 是一款流行的 RESTful A...

    1 年前
  • 了解如何在 Express.js 中处理 404 错误

    前言 作为前端开发者,我们经常会遇到 HTTP 状态码为 404 的情况,这是因为我们请求的资源并不存在于服务器上。如何在 Express.js 中处理 404 错误,是我们需要掌握的一项技能。

    1 年前
  • Cypress:如何解决 wait() 方法失效的问题?

    前言 Cypress 是一款非常流行的前端自动化测试框架,它的 API 简单易用,而且不需要编写繁琐的代码即可完成测试用例的编写。然而,在实际的开发过程中,我们还是会遇到一些问题,其中之一就是 wai...

    1 年前
  • 如何消除 CSS Grid 中元素的空白间隙

    CSS Grid 是一个非常强大的前端布局工具,通过使用网格和单元格,我们可以轻松地将页面分割成各种区域,构建出复杂的布局。然而,当我们在使用 CSS Grid 时,可能会遇到一个问题:网格中的元素之...

    1 年前
  • 基于 Tailwind CSS 制作漂亮的 UI 组件

    Tailwind CSS 是一个专注于快速构建自定义用户界面的实用型 CSS 框架,它的特点是提供了大量的样式类名,方便我们以最短的代码行数实现丰富的 UI 效果。

    1 年前
  • Sequelize 事务操作过程中遇到的问题及其解决方法

    在使用 Sequelize 进行 ORM(对象关系映射)操作时,事务操作是不可避免的。但是,在实际的开发中,我们可能会遇到一些 Sequelize 事务操作中的问题。

    1 年前
  • Promise 如何与 jQuery 插件配合使用?

    前言 在前端开发中,我们通常会使用 jQuery 插件来实现一些页面效果和功能。而使用 jQuery 插件时,我们常常需要处理异步操作,如 Ajax 请求等。此时,Promise 可以帮助我们更好地管...

    1 年前
  • 在 Next.js 应用中如何使用 GraphQL?

    GraphQL 是一种面向 API 的查询语言,可以有效地减少 API 请求和响应所需的数据量,提高应用的性能。Next.js 是一个流行的 React 框架,在构建 React 应用时提供了很多有用...

    1 年前
  • 避免在 ES7 中使用不安全的原生变量

    在前端开发中,ES7(即ES2017)已经成为了很多开发者使用的标准,但是在使用 ES7 时,有些开发者可能会不小心遇到一些不安全的原生变量,从而引发程序错误、漏洞等问题。

    1 年前
  • Vue.js 中的 mixins 应用

    在 Vue.js 中,mixins 是一种重要的组件复用方式。通过 mixins,我们可以将一些常用的、通用的逻辑提取出来,然后在不同的组件中复用。这不仅可以减少代码的冗余,同时也可以提高代码的重用性...

    1 年前
  • Babel 转码器插件的安装与实现

    Babel 是一个 JavaScript 转码器,它可以将较新版的 JavaScript 代码转换为能被不同版本浏览器或者 Node.js 运行的 JavaScript 代码。

    1 年前

相关推荐

    暂无文章