【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 文件事件处理部分)

article/2025/6/23 17:17:02

分析客户端和服务端网络诵信交互实现

  • 【专栏简介】
    • 【技术大纲】
    • 【专栏目标】
    • 【目标人群】
      • 1. Redis爱好者与社区成员
      • 2. 后端开发和系统架构师
      • 3. 计算机专业的本科生及研究生
  • 命令请求的执行过程
    • 案例分析介绍
      • 发送命令请求
      • 读取命令请求
      • 客户端状态的argv属性和argc属性
      • 命令执行器
        • 第一步:命令表-查找命令实现
          • sflags属性的标识
          • 案例分析
            • SET命令
            • GET命令
            • 设置客户端状态的cmd指针
        • 第二步:命令表-执行预备操作
        • 第三步:命令表-调用命令的实现函数
          • 保存了命令回复的客户端状态
        • 第四步:执行后续工作
        • 第五步:将命令回复发送给客户端
        • 第六步:客户端接收并打印命令回复

【专栏简介】

随着数据需求的迅猛增长,持久化和数据查询技术的重要性日益凸显。关系型数据库已不再是唯一选择,数据的处理方式正变得日益多样化。在众多新兴的解决方案与工具中,Redis凭借其独特的优势脱颖而出。

【技术大纲】

为何Redis备受瞩目?原因在于其学习曲线平缓,短时间内便能对Redis有初步了解。同时,Redis在处理特定问题时展现出卓越的通用性,专注于其擅长的领域。深入了解Redis后,您将能够明确哪些任务适合由Redis承担,哪些则不适宜。这一经验对开发人员来说是一笔宝贵的财富。
在这里插入图片描述

在这个专栏中,我们将专注于Redis的6.2版本进行深入分析和介绍。Redis 6.2不仅是我个人特别偏爱的一个版本,而且在实际应用中也被广泛认为是稳定性和性能表现都相当出色的版本

【专栏目标】

本专栏深入浅出地传授Redis的基础知识,旨在助力读者掌握其核心概念与技能。深入剖析了Redis的大多数功能以及全部多机功能的实现原理,详细展示了这些功能的核心数据结构和关键算法思想。读者将能够快速且有效地理解Redis的内部构造和运作机制,这些知识将助力读者更好地运用Redis,提升其使用效率。

将聚焦于Redis的五大数据结构,深入剖析各种数据建模方法,并分享关键的管理细节与调试技巧。

【目标人群】

Redis技术进阶之路专栏:目标人群与受众对象,对于希望深入了解Redis实现原理底层细节的人群

1. Redis爱好者与社区成员

Redis技术有浓厚兴趣,经常参与社区讨论,希望深入研究Redis内部机制、性能优化和扩展性的读者。

2. 后端开发和系统架构师

在日常工作中经常使用Redis作为数据存储和缓存工具,他们在项目中需要利用Redis进行数据存储、缓存、消息队列等操作时,此专栏将为他们提供有力的技术支撑。

3. 计算机专业的本科生及研究生

对于学习计算机科学、软件工程、数据分析等相关专业的在校学生,以及对Redis技术感兴趣的教育工作者,此专栏可以作为他们的学习资料和教学参考。

无论是初学者还是资深专家,无论是从业者还是学生,只要对Redis技术感兴趣并希望深入了解其原理和实践,都是此专栏的目标人群和受众对象

让我们携手踏上学习Redis的旅程,探索其无尽的可能性!


命令请求的执行过程

Redis服务器承担着多项关键职责,它要与众多客户端构建网络连接,对客户端传来的命令请求予以处理。在数据库层面,它负责存储客户端执行命令时所生成的数据,同时借助资源管理手段保障自身的稳定运转。

案例分析介绍

一个命令请求从发送到获得回复的过程中,客户端和服务器需要完成一系列操作。举个例子,如果我们使用客户端执行以下命令:

redis> SET KEY VALUE
OK

