Redis核心架构

一、核心模块如图 

图1-10

  • Client 客户端,官方提供了 C 语言开发的客户端,可以发送命令,性能分析和测试等。
  • 网络层事件驱动模型,基于 I/O 多路复用,封装了一个短小精悍的高性能 ae 库,全称是 a simple event-driven programming library
    • 在 ae 这个库里面,我通过 aeApiState 结构体对 epoll、select、kqueue、evport四种 I/O 多路复用的实现进行适配,让上层调用方感知不到在不同操作系统实现 I/O 多路复用的差异。
    • Redis 中的事件可以分两大类:一类是网络连接、读、写事件;另一类是时间事件,比如定时执行 rehash 、RDB 内存快照生成,过期键值对清理操作。
  • 命令解析和执行层,负责执行客户端的各种命令,比如 SET、DEL、GET等。
  • 内存分配和回收,为数据分配内存,提供不同的数据结构保存数据。
  • 持久化层,提供了 RDB 内存快照文件 和 AOF 两种持久化策略,实现数据可靠性。
  • 高可用模块,提供了副本、哨兵、集群实现高可用。
  • 监控与统计,提供了一些监控工具和性能分析工具,比如监控内存使用、基准测试、内存碎片、bigkey 统计、慢指令查询等。

二、数据存储原理

        在掌握存储原理之前,先看一下全局架构图,后边慢慢分析他们的作用。

        如图 是由 redisDb、dict、dictEntry、redisObejct 关系图:

图1-11

1.redisServer

        每个被启动的服务我都会抽象成一个 redisServer,源码定在server.hredisServer 结构体。结构体字段很多,不再一一列举,部分核心字段如下。

truct redisServer {pid_t pid;  /* 主进程 pid. */pthread_t main_thread_id; /* 主线程 id */char *configfile;  /*redis.conf 文件绝对路径*/redisDb *db; /* 存储键值对数据的 redisDb 实例 */int dbnum;  /* DB 个数 */dict *commands; /* 当前实例能处理的命令表,key 是命令名,value 是执行命令的入口 */aeEventLoop *el;/* 事件循环处理 */int sentinel_mode;  /* true 则表示作为哨兵实例启动 *//* 网络相关 */int port;/* TCP 监听端口 */list *clients; /* 连接当前实例的客户端列表 */list *clients_to_close; /* 待关闭的客户端列表 */client *current_client; /* 当前执行命令的客户端*/
};

        这个结构体包含了存储键值对的数据库实例、redis.conf 文件路径、命令列表、加载的 Modules、网络监听、客户端列表、RDB AOF 加载信息、配置信息、RDB 持久化、主从复制、客户端缓存、数据结构压缩、pub/sub、Cluster、哨兵等一系列 Redis 实例运行的必要信息。

        接下来我们分别看下他们之间的关系和作用。

2.redisDb

        其中redisDb *db指针非常重要,它指向了一个长度为 dbnum(默认 16)的 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;list *defrag_later;clusterSlotToKeyMapping *slots_to_keys;
} redisDb;

        dict 和 expires

  • dict 和 expires 是最重要的两个属性,底层数据结构是字典,分别用于存储键值对数据和 key 的过期时间。
  • expires,底层数据结构是 dict 字典,存储每个 key 的过期时间。

3.dict

        Redis 使用 dict 结构来保存所有的键值对(key-value)数据,这是一个散列表,所以 key 查询时间复杂度是 O(1) 。

struct dict {dictType *type;dictEntry **ht_table[2];unsigned long ht_used[2];long rehashidx;int16_t pauserehash;signed char ht_size_exp[2];
};

dict 的结构体里,有 dictType *type**ht_table[2]long rehashidx 三个很重要的结构。

  • type 存储了 hash 函数,key 和 value 的复制等函数;
  • ht_table[2],长度为 2 的数组,默认使用 ht_table[0] 存储键值对数据。我会使用 ht_table[1] 来配合实现渐进式 reahsh 操作。
  • rehashidx 是一个整数值,用于标记是否正在执行 rehash 操作,-1 表示没有进行 rehash。如果正在执行 rehash,那么其值表示当前 rehash 操作执行的 ht_table[1] 中的 dictEntry 数组的索引。

        重点关注 ht_table 数组,数组每个位置叫做哈希桶,就是这玩意保存了所有键值对,每个哈希桶的类型是 dictEntry。

MySQL:“Redis 支持那么多的数据类型,哈希桶咋保存?”

        他的玄机就在 dictEntry 中,每个 dict 有两个 ht_table,用于存储键值对数据和实现渐进式 rehash。

