Redis实战(10)-一条命令在Redis是如何执行的?

news2024/11/26 18:55:08

Redis Server一旦和某客户端建立连接,就会在事件驱动框架中注册可读事件,对应客户端的命令请求。

整个命令处理过程可分阶段:

  • 命令解析,processInputBufferAndReplicate
  • 命令执行,processCommand
  • 结果返回,addReply

1 命令读取:readQueryFromClient

会从客户端连接的socket中,读取最大为readlen长度的数据,readlen大小为宏定义PROTO_IOBUF_LEN,默认16KB。

接着根据读取数据的情况,进行异常处理,如:

  • 数据读取失败

  • 或客户端连接关闭等

若当前客户端是主从复制中的主节点,readQueryFromClient会把读取的数据,追加到用于主从节点命令同步的缓冲区中。

最后,调用processInputBuffer,进入命令解析阶段。

void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
   ...
   readlen = PROTO_IOBUF_LEN;  // 从客户端socket中读取的数据长度,默认16KB
   ...
   c->querybuf = sdsMakeRoomFor(c->querybuf, readlen);  // 给缓冲区分配空间
   nread = read(fd, c->querybuf+qblen, readlen);  // 调用read从描述符为fd的客户端socket中读取数据
    ...
    processInputBufferAndReplicate(c);  // 进一步处理读取内容
}

2 命令解析:processInputBuffer

根据当前客户端是否有CLIENT_MASTER标记,执行如下分支:

  • Case1

    客户端无CLIENT_MASTER标记,即当前客户端不属于主从的Master。processInputBufferAndReplicate直接调processInputBuffer,对客户端输入缓冲区中的命令和参数进行解析。所以在这里,实际执行命令解析的函数是processInputBuffer

  • Case2

    客户端有CLIENT_MASTER标记。processInputBufferAndReplicate除了会调用processInputBuffer,解析客户端命令,还会调用replicationFeedSlavesFromMasterStream,将主节点接收到的命令同步给从节点

最终命令解析就在processInputBuffer

  • 首先,processInputBuffer函数会执行一个while循环,不断从客户端的输入缓冲区读数据

  • 然后,判断读取到的命令格式,是否以“*”开头:

    • 命令 *开头,processInputBuffer会调processMultibulkBuffer解析读取到的命令

    • 不是*开头,即管道命令,命令和命令间用换行符\r\n分隔的。如使用Telnet发给Redis的命令就属该类型命令。processInputBuffer会调用processInlineBuffer解析命令。

命令解析完成后,processInputBuffer就会调用processCommand,进入命令处理的第三阶段:命令执行。

执行流程图

3 命令执行:processCommand

实际执行命令前的主要逻辑:

  1. processCommand调moduleCallCommandFilters,将Redis命令替换成module想替换的命令

  2. processCommand判断当前命令是否为quit命令并做相应处理

  3. processCommand调lookupCommand,在全局变量server的commands成员变量中查找相关命令

全局变量server的commands成员变量是个哈希表,定义在redisServer结构体:

commands成员变量的初始化是在initServerConfig,调用dictCreate完成哈希表创建,再调用populateCommandTable将Redis提供的命令名称和对应的实现函数,插入哈希表。

而这其中的populateCommandTable使用redisCommand结构体数组redisCommandTable。

redisCommandTable数组在server.c定义,它的每一个元素是redisCommand结构体类型的记录,对应Redis实现的一条命令。即redisCommand结构体记录当前命令所对应的实现函数。

如下代码展示GET、SET等命令信息,实现函数getCommand,setCommand:

所以lookupCommand会根据解析的命令名称,在commands对应的哈希表中查找相应命令。

查到对应命令后,processCommand就会检查,如命令参数是否有效、发送命令的用户是否进行过验证、当前内存的使用情况等。

等processCommand对命令做完各种检查,就开始执行命令,判断当前客户端是否有CLIENT_MULTI标记:

  • 有,说明要处理Redis事务相关命令

    按事务要求,调queueMultiCommand:将命令入队保存,等待后续再一把梭

  • 无,无关事务特性

    调call实际执行命令。call通过调用命令本身,即redisCommand结构体中定义的函数指针完成。每个redisCommand结构体中都定义了其对应实现函数,在redisCommandTable数组。

