Redis设计与实现之服务器与客户端

目录

一、服务器与客户端

1、初始化服务器

1. 初始化服务器全局状态

2. 载入配置文件

3. 创建 daemon 进程

4. 初始化服务器功能模块

5. 载入数据

6. 开始事件循环

2、 客户端连接到服务器

3、命令的请求、处理和结果返回

4、命令请求实例:SET 的执行过程

5、Redis服务器是否已运行特定的复制或集群配置?

二、小结


一、服务器与客户端

前面的章节介绍了所有 Redis 的重要功能组件:数据结构、数据类型、事务、Lua 环境、事件 处理、数据库、持久化,等等,但是我们还没有对 Redis 服务器本身做任何介绍。

不过,服务器本身并没有多少需要介绍的新东西,因为服务器除了维持服务器状态之外,最重 要的就是将前面介绍过的各个功能模块组合起来,而这些功能模块在前面的章节里已经介绍过 了,所以本章将焦点放在服务器的初始化过程,以及服务器对命令的处理过程上。

本章首先介绍服务器的初始化操作,观察一个 Redis 服务器从启动到可以接受客户端连接,需要经过什么步骤。 然后介绍客户端是如何连接到服务器的,而服务器又是如何维持多个客户端的不同状态的。 文章最后将介绍命令从发送到处理的整个过程,并列举了一个 SET 命令的执行过程作为例子。

1、初始化服务器

从启动 Redis 服务器,到服务器可以接受外来客户端的网络连接这段时间,Redis 需要执行一系列初始化操作。 整个初始化过程可以分为以下六个步骤:

1. 初始化服务器全局状态。

2. 载入配置文件。
3. 创建 daemon 进程。
4. 初始化服务器功能模块。

5. 载入数据。

6. 开始事件循环。
以下各个小节将介绍 Redis 服务器初始化的各个步骤。

1. 初始化服务器全局状态

redis.h/redisServer 结构记录了和服务器相关的所有数据,这个结构主要包含以下信息:

  • 服务器中的所有数据库。

  • 命令表:在执行命令时,根据字符来查找相应命令的实现函数。

  • 事件状态。

  • 服务器的网络连接信息:套接字地址、端口,以及套接字描述符。

  • 所有已连接客户端的信息。

  • Lua 脚本的运行环境及相关选项。

  • 实现订阅与发布(pub/sub)功能所需的数据结构。

  • 日志(log)和慢查询日志(slowlog)的选项和相关信息。

  • 数据持久化(AOF 和 RDB)的配置和状态。

  • 服务器配置选项:比如要创建多少个数据库,是否将服务器进程作为 daemon 进程来运 行,最大连接多少个客户端,压缩结构(zip structure)的实体数量,等等。

  • 统计信息:比如键有多少次命令、不命中,服务器的运行时间,内存占用,等等。
    Note: 为了简洁起见,上面只列出了单机情况下的 Redis 服务器信息,不包含 SENTINEL 、

    MONITOR 、CLUSTER 等功能的信息。
    在这一步,程序创建一个 redisServer 结构的实例变量 server 用作服务器的全局状态,并将

    server 的各个属性初始化为默认值。

当 server 变量的初始化完成之后,程序进入服务器初始化的下一步:读入配置文件。

2. 载入配置文件

在初始化服务器的上一步中,程序为 server 变量(也即是服务器状态)的各个属性设置了默认值,但这些默认值有时候并不是最合适的:
• 用户可能想使用 AOF 持久化,而不是默认的 RDB 持久化。
• 用户可能想用其他端口来运行 Redis ,以避免端口冲突。
• 用户可能不想使用默认的 16 个数据库,而是分配更多或更少数量的数据库。

• 用户可能想对默认的内存限制措施和回收策略做调整。

等等。

