【Redis-05】Redis如何实现保存键值对的保存及过期键的管理策略

 在之前的文章我们介绍过,Redis服务器在启动之初,会初始化RedisServer的实例,在这个实例中存在很多重要的属性结构,同理本篇博客中介绍的数据库实现原理也会和其中的某些属性相关,我们继续看一下吧。

1.服务器和客户端实现的数据库

 Redis服务器在启动时,会根据redis.conf文件的中databases xx这个配置决定创建多少个数据库(默认配置是16),启动后默认使用的0号数据库,当然可以使用select dbnum这个命令来切换。需要注意的是在redis集群模式下,只有0号数据库可以用,是无法切换到其他库的。

 Redis服务器会将所有的数据库都保存在服务器状态的redisServer的db数组中,数组的每一项都代表了一个数据库,用redisDb结构来表示。首先看一下redisServer.db的源码:

struct redisServer {
	...
	// 代表数据库的数组
    redisDb *db;
    // 这个记录的配置文件中数据库的数量
	int dbnum;  
    ...
}

 我们通过客户端向Redis写入的任何数据都会记录到这个db数组中,根据前面描述,我们知道可以通过select命令切换到另一个目标数据库,但是客户端是怎么记录的它当前操作的哪个数据库呢?我们继续看一下源码:

typedef struct client {
    ...
    // 指针指向当前客户端正在操作的数据库
    redisDb *db;            /* Pointer to currently SELECTed DB. */
	...
} client;

 看,在client客户端状态中,有一个db指针,指向了server.db数组中的某一项,代表了当前客户端正在操作的数据库。所以通过切换client.db的指针,调整客户端操作的数据库,这就是select命令的实现原理。
在这里插入图片描述

2.数据库字典的实现

 Redis是支持key-value键值对存储的,这其实是通过dict结构来实现的,在前面讲到的内容中,服务器和客户端都指向了一个redisDb的结构,在这个db结构中,就包含存储了键值对的字典结构,首先看一下源码:

typedef struct redisDb {
	...
	// 这个存放的就是键值对
    dict *dict;                 /* The keyspace for this DB */
    // 这个存放的是键值对的过期时间,下面一节会说到
    dict *expires;              /* Timeout of keys with a timeout set */
    ...
} redisDb;

 dict这个指针就指向了存储键值对的字典结构,key是字符串robj类型,value可以是任何的robj类型。当我们分别新增、删除、更新或者查询的时候,其实就是根据输入的key在这个字典上做curd的操作。我们在Redis写入两个键值对,图示如下:
在这里插入图片描述
 除了对数据库键值对的curd操作,基于整个数据操作的一些命令也是在这个dict上面实现的,比如清空所有键值对的flushdb,或者exists、del、dbsize命令等。在执行命令前后,redis还会执行一些其他操作,比如检查是否超出最大内存,更新lru时间,记录慢查询日志,或者向monitor客户端发送命令等等,这就是redis数据字典的实现原理。

3.键值对的生命周期管理

 这里说的生命周期,其实就是指键值对的过期时间。通常我们使用expire key这个命令设置键的过期时间,但其实Redis是有四个命令支持设置过期时间的:

  • expire key seconds 将key的生命周期设置为second秒;
  • pexpire key milliseconds 将key的生命周期设置为milliseconds毫秒;
  • expireat key timestamp 将key的过期时间设置在timestamp这个秒的时间戳过期;
  • pexpireat key timestamp 将key的过期时间设置在timestamp这个毫秒的时间戳过期;

 值得说明的是,虽然有这么多命令支持设置过期时间,但是最终经过转换都是指向pexpireat这一个命令来实现。现在的问题是,这么多键值对的过期时间,在redis服务端是怎么保存和维护的呢,我们继续往下看。
 前面在看redisDb源码的时候,有一个expires属性,我们再把源码拿过来看一下:

typedef struct redisDb {
	...
    // 这个存放的是键的过期时间
    dict *expires;              /* Timeout of keys with a timeout set */
    ...
} redisDb;

 这就很清晰了,通过expires这个指针,指向了一个dict结构,字典中记录的就是所有键值对的过期时间。其中,key是键值对的键,value是long类型的毫秒精度的unix时间戳,即过期的时间点。值得注意的是,保存键值对的dict字典和保存过期时间的expires字典,key指针都指向相同的一个键字符串对象,所以在内存空间上是不会存在浪费的。
