走近源码:Redis 如何执行命令

栏目: 数据库 · 发布时间: 5年前

前文我们了解了 Redis 的启动过程。在initServer()函数中创建了一些循环事件来监听TCP端口和Unix的Sockets,从而使Redis服务器可以接收新的连接。今天我们再一起来看一下Redis究竟是如何处理命令并返回结果的。

处理新连接

Redis在initServer()函数中创建循环事件调用了acceptTcpHandler和acceptUnixHandler函数(都在networking.c文件中)来处理接收到的TCP连接和Unix的Sockets连接。这两个函数又调用了acceptCommonHandler()函数,在这个函数中调用了createClient()函数创建一个新的client对象,用来表示一个新的客户端连接。

createClient()函数具体做了哪些事情呢?

首先为变量c分配了内存,接着将Socket连接置为非阻塞状态,并且设置了TCP无延迟。然后创建了File循环事件(aeCreateFileEvent)来调用readQueryFromClient函数。新建的客户端默认连接的是服务器的第一个数据库(编码为0),最后需要设置好客户端的各种属性和状态。

读一个客户端的命令

刚刚我们提到了readQueryFromClient函数,从名称上就能看出来这个函数是用来从客户端读取命令的。下面来看看函数的具体实现。

Redis会先将命令读入缓冲区,一次最多读取的大小是PROTO_IOBUF_LEN(1024*16)bit。然后调用processInputBufferAndReplicate()函数,来处理缓冲区中的数据,如果客户端是master(主从同步过程),那么Redis会计算处理前后缓冲区的不同部分,以确定从节点接收了多少数据。processInputBufferAndReplicate()函数会处理客户端向服务器发送命令和主节点向从节点发送命令这两种情况,不过最后都需要调用processInputBuffer()函数。

processInputBuffer()函数会先判断客户端是否正常,如果出现连接中断或者客户端阻塞等情况,就会立即停止处理命令,不做无用功。然后根据读取的请求生成相应的Redis可以执行的命令(包括参数)。不同的请求类型分别调用processInlineBuffer()和processMultibulkBuffer()函数。生成好命令之后,交给processCommand()(server.c文件中)函数执行,如果返回C_OK则重置客户端,等待下一个命令。如果返回的是C_ERR,则客户端会被销毁(比如执行QUIT命令)。

processCommand()函数会从Redis启动时加载的命令表中查找命令,然后检查命令的执行权限。

如果是cluster,这时会判断key是否属于当前的master,不属于需要返回重定向信息。

如果内存不够用,这里也需要判断一下是否有可以释放的内存,如果没有,就不能执行命令,返回错误信息。

接下来会判断一些不能接收写命令的情况:

  • 服务器不能进行持久化

  • 作为master,没有足够的可用的slave

  • 此服务器为只读的slave,只有它的master可以接收写命令

在订阅模式中,只能接收指定的命令:(P)SUBSCRIBE / (P)UNSUBSCRIBE / PING / QUIT。

当slave和master失联时,只能接收有flag "t"的命令,例如,INFO,SLAVEOF等。

如果命令没有CMD_LOADING标志,并且当前服务器正在加载数据,则不能接收此命令。

lua 脚本的长度进行限制。

进行完上面的各种条件判断之后,才可以真正开始调用call()函数执行命令。

执行命令并返回

call()函数的参数是client类型的,取出cmd成员进行执行。

1/* Call the command. */
2dirty = server.dirty;
3start = ustime();
4c->cmd->proc(c);
5duration = ustime()-start;
6dirty = server.dirty-dirty;
7if (dirty < 0) dirty = 0;

如果是写命令,就会使服务器变“脏”,也就是服务器需要标记一下内存中的某些页有了改变。这对于Redis的持久化来说非常重要,它可以知道这个命令影响了多少个key。命令执行完之后并没有结束,call函数还会做一些其他操作。例如记录日志,写AOF文件,向从节点同步命令等。

至于返回值,每个命令有各自的处理方法,我们后面在介绍。

到这里,Redis处理命令的过程也就完成了。

后面我们会再通过具体的命令来对这个过程做一个更清晰的介绍。

走近源码:Redis 如何执行命令

往期精彩回顾

瞬间爆红的冰皮月饼—何为冰皮…………

玩转Redis集群之Cluster

玩转Redis集群之Codis

走近源码:Redis 如何执行命令

我怎么这么好看


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

物联网导论(第2版)

物联网导论(第2版)

刘云浩 / 科学出版社 / 2013-8 / 45.00元

物联网是一个基于互联网、传统电信网等信息承载体,让所有能够被独立寻址的普通物理对象实现互联互通的网络。它具有普通对象设备化、自治终端互联化和普适服务智能化三个重要特征。 《物联网工程专业系列教材:物联网导论(第2版)》从物联网的感知识别层、网络构建层、管理服务层和综合应用层这四层分别进行阐述,深入浅出地为读者拨开萦绕于物联网这个概念的重重迷雾,引领求知者渐渐步入物联网世界,帮助探索者把握第三......一起来看看 《物联网导论(第2版)》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具