为了让使用者按自己的要求配置服务器,Redis 允许用户在运行服务器时,提供相应的配置文 件(config file)或者显式的选项(option),Redis 在初始化完 server 变量之后,会读入配置 文件和选项,然后根据这些配置来对 server 变量的属性值做相应的修改:

  1. 如果单纯执行 redis-server 命令,那么服务器以默认的配置来运行 Redis 。

  2. 另一方面,如果给 Redis 服务器送入一个配置文件,那么 Redis 将按配置文件的设置来更新服务器的状态。比如说,通过命令 redis-server /etc/my-redis.conf ,Redis 会根据 my-redis.conf 文件的内容来对服务器状态做相应的修改。

  3. 除此之外,还可以显式地给服务器传入选项,直接修改服务器配置。 举个例子,通过命令 redis-server --port 10086 ,可以让 Redis 服务器端口变更为10086 。

  4. 当然,同时使用配置文件和显式选项也是可以的,如果文件和选项有冲突的地方,那么优 先使用选项所指定的配置值。 举个例子,如果运行命令 redis-server /etc/my-redis.conf --port 10086 ,并且 my-redis.conf 也指定了 port 选项,那么服务器将优先使用 --port 10086 (实际上是 选项指定的值覆盖了配置文件中的值)。

3. 创建 daemon 进程

Redis 默认以 daemon 进程的方式运行。当服务器初始化进行到这一步时,程序将创建 daemon 进程来运行 Redis ,并创建相应的 pid 文件。

4. 初始化服务器功能模块

在这一步,初始化程序完成两件事:
• 为server变量的数据结构子属性分配内存。 • 初始化这些数据结构。为数据结构分配内存,并初始化这些数据结构,等同于对相应的功能进行初始化。比如说,当为订阅与发布所需的链表分配内存之后,订阅与发布功能就处于就绪状态,随时可 以为 Redis 所用了。在这一步,程序完成的主要动作如下: • 初始化 Redis 进程的信号功能。 • 初始化日志功能。
• 初始化客户端功能。

• 初始化共享对象。
• 初始化事件功能。
• 初始化数据库。
• 初始化网络连接。
• 初始化订阅与发布功能。
• 初始化各个统计变量。
• 关联服务器常规操作(cron job)到时间事件,关联客户端应答处理器到文件事件。

• 如果 AOF 功能已打开,那么打开或创建 AOF 文件。

• 设置内存限制。
• 初始化 Lua 脚本环境。 • 初始化慢查询功能。
• 初始化后台操作线程。

完成这一步之后,服务器打印出 Redis 的 ASCII LOGO 、服务器版本等信息,表示所有功能 模块已经就绪,可以等待被使用了:

虽然所有功能已经就绪,但这时服务器的数据库还是一片空白,程序还需要将服务器上一次执 行时记录的数据载入到当前服务器中,服务器的初始化才算真正完成。

5. 载入数据

在这一步,程序需要将持久化在 RDB 或者 AOF 文件里的数据,载入到服务器进程里面。

如果服务器有启用 AOF 功能的话,那么使用 AOF 文件来还原数据;否则,程序使用 RDB 文 件来还原数据。当执行完这一步时,服务器打印出一段载入完成信息:

[6717] 22 Feb 11:59:14.830 * DB loaded from disk: 0.068 seconds

6. 开始事件循环

到了这一步,服务器的初始化已经完成,程序打开事件循环,开始接受客户端连接。 以下是服务器在这一步打印的信息:

[6717] 22 Feb 11:59:14.830 * The server is now ready to accept connections on port 6379

 以下是初始化完成之后,服务器状态和各个模块之间的关系图:

 

2、 客户端连接到服务器

当 Redis 服务器完成初始化之后,它就准备好可以接受外来客户端的连接了。 当一个客户端通过套接字函数 connect 到服务器时,服务器执行以下步骤:

1. 服务器通过文件事件无阻塞地accept客户端连接,并返回一个套接字描述符fd。

  1. 服务器为fd创建一个对应的redis.h/redisClient结构实例,并将该实例加入到服务 器的已连接客户端的链表中。

  2. 服务器在事件处理器为该fd关联读文件事件。

完成这三步之后,服务器就可以等待客户端发来命令请求了。
Redis 以多路复用的方式来处理多个客户端,为了让多个客户端之间独立分开、不互相干扰,

