Redis 异步持久化方案设计与实现

前言

Redis 是一种基于内存的 Key-Value 存储系统,被广泛应用于缓存、消息队列、计数器等场景。与传统的存储系统相比,Redis 的读写速度更快、拥有更好的可扩展性。

然而,Redis 还面临一个非常关键的问题:如果 Redis 进程崩溃或被杀死,那么内存中的数据将会全部丢失。因此,我们需要一种 Redis 持久化方案来解决这个问题。

本文将介绍一种 Redis 异步持久化方案的设计与实现,并提供示例代码。

Redis 的持久化机制

Redis 提供了两种数据持久化的方式:RDB 和 AOF。

RDB

RDB 是 Redis 数据库快照的简称。它可以将 Redis 内存中的数据以二进制的形式写入到硬盘上。RDB 快照有几种触发方式,例如手动执行 SAVE 命令、定期执行 BGSAVE 命令、在 Redis 进程退出时执行自动保存等。

在一个 Redis 数据库中,每个 RDB 文件对应一个特定的时间点的数据库快照。这个时点可以通过 SAVE 或 BGSAVE 命令手动触发,也可以在 Redis 配置文件中设置自动触发的时间点。RDB 文件里存储的是 Redis 数据库在某个时刻刻全部数据的快照。

现在我们需要考虑的是 RDB 的缺点,它只能做到全量备份,时间点上的增量备份难以实现。每次 RDB 执行 BGSAVE 的时候,Redis 会进行一次 fork 操作来创建出一个子进程,子进程会将当前 Redis 进程的内存数据写到硬盘上的一个 RDB 文件里。在写完 RDB 文件后,子进程会发一个信号给父进程,父进程在收到信号后会立刻将新的 RDB 文件重命名为老的 RDB 文件,以保证新的 RDB 文件与 Redis 交互时是有效的。

因此 RDB 的优点为:

  • 整个过程不会影响 Redis 的正常操作;
  • 快照文件是紧凑的,不管 Redis 中数据有多大,总是可以生成非常小的磁盘文件;
  • 它基本可以通过调整 SAVE 或 BGSAVE 命令的执行时间来控制出现数据损失的时间长度。

但RDB的缺点主要在:

  • 由于执行快照的时候需要 fork 出子进程,所以有一定的性能损失;
  • 如果 Redis 在 BGSAVE 过程中崩溃,那么就会丢失这个时刻的数据。

AOF

AOF 是 Append Only File,即追加写日志文件的简称。当 Redis 的内存里的数据有修改时,Redis 会把这些修改操作以追加的方式写入到 AOF 文件中,这些操作都是有原子性的。

与 RDB 不同的是,AOF 是以追加的方式记录 Redis 内存中每个写操作,即每个被写到数据集的命令。这个文件是一个纯文本文件,而且它以 Redis 内存中命令的使用顺序的顺序一步步增长。因此,AOF 文件每次的大小和 Redis 运行时间成正比。

当 Redis 重启后,Redis 会根据 AOF 文件里的指令重新构建数据集,从而恢复数据。

因此,AOF 的优点为:

  • 可以记录每次修改操作,因此不存在数据损失的问题;
  • 不会存在类似于 RDB 在 BGSAVE 过程中失效的情况。

AOF存在的缺点为:

  • AOF 文件通常比 RDB 文件大很多,随着时间的推移,AOF 文件会越来越大,对磁盘的消耗也越来越大;
  • 写操作日志文件是有序的,因此读取速度较慢。

异步持久化方案设计

Redis 可以同时使用 RDB 和 AOF 这两种持久化方式,以达到更好的数据保障效果。异步持久化顾名思义是异步的,即当 Redis 内存中的数据发生变化时,Redis 不会立即将变化写入磁盘,而是通过变化的记录方式,异步的更新到日志文件或者快照文件中。这种方式将操作的数据存放到队列中,当队列满时会建立一个新队列,与此同时由后台线程去执行持久化操作,将日志文件或者快照文件中的操作进行写入到磁盘。这个过程可以通过多路复用机制进行实现,降低系统磁盘 IO 操作对于 Redis 的性能的最大化影响。

