Redis 过期键清理的原理及实现方法

引言

Redis 是一款高性能的内存数据库,被广泛用于缓存、消息队列、排行榜等场景。在 Redis 中,键的过期时间是一项重要功能,通过设置键值对的过期时间可以有效防止缓存数据过期后数据淘汰问题的发生,同时也可以优化内存的使用。

然而,Redis 并不是像其他的内存数据库一样会及时地将过期的键值对删除或者放入数据淘汰算法池中,而是采用惰性删除(Lazy Deletion)和定期删除(Active Expire)相结合的方式来保证过期键的删除。在本篇文章中,我们将详细介绍 Redis 过期键清理的原理和实现方法。

Redis 过期键清理的原理

Redis 通过每秒钟执行一次的定期删除和惰性删除两种方式来清理过期键。

定期删除

定期删除是 Redis 中过期键清理的一种机制。Redis 会每秒钟检查一定比例的过期键是否需要删除,这个比例由配置文件中的 hz 参数控制,默认值为 10。这个参数的含义是每秒钟执行的定时任务的数量。当 hz 参数被设置为 10 时,每秒钟会执行 10 次定时任务,也就是说每 100ms 执行一次。

Redis 对每个数据库都会维护一个过期字典来存储该数据库中所有的过期键。在每次定时任务执行时,Redis 会随机取出一定比例(由配置文件中的 maxmemory-samples 参数控制)的键值对,然后检查它们的过期时间是否已经过期。如果过期了,就将其从数据库中删除。

定期删除虽然能够自动删除过期键,但是它是一种被动的删除方式。用户不能精确地知道哪一个过期键会在下一次定期任务执行被删除,也不能针对性地增加删除比例,从而达到更好的删除效率。

惰性删除

惰性删除是 Redis 中过期键清理的另一种机制。当客户端访问一个已经过期的键值对时,Redis 会判断这个键值对是否已经过期。如果过期了,就将其删除。因此,惰性删除是一种主动的过期键清理方式,能够精准地删除过期的键值对。

但是,惰性删除也有其缺点。当一个键值对已经过期时,如果客户端不再访问该键值对,那么它将一直保留在数据库中消耗内存,直到下一次定期任务执行或者其他的惰性删除操作发生。

综合来讲,Redis 的过期键清理机制是通过定期删除和惰性删除相结合的方式来完成过期键的删除。定期删除是一种被动的过期键清理方式,惰性删除是一种主动的过期键清理方式。两种方式相结合可以保证 Redis 在满足高并发的同时,又能够高效地清理过期键值对,从而避免因为内存不足而导致 Redis 无法工作的情况发生。

Redis 过期键清理的实现

Redis 的过期键清理机制是通过懒汉式(Lazy Loading)的方式来实现的。懒汉式是一种典型的性能优化策略,它采用按需加载的方式来减少不必要的资源消耗,从而达到更高的性能效果。

在 Redis 中,当一个键值对设置了过期时间时,Redis 会将其添加到过期字典中,然后将该键值对添加到相应的数据库中。在后续的访问中,Redis 会对访问的键值对进行检查,如果发现该键值对已经过期,则删除该键值对并从过期字典中删除该键值对。

具体的实现细节如下:

定期删除

定期删除的实现非常简单,Redis 在启动时会启动一个线程来执行一些后台任务,其中就包括定期删除任务。定期删除的任务代码如下:

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

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

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

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

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

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

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

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

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

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

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

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

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

该函数每秒钟被执行的次数是通过 config.h 文件中的 config_hz 宏来指定的,默认是 10

惰性删除

惰性删除是在对 Key 进行读、写等操作的时候进行的。 Redis 实现惰性删除是依靠 Redis 的多态字符串(sdstr)实现。当系统计算哈希值时,系统同时会判断当前 Key 是否过期,如果过期了,就会被移除。因此,惰性删除不需要在 redis 中设置定时任务进行操作。

Redis 过期键清理的实例

添加过期键

添加过期键的方法就是 setex,示例如下:

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

这里设置了一个 5 秒钟的过期时间。

获取键值对

获取键值对的方法就是 get,示例如下:

--- -----

演示效果

我们可以通过以上的命令来对 Redis 中的键值对进行操作。在执行完 setex 命令之后,我们可以使用 get 命令来查看键值对是否有效,当过期时间到达时,再次执行 get 命令就会发现该键值对已经被删除。

总结

Redis 的过期键清理机制采用了懒汉式的思想,通过惰性删除和定期删除两种方式相结合的方式来清理过期键值对。惰性删除主动,可以保证过期键的及时删除,但是需要等待到第一次访问的时候才能被删除,而定期删除被动,可以在一定程度上减少内存的占用,降低 Redis 的运行开销。

我们在实际开发中,如果需要使用 Redis 来缓存数据,就需要根据实际的业务场景和业务需求对过期键的删除机制进行合理的调整,以达到最好的效果。

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


