二. serverCron函数
2.3 更新服务器每秒执行命令次数
serverCron函数中的trackOperationsPerSecond函数会以每100毫秒一次的频率执行,这个函数以抽样计算的方式,估算并记录服务器在最近一秒钟处理的命令请求数量,这个值可以通过info status命令的instantaneous_ops_sec域查看:
127.0.0.1:6379> info stats # Stats total_connections_received:5 total_commands_processed:67 //服务器在最近一秒钟处理的命令请求数量 instantaneous_ops_per_sec:0
关于trackOperationsPerSecond函数的内部实现就不再介绍,大致是当客户端执行INFO命令时,服务器就会调用getOperationsPerSecond函数,根据ops_sec_samples环形数组中的抽样结果,计算出instantaneous_ops_per_sec属性的值。
2.4 更新服务器内存
服务器状态redisServer结构的stat_peak_memory属性记录了服务器的内存峰值大小,每次serverCron函数执行时,程序都会查看服务器当前使用的内存数量,并与stat_peak_memory保存的数值进行比较,如果当前的内存数量比stat_peak_memory属性记录的值要大,那么程序就将当前使用的内存数量记录到stat_peak_memory属性记录中。INFO memory命令的used_memory_peak和used_memory_peak_human两个域分别以两种格式记录了服务器的内存峰值。
127.0.0.1:6379> info memory # Memory used_memory_peak:858952 used_memory_peak_human:838.82K
这两个是域是指过去Redis内存使用的峰值,是反映了内存过去最高峰值,而不是当前使用内存的值。
2.5 处理sigterm信号
在启动服务器时,redis会为服务器进程的singterm信号关联处理器singtermHandler函数,这个信息处理器负责在服务器接收到singterm信号时,打开服务器状态的shutdown_asap标识。 每次serverCron函数运行时,程序都会对服务器状态redisServer结构函数的shutdown_asap属性进行检查,并根据属性的值决定是否关闭服务器。
static void sigtermHandler(int sig){ //打印日志 redisLogFromHandler(reids_warning,"received sigterm, scheduling shutdown..."); //打开关闭标识 server.shutdown_asap=1; }
//下面先打开日志功能,在redis.conf文件中设置日志文件路径,保存配置文件,重启服务。 171 logfile /usr/local/redis/redis.log [[email protected] redis]# redis-server redis.conf //当在客户端执行shutdown关闭服务器时,服务器在接到sigterm信号之后,关闭服务器并打印相关日志。 127.0.0.1:6379> shutdown not connected>
日志显示可以看到,服务器在关闭自身之前会进行RDB持久化操作,这也是服务器拦截sigterm信号的原因,日志信息如下:
43:M 06 Dec 11:07:42.562 # User requested shutdown... 42343:M 06 Dec 11:07:42.562 * Saving the final RDB snapshot before exiting. 42343:M 06 Dec 11:07:42.565 * DB saved on disk 42343:M 06 Dec 11:07:42.565 * Removing the pid file. 42343:M 06 Dec 11:07:42.565 # Redis is now ready to exit, bye bye...
2.6 管理客户端资源
serverCron函数每次执行都会调用clinetsCron函数,该函数会对一定数量的客户端进行检查,包括1.如果客户端与服务器的连接已经超时(如很长时间没有互动),那么程序会释放这个客户端。2.如果客户端在上一次执行命令请求之后,输入缓冲区的大小超过了一定的长度,那么程序会释放客户端当前的输入缓冲区。
2.7 执行被延迟的bgrewriteaof
说到bgsave和bgrewriteaof二个客户端命令,前者针对RDB持久化,后者针对AOF 持久化。在服务器执行bgsave命令的期间,如果客户端向服务器发送了bgrewriteaof命令,那么服务器会将bgrewriteaof命令的执行时间延迟到bgsave命令执行完毕之后。每次serverCron函数执行时,都会检查bgsave命令或者bgrewriteaof命令是否正在执行,如果这两个命令都没在执行,并且aof_rewrite_scheduled属性的值为1,那么服务器就会执行之前被推延的bgrewriteaof命令。
struct redisServer { //如果值为1, 那么表示有bgrewriteaof命令被延迟了 int aof_rewrite_scheduled; }
2.8 检查持久化操作的运作状态
服务器状态使用redisServer结构的rdb_child_pid属性和aof_child_pid属性记录执行bgsave命令和bgrewriteaof命令的子进程的ID,这两个属性也可以用于检查bgsave命令或者bgrewriteaof命令是否正在执行。
struct redisServer { //记录执行bgsave命令的子进程的ID //如果服务器没有在执行bgsave,那么这个属性的值为-1. pid_t rdb_chlid_pid; //记录执行bgrewriteaof命令的子进程的ID //如果服务器没有在执行bgrewriteaof,那么这个属性的值为-1. pid_t aof_chlid_pid; }
每次serverCron函数执行时,程序都会检查rdb_chlid_pid和aof_child_pid两个属性值,只要其中一个属性的值不为-1, 代表正在执行,程序就会执行一次wait3函数,检查子进程是否有信号发给服务器主进程。如果有信号到达:那么对于bgsave命令来说,新的rdb文件已经生成; 对于bbgrewriteaof命令来说,AOF文件已经重写完成; 服务器需要进行相应命令的后续操作,比如用新的RDB文件替换现有RDB文件,或者用重写后的AOF文件替换现有的AOF文件。如果没有信号到达,那么表示持久化操作未完成,程序不做动作。
三.初始化服务器
一个Redis服务器启动后,需要经过一系列的初始化和设置过程。比如(3.1)初始化服务器状态;(3.2)接受用户指定的服务器配置;(3.3)创建相应的数据结构和网络连接等。
3.1 初始化服务器状态结构
初始化服务器第一步就是创建一个struct redisServer类型的实例变量server作为服务器状态,并为结构中的各个属性设置默认值。初始化server变量的工作由redis.c/initServerConfig函数完成。主要包括:设置服务器运行ID(info 命令信息中的run_id);设置服务器的默认运行频率(hz,在18 事件篇中有讲);设置服务器的默认文件路径(info 命令信息中的config_file) ;设置服务器运行架构(info 命令信息中的arch_bits) ;设置服务器的默认端口号(info 命令信息中的tcp_port) ;设置服务器的默认RDB持久化条件和AOF持久化条件;初始化服务器的LRU时钟;创建命令表。 该initServerConfig函数没有创建服务器状态的其他数据结构;数据库;慢查询日志;LUA环境;共享对象,这些数据结构在之后的步骤才会被创建出来
127.0.0.1:6379> info # Server redis_version:4.0.6 redis_git_sha1:00000000 redis_git_dirty:0 redis_build_id:836bbbcc913c7a57 redis_mode:standalone os:Linux 3.10.0-693.el7.x86_64 x86_64 arch_bits:64 multiplexing_api:epoll atomicvar_api:atomic-builtin gcc_version:4.8.5 process_id:58994 run_id:b0694f86c7e794bf851f6193f1f96d85f993f325 tcp_port:6379 uptime_in_seconds:20 uptime_in_days:0 hz:10 lru_clock:659411 executable:/usr/local/redis/redis-server config_file:/usr/local/redis/redis.conf
3.2 载入配置选项
在启动服务器时,用户可以通过给定配置参数或者指定配置文件来修改服务器的默认配置,当服务器在用initServerConfig函数初始化完server变量之后,就会开始载入用户给定的配置参数和配置文件,并根据用户设定的配置,对server变量相关属性的值进行修改。
例1:用户在终端中指定redis服务器端口号,默认端口从6379变为了10086,启动服务
[[email protected] redis]# redis-server --port 10086 60098:C 07 Dec 16:04:05.183 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo //下面通过另一个客户端,指定端口,连接到服务器,通过info来查看,是没有config_file的配置路径。 [[email protected] ~]# redis-cli -h 127.0.0.1 -p 10086 127.0.0.1:10086>info # Server redis_version:4.0.6 ....
例2: 用户通过加载redis.conf配置文件,这是最常见的启动服务。通过info来查看,这种是有config_file的配置路径的
[[email protected] redis]# redis-server redis.conf
通过上面案例知道,如果用户为服务器状态属性指定了新的值,那么服务器就会更新相应的属性值,如果没有为属性设置新的值,那么服务器就用之前initServerConfig函数为属性设置的默认值。
3.3 初始化服务器数据结构
服务器在载入用户指定的配置选项,并对server状态进行更新之后,服务器就可以进入初始化第三个阶段,此时服务器创建的数据结构还包括:server.clients链表;server.db数组;保存频道订阅信息的server.pubsub_channels字典以及server.pubsub_patterns链表; 用于执行Lua脚本的server.lua; 用于保存慢日志的server.slowlog属性。
接着服务器将调用initServer函数,为以上的数据结构分配内存,该函数设置还包括:为服务器设置进程号处理器;创建共享对象;打开服务器监听端口;为serverCron函数创建时间事件;做好AOF持久化写入准备;初始化服务器后台I/O模块。当initServer函数执行完后,服务器将用ascll字符在日志中打印出redis的图标,以及redis的版本号信息。
3.4 还原数据库状态
在完成了对服务器状态server变量的初始化之后,服务器需要载入RDB文件或者AOF文件,并根据文件记录的内容来还原服务器的数据库状态。如果服务器启用了AOF持久化功能,那么服务器使用AOF文件来还原数据库状态;相反 如果服务器没有启用AOF持久化功能,那么服务器使用RDB文件来还原数据库状态。
60183:M 07 Dec 16:06:15.343 * DB loaded from disk: 0.000 seconds
原文地址:https://www.cnblogs.com/lonelyxmas/p/10230775.html