赞
踩
Redis服务器负责与多个客户端建立网络连接,处理客户端发送的命令请求,在数据库中保存客户端执行命令所产生的数据,并通过资源管理来维持服务器自身的运转。
命令请求执行过程
一个命令请求从发送到获得回复的过程中,客户端和服务器需要完成一系列操作。举个例子,如果我们使用客户端执行以下命令:
redis> SET KEY VALUE
OK
那么从客户端发送SET KEY VALUE命令到获得回复oK期间,客户端和服务器共需要执行以下操作:
客户端向服务器发送命令请求SET KEY VALUE。
2)服务器接收并处理客户端发来的命令请求SET KEY VALUE,在数据库中进行设置操作,并产生命令回复OK。
3)服务器将命令回复oK发送给客户端。
4)客户端接收服务器返回的命令回复oK,并将这个回复打印给用户观看。
发送命令请求
Redis服务器的命令请求来自Redis 客户端,当用户在客户端中键入一个命令请求时,客户端会将这个命令请求转换成协议格式,然后通过连接到服务器的套接字,将协议格式的命令请求发送给服务器,如图14-1所示。
读取命令请求
当客户端与服务器之间的连接套接字因为客户端的写人而变得可读时,服务器将调用命令请求处理器来执行以下操作:
读取套接字中协议格式的命令请求,并将其保存到客户端状态的输入缓冲区里面。
对输人缓冲区中的命令请求进行分析,提取出命令请求中包含的命令参数,以及命令参数的个数,然后分别将参数和参数个数保存到客户端状态的argv属性和argc属性里面。
3)调用命令执行器,执行客户端指定的命令。
继续用上一个小节的SET命令为例子,图14-2展示了程序将命令请求保存到客户端状态的输入缓冲区之后,客户端状态的样子。
将得出的分析结果保存到客户端状态的argv属性和argc属性里,如图14-3所示。
命令执行器(1):查找命令实现 P195
命令执行器要做的第一件事就是根据客户端状态的argv [0]参数,在命令表 ( commandtable)中查找参数所指定的命令,并将找到的命令保存到客户端状态的cmd属性里面。
命令表是一个字典,字典的键是一个个命令名字,比如"set"、 "get"、"del"等等;而字典的值则是一个个rediscommand结构,每个rediscommand结构记录了一个Redis命令的实现信息,表14-1记录了这个结构的各个主要属性的类型和作用。
命令执行器(2):执行预备操作 P198
命令执行器(3):调用命令的实现函数 P199
命令执行器(4):执行后续工作 P183
将命令回复发送给客户端
前面说过,命令实现函数会将命令回复保存到客户端的输出缓冲区里面,并为客户端的套接字关联命令回复处理器,当客户端套接字变为可写状态时,服务器就会执行命令回复处理器,将保存在客户端输出缓冲区中的命令回复发送给客户端。
当命令回复发送完毕之后,回复处理器会清空客户端状态的输出缓冲区,为处理下一个命令请求做好准备。
客户端接收并打印命令回复
当客户端接收到协议格式的命令回复之后,它会将这些回复转换成人类可读的格式,并打印给用户观看(假设我们使用的是Redis自带的redis-cli客户端),如图14-8所示。
serverCron函数
Redis服务器中的serverCron函数默认每隔100毫秒执行一次,这个函数负责管理服务器的资源,并保持服务器自身的良好运转。
更新服务器时间缓存
Redis服务器中有不少功能需要获取系统的当前时间,而每次获取系统的当前时间都需要执行一次系统调用,为了减少系统调用的执行次数,服务器状态中的unixtime属性和mstime属性被用作当前时间的缓存。
因为serverCron函数默认会以每100毫秒一次的频率更新unixtime属性和mstime属性,所以这两个属性记录的时间的精确度并不高:
服务器只会在打印日志、更新服务器的LRU时钟、决定是否执行持久化任务、计算服务器上线时间( uptime)这类对时间精确度要求不高的功能上。
对于为键设置过期时间、添加慢查询日志这种需要高精确度时间的功能来说,服务器还是会再次执行系统调用,从而获得最准确的系统当前时间。
更新LRU时钟
服务器状态中的lruclock属性保存了服务器的LRU时钟,这个属性和上面介绍的unixtime属性、mstime属性一样,都是服务器时间缓存的一种。
当服务器要计算一个数据库键的空转时间(也即是数据库键对应的值对象的空转时间),程序会用服务器的lruclock属性记录的时间减去对象的lru属性记录的时间,得出的计算结果就是这个对象的空转时间。
更新服务器每秒执行命令次数
serverCron函数中的trackoperationsPerSecond函数会以每100毫秒一次的频率执行,这个函数的功能是以抽样计算的方式,估算并记录服务器在最近一秒钟处理的命令请求数量,这个值可以通过INFO status命令的instantaneous_ops_per_sec域查看。
更新服务器内存峰值信息
服务器状态中的stat_peak_memory属性记录了服务器的内存峰值大小。
每次serverCron函数执行时,程序都会查看服务器当前使用的内存数量,并与stat_peak_memory保存的数值进行比较,如果当前使用的内存数量比stat_peak_memory属性记录的值要大,那么程序就将当前使用的内存数量记录到stat_peak_memory属性里面。
处理SIGTERM信号
在启动服务器时,Redis会为服务器进程的SIGTERM信号关联处理器sigtermHandler函数,这个信号处理器负责在服务器接到SIGTERM信号时,打开服务器状态的shutdown_asap标识。
每次serverCron函数运行时,程序都会对服务器状态的shutdown_asap属性进行检查,并根据属性的值决定是否关闭服务器:
管理客户端资源
serverCron函数每次执行都会调用clientscron函数,clientsCron函数会对-定数量的客户端进行以下两个检查:
如果客户端与服务器之间的连接已经超时(很长一段时间里客户端和服务器都没有互动),那么程序释放这个客户端。
如果客户端在上一次执行命令请求之后,输人缓冲区的大小超过了一定的长度,那么程序会释放客户端当前的输入缓冲区,并重新创建一个默认大小的输入缓冲区,从而防止客户端的输入缓冲区耗费了过多的内存。
管理数据库资源
serverCron函数每次执行都会调用databasescron函数,这个函数会对服务器中的一部分数据库进行检查,删除其中的过期键,并在有需要时,对字典进行收缩操作。
执行被延迟的BGREWRITEAOF
在服务器执行BGSAVE命令的期间,如果客户端向服务器发来BGREWRITEAOF命令,那么服务器会将BGREWRITEAOF命令的执行时间延迟到BGSAVE命令执行完毕之后。
服务器的aof_rewrite_scheduled标识记录了服务器是否延迟了BGREWRITEAOF命令。
每次serverCron函数执行时,函数都会检查BGSAVE命令或者BGREWRITEAOF命令是否正在执行,如果这两个命令都没在执行,并且aof_rewrite_scheduled属性的值为1,那么服务器就会执行之前被推延的BGREWRITEAOF命令。
检查持久化操作的运行状态
服务器状态使用rdb_child_pid属性和aof_child_pid属性记录执行BGSAVE命令和BGREWRITEAOF命令的子进程的ID,这两个属性也可以用于检查BGSAVE命令或者BGREWRITEAOF命令是否正在执行。
每次serverCron函数执行时,程序都会检查rdb_child_pid和aof_child_pid两个属性的值,只要其中一个属性的值不为-1,程序就会执行一次wait3函数,检查子进程是否有信号发来服务器进程:
如果有信号到达,那么表示新的RDB文件已经生成完毕(对于BGSAVE命令来说),或者AOF文件已经重写完毕(对于BGREWRITEAOF命令来说),服务器需要进行相应命令的后续操作,比如用新的RDB文件替换现有的RDB文件,或者用重写后的AOF 文件替换现有的AOF文件。
如果没有信号到达,那么表示持久化操作未完成,程序不做动作。
将AOF缓冲区中的内容写入AOF文件
如果服务器开启了AOF持久化功能,并且AOF缓冲区里面还有待写入的数据,那么servercron函数会调用相应的程序,将AOF缓冲区中的内容写入到AOF文件里面。
关闭异步客户端
在这一步,服务器会关闭那些输出缓冲区大小超出限制的客户端
增加cronloops计数器的值
服务器状态的cronloops属性记录了servercron函数执行的次数
初始化服务器
一个Redis服务器从启动到能够接受客户端的命令请求,需要经过一系列的初始化和设置过程,比如初始化服务器状态,接受用户指定的服务器配置,创建相应的数据结构和网络连接等等。
初始化服务器状态结构
初始化服务器的第一步就是创建一个struct redisServer类型的实例变量server作为服务器的状态,并为结构中的各个属性设置默认值。
初始化server变量的工作由redis.c/initServerConfig函数完成,以下是这个函数最开头的一部分代码:
以下是initServerConfig函数完成的主要工作:
设置服务器的运行ID。
设置服务器的默认运行频率。
设置服务器的默认配置文件路径。
设置服务器的运行架构。
设置服务器的默认端口号。
设置服务器的默认RDB持久化条件和AOF持久化条件。
初始化服务器的LRU时钟。
创建命令表。
载入配置选项P211
在启动服务器时,用户可以通过给定配置参数或者指定配置文件来修改服务器的默认配置。
初始化服务器数据结构P211
还原数据库状态
执行事件循环
重点
一个命令请求从发送到完成主要包括以下步骤:1)客户端将命令请求发送给服务器;2)服务器读取命令请求,并分析出命令参数;3)命令执行器根据参数查找命令的实现函数,然后执行实现函数并得出命令回复;4)服务器将命令回复返回给客户端。
serverCron函数默认每隔100毫秒执行一次,它的工作主要包括更新服务器状态信息,处理服务器接收的SIGTERM信号,管理客户端资源和数据库状态,检查并执行持久化操作等等。
服务器从启动到能够处理客户端的命令请求需要执行以下步骤:1)初始化服务器状态;2)载入服务器配置;3)初始化服务器数据结构;4)还原数据库状态;5 )执行事件循环。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。