Redis源码---整体架构

news2024/11/15 15:31:29

目录

前言

Redis目录结构

前言

deps目录

src 目录

tests 目录

utils 目录

重要的配置文件

Redis 功能模块与源码对应

前言

服务器实例

数据库数据类型与操作

高可靠性和高可扩展性

辅助功能


  • 前言

  • 以先面后点的方法推进
  • 无特殊说明,都是基于 Redis 5.0.8 版本的
  • 掌握了 Redis 代码的整体架构,就相当于给 Redis 代码画了张全景图
  • 有了这张图,再去学习 Redis 不同功能模块的设计与实现时,就可以从图上快速查找和定位这些功能模块对应的代码文件
  • 而且,有了代码的全景图之后,还可以对 Redis 各方面的功能特性有个全面了解,这样也便于更加全面地掌握 Redis 的功能,而不会遗漏某一特性
  • 学习 Redis 的代码架构要掌握以下两方面内容:
    • 1--代码的目录结构和作用划分
    • 目的是理解 Redis 代码的整体架构,以及所包含的代码功能类别;
    • 2--系统功能模块与对应代码文件,目的是了解 Redis 实例提供的各项功能及其相应的实现文件,以便后续深入学习
  • Redis目录结构

  • 前言

  • 对于 Redis 来说,在它的源码总目录下
  • 一共包含了deps、src、tests、utils四个子目录
  • 这四个子目录分别对应了 Redis 中发挥不同作用的代码
  • deps目录

  • 这个目录主要包含了 Redis 依赖的第三方代码库
  • 包括
    • Redis 的 C 语言版本客户端代码hiredis
    • jemalloc 内存分配器代码
    • readline 功能的替代代码 linenoise
    • lua 脚本代码
  • 这部分代码的一个显著特点,就是它们可以独立于 Redis src 目录下的功能源码进行编译
  • 也就是说,它们可以独立于 Redis 存在和发展
  • 下面这张图显示了 deps 目录下的子目录内容:

  • 那么,为什么在 Redis 源码结构中会有第三方代码库目录呢?
  • 其实主要有两方面的原因:
  • 一方面
    • Redis 作为一个用 C 语言写的用户态程序,它的不少功能是依赖于标准的 glibc 库提供的
    • 比如内存分配、行读写(readline)、文件读写、子进程/线程创建等
    • 但是,glibc库提供的某些功能实现,效率并不高
    • 例子:glibc 库中实现的内存分配器的性能就不是很高,它的内存碎片化情况也比较严重
    • 因此为了避免对系统性能产生影响,Redis 使用了 jemalloc 库替换了 glibc 库的内存分配器
    • 可是,jemalloc 库本身又不属于 Redis 系统自身的功能,把它和 Redis 功能源码放在一个目录下并不合适
    • 所以,Redis 使用了专门的 deps 目录来保存这部分代码
  • 另一方面
    • 有些功能是 Redis 运行所需要的
    • 但是这部分功能又会独立于 Redis 进行开发和演进
    • 这种类型最为典型的功能代码,就是 Redis 的客户端代码
    • Redis 作为 Client-Server 架构的系统,访问 Redis 离不开客户端的支撑
    • 此外,Redis 自身功能中的命令行 redis-cli、基准测试程序 redis-benchmark 以及哨兵,都需要用到客户端来访问 Redis 实例
    • 不过针对客户端的开发,只要保证客户端和实例交互的过程满足 RESP 协议就行
    • 客户端和实例的功能可以各自迭代演进
    • 所以在 Redis 源码结构中,C 语言版本的客户端hiredis,就被放到了 deps 目录中,以便开发人员自行开发和改进客户端功能
    • 总而言之,对于 deps 目录来说
    • 只需要记住它主要存放了三类代码:
      • 一是 Redis 依赖的、实现更加高效的功能库,如内存分配
      • 二是独立于 Redis 开发演进的代码,如客户端
      • 三是 lua 脚本代码
  • src 目录

  • 这个目录里面包含了 Redis 所有功能模块的代码文件,也是 Redis 源码的重要组成部分
  • 同样,先来看下 src 目录下的子目录结构:
  • 可以发现,src 目录下只有一个 modules 子目录,其中包含了一个实现 Redis module 的示例代码
  • 剩余的源码文件都是在 src 目录下,没有再分下一级子目录
  • 因为 Redis 的功能模块实现是典型的 C 语言风格,不同功能模块之间不再设置目录分隔
  • 而是通过头文件包含来相互调用
  • 这样的代码风格在基于 C 语言开发的系统软件中,也比较常见,比如 Memcached 的源码文件也是在同一级目录下
  • 所以,当使用 C 语言来开发软件系统时,就可以参考 Redis 的功能源码结构,用一个扁平的目录组织所有的源码文件,这样模块相互间的引用也会很方便
  • tests 目录

  • 在软件产品的开发过程中,除了第三方依赖库和功能模块源码以外,通常还需要在系统源码中,添加用于功能模块测试和单元测试的代码
  • 而在 Redis 的代码目录中,就将这部分代码用一个 tests 目录统一管理了起来
  • Redis 实现的测试代码可以分成四部分,分别是
    • 单元测试(对应 unit 子目录)
    • Redis Cluster 功能测试(对应 cluster 子目录)
    • 哨兵功能测试(对应 sentinel 子目录)
    • 主从复制功能测试(对应 integration 子目录)
  • 这些子目录中的测试代码使用了 Tcl 语言(通用的脚本语言)进行编写,主要目的就是方便进行测试
  • 另外,每一部分的测试都是一个测试集合,覆盖了相应功能模块中的多项子功能测试
  • 比如:
    • 在单元测试的目录中,可以看到有针对过期 key 的测试(expire.tcl)、惰性删除的测试(lazyfree.tcl),以及不同数据类型操作的测试(type 子目录)等
    • 而在 Redis Cluster 功能测试的目录中,可以看到有针对故障切换的测试(failover.tcl)、副本迁移的测试(replica-migration.tcl)等
  • 不过在 tests 目录中,除了有针对特定功能模块的测试代码外,还有一些代码是用来支撑测试功能的
  • 这些代码在 assets、helpers、modules、support 四个目录中
  • 这里有张图,展示了 tests 目录下的代码结构和层次:

  • utils 目录

  • 在 Redis 开发过程中,还有一些功能属于辅助性功能,包括用于创建 Redis Cluster 的脚本、用于测试 LRU 算法效果的程序,以及可视化 rehash 过程的程序
  • 在 Redis 代码结构中,这些功能代码都被归类到了 utils 目录中统一管理
  • 下图展示了 utils 目录下的主要子目录:

  • 重要的配置文件

  • 除了 deps、src、tests、utils 四个子目录以外,Redis 源码总目录下其实还包含了两个重要的配置文件,一个是 Redis 实例的配置文件 redis.conf,另一个是哨兵的配置文件sentinel.conf
  • 当需要查找或修改 Redis 实例或哨兵的配置时,就可以直接定位到源码总目录下
  • Redis 功能模块与源码对应

  • 前言

  • Redis 代码结构中的 src 目录,包含了实现功能模块的 123 个代码文件
  • 在这 123 个代码文件中,对于某个功能来说,一般包括了实现该功能的 C 语言文件(.c 文件)和对应的头文件(.h 文件)
  • 比如,dict.c 和 dict.h 就是用于实现哈希表的 C 文件和头文件
  • 那么,该如何将这 123 个文件和 Redis 的主要功能对应上呢?
  • 其实,Redis 代码文件的命名非常规范,文件名中就体现了该文件实现的主要功能
  • 比如,对于 rdb.h 和 rdb.c 这两个代码文件来说,从文件名上,就可以看出来它们是实现内存快照RDB 的对应代码
  • 所以这里,为了能快速定位源码,就分别按照 Redis 的服务器实例、数据库操作、可靠性和可扩展性保证、辅助功能四个维度,把 Redis 功能源码梳理成了四条代码路径
  • 服务器实例

  • Redis 在运行时是一个网络服务器实例,因此相应地就需要有代码实现服务器实例的初始化和主体控制流程
  • 而这是由 server.h/server.c 实现的,Redis 整个代码的 main入口函数也是在 server.c 中
  • 如果想了解 Redis 是如何开始运行的,那么就可以从server.c 的 main 函数开始看起
  • 当然,对于一个网络服务器来说,它还需要提供网络通信功能
  • Redis 使用了基于事件驱动机制的网络通信框架,涉及的代码文件包括 ae.h/ae.c,ae_epoll.c,ae_evport.c,ae_kqueue.c,ae_select.c
  • 关于事件驱动框架的具体设计思路与实现方法,后续会详细介绍
  • 而除了事件驱动网络框架以外,与网络通信相关的功能还包括底层 TCP 网络通信和客户端实现
  • Redis 对 TCP 网络通信的 Socket 连接、设置等操作进行了封装,这些封装后的函数实现在anet.h/anet.c 中
  • 这些函数在 Redis Cluster 创建和主从复制的过程中,会被调用并用于建立 TCP 连接
  • 除此之外,客户端在 Redis 的运行过程中也会被广泛使用,比如实例返回读取的数据、主从复制时在主从库间传输数据、Redis Cluster 的切片实例通信等,都会用到客户端
  • Redis 将客户端的创建、消息回复等功能,实现在了 networking.c 文件中,如果想了解客户端的设计与实现,可以重点看下这个代码文件
  • 这里也总结了与服务器实例相关的功能模块及对应的代码文件:
  • 数据库数据类型与操作

  • Redis 数据库提供了丰富的键值对类型,其中包括了 String、List、Hash、Set 和 Sorted Set这五种基本键值类型
  • 此外,Redis 还支持位图、HyperLogLog、Geo 等扩展数据类型
  • 而为了支持这些数据类型,Redis 就使用了多种数据结构来作为这些类型的底层结构
  • 比如,String 类型的底层数据结构是 SDS,而 Hash 类型的底层数据结构包括哈希表和压缩列表
  • 不过,因为 Redis 实现的底层数据结构非常多,所以这里把这些底层结构和它们对应的键值对类型,以及相应的代码文件列在了下表中,可以用这张表来快速定位代码文件:

  • 除了实现了诸多的数据类型以外,Redis 作为数据库,还实现了对键值对的新增、查询、修改和删除等操作接口,这部分功能是在 db.c 文件实现的
  • 当然,Redis 作为内存数据库,其保存的数据量受限于内存大小
  • 因此,内存的高效使用对于Redis 来说就非常重要
  • Redis 是如何优化内存使用的呢?
  • 实际上,Redis 是从三个方面来优化内存使用的,分别是内存分配、内存回收,以及数据替换
  • 首先,在内存分配方面,Redis 支持使用不同的内存分配器,包括 glibc 库提供的默认分配器tcmalloc、第三方库提供的 jemalloc
  • Redis 把对内存分配器的封装实现在了zmalloc.h/zmalloc.c
  • 其次,在内存回收上,Redis 支持设置过期 key,并针对过期 key 可以使用不同删除策略,这部分代码实现在 expire.c 文件中
  • 同时,为了避免大量 key 删除回收内存,会对系统性能产生影响,Redis 在 lazyfree.c 中实现了异步删除的功能
  • 所以这样,就可以使用后台 IO线程来完成删除,以避免对 Redis 主线程的影响
  • 最后,针对数据替换,如果内存满了,Redis 还会按照一定规则清除不需要的数据,这也是Redis 可以作为缓存使用的原因
  • Redis 实现的数据替换策略有很多种,包括 LRU、LFU 等经典算法
  • 这部分的代码实现在了 evict.c 中
  • 同样,这里也把和 Redis 数据库数据类型与操作相关的功能模块及代码文件,总结成了一张图:

  • 高可靠性和高可扩展性

  • 首先,虽然 Redis 一般是作为内存数据库来使用的,但是它也提供了可靠性保证
  • 这主要体现在 Redis 可以对数据做持久化保存,并且它还实现了主从复制机制,从而可以提供故障恢复的功能
  • 这部分的代码实现比较集中,主要包括以下两个部分:
    • 1--数据持久化实现
      • Redis 的数据持久化实现有两种方式:内存快照 RDB 和 AOF 日志,分别实现在了rdb.h/rdb.c 和 aof.c 中
      • 注意,在使用 RDB 或 AOF 对数据库进行恢复时,RDB 和 AOF 文件可能会因为 Redis 实例所在服务器宕机,而未能完整保存,进而会影响到数据库恢复
      • 因此针对这一问题,Redis 还实现了对这两类文件的检查功能,对应的代码文件分别是 redis-check-rdb.c 和 redis-check-aof.c
    • 2--主从复制功能实现
      • Redis 把主从复制功能实现在了 replication.c 文件中
      • 另外还需要知道的是,Redis 的主从集群在进行恢复时,主要是依赖于哨兵机制,而这部分功能则直接实现在了 sentinel.c 文件中
      • 其次,与 Redis 实现高可靠性保证的功能类似,Redis 高可扩展性保证的功能,是通过 Redis Cluster 来实现的,这部分代码也非常集中,就是在 cluster.h/cluster.c 代码文件中
      • 所以这样在学习 Redis Cluster 的设计与实现时,就会非常方便,不用在不同的文件之间来回跳转了
  • 辅助功能

  • Redis 还实现了一些用于支持系统运维的辅助功能
  • 比如,为了便于运维人员查看分析不同操作的延迟产生来源,Redis 在latency.h/latency.c 中实现了操作延迟监控的功能
  • 为了便于运维人员查找运行过慢的操作命令,Redis 在 slowlog.h/slowlog.c 中实现了慢命令的记录功能,等等
  • 此外,运维人员有时还需要了解 Redis 的性能表现,为了支持这一目标,Redis 实现了对系统进行性能评测的功能,这部分代码在 redis-benchmark.c 中

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

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

