从源码看 Redis:深入理解 redisDb 和 redisObject

news2024/9/22 7:23:22

Redis 是一个广泛使用的内存数据库,以其高性能和丰富的数据结构而闻名。不同于磁盘数据库,磁盘数据库将数据读取到文件中维护,而内存数据库将数据存储在内存中,意味着其想要维护数据,必须在代码中维护一个保存数据的结构,而redis由c语言编写,对应的其一定是通过结构体来保存数据的结构。

redisDb结构体

在redis源码中,每个redisDb结构体代表着一个数据库,结构体大致如下

typedef struct redisDb {
    dict *dict;                 
    dict *expires;              
    dict *blocking_keys;        
    dict *ready_keys;           
    dict *watched_keys;         
    int id;                     
    long long avg_ttl;          
    unsigned long expires_cursor; 
} redisDb;

让我们来一个一个解释其意义

dict:

数据字典,其中保存了所有存入的数据,在redis中没有表的概念,数据作为键值对存储,直接存入数据库中,以hash表的结构存储,我在讲解redis中五个基本数据类型中详细讲解了hash表的结构,想了解可以看我的这篇文章Redis五种数据类型,底层存储数据结构,以及相关命令。

expire:

这也是一个数据字典,不同的是,其存储的是key和其对应的过期时间(时间戳)。将过期时间单独存储,有利于redis便利key查找过期key(有的key不设过期时间,单独存储可以防止便利这些没有过期时间的key)

blocking_keys:

这仍然是一个数据字典,其中保存的是正在阻塞等待中的key,比如说一个客户端对一个list数据使用了blpop命令,但list没有数据,此时客户端就会进入阻塞状态,等待list插入数据,当多个客户端都对一个空的list使用blpop命令,那么则需要一个结构来维护他们的先后关系,blocking_keys的作用就是维护阻塞key和等待其数据的客户端的先后关系。

ready_keys:

这也是一个数据字典,当blocking_keys中维护的key有新数据插入时(每次插入数据都会检查是否包含在blocking_keys中),会讲对应的key放入ready_keys中,等待当前事件循环中的插入数据操作完成后,在便利ready_key获取key,并且根据这个key在block_keys和dict中获取客户端和值并且发送(高并发情况下,一次会有大量的插入操作,先执行完当前事件循环的插入操作,并且放入ready_keys中,插入操作完成后再统一返回给客户端)。当使用publish发布订阅消息时,订阅消息也会放入ready_keys中,与blpop不同的是,所有订阅这个消息的客户端都会收到这个消息,没有先后顺序一分,所以不需要维护客户端的先后关系,也就不需要进入block_keys。

watched_keys:

当我们使用redis开启一个事务时,我们需要先确定这个事务依赖于哪些key,然后通过watch key1 key2 ... 的命令来监控这些key,那么当前这个事务就会作为这些key的value被保存在watched_keys中,当对key进行修改操作时,会去查看watch_keys中是否有这个key,如果有,则将key对应的全部事务进行取消。并且便利watched_keys将其他key中保存的当前事务删除。

id:

唯一id,没什么好说的。

avg_ttl:

保存expire中保存的过期时间的平均值,每当平均时间改变时都要重新计算一次。

expires_cursor:

当前便利位置的游标,redis内存淘汰过程中需要便利检查key是否过期,不过大量的key一次性遍历势必会造成程序卡顿,为了防止这种情况,在周期性模式下,一次性会检查一部分key,然后保存当前位置作为游标,下次检查时会接着游标的位置继续遍历。

结构体示意图如下

redisObject

我们在redisDB结构体的中dict数据字典中保存的都是key和数据,而数据的结构则是redisObject,同redisDB一样,redisObject也是一个结构体,代码如下

typedef struct redisObject {
    unsigned type:4;         
    unsigned encoding:4;         
    unsigned lru:LRU_BITS;   
    int refcount;            
    void *ptr;               
};

type:

对象类型,也就是redis五大基本数据类型以及两个高级数据类型(bitmap和hyperloglog底层是string类型,而geo底层是zset类型),其中包括REDIS_STRING,REDIS_LIST,REDIS_SET,REDIS_ZSET,REDIS_HASH,REDIS_MODULE,REDIS_STREAM​​​​​​​

encoding:

编码方式,简单来说redis基本数据类型的保存也要精心设计来提高其内部属性的操作性能,因为一个基本数据类型内部也保存了大量的元素或键值对,而编码方式就是某个类型用了什么样的数据结构来保存其内部的键值对或元素,其中包括SDS,整数列表,压缩列表,双向链表,快速列表,hash表,跳表。想了解更多可以看我的另一个文章Redis五种数据类型,底层存储数据结构,以及相关命令​​​​​​​

lru:

LFU策略