服务器为每个已连接客户端维持一个 redisClient 结构,从而单独保存该客户端的状态信息。 redisClient 结构主要包含以下信息:

  • 套接字描述符。

  • 客户端正在使用的数据库指针和数据库号码。

  • 客户端的查询缓存(query buffer)和回复缓存(reply buffer)。

  • 一个指向命令函数的指针,以及字符串形式的命令、命令参数和命令个数,这些属性会在 命令执行时使用。

  • 客户端状态:记录了客户端是否处于 SLAVE 、MONITOR 或者事务状态。

  • 实现事务功能(比如 MULTI 和 WATCH)所需的数据结构。

  • 实现阻塞功能(比如 BLPOP 和 BRPOPLPUSH)所需的数据结构。

  • 实现订阅与发布功能(比如 PUBLISH 和 SUBSCRIBE)所需的数据结构。

  • 统计数据和选项:客户端创建的时间,客户端和服务器最后交互的时间,缓存的大小,等 等。

    Note: 为了简洁起见,上面列出的客户端结构信息不包含复制(replication)的相关属性。

3、命令的请求、处理和结果返回

 当客户端连上服务器之后,客户端就可以向服务器发送命令请求了。 从客户端发送命令请求,到命令被服务器处理、并将结果返回客户端,整个过程有以下步骤:

  1. 客户端通过套接字向服务器传送命令协议数据。

  2. 服务器通过读事件来处理传入数据,并将数据保存在客户端对应redisClient结构的查询缓存中。

  3. 根据客户端查询缓存中的内容,程序从命令表中查找相应命令的实现函数。

  4. 程序执行命令的实现函数,修改服务器的全局状态server变量,并将命令的执行结果保 存到客户端 redisClient 结构的回复缓存中,然后为该客户端的 fd 关联写事件。

  5. 当客户端fd的写事件就绪时,将回复缓存中的命令结果传回给客户端。至此,命令执行 完毕。

4、命令请求实例:SET 的执行过程

为了更直观地理解命令执行的整个过程,我们用一个实际执行 SET 命令的例子来讲解命令执行的过程。

假设现在客户端 C1 是连接到服务器 S 的一个客户端,当用户执行命令 SET YEAR 2013 时,客 户端调用写入函数,将协议内容 *3\r\n$3\r\nSET\r\n$4\r\nYEAR\r\n$4\r\n2013\r\n" 写 入连接到服务器的套接字中。

当 S 的文件事件处理器执行时,它会察觉到 C1 所对应的读事件已经就绪,于是它将协议文本 读入,并保存在查询缓存。

通过对查询缓存进行分析(parse),服务器在命令表中查找 SET 字符串所对应的命令实现函数, 最终定位到 t_string.c/setCommand 函数,另外,两个命令参数 YEAR 和 2013 也会以字符串 的形式保存在客户端结构中。

接着,程序将客户端、要执行的命令、命令参数等送入命令执行器:执行器调用 setCommand 函数,将数据库中 YEAR 键的值修改为 2013 ,然后将命令的执行结果保存在客户端的回复缓存 中,并为客户端 fd 关联写事件,用于将结果回写给客户端。

因为 YEAR 键的修改,其他和数据库命名空间相关程序,比如 AOF 、REPLICATION 还有事 务安全性检查(是否修改了被 WATCH 监视的键?)也会被触发,当这些后续程序也执行完毕之 后,命令执行器退出,服务器其他程序(比如时间事件处理器)继续运行。

当 C1 对应的写事件就绪时,程序就会将保存在客户端结构回复缓存中的数据回写给客户端, 当客户端接收到数据之后,它就将结果打印出来,显示给用户看。

以上就是 SET YEAR 2013 命令执行的整个过程。

5、Redis服务器是否已运行特定的复制或集群配置?

要确定Redis服务器是否已运行特定的复制或集群配置,可以使用以下命令之一:

  1. 对于复制:

    redis-cli info replication
    

    此命令将返回Redis服务器的复制信息。如果服务器配置为主服务器,则会显示主服务器的连接信息和从服务器的数量。如果服务器配置为从服务器,则会显示其连接到的主服务器信息。

  2. 对于集群:

    redis-cli cluster info
    

    此命令将返回Redis集群的信息。如果服务器正在运行一个集群,则会显示集群的状态和节点信息。