在这里插入图片描述

 除此之外,跟过期时间操作相关的两个命令,当然也是基于expires这个字典来实现的:

  • ttl 返回键值对的剩余时间
  • persist删除键值对的过期时间

4.过期键的管理策略

 既然有过期时间,那么键值对过期之后,是不是立即被删除了呢?答案肯定不是,redis通过惰性删除和定期删除两种策略实现对过期键的管理:

  • 惰性删除策略:当程序访问到某个键值对的时候,会对过期时间检查,如果过期就删除,否则不处理。
  • 定期删除策略:基于serverCron时间事件函数,从一定数量的数据库中取出一定数量的随机键进行检查,并删除其中过期的键值对。

 使用这两种过期键管理策略可以最大程度上在合理使用CPU时间和避免浪费内存空间之间取得平衡。

5.持久化对过期键的处理

  • rdb 持久化
    • save或者bgsave会检查键的过期时间,已过期的键不会保存到的持久化的rdb文件中。
    • 服务器启动载入rdb文件时,如果是主服务器,过期键会被忽略加载;如果是从服务器,不论是否过期,都会被加载。
  • aof 持久化
    • 写入aof文件时,key是会写入的,过期之后,通过追加del命令,才会显示的删除此过期键。
    • bgrewriteaof 重写时会检查键的过期时间,已过期的键不会写入新的aof文件中。
    • 服务器启动载入aof文件时,过期键也会被忽略,不会被加载。

6.主从复制对过期键的处理

 主从复制,为了保证数据的一致性,通常由主服务器执行更新的操作,然后将命令发送给从服务器。在3.2版本之前,由于惰性删除策略的存在,主服务器遇到对过期键的访问,会删除此键值对,并给客户端返回null值,但是从服务器由于不能执行删除操作,即便是此键已过期,也会返回对应的value值,出现数据不一致导致的脏读问题。

 在3.2版本之后,这个问题得到了修改,从服务器会判断当前键是否过期,如果已过期并且是从服务器的话,也会返回null值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/282057.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JavaSE语法之十二:Object类

文章目录 一、概念二、获取对象信息三、对象比较equals方法四、hashcode方法 一、概念 Object是Java默认提供的一个类。Java里面除了Object类,所有的类都是存在继承关系的,默认会继承Object父类,即所有的类的对象都可以使用Object的引用进行…

安装与部署Hadoop

一、前置安装准备1、机器2、java3、创建hadoop用户 二、安装Hadoop三、环境配置1、workers2、hadoop-env.sh3、core-site.xml4、hdfs-site.xml5、linux中Hadoop环境变量 四、启动hadoop五、验证 一、前置安装准备 1、机器 主机名ip服务node1192.168.233.100NameNode、DataNod…

纯CSS的华为充电动画,它来了

📢 鸿蒙专栏:想学鸿蒙的,冲 📢 C语言专栏:想学C语言的,冲 📢 VUE专栏:想学VUE的,冲这里 📢 Krpano专栏:想学Krpano的,冲 &#x1f514…

准备好通过 “Breakin’ B.I.G.” 在嘻哈音乐界大放异彩吧!

在 The Sandbox 推出人物化身系列后,是时候通过 “Breakin’ B.I.G.” 重返嘻哈音乐的黄金时代了。该体验于 12 月 20 日推出,一直持续到 1 月 3 日,让玩家回到 20 世纪 90 年代,体验以 Notorious B.I.G 为主角的 2D 街舞游戏。 获…

【深度学习-目标检测】01 - R-CNN 论文学习与总结

论文地址:Rich feature hierarchies for accurate object detection and semantic segmentation 论文学习 摘要(Abstract) 对象检测性能的现状: 在PASCAL VOC数据集上测量的对象检测性能在过去几年已经达到了一个高点。最佳性能…

python使用openpyxl为excel模版填充数据,生成多个Sheet页面

目标:希望根据一个给定的excel模版,生成多个Sheet页面,比如模版: 示例程序 import openpyxlexcel_workbook openpyxl.load_workbook("模版.xlsx") for _i in range(3): # 比如填充3个页面# 复制模版sheet页&#x…

arkts状态管理使用(@State、@Prop、@Link、@Provide、@Consume、@objectLink和@observed)

一、状态管理 1.在声明式UI中,是以状态驱动视图更新: ①状态(State):指驱动视图更新的数据(被装饰器标记的变量) ②视图(View):基于UI描述渲染得到用户界面 注意: ①…

