Redis客户端
Redis是典型的一对多服务器程序,一个服务器可以与多个客户端建立网络连接,每个客户端可以向服务器发送命令请求,服务器可以处理请求并回复。
redis中,所有的客户端信息都保存在redisServer的clients结构体中。
1 | struct redisServer { |
一个具体的结构如下:
客户端属性
客户端属性分为两类:
一类是比较普通的属性,一类是和特定功能相关的属性。
套接字描述符
客户端状态的fd属性记录了客户端正在使用的套接字描述符:
1 | typedef struct redisClient { |
根据客户端的种类不同,fd可以为-1 或者大于-1的整数。
伪客户端的fd属性为-1,它处理的命令请求来源于AOF文件或者Lua脚本,而不是网络,所以这种客户端不需要套接字连接。有两个地方会用到,一个用于载入AOF文件,另一个用于执行Lua脚本中包含的Redis命令。
普通客户端的fd属性为大于-1的整数,普通客户端使用套接字来与服务器进行通信,服务器用fd属性来记录客户端套接字。
名字
1 | typedef struct redisClient { |
标记
1 | typedef struct redisClient { |
输入缓冲区
1 | typedef struct redisClient { |
一个具体的结构如下:
命令与参数
在服务器将客户端发送的命令请求保存到客户端的querybuf中之后,服务器会将命令的内容进行解析,并将得出命令参数以及命令参数的个数,分别保存到客户端的argv和argc属性当中。
1 | typedef struct redisClient { |
一个具体的例子如下:
命令的实现函数
当服务器从协议内容中分析得出argv和argc的属性之后,服务器会根据argv[0]的值去命令表中查看对应命令的实现。
一个具体的命令表如下所示:
其中redisCommand结构如下:
1 | typedef struct redisClient { |
查找对具体的命令对应的操作之后,会把客户端状态的cmd指向该命令所对应的具体执行过程的结构体,也就是上面的redisCommand。
输出缓冲区
执行命令得到的回复会被保存在客户端状态的输出缓冲区里,每个客户端都有两个输出缓冲区,一个缓冲区的大小是固定的,另一个缓冲区的大小是可变的。
固定大小的缓冲区用于保存那些长度比较小的回复,比如OK,简短的字符串值,整数,错误恢复等。
可变大小的缓冲区用于保存那些长度比较大的回复,比如一个非常长的字符串值,一个包含很多元素的集合等。
客户端固定大小的缓冲区由buf和bufpos两部分组成:
1 | typedef struct redisClient { |
其中buf是一个字节数组,而bufpos记录了字节数组中已经使用的字节数量。
当buf数组的空间使用完,或者因为回复太大没办法放进去时,就会采用可变大小缓冲区。
可变大小缓冲区由reply链表和一个或多个字符串对象组成
1 | typedef struct redisClient { |
通过使用链表来链接多个字符串对象,服务器可以为客户端保存一个非常长的命令回复。具体结构如下:
时间
客户端还有几个其他的关键属性
1 | typedef struct redisClient { |
ctime属性记录了创建客户端的时间,这个时间用于计算客户端与服务器连接了多长时间。
lastinteraction记录了客户端最后一次与服务器互动的时间,这个互动可以是客户端向服务器发送命令,也可以是服务器向客户端发送命令回复。
obuf_soft_limit_reached_time记录了输出缓冲区第一次到达软性限制的时间。
客户端的创建与关闭
创建普通客户端
如果客户端是使用网络连接的普通客户端,那么客户端在使用connect连接到服务器时,服务器会在redisServer的clients属性后多链接一个客户端。如下图所示
关闭普通客户端
一个客户端可以因为多种原因被关闭:
如果客户端进程退出或被杀死,那么客户端与服务器之间的网络连接被关闭,造成客户端被关闭。
如果客户端发送带有不符合协议格式的请求命令,也会被关闭。
如果客户端成为了CLIENT KILL 命令的目标,也会被关闭。
如果用户为服务器设置了timeout属性,那么客户端的空转时间超过timeout选项设置的值,客户端也会关闭。
如果客户端发送的请求命令大于输入缓冲区的大小会被关闭。
如果要发送给客户端的命令回复大小超过了输出缓冲区的大小限制,那么这个客户端也会被关闭。
服务器使用两种模式来限制输出缓冲区大小:
1、硬性限制:如果缓冲区大小超出了硬性限制大小,客户端会被立刻关闭。
2、软性限制:超过软性限制大小但是没超过硬性大小,那么服务器将使用客户端状态obuf_soft_limit_reached_time属性记录客户端到达软性限制的起始时间,之后会监视这个客户端,如果超出软性限制的时间超过了服务器设定的时间,那么客户端会被关闭。
参考
《Redis设计与实现》