那么从客户端发送SET KEY VALUE命令到获得回复OK期间,客户端和服务器共需要执行以下操作:
在这里插入图片描述

  1. 客户端向服务器发送命令请求SET KEY VALUE
  2. 服务器接收并处理客户端发来的命令请求SET KEY VALUE,在数据库中进行设置操作,并产生命令回复OK
  3. 服务器将命令回复OK发送给客户端
  4. 客户端接收服务器返回的命令回复OK

发送命令请求

Redis服务器的命令请求来自Redis客户端,当用户在客户端中键人一个命令请求时,客户端会将这个命令请求转换成协议格式,然后通过连接到服务器的套接字,将协议格式的命令请求发送给服务器。

举个例子,假设用户在客户端键人了命令:
在这里插入图片描述

SET KEY VALUE

那么客户端会将这个命令转换成协议:

*3\r\ns3\r\nsET\r\ns3\r\nKEY\r\ns5\r\nVALUE\r\n

然后将这段协议内容发送给服务器

读取命令请求

当客户端与服务器之间的连接套接字因为客户端的写入而变得可读时,服务器将调用命令请求处理器来执行以下操作:

  1. 读取套接字中协议格式的命令请求,并将其保存到客户端状态的输入缓冲区里面。
  2. 对输人缓冲区中的命令请求进行分析,提取出命令请求。
    • 命令参数
    • 参数个数
    • 参数和参数个数保存到客户端状态的argv属性和argc属性里面
  3. 调用命令执行器,执行客户端指定的命令

继续用上一个小节的SET命令为例子,下图展示了程序将命令请求保存到客户端状态的输人缓冲区之后,客户端状态的样子。
在这里插入图片描述
之后,分析程序将对输入缓冲区中的协议进行分析:*3\r\ns3\r\nsET\r\ns3\r\nKEY\r\ns5\r\nVALUE\r\n,并将得出的分析结果保存到客户端状态的argv属性和argc属性里面。

客户端状态的argv属性和argc属性

在这里插入图片描述
服务器将通过调用命令执行器来完成执行命令所需的余下步骤,以下将分别介绍命令执行器所执行的工作。

命令执行器

命令执行器要做的第一件事就是根据客户端状态的argv[0]参数,在命令表(command table)中查找参数所指定的命令,并将找到的命令保存到客户端状态的cmd属性里面。
在这里插入图片描述

第一步:命令表-查找命令实现

命令表本质上是一个字典,该字典的键为具体的命令名称,例如 “set”“get”“del” 等;而字典所对应的值是redisCommand结构

每个redisCommand结构会记录一个 Redis 命令的实现相关信息,下面展示了这个结构各个主要属性的类型以及它们所起到的作用。
在这里插入图片描述

sflags属性的标识

sflags属性可以使用的标识值,以及这些标识的意义

  • w:这是一个写人命令,可能会修改数据库SET、RPUSH、DEL等等
  • r:这是一个只读命令,不会修改数据库GET、STRLEN、EXISTS等等
  • m:这个命令可能会占用大量内存,执行之前需要先检查服务器的内存使用情况,如果内存紧缺的话就禁止执行这个命令SET、APPEND、RPUSH、LPUSH、SADD、
  • a:这是一个管理命令SAVE、BGSAVE、SHUTDOWN等等
  • P:这是一个发布与订阅功能方面的命令:PUBLISH、SUBSCRIBE、PUBSUB等等
  • s:这个命令不可以在Lua脚本中使用BRPOP、BLPOP、BRPOPLPUSH、SPOP等等
  • R:这是一个随机命令,对于相同的数据集和相同的参数,命令返回的结果可能不同SPOP、SRANDMEMBER、SSCAN、RANDOMKEY等等
  • S:当在Lua脚本中使用这个命令时,对这个命令的输出结果进行一次排序,使得命令的结果有序,SINTER、SUNION、SDIFF、SMEMBERS、KEYS等等
  • l:这个命令可以在服务器载人数据的过程中使用:INFO、SHUTDOWN、PUBLISH等等。
  • t:这是一个允许从服务器在带有过期数据时使用的命令:SLAVEOF、PNG、WFO等等。
  • M:这个命令在监视器(monitor)模式下不会自动被传播(propagate),EXEC