猜你喜欢

  • Web Components 扩展原生控件的能力详解

    Web Components 扩展原生控件的能力详解 在 Web 开发领域中,我们总是希望能够创建自己的 UI 组件,并且这些组件能够与其它组件和应用程序进行良好的交互。

    5 个月前
  • Docker 监控实践:利用 Prometheus 监控 Docker 容器

    随着 Docker 的普及和应用场景的增加,如何对 Docker 容器进行监控成为了一个重要的问题。在 Docker 容器管理与监控方面,Prometheus 是一个优秀的工具,可以对 Docker ...

    5 个月前
  • 如何使用 Babel 实现 JS 的解构赋值

    在 JavaScript 中,解构赋值是一种强大的方式,可以快速方便地从数组或对象中取出值并赋值到变量中。最初 JS 并没有这种语法,但是随着 ES6 的正式发布,这种用法变得越来越普遍。

    5 个月前
  • RESTful API 如何实现接口幂等性

    RESTful API 如何实现接口幂等性 在 Web 开发中,RESTful API 是一个非常常见的架构风格。它将 Web 应用程序视为一组资源,通过 HTTP 协议对这些资源进行 CRUD(创建...

    5 个月前
  • Node.js 开发日记:Koa2 如何上传带有图片的表单数据?

    众所周知,Koa2 是一个非常流行的 Node.js 框架,它具有轻量级、高效、易扩展等特点,而且非常适合前端开发人员使用。在实际应用中,经常需要实现上传表单数据的操作,尤其是上传带有图片的表单数据,...

    5 个月前
  • 如何在 Deno 中使用 NPM 包?

    前言 Deno 是由 Ryan Dahl 创造并维护的一个基于 V8 引擎和 Rust 语言编写的运行时环境。与 Node.js 相比,Deno 提供了更好的安全性、更简单的依赖导入、更好的调试工具等...

    5 个月前
  • Next.js 中的前后端分离技术解析

    伴随着 Web 应用程序开发框架的日益普及,前后端分离的开发模式变得越来越受欢迎。Next.js 是一种现代化的 React 框架,其内置了前后端分离的技术。它使用了一个特殊的文件系统结构和一些其他工...

    5 个月前
  • Sequelize 模型的自定义方法及其使用

    Sequelize 是一个基于 Node.js 的 ORM 框架,它提供了便捷的方式来处理关系型数据库的查询任务。在使用 Sequelize 操作数据库时,我们通常会定义一个模型(Model),这个模...

    5 个月前
  • 使用 Headless CMS 构建 SEO 友好的博客

    在互联网时代,博客成为人们展示自我、分享知识的重要手段。为了让自己的博客在搜索引擎上有良好的排名,需要进行 SEO 优化。而使用 Headless CMS 则是一种构建 SEO 友好的博客的优秀选择。

    5 个月前
  • 常见的 CSS Reset 大全

    CSS Reset 是一种用于规范化浏览器默认样式的技术,它对于前端开发来说是非常常见也很有用的。通过使用 CSS Reset,我们可以确保不同浏览器在渲染页面时保持一致的样式,从而提高页面的可维护性...

    5 个月前
  • Cypress:如何使用 cypress-axe 检查无障碍性?

    在前端开发中,无障碍性 (Accessibility) 一直是一个很重要的话题,因为有着不同程度的残疾和特殊需要的人群需要使用网站和应用程序。通过遵循无障碍性标准,我们可以让所有用户都能流畅的使用网站...

    5 个月前
  • 用 ESLint 来帮你实现团队的代码统一

    前言 在团队合作中,代码风格的统一性非常重要。不仅仅是为了代码的可读性,也为了方便代码管理和维护。因为团队中不同的成员有不同的习惯,不统一的代码风格不仅会影响代码阅读,而且会影响团队的开发效率。

    5 个月前
  • ES11 中的模块化开发详解

    随着前端项目越来越庞大、复杂,模块化开发成为了越来越重要的一环。ES6 及以前的语法已经提供了模块化开发的支持,但是也存在一些不足之处。ES11 引入的模块化开发新特性可以更好地满足复杂项目的开发需求...

    5 个月前
  • Promise 构造函数中应该传递什么参数

    在 JavaScript 中,Promise 构造函数是用于创建 Promise 对象的重要工具。在构造一个 Promise 对象时,我们需要传递一个参数。那么这个参数应该是什么呢?本文将详细解释 P...

    5 个月前
  • 使用 Mocha 和 Chai 进行简单的单元测试教程

    在前端开发中,单元测试是一个重要的环节,它可以帮助我们提升代码的可维护性、可读性和可靠性。Mocha 和 Chai 是两个常用的 JavaScript 测试框架,它们可以让我们轻松编写和运行单元测试。

    5 个月前
  • 如何实现无刷新的数据分页(SPA)

    在前端开发中,数据分页是一个经常用到的功能。传统的数据分页是通过向后台请求数据,在前端渲染页面并进行分页展示。但是这种方式存在一个问题,当数据量过大时,页面加载过慢。

    5 个月前
  • 在 Kubernetes 中使用 Init Container 进行容器初始化的管理

    在 Kubernetes 中使用 Init Container 进行容器初始化的管理 在 Kubernetes 中,我们经常需要管理容器的初始化过程。Init Container 是一种特殊类型的容器...

    5 个月前
  • 如何使用 Mongoose 和 MongoDB 创建模型

    前言 在当前的 Web 开发中,前端和后端的数据传输成为了极其重要的一环。而 MongoDB 是目前较为常用的 NoSQL 数据库之一,它的灵活性和可伸缩性使得其在大数据处理方面有着更好的表现。

    5 个月前
  • SASS 之使用 @debug 指令调试样式表的技巧

    在编写大型复杂的样式表时,我们经常会遇到各种问题,例如样式不生效、样式冲突等。这时候,我们需要一种有效的方式来调试样式表,找出问题所在。在 SASS 中,@debug 指令就是一个非常有用的工具,可以...

    5 个月前
  • TypeScript 中如何操作数组?

    在 TypeScript 中,数组是一种重要的数据类型,很多前端开发任务都要用到数组。在本文中,我们将探讨 TypeScript 中如何操作数组,包括数组的创建、遍历、操作等。

    5 个月前

相关推荐

    暂无文章