对于每个与服务器进行连接的客户端,服务器都为这些客户端建立相应的redis.h/redisClient结构
1.客户端属性
/*
* 客户端结构
*
* 为每个连接到服务器的客户端保存维持一个该结构的映射,
* 从而实现多路复用。
*/
typedef struct redisClient {
// socket 文件描述符
int fd;
// 指向当前目标数据库的指针
redisDb *db;
// 当前目标数据库的号码
int dictid;
// 查询缓存
sds querybuf;
size_t querybuf_peak; /* Recent (100ms or more) peak of querybuf size */
// 参数的个数
int argc;
// 字符串表示的命令,以及命令的参数
robj **argv;
// 命令,以及上个命令
struct redisCommand *cmd, *lastcmd;
// 回复类型
int reqtype;
int multibulklen; /* number of multi bulk arguments left to read */
long bulklen; /* length of bulk argument in multi bulk request */
// 保存回复的链表
list *reply;
// 链表中保存的所有回复的总字节大小
unsigned long reply_bytes; /* Tot bytes of objects in reply list */
// 统计数据
int sentlen;
time_t ctime; /* Client creation time */
time_t lastinteraction; /* time of the last interaction, used for timeout */
time_t obuf_soft_limit_reached_time;
int flags; /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... */
// 复制功能相关
int slaveseldb; /* slave selected db, if this client is a slave */
int authenticated; /* when requirepass is non-NULL */
// 客户端当前的同步状态
int replstate; /* replication state if this is a slave */
// 同步数据库的文件描述符
int repldbfd; /* replication DB file descriptor */
// 同步数据库文件的偏移量
long repldboff; /* replication DB file offset */
// 同步数据库文件的大小
off_t repldbsize; /* replication DB file size */
int slave_listening_port; /* As configured with: SLAVECONF listening-port */
// 事务实现
multiState mstate; /* MULTI/EXEC state */
// 阻塞状态
blockingState bpop; /* blocking state */
list *io_keys; /* Keys this client is waiting to be loaded from the
* swap file in order to continue. */
// 被监视的 KEY
list *watched_keys; /* Keys WATCHED for MULTI/EXEC CAS */
// 订阅与发布
dict *pubsub_channels; /* channels a client is interested in (SUBSCRIBE) */
list *pubsub_patterns; /* patterns a client is interested in (SUBSCRIBE) */
/* Response buffer */
// 回复缓存的当前缓存
int bufpos;
// 回复缓存,可以保存多个回复
char buf[REDIS_REPLY_CHUNK_BYTES];
} redisClient;
1.1 套接字描述符
客户端状态的 fd 属性记录了客户端正在使用的套接字描述符
根据客户端类型不同,fd属性的值可以是-1或者大于-1的整数:
- 伪客户端为-1 AOF文件,Lua脚本
- 普通客户端大于-1的整数:记录客户端套接字的描述符。
1.2 名字
在默认情况下,一个连接到服务器的客户端是没有名字的 CLIENT list
CLIENT setname
1.3 标志
flags记录客户端的角色,以及客户端目前所处的状态
1.4 输入缓冲区
用于保存客户端发送的命令请求
1.5 命令与命令参数
argv
argv[0]命令 ,其他参数
argc
参数个数,包括argv[0]
1.6 命令的实现函数
针对命令表的查找操作不区分输入字母的大小写
1.7 输出缓冲区
执行命令所得的命令回复会被保存在客户端状态的输出缓冲区里面,每个客户端都有两个输出缓冲区可用,一个缓冲区的大小是固定的,另一个缓冲区的大小是可变的:
- 固定大小的缓冲区用于保存那些长度比较小的回复,比如OK,简短的字符串值、整数值、错误回复等
- 可变大小的缓冲区用于保存那些长度比较大的回复,比如一个非常长的字符串值,一个由很多项组成的列表,一个包含了很多元素的集合等等
固定缓冲区由buf和bufpos两个属性组成。
可变大小缓冲区由reply链表和一个或多个字符串对象组成
1.8 身份验证
authenticated属性用于记录客户端是否通过了身份验证
仅在服务器启用了身份验证功能时使用。
1.9 时间
2.客户端的创建与关闭
2.1 创建普通客户端
2.2 关闭普通客户端
被关闭原因:
- 客户端进程退出或者被杀死
- 客户端向服务器发送了带有不符合协议格式的命令请求
- 客户端成为了CLIENT KILL命令的目标
- 服务器设置了timeout配置选项,那么当客户端的空转时间超过timeout选项设置的值时,客户端将被关闭。
- 客户端发送的命令请求的大小超过了输入缓冲区的限制大小(默认为1GB)
- 要发送给客户端的命令回复的大小超过了输出缓冲区的限制大小
服务器使用两种模式来限制客户端输出缓冲区的大小:
- 硬性限制:超过硬性限制,立即关闭客户端
- 软性限制:超过软性限制,没有超过硬性限制,obuf_soft_limit_reached_time属性记录客户端达到软性限制的起始时间;之后服务器继续监视客户端,如果输出缓冲区的大小超出软性限制,并且持续时间超过服务器设定的时长,那么服务器将关闭客户端;相反,在指定时间之内,不在超出软性限制,客户端就不会被关闭,并且obuf_soft_limit_reached_time属性的值也会被清0.
2.3 Lua脚本的伪客户端
lua_client伪客户端在服务器运行的整个生命期中会一直存在,只有服务器被关闭时,这个客户端才会被关闭。
2.4 AOF文件的伪客户端
在载入完成后,关闭这个伪客户端