案例分析

SET命令和GET命令作为例子,展示了redisCommand结构。

SET命令

SET命令的名字为"set",实现函数为setCommand

  • 个数(arity):3命令接受三个或以上数量的参数
  • 标识(sflags):“wm”,表示SET命令是一个写人命令,并且在执行这个命令之前,服务器应该对占用内存状况进行检查,因为这个命令可能会占用大量内存。
GET命令

GET命令的名字为"get",实现函数为getCommand函数;

  • 个数(arity):2,表示命令只接受两个参数
  • 标识(sflags):“r”,表示这是一个只读命令
    在这里插入图片描述
设置客户端状态的cmd指针

SET命令的例子,当程序以argv[0]作为输人,在命令表中进行查找时,命令表将返回"set"键所对应的redisCommand结构,客户端状态的cmd指针会指向这个redisCommand结构。
在这里插入图片描述

第二步:命令表-执行预备操作

服务器已经将执行命令所需的命令实现函数:
在这里插入图片描述
但是在真正执行命令之前,程序还需要进行一些预备操作,从而确保命令可以正确、顺利地被执行,这些操作包括:

(尴尬,ProcessOn到期了,所以暂时就用了有水印的,后续会去除水印,哈哈)
在这里插入图片描述

  1. 检查客户端cmd指针是否为NULL,若是,表明命令未匹配实现,服务器终止后续操作并返回错误。
  2. 依据cmd指向的redisCommandarity属性,核查命令参数个数,不符则终止后续并返回错误,如arity为3,参数需≥3个。
  3. 检查客户端是否通过身份验证,未通过仅能执行AUTH命令,否则返回错误。
  4. 若开启maxmemory,执行命令前检查内存占用,必要时回收,失败则终止后续并返回错误。
  5. 客户端用SUBSCRIBEPSUBSCRIBE时,服务器仅执行SUBSCRIBEPSUBSCRIBEUNSUBSCRIBEPUNSUBSCRIBE,其他命令拒绝。
  6. 服务器数据载入时,客户端命令需带特定标识(如INFO等)才执行,否则拒绝。
  7. 服务器因Lua脚本超时阻塞,仅执行SHUTDOWN,nosaveSCRIPTKILL
  8. 客户端执行事务时,仅执行EXECDISCARDMULTIWATCH,其他入事务队列。
  9. 开启监视器功能,将命令及参数信息发送给监视器。完成预备操作后,服务器执行命令。
第三步:命令表-调用命令的实现函数

服务器已经将要执行命令的实现保存到了客户端状态的cmd属性里面,并将命令的参数对象参数个数分别保存到了客户端状态的argv属性和argc属性里面,当服务器决定要执行命令时,它只要执行以下语句就可以了:

// client是指向客户端状态的指针
client->cmd->proc(client);

因为,执行命令所需的实际参数都已经保存到客户端状态的argv属性里面了,所以命令的实现函数只需要一个指向客户端状态的指针作为参数即可,继续以之前的SET命令为例子,展示了客户端包含了命令实现、参数和参数个数的样子。

对于这个例子来说,执行语句:

client -> cmd -> proc(client) -> setCommand(client)

在这里插入图片描述
被调用的命令实现函数会执行指定的操作,并产生相应的命令回复,这些回复会被保存在客户端状态的输出缓冲区里面(buf属性和reply属性),之后实现函数还会为客户端的套接字关联命令回复处理器,这个处理器负责将命令回复返回给客户端。

保存了命令回复的客户端状态

在这里插入图片描述
对于前面SET命令的例子来说,函数调用setCommand(client)将产生一个"+OK\r\n”回复,这个回复会被保存到客户端状态的buf属性里面。

