Redis由一个redisClient结构体来保存和服务端发生连接的客户端当前的状态信息和执行相关功能时需要用到的数据结构,包括下面这些信息:
fd:套接字描述符
name:名字
flags
querybuf:输入缓冲区
输出缓冲区
cmd:当前要执行的命令与命令参数
authenticated:身份验证标识
时间
套接字描述符
fd属性保存客户端正在使用的套接字描述符。普通客户端它是一个大于-1的整数,如果客户端是伪客户端该属性值为-1,redis在加载AOF文件或执行Lua脚本时会创建一个伪客户端(Fake Client)来执行命令。
名字
默认情况下客户端是没有名字的,当客户端执行了CLIENT setname命令之后,服务器会给该客户端设置名字,并把名字保存在redisClient结构体的name属性中。
标志
flags属性,记录了客户端的角色,以及客户端所处的状态,flags可以表示单个标志,也可以表示多个标志比如flags= flag1 | flag2 | ...。该属性有下列枚举值:
REDIS_MASTER:主从服务器进行复制操作时,主服务器会成为从服务器的客户端,从服务器也会成为主服务器的客户端,该状态表示当前客户端正在执行主从复制操作,并且客户端是一个主服务器。
REDIS_SLAVE:和REDIS_MASTER相对应,该状态表示客户端是主从复制时的从服务器角色。
REDIS_PRE_PSYNC:标识客户端是一个低于2.8版本的从服务器,主服务器不能使用PSYNC与这个从服务器进行部分同步操作。
REDIS_LUA_CLIENT:标识客户端是一个专门处理LUA脚本的伪客户端。
REDIS_MONITOR:标识客户端正在执行MONITOR命令
REDIS_UNIX_SOCKET:标识服务器使用UNIX套接字来连接客户端。
REDIS_BLOCKED:标识客户端被BRPOP、BLPOP等命令阻塞。
REDIS_UNBLOCKED:标识客户端已经从REDIS_BLOCKED状态脱离。
REDIS_MULTI:标识客户端正在执行事务。
REDIS_DIRTY_CAS:标识表示事务正在使用WATCH命令监视的key已经被修改。
REDIS_DIRTY_EXEC:标识事务在命令入队时出现了错误,REDIS_DIRTY_CAS和REDIS_DIRTY_EXEC:标识事务的安全性已经被破坏,事务会执行失败。
REDIS_CLOSE_ASAP:标识输出缓冲区超出了服务器允许的范围,服务器在下一次执行serverCron函数时会关闭这个客户端。
REDIS_CLOSE_AFTER_REPLY:标识有用户对该客户端执行了CLIENT KILL命令。
REDIS_ASKING:标识客户端向集群节点发送了ASKING命令。
REDIS_FORCE_AOF:强制服务器将当前命令写入AOF文件。
REDIS_FORCE_REPL:强制主服务器将当前执行的命令复制给所有从服务器。
REDIS_MASTER_FORCE_REPLY:从服务器向主服务器发送REPLICATION ACK命令前,主服务器对应的客户端需要打开该标识。
输入缓冲区
querybuf属性,它是一个sds类型。缓存客户端的命令,缓冲区的大小根据内容的大小动态的扩大或缩小,但是最大大小不能超过1G,否则服务器会采取保护措施关闭客户端。
输出缓冲区
缓存服务器给客户端的回复,每个客户端有两个缓冲区,一个固定长度(默认16K),用来存储长度较小的回复,一个动态长度,用来回复长度比较大的命令,但是为了避免缓冲区过来占用太多资源,服务器使用两种模式来限制缓冲区大小:
1、硬性限制:当缓冲区大小超出硬性限制大小之后,服务器马上关闭客户端。
2、软性限制:当缓冲区大小超出软性限制大小之后,但没有超出硬性限制,服务器通过obuf_soft_limit_reached_time属性记录客户端到达软性限制的起始时间,之后服务器会持续监视客户端,如果输出缓冲区一直超出软性限制,并且持续时间超过服务器设定的时长,那么服务器将关闭客户端;相反地如果输出缓冲区在指定时间内不再超出软性限制,那么客户端不会被关闭,并且obuf_soft_limit_reached_time属性值也会被清零。
client-output-buffer-limit选项可以为普通客户端、从服务器客户端、执行发布与订阅功能的客户端设置不同的软性限制和硬性限制,该选项格式为client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>,以下是三个设置示例:
client-output-buffer-limit normal 0 0 0,对普通客户端不限制输出缓冲区大小;
client-output-buffer-limit slave 256mb 64mb 60,从服务器客户端硬性显示为256M,软性限制为64M,软性限制时长60s;
client-output-buffer-limit pubsub 32mb 8mb 60,发布订阅客户端硬性限制32M,软性限制8M,软性限制时长60s。
当前要执行的命令与命令参数
服务端对输入缓存区中的命令进行解析之后,把命令参数和命令参数个数分别保存在redisClient结构体的argv属性和argc属性中。命令对应的结构体是redisCommand,在redisCommand中会记录该命令执行的总次数和总时长,redisClient结构体中的cmd属性是一个redisCommand类型,存储当前客户端正在执行的命令。服务器中维护了一个hash表保存所有Redis命令,key为命令名,value为redisCommand结构。
身份验证标识
authenticated属性记录客户端是否通过了身份验证,0位通过,1已通过。当客户端未通过验证时服务器会拒绝该客户端除AUTH命令外的任何其它命令。
时间
客户端还保存几个跟时间相关的属性:
ctime:客户端创建的时间。
lastinteraction:客户端最后一次与服务器互动的时间。
obuf_soft_limit_reached_time:输出缓冲区第一次达到软性限制的时间。
关闭普通客户端
保存客户端状态会消耗服务端的内存资源和句柄资源,为了能够及时的释放资源,Redis服务器在下列条件会关闭客户端:
客户端进程退出或被杀死。
客户端向服务器发送了不符合格式的命令。
客户端被执行了CLIENT KILL命令。
用户为服务器设置了timeout选项,那么当客户端的空转时长超过timeout时,客户端会被关闭,不过也有例外,比如当客户端被BLPOP等命令阻塞或正在执行发布订阅命令,这时即使空转时间超过了timeout也不会关闭连接。
客户端发送的命令请求的大小超出了输入缓冲区大小(默认1G)。
客户端的命令回复大小超过了输出缓冲区的硬性限制,或者超出软性限制达到一定的时长。