Redis中各种操作都可以通过命令来完成,因此理解redis对命令的处理流程会有助于理解redis的整个流程。本文主要对redis的命令处理流程进行详细分析。

Redis将所有它能支持的命令以及对应的“命令处理函数”之间对应关系存放在数组redisCommandTable[]中,该数组中保存元素的类型为结构体redisCommand,此中包括命令的名字以及对应处理函数的地址,如:

struct redisCommand {char *name; // 命令的名字redisCommandProc*proc; // 命令的实现函数…
}

数组redisCommandTable[]被作为全局变量进行创建和初始化,其定义位置在redis.c文件中。在redis中,所有的redis服务器相关的信息都是通过结构体struct redisServer来维持,一个redis服务器也就由一个唯一的struct redisServer类型的全局变量server来描述。在函数 initServerConfig()中,将会完成server的相关初始化工作,其中包含有对命令的初始化操作,在server中命令将被用字典的方式进行存储,以方便查询,其具体操作包括两步:

首先,通过函数dictCreate()创建一个commandTableDictType类型的字典,并将该字典保存在全局变量server的commands成员中。

然后,调用函数populateCommandTable()将数组redisCommandTable[]中的命令添加到(1)中创建的字典里,以便后续的命令查询操作。

本文后续部分将分别描述redis接受客户端连接、客户端传递操作命令、以及redis执行操作命令的整个流程。

       流程一:redis如何接受客户端的连接

Redis支持网络域通信(不同机子上的程序间通过tcp/udp连接(redis使用tcp)进行通信)以及UNIX域通信(即同一台机子上的不通进程间使用unix域进行通信),下面的介绍中将主要介绍网络域通信,unixt域的通信过程与之类似,不再累述。

每个客户端通过网络连接到redis时,redis将调用函数createClient()为该连接创建一个客户端结构体redisClient,以便保存该客户端的所有信息,该新连接即为业务连接,其主要用于客户端与redis之间的实际数据通信。Redis在createClient()函数中将为连接设置处理函数readQueryFromClient(),也即业务连接上有数据到来时将调用此函数进行处理。

redis启动时将调用initServer()函数,在该函数中将设置监听socket的处理函数,其过程主要有以下三步:

(1)调用函数anetTcpServer创建redis的监听socket,所有客户端对redis的网络连接都连接到该socket所监听的端口上。

(2)调用函数aeCreateFileEvent设置监听socket的处理函数:acceptTcpHandler(),也就是当redis的监听socket收到数据(有新的连接到来)时将调用该函数进行处理。

(3)lacceptTcpHandler()中将首先调用函数anetTcpAccept为新进来的业务连接创建一个业务socket;该业务socket后续将完成客户端与服务器之间所有的业务数据传输;然后通过函数acceptCommonHandler()调用createClient()为新连接创建一个客户端结构体redisClient.

(4)在函数createClient()中,将调用函数aeCreateFileEvent设置该客户端的业务数据处理函数readQueryFromClient,即,当该客户端的业务socket中有数据到来了,则调用readQueryFromClient进行处理。

上述过程将按照以下流程进行处理:

图1、 redis接受客户端连接的调用过程

由图1可以看出,当客户端有请求数据(即redis的业务数据)到来时,redis中对应该客户端的业务socket将处于可读就绪状态,然后redis将调用函数readQueryFromClient()对到达的业务数据进行处理。

       流程二 :redis的命令处理流程

通过流程一客户端可以连接到redis上,然后客户端就可以通过该连接向redis发送操作命令,redis接到命令之后执行相应的函数完成具体操作,然后将操作结果发送给客户端,其具体过程如下所示:

(1)客户端的请求数据由网络传递到redis的业务socket,redis将调用函数readQueryFromClient()读取数据到redisClient结构体的接收缓存querybuf中。

(2)readQueryFromClient()将调用processInputBuffer()对该客户端输入缓存中的数据进行处理。

(3)函数processInputBuffer()中,将首先解析收到的客户端数据,此解析过程将通过调用函数processInlineBuffer()或processMultibulkBuffer()完成,此过程将解析出客户端的命令名称,命令的参数个数以及具体参数值,redis有其自己定义的通信协议,只需按照此协议即可完成命令解析,其过程可参考本文最后的“附1. redis命令解析”。

(4)函数processInputBuffer()中,命令解析完成之后将调用函数processCommand()完成命令处理过程。

(5)在函数processCommand()中,将根据命令的名字查找相应的处理函数,命令的名字由前面的命令解析过程确定,命令查询操作将通过函数lookupCommand()完成,此函数将查找server的命令字典以快速找到对应的命令执行函数。

(6)在函数processCommand()中,查找到命令执行函数之后,还需调用call()函数来具体执行相应的“命令执行函数”。

上述处理过程可参考下图2所示:

                                               图2、 redis命令执行过程

上图中的数字标号表示同级别的执行先手顺序。

----------------------------------------------------------------------------------------------------------------------

附1.redis命令解析

Redis的通信按照其自己定义的协议进行,按照这种协议可保证命令的二进制安全,其协议规定如下:

l所有命令和数据都已\r\n(即CRLF)结尾;

l命令按照下面的格式进行组织。

*< 参数数量>CR LF
$< 参数1 的字节数量> CR LF
< 参数1 的数据> CR LF
...
$< 参数N 的字节数量> CR LF
< 参数N 的数据>CR LF