第四步:执行后续工作

在执行完实现函数之后,服务器还需要执行一些后续工作:
在这里插入图片描述

  1. 若开启慢查询日志功能,慢查询日志模块检查是否为刚执行命令请求添加新日志。
  2. 依据刚执行命令耗时,更新redisCommand结构的milliseconds属性,calls计数器加1。
  3. 若开启AOF持久化功能,AOF持久化模块将刚执行命令请求写入AOF缓冲区。
  4. 若有从服务器复制当前服务器,将刚执行命令传播给所有从服务器。

当以上操作都执行完了之后,服务器对于当前命令的执行到此就告一段落了,之后服务器就可以继续从文件事件处理器中取出并处理下一个命令请求了。

第五步:将命令回复发送给客户端

当客户端的套接字变为可写状态时,命令回复处理器会将协议格式的命令回复"+OK\r\n”发送给客户端。

  1. 命令执行处理器会将命令回复保存到客户端的输出缓冲区里面,并为客户端的套接字关联命令回复处理器,当客户端套接字变为可写状态时,服务器就会执行命令回复处理器,将保存在客户端输出缓冲区中的命令回复发送给客户端。
  2. 当命令回复发送完毕之后,回复处理器会清空客户端状态的输出缓冲区,为处理下一个命令请求做好准备。
第六步:客户端接收并打印命令回复

当客户端接收到协议格式的命令回复之后,它会将这些回复转换成人类可读的格式,并打印给用户查看
在这里插入图片描述
继续以之前的SET命令为例子,当客户端接到服务器发来的"+OK\r1n"协议回复时,它会将这个回复转换成"OK\n",然后打印给用户看:

redis>SET KEY VALUE
OK

以上就是Redis客户端和服务器执行命令请求的整个过程了。


http://www.hkcw.cn/article/JkWoFLuQNH.shtml

相关文章

第29次CCF计算机软件能力认证-3-LDAP

LDAP 刷新 时间限制: 10.0 秒 空间限制: 512 MiB 下载题目目录(样例文件) 题目背景 西西艾弗岛运营公司是一家负责维护和运营岛上基础设施的大型企业,拥有数千名员工。公司内有很多 IT 系统。 为了能够实现这些…

2025年- H63-Lc171--33.搜索旋转排序数组(2次二分查找,需二刷)--Java版

1.题目描述 2.思路 输入:旋转后的数组 nums,和一个整数 target 输出:target 在 nums 中的下标,如果不存在,返回 -1 限制:时间复杂度为 O(log n),所以不能用遍历,必须使用 二分查找…

HomeKit 基本理解

概括 HomeKit 将用户的家庭自动化信息存储在数据库中,该数据库由苹果的内置iOS家庭应用程序、支持HomeKit的应用程序和其他开发人员的应用程序共享。所有这些应用程序都使用HomeKit框架作为对等程序访问数据库. Home 只是相当于 HomeKit 的表现层,其他应用在实现 …

秒杀系统—5.第二版升级优化的技术文档三