请注意,这些命令需要Redis客户端(如redis-cli)与Redis服务器建立连接才能运行。

二、小结

  • 服务器经过初始化之后,才能开始接受命令。
  • 服务器初始化可以分为六个步骤:

        1. 初始化服务器全局状态。

        2. 载入配置文件。

        3. 创建 daemon 进程。
        4. 初始化服务器功能模块。

        5. 载入数据。

        6. 开始事件循环。

  • 服务器为每个已连接的客户端维持一个客户端结构,这个结构保存了这个客户端的所有

    状态信息。

  • 客户端向服务器发送命令,服务器接受命令然后将命令传给命令执行器,执行器执行给 定命令的实现函数,执行完成之后,将结果保存在缓存,最后回传给客户端。

 

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

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

相关文章

数据仓库【1】:简介

数据仓库【1】:简介 1、诞生背景1.1、数据仓库诞生原因1.2、历史数据积存1.3、企业数据分析需要 2、基本概述2.1、数据仓库(Data Warehouse,DW)2.2、数据仓库特点2.3、数据仓库 VS 数据库 3、技术实现3.1、数据仓库建设方案3.2、传…

sql_lab之sqli中的搜索型注入

搜索型注入 原理是运用模糊查询: select * from users where username like %a% 1.找到具有模糊查询的搜索框的注入点 2.构造闭合 因为模糊查询的代码是 select * from users where username like %a% 所以应该 鱼%’ -- s 判断构造闭合的函数是否正确 鱼%…

【JavaEE初阶一】线程的概念与简单创建

1. 认识线程(Thread) 1.1 关于线程 1.1.1 线程是什么 由前一节的内容可知,进程在进行频繁的创建和销毁的时候,开销比较大(主要体现在资源的申请和释放上),线程就是为了解决上述产生的问题而提…

apache禁止遍历目录

禁止Apache显示目录索引,禁止Apache显示目录结构列表,禁止Apache浏览目录,这是网上提问比较多的,其实都是一个意思。下面说下禁止禁止Apache显示目录索引的常见的3种方法。 要实现禁止Apache显示目录索引,只需将 Optio…

Jenkins的特殊操作定时自动执行任务以及测试报告调优

java -Dhudson.model.DirectoryBrowserSupport.CSP -jar Jenkins.war 测试报告 不美丽 执行上面的代码 重启jenkins 就好了

Ai企业系统源码 Ai企联系统源码 商用去授权 支持文心 星火 GPT4等等20多种接口

智思Ai系统2.4.9版本去授权(可商用)支持市面上所有版本的接口例如:文心、星火、GPT4等等20多种接口!代过审AI小程序类目!!! 安装步骤: 1、在宝塔新建个站点,php版本使用…

使用pytorch神经网络拟合计算模型

一. 内容简介 python调用百度翻译api,将中文论文翻译英文,并保留部分格式 二. 软件环境 2.1vsCode 2.2Anaconda version: conda 22.9.0 2.3数据文件 链接:https://pan.baidu.com/s/1csJOoErGyx77MW_FImVKjg?pwd1234 三.主要流程 3.…

铁山靠之——HarmonyOS组件 - 2.0

HarmonyOS学习第二章 一、HarmonyOS基础组件的使用1.1 组件介绍1.2 Text1.2.1 文本样式1.2.2 设置文本对齐方式1.2.3 设置文本超长显示1.2.4 设置文本装饰线 1.3 Image1.3.1 设置缩放类型1.3.2 加载网络图片 1.4 TextInput1.4.1 设置输入提示文本1.4.2 设置输入类型1.4.3 设置光…

王道考研计算机网络——数据链路层

码元和信号变化是一一对应的 低通:低于最高频率的可以通过 奈氏准则无噪声,香农定理有噪声 给出db,利用公式求出S/N 放到数字信道上传输就是基带信号,放到模拟信道上传输就是宽带信号 把基带信号调制成宽带信号之后,…

