Redis中各类操做均可以经过命令来完成,所以理解redis对命令的处理流程会有助于理解redis的整个流程。本文主要对redis的命令处理流程进行详细分析。 redis
Redis将全部它能支持的命令以及对应的“命令处理函数”之间对应关系存放在数组redisCommandTable[]中,该数组中保存元素的类型为结构体redisCommand,此中包括命令的名字以及对应处理函数的地址,如: 数组
首先,经过函数dictCreate()建立一个commandTableDictType类型的字典,并将该字典保存在全局变量server的commands成员中。 缓存
而后,调用函数populateCommandTable()将数组redisCommandTable[]中的命令添加到(1)中建立的字典里,以便后续的命令查询操做。 安全
本文后续部分将分别描述redis接受客户端链接、客户端传递操做命令、以及redis执行操做命令的整个流程。 服务器
流程一:redis如何接受客户端的链接 网络
Redis支持网络域通讯(不一样机子上的程序间经过tcp/udp链接(redis使用tcp)进行通讯)以及UNIX域通讯(即同一台机子上的不通进程间使用unix域进行通讯),下面的介绍中将主要介绍网络域通讯,unixt域的通讯过程与之相似,再也不累述。 socket
每一个客户端经过网络链接到redis时,redis将调用函数createClient()为该链接建立一个客户端结构体redisClient,以便保存该客户端的全部信息,该新链接即为业务链接,其主要用于客户端与redis之间的实际数据通讯。Redis在createClient()函数中将为链接设置处理函数readQueryFromClient(),也即业务链接上有数据到来时将调用此函数进行处理。 tcp
redis启动时将调用initServer()函数,在该函数中将设置监听socket的处理函数,其过程主要有如下三步: 函数
(1)调用函数anetTcpServer建立redis的监听socket,全部客户端对redis的网络链接都链接到该socket所监听的端口上。 spa
(2)调用函数aeCreateFileEvent设置监听socket的处理函数:acceptTcpHandler(),也就是当redis的监听socket收到数据(有新的链接到来)时将调用该函数进行处理。
(3)lacceptTcpHandler()中将首先调用函数anetTcpAccept为新进来的业务链接建立一个业务socket;该业务socket后续将完成客户端与服务器之间全部的业务数据传输;而后经过函数acceptCommonHandler()调用createClient()为新链接建立一个客户端结构体redisClient.
(4)在函数createClient()中,将调用函数aeCreateFileEvent设置该客户端的业务数据处理函数readQueryFromClient,即,当该客户端的业务socket中有数据到来了,则调用readQueryFromClient进行处理。
上述过程将按照如下流程进行处理:
图一、 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所示:
图二、 redis命令执行过程
上图中的数字标号表示同级别的执行先手顺序。
----------------------------------------------------------------------------------------------------------------------
附1.redis命令解析
Redis的通讯按照其本身定义的协议进行,按照这种协议可保证命令的二进制安全,其协议规定以下:
l全部命令和数据都已\r\n(即CRLF)结尾;
l命令按照下面的格式进行组织。
例如,有以下数据:
*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