大纲 8.秒杀系统的秒杀库存服务实现 9.秒杀系统的秒杀抢购服务实现 10.秒杀系统的秒杀下单服务实现 11.秒杀系统的页面渲染服务实现 12.秒杀系统的页面发布服务实现 8.秒杀系统的秒杀库存服务实现 (1)秒杀商品的库存在Redis中的结构 (2)库存分片并同步到Redis的实现 (3…

尚硅谷-尚庭公寓知识点

文章目录 尚庭公寓知识点1、转换器(Converter)2、全局异常3、定时任务1. 核心步骤(1) 启用定时任务(2) 创建定时任务 2. Scheduled 参数详解3. Cron 表达式语法4. 配置线程池(避免阻塞)5. 动态控制任务(高级用法)6. 注意事项 4、M…

字符串~~~

字符串~~ KMP例题1.无线传输2.删除字符串3.二叉树中的链表 AC自动机Manacher例题 扩展KMP字符串哈希 KMP (1) (2) (3) 经典例题 https://leetcode.cn/problems/find-the-index-of-the-first-occurre…

WEB3——简易NFT铸造平台之nft.storage

🧠 1. nft.storage 是什么? https://nft.storage 是 一个免费的去中心化存储平台,由 Filecoin 背后的 Protocol Labs 推出。 它的作用是: ✅ 接收用户上传的文件(图片、JSON 等) ✅ 把它们永久存储到 IPFS…

MCP架构全解析:从核心原理到企业级实践

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…

注销微软账户

若你需要注销微软账号,请点击下方超链接。 点击此处

华为OD机试真题——生成哈夫曼树(2025A卷:100分)Java/python/JavaScript/C/C++/GO六种最佳实现

2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 本文收录于专栏:《2025华为OD真题目录+全流程解析/备考攻略/经验分享》 华为OD机试真题《生成…

Python实现P-PSO优化算法优化BP神经网络分类模型项目实战

说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 随着人工智能技术的快速发展,神经网络在分类任务中展现了强大的性能。BP(Back Propagation&…

学习海康VisionMaster之表面缺陷滤波

一:进一步学习了 今天学习下VisionMaster中的表面缺陷滤波:简单、无纹理背景的表面缺陷检测,可以检测表面的异物,缺陷,划伤等 二:开始学习 1:什么表面缺陷滤波? 表面缺陷滤波的核心…

34.x64汇编写法(一)

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 上一个内容:33.第二阶段x64游戏实战-InLineHook 首先打开 Visual Studio,然后创…

Java网络编程实战:TCP/UDP Socket通信详解与高并发服务器设计

🔍 开发者资源导航 🔍🏷️ 博客主页: 个人主页📚 专栏订阅: JavaEE全栈专栏 内容: socket(套接字)TCP和UDP差别UDP编程方法使用简单服务器实现 TCP编程方法Socket和ServerSocket之间的关系使用简…

算法:滑动窗口

1.长度最小的子数组 209. 长度最小的子数组 - 力扣(LeetCode) 运用滑动窗口(同向双指针)来解决,因为这些数字全是正整数,在left位置确定的下,right这个总sum会越大,所以我们先让num…

AI笔记 - 网络模型 - mobileNet

网络模型 mobileNet mobileNet V1网络结构深度可分离卷积空间可分![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/aff06377feac40b787cfc882be7c6e5d.png) 参考 mobileNet V1 网络结构 MobileNetV1可以理解为VGG中的标准卷积层换成深度可分离卷积 可分离卷积主要有…

新中地三维GIS开发智慧城市效果和应用场景

近年来,随着科技的发展和城市化进程的加速,智慧城市成为了全球各大城市的一个重要发展方向。 在这一背景下,三维GIS技术以其独特的优势,成为构建智慧城市不可或缺的工具。新中地GIS开发特训营正是在这样的大环境下应运而生&#…

Linux笔记---线程

1. 线程的介绍 1.1 线程的概念 基本定义: 线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程(Process)之中(或者说是进程的一部分、对进程的划分),是进程中的实际…

Java数据结构之ArrayList(如果想知道Java中有关ArrayList的知识点,那么只看这一篇就足够了!)

前言:ArrayList是Java中最常用的动态数组实现之一,它提供了便捷的操作接口和灵活的扩展能力,使得在处理动态数据集合时非常方便。本文将深入探讨Java中ArrayList的实现原理、常用操作以及一些使用场景。 一:体系结构 二&#xff…

antddesign使用iconfont的字体库和图标库

antddesign使用iconfont 使用iconfont自定义字体 1️⃣选择一种需要的字体,点击【字体包下载】: 2️⃣下载好的字体放到项目目录下:src/assets/fonts: 3️⃣新建styles/font.css文件: /* src/styles/fonts.css */ f…