机场信息集成系统系列介绍(6):机场协同决策支持系统ACDM*续集

目录 1、A-CDM实施效果评估背景 2、评估核心指标项 (1)机位效率 (2)登机效率 (3)推出效率 (4)滑行效率 (5)协同效率 3、其他指标项 (1&a…

MongoDB Certified Associate Developer 认证考试心得

介绍 前段时间通过了 MongoDB Associate Developer 考试,也记下了一些心得,结果忘记发出来了,现在重新整理下。通过考试后证书是这样的: MongoDB 目前有两个认证证书 1. MongoDB Associate Developer 认证掌握使用MongoDB 来构建现代应用…

kivy开发一个登陆界面

Kivy Kivy是一个用于开发跨平台移动应用(如Android和iOS)以及桌面应用(如Windows、Linux和macOS)的Python框架。它采用开源许可证(MIT许可证),提供了丰富的图形界面组件和工具,以便…

Tensorflow2.X的GPU版框架最快最稳搭建方法

一、环境基础 Windows10以上 已装Anaconda 支持GPU 二、搭建步骤 1. 在Anaconda中创建并进入虚拟环境 conda create -n envname python3.8 conda activate envname 注意:envname 替换为你自己想命名的,下文将以“Ljdenv”出现 2.安…

二叉树的后序遍历,力扣

目录 建议先刷一下中序遍历 题目地址: 题目: 我们直接看题解吧: 解题方法: 注: 解题分析: 解题思路: 代码实现: 代码实现(递归): 代码实现&#x…

【2023年终总结】谈谈一个新人眼里的阿里方法论

写在开头 2023年转眼就过去了,今年我从一名大学生转变某阿里系大厂的“搬砖打工人”,这一转变真的是给我“涉世未深的纯洁心灵”带来了大大的“震撼”。 角色的转变是需要时间进行“内部消化”的。无论是对于个人的价值认知或者是行为方式来说&#xf…

面试官:谈谈对CyclicBarrier的理解

程序员的公众号:源1024,获取更多资料,无加密无套路! 最近整理了一波电子书籍资料,包含《Effective Java中文版 第2版》《深入JAVA虚拟机》,《重构改善既有代码设计》,《MySQL高性能-第3版》&…

kivy中用anchrolayout

说明 AnchorLayout 是 Kivy 框架中用于管理界面元素位置的一种布局方式。AnchorLayout 的特点是,它可以将其子元素锚定到布局的边界上,例如顶部、底部、左侧或右侧。这使得在需要元素相对于其容器边界保持固定位置时非常有用。 界面 # mylayout.kvAnch…

K8s资源管理介绍

用这个官网下的,kube-flannel.yml ,就不会nodes not-ready --- kind: Namespace apiVersion: v1 metadata:name: kube-flannellabels:k8s-app: flannelpod-security.kubernetes.io/enforce: privileged --- kind: ClusterRole apiVersion: rbac.author…

基于NASM搭建一个能编译汇编语言的汇编软件工具环境(利用NotePad++)

文章目录 一、创建汇编语言源程序二、Notepad的下载、安装、使用三、下载和安装编译器NASM3.1 下载NASM编译器3.2 安装并配置环境变量 四、编译汇编语言源程序(使用命令)五、下载和使用配套源码及工具六、将编译功能集成到Notepad 一、创建汇编语言源程序…

回首2023: 程序员跳出舒适圈

1 前言 今天的冬日暖阳高照,照耀着我穿着羽绒服的身体,让我感到火一般的燥热,仿佛错觉中已经到了阳春三月。刚刚把孩子洗好,我坐在电脑前,准备整理一下思绪,回顾一下2023年的生活和工作。 2 2023 回顾 回…

如何处理并下载Sentinel-5数据

SENTINEL-5是欧洲空间局(European Space Agency,ESA)Copernicus计划中的一颗地球观测卫星。SENTINEL-5的主要任务是监测大气成分,特别是臭氧、氮二氧化物、二氧化硫、甲烷和其他气体的分布。这些观测对于了解大气污染、气候变化和…

React快速入门之交互性

响应事件 创建事件处理函数 处理函数名常以handle事件名命名 function handlePlayClick() {alert(Playing);}传递事件处理函数 函数名、匿名两种方式&#xff01; function PlayButton() {function handlePlayClick() {alert(Playing);}return (<Button handleClick{handl…