为了减少持久化过程对 Redis 的性能影响,我们可以选择异步的方式实现持久化方案。当出现数据修改异常时,使用 AOF 方式进行保障,以保证数据的强一致性。具体的,Redis 会将修改操作先记录到 AOF 日志文件中,然后再进行相应的操作,由后台线程来处理 AOF 数据,将修改的数据持久化到磁盘上。当 Redis 内存中的数据突然有大量更新时,这种方式的异步持久化能够让 Redis 可以非常平滑地来处理这些请求,一次性地将很多条命令打包在一起。

我们使用一个列表来存储日志文件中的操作记录,使用一个线程池来异步实现对文件的写入。实现完整的 AOF支持的同时保证了对Redis主流程的非阻塞调用,因为线程池中的线程与 Redis 主线程不是同一个线程。

在 Redis 的配置文件中,我们可以将 appendonly 参数置为 yes,则开启 AOF 的持久化机制。

异步持久化实现

我们实现使用 Redis 的异步持久化方案,需要按照以下步骤进行:

  1. 打开 AOF 文件,若文件存在,则读取文件中的内容作为 Redis 数据库的起始状态;
  2. Redis 处理每个命令前,将命令转化成 AOF 格式追加到 AOF 文件中,AOF 文件中每行是一条 Redis 命令;
  3. 每次数据修改时,会将修改记录保存到队列中,和其它日志合并成批量提交到持久化日志文件中;
  4. 同时,开启一个新的后台线程,将通过线程池异步地将日志写入到磁盘中。

我们来看一下是如何实现的:

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

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

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

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

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

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

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

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

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

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

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

在 Redis 的命令执行前,我们需要把命令以 AOF 的格式写入到持久化文件中。我们需要重写 Redis 命令的方法,将 Redis 命令写入 AOF 文件:

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

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

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

我们随便实现一个 Redis 命令:

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

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

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

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

在进行 Redis 操作时,执行完操作先将其转成 AOF 格式,然后放入队列中:

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

最后,我们在 Redis 容器的生命周期中,添加一个钩子函数,当容器被终止时,将当前的 AOF 存档:

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

总结

异步持久化方案是 Redis 实现高可用的一个关键机制。本文通过介绍 Redis 的 RDB 和 AOF 两种持久化机制,详细讲解了 Redis 异步持久化方案的设计与实现,解决了 Redis 内存数据丢失的问题。

在实现过程中,我们需要注意线程池的配置,注意 AOF 文件的有序性与 AOF 控制文件的正确性,同时实现 AOF 的写操作缓存,防止 Redis 运行速度降低。最后,我们还介绍了 Redis 持久化方案设计的优点和缺点,读者可以根据具体需求选择不同的方案。

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


