本文转载自微信公众号《Java极客技术》,作者鸭血范。转载本文请联系Java极客技术公众号。大家好,我是阿芬。Redis作为工作中不可或缺的缓存组件,相信很多朋友都会用到。在我们的日常使用中,我们通过代码或者客户端连接到Redis服务器来操作数据。那么一个简单的setnameziyou命令是如何执行的,中间经历了哪些过程,想必没几个人懂。今天阿粉就给大家展示一个简单的setnameziyou命令是如何执行的。我们可以看到,执行命令setnameziyou后,首先在终端显示OK。让我们看一下整个过程中的步骤。整个命令的执行分为以下几个步骤。先看流程再仔细分析:客户端发送命令请求;服务器读取命令请求;命令执行器执行操作;命令执行器查找命令执行函数;命令执行器执行初步操作;命令执行器调用命令的实现函数;命令执行器执行后续工作;服务器向客户端发送命令回复;客户端接收并打印命令回复内容;客户端先发送一个命令请求,当客户端和服务端建立连接后,当我们输入命令集名称ziyou命令请求时,客户端会将命令转换为协议,然后将转换后的协议通过连接。例如,当我们输入命令集名称ziyou时,客户端会将原命令转换为*3\r\n$3\r\nset\r\n$4\r\nname\r\n$5\r\nziyou,这个协议大家应该都不陌生,也就是Redis管道的文件格式。简要说明本协议的含义。前面的*3表示这条命令一共有三个参数,$3、$4、$5代表对应参数的长度。服务器读取命令请求。当服务端收到客户端的数据后,会调用命令请求处理器来处理相应的消息。这部分主要涉及三个操作,第一个是保存命令,即将命名的请求信息读取并保存到对应客户端的输入缓冲区中;保存后会解析输入缓冲区中的内容,即解析上面转换后的协议,解析出要执行的命令和对应的参数,将参数内容和参数个数保存在客户端对应的参数中;第三步,调用命令执行器执行命令。执行的命令和参数保存在RedisClient结构体的argv参数中,如下图,命令解析完成后,可以更好的执行第三步:commandexecutorcommandexecutorsearchimplementationfunction思考一个问题,这里我们argv[0]参数中的命令是执行一个set操作,这里是一个set字符串,那么Redis服务器是如何执行的呢?我们可以想到的是,我们需要根据这个字符串找到对应的函数进行操作,Redis里面有一个命令表,是一个字典结果,key是对应的命令名,字典的值为一个RedisCommand结构体,记录了命令的执行信息。结构如下,简单来说就是通过argv[0]中的命令名在命令表中找到对应的redisCommand结构,然后根据proc指针找到对应的执行命令。这里说明一下,命令名的大小写是没有影响的,我们在打字的时候不需要关心命令名的大小写。命令执行器执行准备操作。Redis服务器在执行相关命令之前,为了保证命令能够正确执行,需要进行相关的准备处理。一些前置操作如下:检查命令的参数是否与输入的参数个数一致。直接返回错误;检查客户端是否通过认证,如果没有,只能执行AUTH命令进行认证;检查服务器内容使用情况,为保证命令执行成功,可能需要进行内容回收;除了上述功能之外,还有很多动作需要准备执行,而且根据服务器的部署,需要在单机或集群上执行的操作也不同。只有所有准备操作都执行成功后,用户的命令才会真正执行。可见Redis的性能确实是高效的。在这样的操作过程中,能够保持命令执行的速度如此之快。不得不说,真的很优秀。命令执行器调用命令的实现函数。前面的准备操作完成后,命令执行器就会调用相应的实现函数。在我们这里的例子中,调用了setCommand(redisClient*c)函数来执行数据写入操作。具体来说keyvalue和valuevalue已经保存在redisClient结构体中,所以只要传一个指针进去即可。setCommand()命令执行后,会返回一个OK\r\n,保存在客户端的输出缓冲区中,输出缓冲区的内容返回给客户端显示给用户,如上图显示的内容。命令执行器执行后续工作。命令执行器调用具体的实现函数后,服务端就会有一些相应的操作要做。例如开启慢日志功能,会检查是否写入慢日志;如果启用了AOF则需要将刚刚执行的命令写入AOF的缓冲区;而如果有服务器备份或者监控,刚刚执行的命令会广播过去。服务器向客户端发送命令回复,实现函数执行后,执行结果保存在客户端的输出缓冲区中。此时,服务器的命令回复处理器会将缓冲区中的命令回复发送给客户端。commandreplyprocessor发送完数据后,会清空client的outputbuffer,方便后续命令存储数据,reply数据也通过协议进行转换。客户端接收并打印命令回复内容。客户端收到回复数据后,将数据转换成可读的形式输出到控制台。这给了我们第一张图片的结果。总结通过以上所有流程,我们可以看出,就是setnameziyou这样简单的一条语句,整个执行过程还是很复杂的。在设计Redis服务器时,需要考虑很多事情,比如安全性、性能等等。引述《Redis 设计与实现第二版》