分布式锁的加锁操作就是使用SET命令,就通过SET命令看一个命令实际执行过程。

SET命令对应实现函数setCommand:

  • 首先会判断命令参数,如是否带有NX、EX、XX、PX等可选项,若有,就会记录这些标记
  • 然后,调用setGenericCommand:根据setCommand记录的命令参数标记,进行相应处理。如命令参数中有NX,则setGenericCommand会调用lookupKeyWrite,查找要执行SET命令的K是否已存在
  • 若K已存在,则setGenericCommand会调用addReply,返回NULL,正符合分布式锁语义。

若SET命令可正常执行,即:

  • 命令带NX选项,但K不存在

  • 或带有XX选项,但K已存在

这样setGenericCommand就会调用setKey完成KV对的实际插入:

setKey(c->db,key,val);

然后,若命令设置了TTL,setGenericCommand还会调用setExpire函数设置过期时间。最后,setGenericCommand调用addReply函数,将结果返给客户端:

addReply(c, ok_reply ? ok_reply : shared.ok);

SET命令执行流程图

无论:

  • 在命令执行过程中,发现不符合命令的执行条件
  • 或是命令能成功执行

addReply函数都会被调用以返回结果。所以,这就进入命令处理过程的最后一个阶段:结果返回阶段。

4 结果返回:addReply

调用prepareClientToWrite,并在prepareClientToWrite中调用clientInstallWriteHandler,将待写回客户端加入到全局变量server的clients_pending_write列表。

然后,addReply会调用_addReplyToBuffer等函数,将要返回的结果添加到客户端的输出缓冲区。

至此,这就是一条命令如何从读取,经过解析、执行等步骤,最终将结果返给客户端,该过程以及涉及的主要函数:

若在前面命令处理过程中,都由I/O主线程处理,则命令执行的原子性肯定能得到保证,分布式锁的原子性也相应得到保证。

FAQ

但若这个处理过程配合I/O多路复用机制和多IO线程机制,那这俩机制是在这个过程的什么阶段发挥作用?会不会影响命令执行原子性?

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

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

相关文章

APEX:开启Android系统新篇章的应用扁平化技术

APEX:开启Android系统新篇章的应用扁平化技术 Android Pony Express (APEX) 是在 Android Q 中引入的一种容器格式,用于安装流程中较低级系统模块的更新。该格式方便了系统组件的更新,这些组件不适合标准的 Android 应用程序模型。一些示例组…

计算机系大学生,可以通过Java做什么副业?这篇文章给你答案!

文章目录 前言发现副业机会提高效率面向人群 如何开启自己的副业价格优势需要课设的人多吗怎么宣传生成器的使用 生成器介绍安装功能介绍文档查询功能生成的JavaWeb系统示例生成的C#生成的Javaswing生成的VueER图 、UML、功能图..生成的C、C系统 前言 计算机系科班出身的学生&a…

轻量服务器2核与1核的区别

​ 1.核心数量 轻量服务器2核与1核最明显的区别在于核心数量。1核服务器只有一个处理器核心,而2核服务器有两个处理器核心。这使得2核服务器在处理数据时能够同时执行更多的任务。 2.并行处理能力 由于只有1个核心,1核服务器不具备并行处理任务的能力。而…

天津专升本文化课考试计算机应用基础考试大纲(2023年9月修订)

天津市高等院校“高职升本科”招生统一考试计算机应用基础考试大纲(2023年9月修订) 一、考试性质 天津市高等院校“高职升本科”招生统一考试是由合格的高职高专毕业生参加的选拔性 考试。高等院校根据考生的成绩,按照已确定的招生计划&am…

低功耗蓝牙物联网:未来连接的无限可能

物联网是连接各种设备和传感器的网络,其目的是实现信息的交换和共享,提高效率并优化生活。在这个领域,低功耗蓝牙(BLE)正在发挥着越来越重要的作用。 低功耗蓝牙是一种无线通信技术,它的主要特点是低功耗和…

HarmonyOS之 组件的使用

一 容器 1.1 容器分类 Column表示沿垂直方向布局的容器。Row表示沿水平方向布局的容器。 1.2 主轴和交叉轴 主轴:在Column容器中的子组件是按照从上到下的垂直方向布局的,其主轴的方向是垂直方向;在Row容器中的组件是按照从左到右的水平方向…

