1. 客户端
1.1 客户端属性
客户端状态包含的属性分为两类:
- 一类是比较通用的属性,无论客户端执行什么工作,都需要用到这些属性。本节主要涉及这些属性
- 另外一类是和特定功能相关的属性,比如操作数据库时用到的db属性和dictid属性,执行事务时需要用到的mstate属性,以及执行WATCH命令时要用到的watched_keys属性等等。
1.1.1 套接字描述符
CLIENT list命令可以显示所有连接到服务器的普通客户端,fd即为服务器连接客户端所使用的套接字描述符。当fd=-1时,表示伪客户端,用于载入AOF文件并还原数据库状态,或者用于执行Lua脚本中包含的命令。
1.1.2 名字
默认情况下,一个连接到服务器的客户端是没有名字的。可以使用CLIENT setname命令为客户端设置一个名字,让客户端身份变得更清晰。
1.1.3 标志
客户端的标志属性flags记录了客户端的角色以及客户端目前的状态
flags = <flag1> | <flag2> | ...
有关标志的含义可以在redis.h文件中查看。
1.1.4 输入缓冲区
客户端的输入缓冲区用于保存客户端发送的命令请求。当超过1GB时,服务器会关闭该客户端
1.1.5 命令与命令参数
在服务器会对客户端的命令请求内容进行分析,并将得出的命令参数以及命令参数的个数分别保存在客户端状态的argv属性和argc属性。argv是一个数组,argv[0[是要执行的命令,之后的其他项是传给命令的参数。
1.1.6 命令的实现函数
当服务器从协议内容中分析得出argv属性和argc属性的值后,服务器会根据argv[0]的值,在命令表(字典结构)中查找命令所对应的命令实现函数。
redisCommand 结构保存了命令的实现函数、命令的标志、命令应该给定的参数个数、命令的总执行次数和总消耗时长等信息。
1.1.7 输出缓冲区
执行命令所得的命令回复会被保存在客户端状态的输出缓冲区里,每个客户端有两个输出缓冲区:
- 固定大小的缓冲区
buf 是一个大小为REDIS_REPLY_CHUNK_BYTES字节的字节数组,而bufpos属性记录buf数组目前已经使用的字节数量。
- 可变大小的缓冲区
由reply链表和一个或多个字符串对象组成
1.1.8 身份验证
客户端状态的authenticated属性用于记录客户端是否通过了身份验证,若为0,没有通过;为1表示通过了身份验证,可以执行命令。
1.1.9 时间
ctime属性记录了创建客户端的时间,即客户端和服务器已经连接了多少秒,通过CLIENT list命令的age参数记录。
lastinteraction属性记录了客户端和服务器最后一次进行互动的时间,可以用来计算客户端的空闲(idle)时间。
obuf_soft_limit_reached_time属性记录了输出缓冲区第一次到达软性限制(soft limit)的时间。如果输出缓冲区的大小超过软性限制所设置的大小,且持续时间超过了服务器设置的时长,那么服务器会关闭客户端。
2. 服务器
2.1 serverCron函数
2.1.1 更新服务器时间缓存
Redis服务器中有不少功能需要获取系统的当前时间,而每次获取系统时间都需要执行系统调用,为了减少系统调用执行次数,服务器状态中的unixtime属性和mstime属性被用作当前时间的缓存
serverCron函数默认以每100毫秒一次的频率更新unixtime属性和mstime属性,所以这两个属性记录的时间并不准确:
- 服务器只会在打印日志、更新服务器的LRU时钟、决定是否执行持久化任务、计算服务器上线时间这种对时间精度要求不高的情况下使用unixtime属性和mstime属性
- 对于为键设置过期时间、添加慢查询日志这种需要高精度时间的功能来说,服务器还是会执行系统调用
2.1.2 更新LRU时钟
服务器状态中lruclock属性保存了服务器的LRU时钟,默认每10秒更新一次时钟缓存。程序用服务器的lruclock属性记录的时间减去对象lru属性记录的时间来得出数据库键的空转时间。
2.1.3 更新服务器每秒执行命令次数
trackOperationsPerSecond函数会以每100毫秒一次的频率执行,通过抽样计算的方式估算并记录服务器在最近一秒钟处理的命令请求数量。
2.1.4 更新服务器内存峰值记录
每次serverCron函数执行时,都会查看服务器当前使用的内存数量,并与stat_peak_memory保存的数值进行比较,保留较大的值。
2.1.5 处理SIGTERM信号
在启动服务器时,Redis会为服务器进程的SIGTERM信号关联处理器sigtermHandler函数,这个信号处理器在接到SIGTERM信号时,打开服务器的shutdown_asap标识,每次serverCron函数运行时,程序都会对服务器状态的shutdown_asap属性进行检查,值为1时,关闭服务器,值为0时,不做动作。当服务器接收到SIGTERM信号后,会先进行持久化操作,然后关闭服务器。
2.1.6 管理客户端资源
serverCron函数每次执行都会调用clientsCron函数,clientsCron函数会对一定数量的客户端进行以下两个检查:
- 如果客户端和服务器之间的连接已经超时,那么程序释放这个客户端
- 如果客户端上一次执行命令请求之后,输入缓冲区的大小超过了一定的长度,那么程序会释放客户端当前的输入缓冲区,并重新创建一个默认大小的输入缓冲区,防止客户端的输入缓冲区耗费过多内存
2.1.7 管理数据库资源
serverCron函数每次执行都会调用databasesCron函数,这个函数对服务器中的一部分数据库进行检查,删除其中的过期键,在满足条件时,对字典进行收缩。
2.1.8 执行被延迟的BGREWRITEAOF
在服务器执行BGSAVE命令期间,如果客户端向服务器发来BGREWRITEAOF命令,那么服务器会将BGREWRITEAOF命令的执行时间延迟到BGSAVE命令执行完毕之后。
aof_rewrite_scheduled表示记录了服务器是否延迟了BGREWRITEAOF命令,如果为1,则表示命令被延迟了。
2.1.9 检查持久化操作运行状态
rdb_child_pid属性为-1表示没有执行BGSAVE命令;aof_child_pid属性为-1表示没有执行GREWRITEAOF命令。
下面的流程图展示了检查过程:
2.1.10 AOF缓冲区中的内容写入AOF文件
第四章持久化有介绍
2.1.11 关闭异步客户端
服务器会关闭输出缓冲区大小超出了限制的客户端
2.1.12 增加cronloops计数器的值
cronloops属性记录了serverCron函数执行的次数,用于某些serverCron函数执行N次,就执行一次的程序。