typedef struct dictEntry {void *key;union {// 指向实际 value 的指针void *val;uint64_t u64;int64_t s64;double d;} v;// 散列表冲突生成的链表struct dictEntry *next;void *metadata[];
} dictEntry;
  • *key 指向键值对的键的指针,指向一个 sds 对象,key 都是 string 类型。
  • v 是键值对的 value 值,是个 union(联合体),当它的值是 uint64_t、int64_t 或 double 数字类型时,就不再需要额外的存储,这有利于减少内存碎片。(为了节省内存操碎了心)当值为非数字类型,就是用 val 指针存储。
  • *next指向另一个 dictEntry 结构, 多个 dictEntry 可以通过 next 指针串连成链表, 从这里可以看出, ht_table 使用链地址法来处理键碰撞:当多个不同的键拥有相同的哈希值时,哈希表用一个链表将这些键连接起来。

4.redisObject

        dictEntry*val 指针指向的值实际上是一个 redisObject 结构体,这是一个非常重要的结构体。

        我的 key 是字符串类型,而 value 可以是 String、Lists、Set、Sorted Set、Hashes 等数据类型。

        键值对的值都被包装成 redisObject 对象, redisObjectserver.h 中定义。

typedef struct redisObject {unsigned type:4;unsigned encoding:4;unsigned lru:LRU_BITS;int refcount;void *ptr;
} robj;
  • type:记录了对象的类型,string、set、hash 、Lis、Sorted Set 等,根据该类型来确定是哪种数据类型,这样我才知道该使用什么指令执行嘛。
  • encoding:编码方式,表示 ptr 指向的数据类型具体数据结构,即这个对象使用了什么数据结构作为底层实现保存数据。同一个对象使用不同编码内存占用存在明显差异,节省内存,这玩意功不可没。
  • lru:LRU_BITS:LRU 策略下对象最后一次被访问的时间,如果是 LFU 策略,那么低 8 位表示访问频率,高 16 位表示访问时间。
  • refcount :表示引用计数,由于 C 语言并不具备内存回收功能,所以 Redis 在自己的对象系统中添加了这个属性,当一个对象的引用计数为 0 时,则表示该对象已经不被任何对象引用,则可以进行垃圾回收了。
  • ptr 指针:指向值的指针,对象的底层实现数据结构。

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

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

相关文章

Python爬虫大师课:HTTP协议深度解析与工业级请求封装

Python爬虫大师课:HTTP协议深度解析与工业级请求封装 从零构建企业级爬虫框架(附完整源码) 一、爬虫基础:网络世界的通行证 ​​HTTP协议核心数据​​: 全球网站数量:20亿 HTTP请求占比:83% …

机器学习——PCA(主成分分析)降维

PCA(主成分分析)降维详解一、什么是 PCAPCA(Principal Component Analysis,主成分分析)是一种常用的数据降维方法。它通过线性变换将原始的高维数据映射到低维空间,同时尽可能保留原数据的主要信息&#xf…

把 AI 装进“冰箱贴”——基于超低功耗语音合成的小屏电子价签

标签:电子价签、语音合成、TTS、超低功耗、电子墨水、BLE、离线语音 ---- 1. 背景:价签也要开口说话? 超市做促销,顾客拿价签一扫,“今日番茄 2.99 元/斤,会员再享 9 折” 直接语音播放。 硬件限制&#xf…

挖漏洞是什么意思?挖漏洞赚钱入门到精通,收藏这篇就够了!

挖漏洞是什么意思?挖漏洞赚钱入门到精通,收藏这篇就够了! 什么是漏洞挖掘 漏洞挖掘是指通过分析软件、系统或网络中存在的安全漏洞来发现并利用这些漏洞。漏洞挖掘是信息安全领域的一项重要工作,可以帮助企业和组织提高系统的安…

如何理解AP中SM中宿主进程?

在AUTOSAR Adaptive Platform(AP)中,状态管理(State Management, SM)的宿主进程(Host Process) 是实现状态机运行的核心载体,其本质与运作机制可通过以下结构化解析深入理解&#xf…

无人机光电探测模块技术分析

一、技术要点1. 多光谱成像技术 可见光与红外融合:白天依赖可见光高分辨率成像(识别外形、颜色),夜间或低光照条件下切换至红外热成像(捕捉0.5℃级温差),通过双波段互补提升全天候能力。 激光…

第40周——GAN入门

目录 目录 目录 前言 一、定义超参数 二、下载数据 三、配置数据 四、定义鉴别器 五、训练模型并保存 总结 前言 🍨 本文为🔗365天深度学习训练营中的学习记录博客🍖 原作者:K同学啊 一、定义超参数 import argparse import os i…

Nginx性能优化与安全配置:打造高性能Web服务器

系列文章索引: 第一篇:《Nginx入门与安装详解:从零开始搭建高性能Web服务器》第二篇:《Nginx基础配置详解:nginx.conf核心配置与虚拟主机实战》第三篇:《Nginx代理配置详解:正向代理与反向代理…

二分算法(模板)

例题1: 704. 二分查找 - 力扣(LeetCode) 算法原理:(二分) 通过遍历也可以通过,但是二分更优且数据量越大越能体现。 二分思路: 1.mid1 (left right)/2 与 mid2 right (right …

VUE3 学习笔记2 computed、watch、生命周期、hooks、其他组合式API

computed 计算属性在vue3中,虽然也能写vue2的computed,但还是更推荐使用vue3语法的computed。在Vue3中,计算属性是组合式API,要想使用computed,需要先对computed进行引入:import { computed } from vuecomp…

【java面试day13】mysql-定位慢查询

文章目录问题💬 Question 1相关知识问题 💬 Question 1 Q:这条sql语句执行很慢,你如何分析呢? A:当一条 SQL 执行较慢时,可以先使用 EXPLAIN 查看执行计划,通过 key 和 key_len 判…

3分钟解锁网页“硬盘“能力:离线运行VSCode的新一代Web存储技术

Hi,我是前端人类学(之前叫布兰妮甜)! “这不是浏览器,这是装了个硬盘。” —— 用户对现代Web应用能力的惊叹 随着Origin Private File System和IndexedDB Stream等新技术的出现,Web应用现在可以在用户的设…

LT6911GXD,HD-DVI2.1/DP1.4a/Type-C 转 Dual-port MIPI/LVDS with Audio 带音频

简介LT6911GXD是一款高性能HD-DVI2.1/DP1.4a/Type-c转Dual-port MIPI/LVDS芯片,兼容 HDMI2.1、HDMI2.0b、HDMI1.4、DVI1.0、DisplayPort 1.4a、eDP1.4b 等多种视频接口标准。支持4K(38402160)60Hz的DSC直通。应用场景AR/VR设备LT6911GXD 支持高达 4K(384…

【100页PPT】数字化转型某著名企业集团信息化顶层规划方案(附下载方式)

篇幅所限,本文只提供部分资料内容,完整资料请看下面链接 https://download.csdn.net/download/2501_92808811/91662628 资料解读:数字化转型某著名企业集团信息化顶层规划方案 详细资料请看本解读文章的最后内容 作为企业数字化转型领域的…

高精度标准钢卷尺优质厂家、选购建议

高精度标准钢卷尺的优质厂家通常具备精湛工艺与权威精度认证等特征,能为产品质量提供保障。其选购需兼顾精度标识、使用场景、结构细节等多方面,具体介绍如下:一、高精度标准钢卷尺优质厂家**1、河南普天同创:**PTTC-C5标准钢卷尺…

38 C++ STL模板库7-迭代器

C STL模板库7-迭代器 文章目录C STL模板库7-迭代器一、迭代器的核心作用二、迭代器的五大分类与操作三、关键用法与代码示例1. 迭代器的原理2. 迭代器用法与示例3. 迭代工具用法示例4. 使用技巧迭代器是C中连接容器与算法的通用接口,提供了一种访问容器元素的统一方…

【0基础3ds Max】学习计划

3ds Max 作为一款功能强大的专业 3D 计算机图形软件,在影视动画、游戏开发、建筑可视化、产品设计和工业设计等众多领域有着广泛的应用。 目录前言一、第一阶段:基础认知(第 1 - 2 周)​二、第二阶段:建模技术学习&…

用 Enigma Virtual Box 将 Qt 程序打包成单 exe

上一篇介绍了用windeployqt生成可运行的多文件程序,但一堆文件分发起来不够方便。有没有办法将所有文件合并成一个 exe? 答案是肯定的 用Enigma Virtual Box工具就能实现。本文就来讲解如何用它将 Qt 多文件程序打包为单一 exe,让分发更轻松。 其中的 一定要选 第二个 一…

【LeetCode 热题 100】45. 跳跃游戏 II

Problem: 45. 跳跃游戏 II 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说&#xff0c;如果你在索引 i 处&#xff0c;你可以跳转到任意 (i j) 处&#xff1a; 0 < j < nums[i] 且 i j &…

池式管理之线程池

1.初识线程池问&#xff1a;线程池是什么&#xff1f;答&#xff1a;维持管理一定数量的线程的池式结构。&#xff08;维持&#xff1a;线程复用 。 管理&#xff1a;没有收到任务的线程处于阻塞休眠状态不参与cpu调度 。一定数量&#xff1a;数量太多的线程会给操作系统带来线…