猜你喜欢

  • 使用 Node.js 和 Passport.js 进行身份验证

    在 WEB 前端开发中,用户身份验证是一个必不可少的功能,它可以保护用户的隐私和数据安全。在 Node.js 中,使用 Passport.js 框架可以轻松地实现用户的身份认证。

    1 年前
  • 使用 Express.js+Sequelize 构建 ORM 应用

    什么是 ORM? ORM 是一种将对象模型与数据库模型进行映射的技术,它可以将数据库中的表映射成为代码中的对象,从而简化开发人员的工作。使用 ORM 可以使开发人员更加专注于业务逻辑的开发,而无需关注...

    1 年前
  • PWA 技术在智能家居中的应用案例

    前言 随着智能家居的快速普及,越来越多的人开始使用手机来控制家电设备。然而,传统的 Web 应用往往需要用户频繁切换页面,操作繁琐,用户体验不佳。针对这一问题,PWA 技术可以提供更好的解决方案。

    1 年前
  • React Router 的 history 模块学习笔记

    什么是 React Router? React Router 是一个由 React 社区维护的路由库,它可以把页面的 URL 与组件的状态进行绑定,允许用户通过浏览器的前进和后退按钮在应用中进行导航。

    1 年前
  • 在 ES7 中使用 Promise.prototype.then() 处理异步操作

    异步操作的背景 在实际的前端开发中,异步操作非常常见,比如获取远程数据,异步更新界面等等。而与此同时,JavaScript语言本身的异步处理机制也随着时间的推移逐渐发展、完善。

    1 年前
  • TypeScript 中的联合类型

    TypeScript 是一种开源的编程语言,它是 JavaScript 的超集,扩展了 JavaScript 的功能,包括更好的静态类型检查、接口、泛型、枚举类型等。

    1 年前
  • Redis 中分页的实现技巧

    前言 Redis 是一种高效的内存型数据库,拥有多种数据结构的支持。在前端领域中,Redis 常用在缓存、会话管理、实时统计等方面。其中,分页的需求也很常见,在本文中,我们将介绍 Redis 中分页的...

    1 年前
  • 在 Next.js 中使用 MongoDB 数据库的方法

    简介 MongoDB 是一种文档数据库,不同于传统的关系型数据库,它的数据以 BSON 格式(Binary JSON)存储在集合(Collection)中。MongoDB 具有高可扩展性、高性能、无需...

    1 年前
  • Babel 为什么不能识别 JavaScript 的内置对象?

    前言 在使用 Babel 进行 JavaScript 代码转换的过程中,你可能会遇到一些类似于“'Promise' 没有被定义”的错误提示。那么这是为什么呢?为什么 Babel 不能直接识别 Java...

    1 年前
  • React 项目中使用 Reactstrap 组件时的技巧

    React 项目中使用 Reactstrap 组件时的技巧 Reactstrap 是一个基于 React 的 UI 组件库,它提供了许多易用的现成组件,方便前端开发人员进行快速开发。

    1 年前
  • GraphQL 与 React 的集成最佳实践

    GraphQL 是一种用于 API 的查询语言,可以让前端开发者更加灵活地请求数据。配合 React 使用,GraphQL 可以提升前端应用的性能以及开发效率。本篇文章将介绍如何将 GraphQL 集...

    1 年前
  • 新特性解析:ES11 新增的 Promise.allSettled 方法

    在 JavaScript 的 ES11 版本中,新增了一个 Promise.allSettled 方法,该方法可以让我们更加方便地处理 Promise 一起执行的情况,本次文章将会详细解析该方法的使用...

    1 年前
  • 从 Koa1 升级到 Koa2 的注意事项

    在前端开发中,Koa 是一款非常流行的轻量级 Node.js 框架,它被广泛应用于构建 Web 应用程序和 API 服务。Koa1 是早期版本的 Koa,而 Koa2 则是其后续版本,它引入了许多新功...

    1 年前
  • 避免 Server-Sent Events 连接超时的方法

    避免 Server-Sent Events 连接超时的方法 在前端开发中,Server-Sent Events(SSE)是支持服务器向客户端发送实时信息的一种技术。

    1 年前
  • 简单了解 Enzyme 的基本使用方法

    对于前端开发,测试是一个必不可少的环节。在 React 开发中,测试组件的功能是否正常也是十分重要的。而Enzyme是React测试工具中比较流行的一个,本文就带大家简单了解Enzyme的基本使用方法...

    1 年前
  • 使用 ES8 的 async/await 减少网络请求的并发

    前言 在前端开发中,与后端 API 交互是很常见的需求。通常我们会使用 Ajax 或者 Fetch API 等技术发起网络请求。但是,有时候会出现一个页面需要发起多个网络请求的情况,这时候就需要考虑网...

    1 年前
  • SASS 使用中出现的语法错误及解决方法

    前言 SASS 是一种强大的 CSS 预处理器,它可以让我们的 CSS 编写更加高效、可维护和可扩展。但是,在使用 SASS 过程中我们难免会遇到一些语法错误或者编译出错的问题,这篇文章将会详细介绍一...

    1 年前
  • Docker 中安装配置 MongoDB

    什么是 Docker? Docker 是一种容器化技术,它可以让你将应用程序及其依赖项打包到一个可移植的容器中,然后可以部署到任何地方,从而消除了开发和部署的痛苦。

    1 年前
  • PM2 常见常见错误及解决方法

    什么是 PM2 首先,我们来介绍一下 PM2。PM2 是一个进程管理工具,用于管理 Node.js 应用程序的进程。它可以帮助我们简化应用程序的部署、监控以及维护等工作。

    1 年前
  • 使用 ES6/7/8/9/10 中的 Array.slice() 方法

    Array.slice() 是一个 JavaScript 数组方法,用于从给定的数组中返回一个新数组,包含原始数组的一部分。在 ES6/7/8/9/10 中,Array.slice() 方法不仅仅可以...

    1 年前

相关推荐

    暂无文章