文档章节

redis命令执行流程分析

商者
 商者
发布于 2016/04/06 21:27
字数 1702
阅读 75
收藏 9

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

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

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. struct redisCommand {  
  2.     char *name; // 命令的名字  
  3.     redisCommandProc*proc; // 命令的实现函数  
  4.          …  
  5. }  

       数组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命令按照下面的格式进行组织。

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. *< 参数数量>CR LF  
  2. $< 参数1 的字节数量> CR LF  
  3. < 参数1 的数据> CR LF  
  4. ...  
  5. $< 参数N 的字节数量> CR LF  
  6. < 参数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

本文转载自:

商者

商者

粉丝 43
博文 142
码字总数 43255
作品 0
海淀
架构师
私信 提问
Linux Redis自动化挖矿感染蠕虫分析及安全建议

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 自从Redis未授权问题获取Linux系统root权限的攻击方法的披露后,由于其易用性,利用该问题入侵Linux服务进行挖矿、扫描等的黑客行...

腾讯云加社区
2018/06/12
0
0
【Redis源码剖析】 - Redis之事务的实现原理

原创作品,转载请标明:http://blog.csdn.net/Xiejingfa/article/details/51262268 Redis源码剖析系列文章汇总:传送门 今天为大家带来Redis中事务部分的源码分析。Redis的事务机制允许将多个...

xiejingfa
2016/04/27
0
0
Redis高可用原理,这下能看懂了吧!

本文作者深入分析了 Redis 高可用的方方面面,并且做了有效总结,相信对广大读者可以起到很好的领路作用。 Redis 中为了实现高可用采用了如下两个方式: 主从复制数据。 采用哨兵监控数据节点...

51CTO技术栈
05/15
0
0
redis源码分析之事务Transaction(下)

接着上一篇,这篇文章分析一下redis事务操作中multi,exec,discard三个核心命令。 看本篇文章前需要先对上面文章有所了解: redis源码分析之事务Transaction(上) 一、redis事务核心命令简...

凌风郎少
2017/11/12
0
0
Redis 数据同步机制分析

Redis的主从同步机制可以确保redis的master和slave之间的数据同步。按照同步内容的多少可以分为全同步和部分同步;按照同步的时机可以分为slave刚启动时的初始化同步和正常运行过程中的数据修...

空云万里晴
2016/06/16
86
0

没有更多内容

加载失败,请刷新页面

加载更多

排序––快速排序(二)

根据排序––快速排序(一)的描述,现准备写一个快速排序的主体框架: 1、首先需要设置一个枢轴元素即setPivot(int i); 2、然后需要与枢轴元素进行比较即int comparePivot(int j); 3、最后...

FAT_mt
37分钟前
3
0
mysql概览

学习知识,首先要有一个总体的认识。以下为mysql概览 1-架构图 2-Detail csdn |简书 | 头条 | SegmentFault 思否 | 掘金 | 开源中国 |

程序员深夜写bug
今天
9
0
golang微服务框架go-micro 入门笔记2.2 micro工具之微应用利器micro web

micro web micro 功能非常强大,本文将详细阐述micro web 命令行的功能 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go-micro环境, golang微服务框架...

非正式解决方案
今天
6
0
前端——使用base64编码在页面嵌入图片

因为页面中插入一个图片都要写明图片的路径——相对路径或者绝对路径。而除了具体的网站图片的图片地址,如果是在自己电脑文件夹里的图片,当我们的HTML文件在别人电脑上打开的时候图片则由于...

被毒打的程序猿
今天
8
0
Flutter 系列之Dart语言概述

Dart语言与其他语言究竟有什么不同呢?在已有的编程语言经验的基础上,我们该如何快速上手呢?本篇文章从编程语言中最重要的组成部分,也就是基础语法与类型变量出发,一起来学习Dart吧 一、...

過愙
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部