相关文章

AI Codec,视频模板技术,高效视频处理,RTC+AI,感知编码,CV-CUDA,窄带高清AI...

AI Codec,NPU硬件加速Topic《基于AI和NPU的Codec变革》孔德辉 中兴微电子 多媒体技术总监伴随通信容量(包括5G以及千兆有线网络)的发展,高带宽为更多用户接入超高清视频提供了可能。但是随着用户数量的增加,高质量的压…

排序基础之选择排序法

目录 前言 一、什么是选择排序 二、实现选择排序 三、使用泛型扩展 四、使用自定义类型测试 前言 今天天气不错,这么好的天气不干点啥实在是有点可惜了,于是乎,拿出键盘撸一把! 来,今天来学习一下排序算法中的选…

港科夜闻|全国政协副主席梁振英先生率香港媒体高管团到访香港科大(广州)...

关注并星标每周阅读港科夜闻建立新视野 开启新思维1、全国政协副主席梁振英先生率香港媒体高管团到访香港科大(广州)。2月21日下午,在全国政协副主席、广州南沙粤港合作咨询委员会顾问梁振英先生的带领下,香港20余家媒体的高管及知名媒体人士到访香港科大…

电脑技巧:分享8个Win11系统必备小技巧

目录 1、让任务栏显示“右键菜单” 2、任务栏置顶 3、还原经典右键菜单 4、Win11版任务管理器 5、新版AltTab 6、开始菜单不再卡 7、为Edge浏览器添加云母效果 8、自动切换日/夜模式 Win11在很多地方都做了调整,但由于涉及到诸多旧有习惯,再加上…