例如,有如下数据:

*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n

即可按照上述方式理解为该数据的含义:它共有三个参数(即命令中开头的字符:*3),其中第一个参数的长度是3个字节,其值为SET;第二个参数的长度为5,值为mykey,第三个参数的长度为7,值为myvalue,因此这条数据的含义是一条如下的命令:

SETnmykey nmyvalue

redis命令执行流程分析相关推荐

  1. 【网络安全】Metasploit生成的Shellcode的导入函数解析以及执行流程分析(2)

    密码破解的利器--彩虹表(rainbow table) 确定 shellcode 依赖于哪些导入将使研究人员进一步了解其其余逻辑.不用动态分析shellcode,并且考虑到研究人员已经弄清楚了上面的哈 ...

  2. mysql 8.0 一条insert语句的具体执行流程分析(三)

    代码版本:mysql 8.0.22 编程语言:c++ && c++11 && c++14 && c++17 上一篇文章:mysql 8.0 一条inse ...

  3. 又被野外利用了!新曝光Office产品多个远程命令执行漏洞分析

    本文讲的是又被野外利用了!新曝光Office产品多个远程命令执行漏洞分析, 早在2015年,FireEye曾发布过两次关于Office的Encapsulated PostScript (EPS)图形文 ...

  4. Java-Mybatis(二): Mybatis配置解析、resultMap结果集映射、日志、分页、注解开发、Mybatis执行流程分析

    Java-Mybatis-02 学习视频:B站 狂神说Java – https://www.bilibili.com/video/BV1NE411Q7Nx 学习资料:mybatis 参考文档 – ht ...

  5. 「Vue 学习笔记 1」Vue 项目快速搭建,初始项目各个文件夹作用介绍和启动代码执行流程分析

    「Vue 学习笔记 1」Vue 项目快速搭建,初始项目各个文件夹作用介绍和启动代码执行流程分析 前言 一.我的开发环境 二.使用 Vue CLI (Vue 脚手架)快速搭建项目 三.初始项目的目录结构 ...

  6. Go003:Go程序开发的步骤+Golang执行流程分析

    开发的步骤 一.开发这个程序页目时,go的目录结构怎么处理 二.开发一个hell.go程序 对上图的说明 1.go文件的后缀是.go 2.package main 表示hello.go文件所在的包是m ...

  7. 动态执行流程分析和性能瓶颈分析的利器——gperftools的Cpu Profiler

    在<动态执行流程分析和性能瓶颈分析的利器--valgrind的callgrind>中,我们领略了valgrind对流程和性能瓶颈分析的强大能力.本文将介绍拥有相似能力的gperftools ...

  8. 动态执行流程分析和性能瓶颈分析的利器——valgrind的callgrind

    在<内存.性能问题分析的利器--valgrind>一文中我们简单介绍了下valgrind工具集,本文将使用callgrind工具进行动态执行流程分析和性能瓶颈分析.(转载请指明出于brea ...

  9. Java多线程- 线程池的基本使用和执行流程分析 - ThreadPoolExecutor

    线程池的实现原理 池化技术 一说到线程池自然就会想到池化技术. 其实所谓池化技术,就是把一些能够复用的东西放到池中,避免重复创建.销毁的开销,从而极大提高性能. 常见池化技术的例如: 线程池 内存池 ...

最新文章

  1. Python教程WEB安全篇
  2. 洛谷P4550 收集邮票(概率期望)
  3. android 发送重启广播,Android实现关机重启的方法分享
  4. Dynamic ReLU论文解读
  5. g4e基础篇#6 了解Git历史记录
  6. [react] React Hooks帮我们解决了哪些问题?
  7. 这9个Python问题你能回答几个?
  8. 伯克利推出世界最快的KVS数据库Anna:秒杀Redis和Cassandra
  9. msm8953抓取audio kernel dsp log
  10. 关于事业发展,雷林鹏教你如何找到方向?
  11. Docker 大势已去,Podman 崛起
  12. Latex所有数学符号一览
  13. vivox50支持鸿蒙,【vivoX50Pro评测】轻薄机身内大有玄妙 深挖vivo X50系列技术创新-中关村在线...
  14. 模式分解的无损性判断
  15. 最难忘的一节计算机课,最让我难忘的一节课作文「共5篇」
  16. 关于Data Matrix 基于ECC200标准的编码原理和相关开源代码
  17. 笔记本电脑找不到个人热点的解决方法
  18. 实验6:安装EVE-NG
  19. 河北外国语学院计算机宿舍,2021年河北外国语学院新生宿舍条件和宿舍环境图片...
  20. AI人工智能外呼机器人测试项目经历

热门文章

  1. 页面文字请使用css进行控制,css控制页面文字不能被选中user-select:none;
  2. java 装饰器_装饰器模式(Java)
  3. 上项线体表位置_体表定位
  4. jmeter和oracle,jmeter测试Oracle数据库
  5. vissim跟驰模型_MATLAB——基于元胞自动机的单向3车道模型
  6. python基础语法 第3关_Python基础语法 第3节课 (列表)
  7. 虚拟机使用桥接模式设置Linux静态IP
  8. t检验的p值对照表_统计学|各类统计检验方法大汇总
  9. matlab中如何做连乘循环,如何利用for循环实现矩阵连乘
  10. python 安装包列表导出到 txt