redis客户端与服务器
1、对于每个与服务器连接的客户端,服务器都会为这些客户端建立相应的redis.h/redisClient结构,这个结构保存了客户端当前的状态信息,以及执行相关功能时需要用到的数据结构,其中包括:
- 客户端的套接字描述符
- 客户端的名字
- 客户端的标志值
- 客户端正在使用的数据库指针,以及该数据库的号码
- 客户端当前要执行的命令
- 客户端的输入缓冲区和输出缓冲区
- 客户端的复制状态信息,以及进行复制所需的数据结构
- 客户端执行BRPOP、BLPOP等列表阻塞命令时使用的数据结构
- 客户端的事务状态,以及执行WATCH命令时用到的数据结构
- 客户端执行发布与订阅功能时用到的数据结构
- 客户端身份验证标志
- 客户端的创建时间,客户端和服务器最后一次通信时间,以及客户端的输出缓冲区大小超出软性限制的时间
struct redisServer{
list * clients; *****
}
2、客户端属性
1)、套接字描述符(int fd)
fd值为-1,伪客户端,伪客户端的命令请求来源于AOF文件或Lua脚本,而不是网络,不需要套接字连接
fd为大于-1的整数
2)、name
默认为null,设置方式: client setname yhq
3)、标志(flags)
4)、输入缓冲区(sds querybuf)
5)、命令与命令参数
服务器对querybuf命令解析,将得出的命令参数和参数个数,分别保存到argv属性和argc属性
6)、命令的实现参数
服务器从argv[0]得到命令名称,在名称表中查找对应的命令实现函数。命令表是一字典,字典的值是SDS结构,存了命令的名称,值是redisCommand结构,这个结构保存了命令的实现函数、命令的标志、命令应该给定的参数,命令的总执行次数和总消耗时长等共计信息。然后,程序会把cmd指向该redisCommand结构。再之后,服务器就可以使用cmd指向的redisCommand,argv,argc,调用命令实现函数,执行客户端指定的命令。
7)、输出缓冲区
8)、身份验证
9)、时间
3、关闭普通客户端
- 客户端进程退出或者被杀死,那么客户端和服务器之间的网络连接将被关闭,从而造成客户端被关闭
- 命令不符合协议格式,那么客户端也会被服务器关闭
- 客户端成为client kill的目标
- 客户端空转时间超过设置的timeout配置选项
- 客户端发送的命令超过了输入缓冲区限制大小
- 发送给客户端的命令超过了输出缓冲区的限制大小
4、命令请求的执行过程
4.1 发送命令请求
客户端会将用户命令请求转换成协议格式,然后通过连接到服务器的套接字,将协议格式命令请求发送给服务器
4.2 读取命令请求
当客户端与服务器直接的连接套接字因为客户端的写入而变得可读时,服务器将调用命令请求处理器来执行以下操作:
1) 读取套接字协议格式的命令请求,并将其保存在客户端状态的输入缓冲区里
2) 对输入缓冲区中的命令请求进行分析,解析后放到客户端状态的argv属性和argc属性
3)调用命令执行器,执行客户端指定的命令
3.1)查找命令实现
3.2)执行预编译操作
cmd是否指向null,检查参数个数、身份认证、内存占用情况是否大于maxmemory、bgsave、subscribe、psubscribe、服务器正在进行数据载入、因执行lua脚本儿超时并进入阻塞状态、执行事务、监视器
3.3)调用命令的实现函数
3.4)执行后续工作
慢查询日志功能、命令耗时、AOF、主从服务器(传播给所有从服务器)
4.3、将命令回复发送给客户端
命令实现函数会将命令回复保存到客户端的输出缓冲区里面,并为客户端的套接字关联命令回复处理器,当客户端套接字变为可写状态时,服务器就会执行命令回复处理器,并将保存在客户端输出缓冲区的命令回复发送给客户端。当命令回复发送完毕之后,回复处理器会清空客户端状态的输出缓冲区,为下一个命令请求做好准备
4.4、客户端接收并打印命令回复
5、初始化服务器
一个redis服务器从启动到接收客户端命令请求,需要经过一系列初始化和配置过程,比如初始化服务器状态,接受用户指定的服务器配置,创建相应的数据结构,网络连接,欢迎数据库状态,执行事件循环等等