SRE中 的SLO,SLI等知识 归纳

SLA Service Level Agreement 服务质量/水平协议SLO Service Level Objective 服务质量/水平目标SLI Services Level Indicator 服务质量/水平指标下面用人、事、物的逻辑进行阐释。人和事用从上到下,从左到右的顺序。客户 - 每 1 个客户在使用产品服务时&…

gin 框架初始教程

一 、gin 入门1. 安装gin :下载并安装 gin包:$ go get -u github.com/gin-gonic/gin2. 将 gin 引入到代码中:import "github.com/gin-gonic/gin"3.初始化项目go mod init gin4.完整代码package mainimport "github.com/gin-go…

JavaSE10-循环语句(for、while、do...while)

文章目录一、for循环1.格式2.执行流程二、while循环1.格式三、do...while循环1.格式四、循环控制(break、continue)1.break2.continue五、案例1.请输出下列的形状2.打印99乘法表一、for循环 1.格式 初始化语句只有在最开始的时候执行了一次如果第一次进行条件判断的时候结果为…

测试开发 | 视频编辑SDK测试

短视频编辑SDK测试有一段时间了,因此抽时间对编辑SDK的相关内容进行简要复盘。 功能说明 短视频编辑SDK支持gif,不同格式的图片,视频文件的拼接导入,编辑,添加特效,合成导出等功能。更具体的介绍可以参照…

