Redis服务器中的serverCron函数默认每100ms执行一次,这个函数负责管理服务器中的部分资源,并保持服务器自身的良好运转状态。接下来,我们就来梳理一下serverCron函数执行期间做了哪些重要的事情。
1. 更新服务器的时间缓存
由于Redis中有不少功能都要获取系统的当前时间,每次调用如果都执行一次系统调用势必会给系统造成比较大的压力,因此在服务器状态中保存了和时间相关的两个属性:
struct redisServer {
// 保存秒精度的当前unix时间戳
time_t unixtime; /* Unix time sampled every cron cycle. */
// 保存毫秒精度的当前unix时间戳
mstime_t mstime; /* 'unixtime' in milliseconds. */
}
这两个时间会在serverCron函数每次执行时被更新。当时需要注意的是,这两个时间只会在对获取的时间戳精度要求不高的过能上使用,比如说打印日志,是否执行持久化,计算客户端存活时间等操作,对于计算过期时间,慢sql日志计算等功能还是要获取服务器实时时间戳的。
2.更新lru时钟
服务器状态中,lruclock属性保存了服务器的LRU时钟,也是服务器缓存时间的一种,每10s更新一次。
struct redisServer {
// 服务器lru时钟
unsigned int lruclock; /* Clock for LRU eviction */
}
我们知道每个redisObject对象都有一个lru时钟,用于表示当前对象的最后被访问的时间,如果要计算它的空转时长,程序就会使用 redisServer.lruclock - redisObject.lru来计算,所以说这个计算值本身是有误差的。
3.更新服务器内存峰值记录
在服务器状态中,stat_peak_memory这个属性记录了服务器最大内存的峰值记录,每次执行serverCron函数时会检查服务器当前的内存值,与stat_peak_memory比较,如果大于stat_peak_memory 就会更新此值。
struct redisServer {
// 最大内存使用记录
size_t stat_peak_memory; /* Max used memory record */
}
4.管理客户端资源
我们知道同一个服务器会有很多客户端的链接,所以serverCron函数其中一个作用就是调用clientsCron函数,检查客户端的一些状态:
- 如果某个客户端的空转时长超时,会释放此客户端;
- 如果某个客户端的输入缓冲区超过一定长度,会释放输入缓冲区sds的内容,并重建一个新的输入缓冲区替换。
5.过期键的管理
Redis服务器对于过期键的管理是通过惰性删除和定期删除两种策略来实现,其中定期删除就是基于serverCron函数来执行的,每次此函数执行都会在所有数据库中随机选择一部分的键值对进行检查,如果过期就会删除。
6.将AOF缓冲区中的内容写入到AOF文件中
之前我们提到在redisServer中有一个aof_buf的缓冲区用于记录服务器执行的各种写命令,serverCron函数执行时会将aof_buf缓冲区中的内容写入到操作系统文件缓冲pagecache中,然后再执行落盘到磁盘文件的过程。当然后者的是否执行落盘,还是要看appendfsync的配置策略。
写在最后,做个总结。其实serverCron函数执行的操作远不止上面这6项,如果对serverCron函数感兴趣可以深入源码继续解读,我记录的这6项是平时接触比较多的一项操作的。