TiDB 7.1.0 LTS 特性解读丨关于资源管控 (Resource Control) 应该知道的 6 件事

TiDB 7.1.0 LTS 在前段时间发布,相信很多同学都已经抢先使用了起来,甚至都已然经过一系列验证推向了生产环境。面对 TiDB 7.1 若干重要特性,新 GA 的资源管控 (Resource Control) 是必须要充分理解、测试的一个重量级特性。对于常年奋斗在一线…

编译vtk源码

vtk和opengl关系 VTK(Visualization Toolkit)和OpenGL(Open Graphics Library)都是用于图形可视化和渲染的重要工具,但它们在图形编程中的角色和关系略有不同。 OpenGL: OpenGL是一种开放的图形库和API&a…

uniapp自定义播放器

问题描述:我是真无语啊,就是有一个目录切换的地方,然后切换音频,结果你猜怎么着,嘿,音频他不播放了。也就是下面这个方法都不进去了打印的时候,音频播放都播放不了了,我尝试了销毁在…

前端提交规范 ESLint + Prettier + husky + lint-staged

如何统一代码风格,规范提交呢? 推荐使用前端规范全家桶 ESLint Prettier husky lint-staged。 eslint (github.com/eslint/esli…)JavaScript 代码检测工具,检测并提示错误或警告信息prettier (github.com/prettier/pr…) 代码自动化格式…

【面试题】Js数组去重都有哪些方法?

前端面试题库 (面试必备) 推荐:★★★★★ 地址:前端面试题库 表妹一键制作自己的五星红旗国庆头像,超好看 1. indexOf 定义: indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置…

基于SSM的田径运动会成绩管理系统的设计与实现

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用Vue技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…

秒懂生成式AI—大语言模型是如何生成内容的?

备受关注的大语言模型,核心是自然语言的理解与文本内容的生成,对于此,你是否好奇过它们究竟是如何理解自然语言并生成内容的,其工作原理又是什么呢? 要想了解这个,我们就不得不先跳出大语言模型的领域&…

Hadoop初识及信息安全(大数据的分布式存储和计算平台)

目录 什么是Hadoop Hadoop的特点 Hadoop优点 Hadoop的缺点 Hadoop的重要组成 信息安全 什么是Hadoop Hadoop 是一个适合大数据的分布式存储和计算平台。 Hadoop的广义和狭义区分: 狭义的Hadoop:指的是一个框架,Hadoop是由三部分组成:H…

做测试半年,我已经掉了4个坑……

从事软件测试工作已经半年多了,刚入职的时候还是一个缺乏实际经验的小白,而现在拿到需求之后也能比较快速地熟悉业务并顺利开展测试,虽然不能说掌握了很多技能,但是相比之前也是有不少收获的,在这个过程中我总结了一点…

使用vue-cli搭建SPA项目

一.SPA项目的构建 前提 nodeJS环境已经搭建完毕 node -v npm -v 什么是SPA项目 SPA(Single Page Application)项目是一种使用单页面架构的Web应用项目。在SPA项目中,整个应用程序只有一个HTML页面,通过动态加载数据和更新DOM来实…

计算机竞赛 深度学习+opencv+python实现昆虫识别 -图像识别 昆虫识别

文章目录 0 前言1 课题背景2 具体实现3 数据收集和处理3 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数:2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 4 MobileNetV2网络5 损失函数softmax 交叉熵5.1 softmax函数5.2 交叉熵损失函数 6 优化器SGD7 学…

springboot实现发送邮箱验证码

准备工作 在邮箱官网开放SMTP授权,获取相应密钥,才可以进行发送邮件 这里以网易163邮箱为例,登录邮箱后,依次点击“设置-POP3/SMTP/IMAP” ,然后开启SMTP服务。这时候会提示一个授权码,例如:H…

I2C子系统、读取温湿度的逻辑及代码

一、IIC子系统 两根线: scl:时钟线 sda:数据线 iic有4种信号: 起始信号(start):scl是高电平,sda下降沿 终止信号(stop):scl高电平,sda上升沿 应答信号&#xf…

面试官:说说JavaScript中的数据类型?区别?

🎬 岸边的风:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想,就是为了理想的生活 ! 目录 一、概述 二、显示转换 Number() parseInt() String() Boolean() 三、隐式转换 自动转换为布尔值 自动转换…