JSON在Java中的使用

目录 第一章、快速了解JSON1.1)JSON是什么1.2)json的语法格式①键值对、字符串、数字、布尔值、数组、对象②嵌套的格式 1.3)为什么使用JSON 第二章、发送和接收JSON格式数据2.1)postman发送JSON格式数据2.2)Java后端接…

【csapp】cachelab

文章目录 Part APart B32 * 3264 * 6461 * 67 实验全程参考大佬的博客CS:APP3e 深入理解计算机系统_3e CacheLab实验 ,感觉大佬在矩阵转置那块介绍的还是有些简略,我自己又做了点动图加以补充理解。膜拜大佬! Part A 先解决解析命令行参数的…

STM32实战之深入理解I²C通信协议

目录 IC的物理层 IC的协议层 IC特点 IC 总线时序图 软件模拟IC时序分享 例程简介 例程分享 STM32的IC外设 IIC(Inter-Integrated Circuit),也称为IC或TWI(Two-Wire Interface),是一种广泛使用的串行…

MyBatis——MyBatis的缓存

MyBatis的缓存 创建工程: 1缓存介绍 为什么使用缓存? 首次访问时,查询数据库,并将数据存储到内存中;再次访问时直接访问缓存,减少IO、硬盘读写次数、提高效率 Mybatis中的一级缓存和二级缓存?…

【SD】通过种子数 差异强度 进行 角色融合【2】

通过 对 2个种子 进行对比 生成 2张图片 风格相符合的图片 best quality,masterpiece,chibi,full body, 我们首先生成1张图 Seed: 726932558 我们再次生成一张图 Seed: 3824894478 随机种子:图一 随机种子:图二 差异强度:0.2 差异强度0.4 差…

31. Ajax

简介 AJAX 是 Asynchronous JavaScript And XML 的简称。直译为,异步的JS和XML。AJAX的实际意义是,不发生页面跳转、异步载入内容并改写页面内容的技术。AJAX也可以简单的理解为通过JS向服务器发送请求。 AJAX这门技术很早就被发明,但是直到…

前端框架前置学习(4) AJAX

同步代码和异步代码 同步代码 浏览器按照我们书写代码的顺序一行一行地执行程序.浏览器会等待代码的解析和工作,在上一行代码完成之后才会执行下一行代码.这被称之为同步程序 逐行执行,需要原地等待结果 异步代码 异步编码技术使得程序可以在执行一个可能长期运行的任务的…

助力打造清洁环境,基于轻量级YOLOv8开发构建公共场景下垃圾堆放垃圾桶溢出检测识别系统

公共社区环境生活垃圾基本上是我们每个人每天几乎都无法避免的一个问题,公共环境下垃圾投放点都会有固定的值班时间,但是考虑到实际扔垃圾的无规律性,往往会出现在无人值守的时段内垃圾堆放垃圾桶溢出等问题,有些容易扩散的垃圾比…

将elementUI,NaiveUI的progress环形进度条设置为渐变色

需求 :进度条要有一个渐变效果。效果图: NaiveUI和elementUI的官方progress组件都是只能设置一种颜色,不符合需求所以改一下。 其实NaiveUI和elementUI设置进度条的实现方式基本一样都是使用svg渲染出两个path,第一个是底色&…

<meta name=“Keywords“ content=““ >、<meta name=“Description“ content=““ > 等用法解释

今天在看网站代码&#xff0c;发现类似<meta name"Keywords" content"" >、<meta name"Description" content"" >这样的写法&#xff0c;不知道具体代表什么意思&#xff0c;于是上网搜了一下&#xff0c;下面是在网上找到…

Python电能质量扰动信号分类(三)基于Transformer的一维信号分类模型

目录 引言 1 数据集制作与加载 1.1 导入数据 1.2 制作数据集 2 Transformer分类模型和超参数选取 2.1 定义Transformer分类模型 2.2 定义模型参数 3 Transformer模型训练与评估 3.1 模型训练 3.2 模型评估 代码、数据如下&#xff1a; 往期精彩内容&#xff1a; 电…