在 LFU 内存淘汰策略下,lru 字段表示键的访问频率,但并不是记录具体的访问次数。Redis 使用一种近似算法来计算访问频率,以节省内存并仍然能够体现出键的访问频率。具体操作如下:

访问频率计算:
  • Redis 使用 LFU 算法时,lru 字段存储的是一个代表访问频率大小的整数(并不是访问次数)。
  • 每次访问键时,Redis 会根据一个公式来决定是否增加该计数器的值。这个公式是 1 / (lru现在的值 * lfu_log_factor + 1),其中 lfu_log_factor是用于控制lru增涨速度的系数,默认为 10。
  • 根据这个公式计算出的概率值,再生成一个 0 到 1 之间的随机数,如果随机数小于这个概率值,则增加 lru 的值。

通过这种方式,随着lru的增大公式计算的值就会越来愈小,生成随机数小于这个概率值的概率就会越来越小,增加就会越来愈慢,以达到反应当前key的访问频率,并且节省内存的目的。

减少频率:
  • 每过一段时间,Redis 会减小 lru 字段的值,默认是每分钟减小一次。这确保了即使频繁访问过的键,如果长时间不再被访问,其频率计数也会逐渐减少。

LRU 策略

在 LRU 内存淘汰策略下,lru 字段记录的是键的最近访问时间的时间戳。Redis 使用一个 24 位的时间戳来表示键的最近访问时间。具体操作如下:

访问时间记录:
  • 每次访问键时,Redis 会更新该键的 lru 字段,记录当前的时间戳。
淘汰策略:
  • 当内存达到上限,需要淘汰键时,Redis 会选择那些 lru 字段值最小(即最久未被访问)的键进行淘汰。

refcount:

引用计数,用于内存管理。当引用计数为 0 时,表示没有任何地方引用该对象,内存可以被回收。

ptr:

指向实际数据值的指针。实际数据的类型和结构取决于 typeencoding 字段的值。比如说如果是string类型,那么就可以指向一个SDS结构体的对象,如果是hash类型,有可能会指向一个hash表等等。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【eNSP模拟实验】STP生成树查询及根桥设置

STP协议的解释和作用 STP协议(Spanning Tree Protocol):生成树协议。是一种工作在OSI网络模型中的第二层(数据链路层)的通信协议,基本应用是防止交换机冗余链路产生的环路。用于确保以太网中无环路的逻辑拓扑结构,从而…

【算法训练记录——Day45】

Day45——动态规划Ⅶ 1.leetcode19_打家劫舍2.leetcode213_打家劫舍Ⅱ3.leetcode337_打家劫舍Ⅲ 1.leetcode19_打家劫舍 思路:我的理解是不能出现连续两次偷窃,即 要么今晚不偷 dp[i] dp[i-1]; 要么今晚开干! dp[i] dp[i-2] nums[i]; 怎么…

NVM 安装node报错 Could not retrieve https://nodejs.org/dist/latest/SHASUMS256.txt.

报错内容: Could not retrieve https://nodejs.org/dist/latest/SHASUMS256.txt. 解决这个办法需要修改nvm的淘宝镜像 在nvm的目录下编辑settings.txt 将下面内容: node_mirror:npm.taobao.org/mirrors/node/ npm_mirror:npm.taobao.org/mirrors/npm/…

酷柚易汛ERP再次迎来升级,八月重拳出击!

1、修复调拨单批量导入下载模版错误 2、修复添加门店选择地址详情报错 3、修复采购清单 关联其他支出单 跳转 之后审核 原采购清单 关联其他支出单消失问题 4、修复以销订购 填了了采购数量 仍然提示请填写本次采购数量问题 5、修复应付款/收款明细表 单据编号是 核销单/其他…

Linux第八节 - make / mikefile

