Redis5.0关于INFO命令Clients模块缓存统计的优化
背景:某天看到Redis5.0 INFO 命令Clients模块返回的内容为client_recent_max_input_buffer,client_recent_max_output_buffer(如下图左);而5.0之前返回的内容为client_longest_output_list,client_biggest_input_buf。好奇心驱使我去查找相关源码内容
一、Redis5.0机制
1、INFO命令Clients模块调用信息如下图,可以看到该模块调用的是getExpansiveClientsInfo 函数。
getExpansiveClientsInfo 函数内容如下,该代码的注释里说此函数是返回被clientsCronTrackExpansiveClients记录的使用最大内存的结果
内容是循环对比,获取ClientsPeakMemInput[CLIENTS_PEAK_MEM_USAGE_SLOTS]、ClientsPeakMemoutput[CLIENTS_PEAK_MEM_USAGE_SLOTS]数组里面的最大值
我们继续来看clientsCronTrackExpansiveClients()函数的内容,里面调用了计算输入缓冲区和输出缓冲区大小的函数。即该函数是记录输入&输出缓冲区的大小
继续来看clientsCronTrackExpansiveClients函数的调用关系,发现该函数由系统内部的定时任务clientsCron定时调用。
总结:Redis5.0版本INFO命令Clients模块是通过clientsCron定时任务调用统计函数clientsCronTrackExpansiveClients去记录最近最大的输入和输出缓冲,
然后在执行INFO命令Clients模块调用getExpansiveClientsInfo,返回前面定时任务已获取到的结果。
二、Redis4.0机制
Redis4.0版本INFO命令Clients模块返回的是lol,bib两个值,继续查看这两个值相关的源码,
发现在INFO命令返回结果之前调用了getClientsMaxBuffers(&lol,&bib)函数;
继续查看getClientsMaxBuffers(&lol,&bib)函数,发现该函数也是循环对比当前客户端列表,取其中最长的输出链表和最大的输入缓冲区。
总结:Redis4.0在执行INFO命令时,循环对比当前的输入输出缓冲,获取最大的输出链表和最大的输入缓冲区。
用图形表示即:
总结:
Redis5.0之前是在执行INFO命令时,获取当前所有的客户端连接信息,并循环对比,返回相关信息。
在客户端较多的情况下,容易出现循环对比导致INFO命令执行时间较长,进入了slowlog日志中。
Redis5.0则在ClientCron定时任务中记录客户端的统计信息,并循环更新相关数组(默认8个元素)。在执行INFO命令时,对比数组结果,返回相关统计信息。
没有5.0之前的版本那么精确(不影响结果),但对性能影响较小。