Elasticsearch:如何轻松安全地对实时 Elasticsearch 索引重新索引你的数据

在很多的时候,由于一些需求,我们不得不修改索引的映射,也即 mapping,这个时候我们需要重新索引(reindex)来把之前的数据索引到新的索引中。槽糕的是,我们的这个索引还在不断地收集实时数据&…

Python3-数字

Python3 数字(Number) Python 数字数据类型用于存储数值。 数据类型是不允许改变的,这就意味着如果改变数字数据类型的值,将重新分配内存空间。 Python 支持三种不同的数值类型: 整型(int) - 通常被称为是整型或整数,是正或负整数&#x…

8.Spring Security 权限控制

1.简介入门JavaEE和SpringMVC :Spring Security就是通过11个Fliter进行组合管理小Demouser实体类user.type字段,0普通用户,1超级管理员,2版主补全get set tostringimplement UserDetails,重写以下方法// true: 账号未过…

_improve-2

-------------------- 左边定宽,右边自适应方案 float margin,float calc /* 方案1 */ .left {width: 120px;float: left; } .right {margin-left: 120px; } /* 方案2 */ .left {width: 120px;float: left; } .right {width: calc(100% - 120px);fl…

【深度学习】线性回归、逻辑回归、二分类,多分类等基础知识总结

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言1. 线性回归2、逻辑回归3. 单层神经元的缺陷&多层感知机softmax 多分类前言 入行深度学习快2年了,是时间好好总结下基础知识了.现在看可能很多结论和刚学的…

SystemVerilog-时序逻辑建模(5)多个时钟和时钟域交叉

数字硬件建模SystemVerilog-时序逻辑建模(5)多个时钟和时钟域交叉数字门级电路可分为两大类:组合逻辑和时序逻辑。锁存器是组合逻辑和时序逻辑的一个交叉点,在后面会作为单独的主题处理。组合逻辑描述了门级电路,其中逻…

办公室人员离岗识别检测系统 yolov7

办公室人员离岗识别检测系统根据yolov7网络模型深度学习技术,办公室人员离岗识别检测算法能够7*24小时全天候自动识别人员是否在岗位。YOLOv7 在 5 FPS 到 160 FPS 范围内,速度和精度都超过了所有已知的目标检测器,并在V100 上,30…

2023/2/26 Vue学习笔记 配置代理解决跨域[CORS ]的问题

利用vue的脚手架巧妙的解决ajax跨域的问题 1 我们首先利用springboot服务搭建 注意这里引出了跨域[CORS ]的问题: Access to XMLHttpRequest at http://localhost:5000/getUserInfo from origin http://localhost:8080 has been blocked by CORS policy: No Access-Control-A…

【Java】Spring Boot 2 集成 nacos

【Java】Spring Boot 2 集成 nacos 官方文档&#xff1a;https://nacos.io/zh-cn/docs/quick-start-spring-boot.html pom 本次Springboot版本 2.2.6.RELEASE&#xff0c;nacos-config 版本 0.2.7&#xff0c;nacos-discovery版本 0.2.7 parent <parent><groupId&…

带你深层了解c语言指针

前言 &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f; c语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:介绍c语言中有关指针更深层的知识. 金句分享: ✨今天…

麻省理工学院,Web3 人才辈出

2 月 22 日&#xff0c;NFT 交易平台 Blur 创始人公开身份&#xff0c;曾就读于麻省理工学院计算机系。除了 NFT 交易平台&#xff0c;在公链、交易所、VC、媒体、Layer2 等 Web3 和 Crypto 的多个赛道&#xff0c;麻省理工学院&#xff08;MIT&#xff09;的毕业生和教授们均有…

HDMI协议介绍(二)--DataIsland Packets

前言 前文简单介绍了HDMI传输的三个周期&#xff1a;控制周期、DataIsland周期和Video周期。DataIsland传输音频和辅助数据&#xff0c;这些数据以Packet的形式传输。本文简单介绍DataIsland Packet。 目录 前言 数据岛概述 数据岛包的构造 Packet Header Paket Body Dat…