参考:《Redis设计与实现》
文章目录
1、命令请求执行过程
1、客户端发送命令请求
当用户在客户端输入一个命令,客户端会将这个命令转换为协议格式,通过连接到服务端的套接字,将协议命令发送给服务端。
过程图示:
2、读取命令组装结构
读取命令操作主要分成下面两步:
- 读取套接字中的格式请求,并将其保存到客户端状态的输入缓冲区里面。
- 对输入缓冲区的命令进行分析,提取命令参数与个数信息保存到argv和argc属性中
比如说set key value
这个命令,提取之后填充到客户端状态的参数中的数据结构如下所示:
3、查找命令执行对象(cmd)
在命令表(command table)中查找参数指定的命令,命令表是一个字典,字典的键是命令的名字,字典的值就是redisCommand结构。
以下是redisCommand结构的主要属性:
typedef struct redisCommand{
char *name; //命令的名字
redisCommandProc proc;//函数指针,指向命令的实现函数
int arity ;//命令参数的个数,用于检查命令的请求格式是否正确
char *sflags;//命令的属性,命令的存在值看后面的描述
int flags;//对sflags标识进行分析得出的二进制标识,由程序自动生成
long long calls; //服务器总共执行了多少次这个命令
long long milliseconds;//服务器执行这个命令消耗的总时长
}
sflags标识的值,以及意义:
命令的大小写不影响命令表的查询结果。
4、检查校验操作
- 检查客户端状态的cmd指针是否指向NULL,如果是的话说明用户输入的命令名字找不到相应的命令实现。则应该返回错误
- 根据客户端状态的arity属性,检查命令给定的参数个数是否正确。参数不正确时直接返回错误
- 检查客户端是否通过身份验证,没有通过身份验证返回错误
- 如果服务器打开了maxmemory功能,在执行命令之前,检查内存占用情况,在需要的时候进行内存回收,回收失败返回错误
- …(具体其他的检查操作查看原书描述)
5、执行命令
在之前的操作中,服务器已经把执行命令保存到客户端状态中,所以执行命令操作其实只是通过指针进行一次函数调用即可。被调用的函数实现指定操作,并产生对应的命令回复,这些回复保存在客户端状态的输出(固定)缓冲区中。
6、后续操作
在执行完命令之后,服务器还会执行相应的后续操作,包括下面的操作:
- 如果服务器开启了慢查询日志,那么慢查询日志模块会检查是否需要添加一条新的慢查询日志。
- 更新milseconds和calls计数器
- 如果开启了AOF持久化功能,持久化模块会将刚刚执行的命令写入到AOF文件
- 如果其他服务器正在复制当前服务器,服务器会将命令发送给其他服务器
7、客户端接收命令并打印
客户端收到命令格式的回复消息,会将这些命令转换成可读格式打印在客户端。
2、ServerCron函数
因为ServerCron函数执行的操作比较多,这边只记录我觉得稍微重要点的操作,其他的操作直接参考原书
1、管理客户端资源
ServerCron每次都会调用ClientCron函数,clientCron每次都会对一定数量的客户端进行检查:
- 如果客户端和服务端连接已经超时,程序会释放这个客户端。
- 如果客户端上一次请求,输入缓冲区超过一定长度,服务端会释放客户端当前输入缓冲区,并重新创建一个新的输入缓冲区,从而防止客户端的输入缓冲区消费过多的内存。
2、管理数据库资源
ServerCron每次都会调用databaseCron函数,对一部分数据库进行检查,删除其中的过期键,按照需要对字典进行收缩操作。
3、初始化服务器
略,直接参考原文。