一、补充与复习 Linux在运行可执行程序的时候,有两种运行方式: ./mytest (表示当前路径下的可执行程序 - 用/分隔开) /home/shy/108/lesson8/mytest (也可以运行程序,但是是在绝对路径下!&…

图观 | 嬴图GraphRAG在博物馆文物馆藏中的应用探讨

图数据库技术是AI走向强人工智能的必经之路和重器!因为图数据库(含知识图谱)最大限度还原(模拟)了人的思维和思考方式。 —— 摘自孙宇熙《图数据库原理、架构与应用》 前言: 博物馆文物馆藏管理和观众服务…

基于内地城市生活垃圾收运场景的路线规划算法

基于混合遗传算法和模拟退火算法的优化垃圾收集路线规划 摘要 本论文提出了一种基于混合遗传算法(GA)和模拟退火算法(SA)的创新路线规划方法,旨在优化内地城市的生活垃圾收集效率。算法结合了遗传算法的全局搜索能力…

中证500etf期权合约一手多少钱?

中证500etf期权合约一手需要的资金取决于多个因素,比如做一手需要几十块钱到几百块钱不等,不过买卖中证500etf期权合约一手多少钱,也是包括期权的执行价格、权利金、保证金要求等。下文为大家介绍中证500etf期权合约一手多少钱?本…

.\venv\Scripts\activate : 无法加载文件 E:\,因为在此系统上禁止运行脚本。

问题描述: 问题原因: Windows PowerShell 的执行策略用于控制脚本的运行权限和安全性。 以下是几种常见的执行策略及其特点: AllSigned:只允许运行经过数字签名的脚本。这意味着无论是本地创建的还是从网络获取的脚本&#xff0…

如何设计一个高性能的分布式系统?

本文讨论的主题是高性能,主要思路是围绕快展开,这么设计为什么会快? 文章目录 架构设计:微服务架构负载均衡数据一致性方案选择容错处理:双机互备消息队列缓存总结 架构设计:微服务架构 第一个设计是应用…

“再来一单“业务功能开发

文章目录 概要整体架构流程技术细节小结 概要 再来一单”功能常见于餐饮、零售、外卖等行业,主要目的是为了简化用户的重复购买流程,提高用户体验和效率。 需求分析以及接口设计 再来一单就是将原订单中的商品重新加入到购物车中,所以本质上是"增…

人工智能助力芯片半导体发展,开拓芯片设计技术新趋势

微型硅片上可以容纳多少个晶体管?这些晶体管是构成世界各地技术的集成电路(IC)的基础。1971年,第一款微处理器集成有2,300个晶体管,而如今的硅片上却超过了1000亿个晶体管。在摩尔定律失效之前,每两年晶体管…

10、billu-b0x2

难度 中 目标 root权限 首先确定靶机ip地址 netdiscover -i eth0 -r 192.168.189.0/24 kali 192.168.189.58 靶机 192.168.189.184 信息收集端口扫描 看到一个80和8080,先重点摸一下网站的内容 然后看到信息里有个robots.txt 首先就去访问一下 看到有许多不允许…

高频JMeter软件测试面试题

近期,有很多粉丝在催更关于Jmeter的面试题,索性抽空整理了一波,以下是一些高频JMeter面试题,拿走不谢~ 一、JMeter的工作原理 JMeter就像一群将请求发送到目标服务器的用户一样,它收集来自目标服务器的响应以及其他统计…

传统产品经理VS现在AI产品经理,你要学习的太多了,超详细收藏我这一篇就够了

传统产品经理想要转行成为AI产品经理,需要经历一系列的学习和实践过程。下面是一份详细的学习路线图,旨在帮助你顺利转型。 学习路线图 了解AI基础知识 AI概览:阅读《人工智能:一种现代的方法》这样的书籍,以获得对AI…

初谈Linux多线程--线程控制

文章目录 线程的概述理解线程Linux中的线程重新理解的进程Windows的线程线程的优点线程的缺点理解线程调度成本低 进程VS线程 线程控制创建线程等待线程线程函数传参线程的返回值新线程的返回值新线程返回值错误返回值为类对象 创建多线程线程的终止线程的分离pthread_detach 线…

AIExpo2024奖项申报正式启动,三大奖项为你闪耀

由新一代人工智能产业技术创新战略联盟、苏州市人工智能协同创新中心联合主办,苏州启智创新科技有限公司、苏州工业园区科技发展有限公司共同承办的第六届全球人工智能产品应用博览会(以下简称“智博会”)将于2024年9月11-12日在苏州国际博览…

二叉搜索树,Map,Set,LeetCode刷题

二叉搜索树&#xff0c;Map&#xff0c;Set 1. 二叉搜索树2. 二叉搜索树的模拟实现1.1 插入操作1.2 查找操作1.3 删除操作 3. 二叉搜索树时间复杂度分析4. TreeMap和TreeSet5. Map5.1 Map的常用方法5.2 Map.Entry<K,V> 6. Set6.1 Set的常用方法 LeetCode刷题1. 二叉搜索树…

Total Eclipse 挑战赛:在以太坊首个 SVM L2 上开发应用

摘要&#xff1a;Eclipse 基金会宣布了其首届黑客马拉松计划&#xff0c;即"The Total Eclipse Challenge"&#xff0c;作为一场独一无二的黑客松活动 &#xff0c;邀请了优秀的开发者们在链上开发创新的应用。 "The Total Eclipse 挑战赛" 是一项为期两周…

如何更好地做出判断?

笛卡尔有句名言&#xff1a;无法下判断的人&#xff0c;不是欲望太奢侈&#xff0c;就是觉悟还不够。 这里说的判断&#xff0c;其实也就是选择。我们人生面临着各种维度的选择&#xff0c;大到人生方向&#xff0c;小到一顿饭吃什么&#xff0c;可以说&#xff0c;选择伴随着我…