【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 时间事件处理部分)

article/2025/7/27 18:22:56

揭秘高效存储模型与数据结构底层实现

  • 【专栏简介】
    • 【技术大纲】
    • 【专栏目标】
    • 【目标人群】
      • 1. Redis爱好者与社区成员
      • 2. 后端开发和系统架构师
      • 3. 计算机专业的本科生及研究生
  • 时间事件:serverCron函数
    • 更新服务器时间缓存
      • 更新LRU时钟-lruclock
      • 更新服务器每秒执行命令次数-instantaneous_ops_per_sec
        • getoperationsPerSecond
      • 更新服务器内存峰值记录-stat_peak_memory
        • INFO memory
      • 处理SIGTERM信号
      • 管理客户端资源
      • 执行被延迟的BGREWRITEAOF
      • 检查持久化操作的运行状态

【专栏简介】

随着数据需求的迅猛增长,持久化和数据查询技术的重要性日益凸显。关系型数据库已不再是唯一选择,数据的处理方式正变得日益多样化。在众多新兴的解决方案与工具中,Redis凭借其独特的优势脱颖而出。

【技术大纲】

为何Redis备受瞩目?原因在于其学习曲线平缓,短时间内便能对Redis有初步了解。同时,Redis在处理特定问题时展现出卓越的通用性,专注于其擅长的领域。深入了解Redis后,您将能够明确哪些任务适合由Redis承担,哪些则不适宜。这一经验对开发人员来说是一笔宝贵的财富。
在这里插入图片描述

在这个专栏中,我们将专注于Redis的6.2版本进行深入分析和介绍。Redis 6.2不仅是我个人特别偏爱的一个版本,而且在实际应用中也被广泛认为是稳定性和性能表现都相当出色的版本

【专栏目标】

本专栏深入浅出地传授Redis的基础知识,旨在助力读者掌握其核心概念与技能。深入剖析了Redis的大多数功能以及全部多机功能的实现原理,详细展示了这些功能的核心数据结构和关键算法思想。读者将能够快速且有效地理解Redis的内部构造和运作机制,这些知识将助力读者更好地运用Redis,提升其使用效率。

将聚焦于Redis的五大数据结构,深入剖析各种数据建模方法,并分享关键的管理细节与调试技巧。

【目标人群】

Redis技术进阶之路专栏:目标人群与受众对象,对于希望深入了解Redis实现原理底层细节的人群

1. Redis爱好者与社区成员

Redis技术有浓厚兴趣,经常参与社区讨论,希望深入研究Redis内部机制、性能优化和扩展性的读者。

2. 后端开发和系统架构师

在日常工作中经常使用Redis作为数据存储和缓存工具,他们在项目中需要利用Redis进行数据存储、缓存、消息队列等操作时,此专栏将为他们提供有力的技术支撑。

3. 计算机专业的本科生及研究生

对于学习计算机科学、软件工程、数据分析等相关专业的在校学生,以及对Redis技术感兴趣的教育工作者,此专栏可以作为他们的学习资料和教学参考。

无论是初学者还是资深专家,无论是从业者还是学生,只要对Redis技术感兴趣并希望深入了解其原理和实践,都是此专栏的目标人群和受众对象

让我们携手踏上学习Redis的旅程,探索其无尽的可能性!


时间事件:serverCron函数

Redis服务器运行体系中,serverCron函数作为关键的周期性任务执行单元,以默认每100毫秒一次的频率循环运作。该函数肩负着服务器资源调配维护的重任,是保障Redis服务稳健运行的核心组件。

下文将系统阐述serverCron函数的具体执行流程,同时深入解析redisServer结构(即服务器状态)中与serverCron函数紧密关联的各项属性。

更新服务器时间缓存

Redis服务器中有不少功能需要获取系统的当前时间,而每次获取系统的当前时间都需要执行一次系统调用,为了减少系统调用的执行次数,服务器状态中的unixtime属性和mstime属性被用作当前时间的缓存:

struct redisServer{//保存了秒级精度的系统当前Unix时间戳time_t unixtime;//保存了毫秒级精度的系统当前Unix时间戳long long mstime;
};

因为serverCron函数默认会以每l00毫秒一次的频率更新unixtime属性和mstime属性,所以这两个属性记录的时间的精确度并不高:

  • 缓存主要用于场景服务器只会在打印日志、更新服务器LRU时钟、**决定是否执行持久化任务、**计算服务器上线时间(uptime)这类对时间精确度要求不高的功能上。

对于为键设置过期时间、添加慢查询日志这种需要高精确度时间的功能来说,服务器还是会再次执行系统调用,从而获得最准确的系统当前时间

更新LRU时钟-lruclock

服务器状态中的lruclock属性保存了服务器的LRU时钟,这个属性和上面介绍的unixtime属性、mstime属性一样,都是服务器时间缓存的一种:

struct redisServer//默认每10秒更新一次的时钟缓存,//用于计算键的空转(idle)时长。unsigned lruclock:22;
};

每个Redis对象都会有一个lru属性,这个lru属性保存了对象最后一次被命令访问的时间:

typedef struct redisobject{unsigned lru:22;
} robj;

当服务器要计算一个数据库键的空转时间(也即是数据库键对应的值对象的空转时间),程序会用服务器的lruclock属性记录的时间减去对象的lru属性记录的时间,得出的计算结果就是这个对象的空转时间:

redis>SET msg "hello world"
OK# 等待一小段时间
redis>OBJECT IDLETIME msg
(integer)20# 等待一阵子
redis>OBJECT IDLETIME msg
(integer)180# 访问msg键的值
redis>GET msg
"hello world# 键处于活跃状态,空转时长为0
redis>OBJECT IDLETIME msg 
(integer)0

serverCron函数默认会以每10秒一次的频率更新lruclock属性的值,因为这个时钟不是实时的,所以根据这个属性计算出来的LRU时间实际上只是一个模糊的估算值。

lruclock时钟的当前值可以通过INFO server命令的lruclock域查看:

redis>INFO server
# Server
lruclock:55923

更新服务器每秒执行命令次数-instantaneous_ops_per_sec

serverCron函数里,trackOperationsPerSecond函数会按照每100毫秒一次的频率来执行。

此函数借助抽样计算的手段,对服务器在最近一秒内所处理的命令请求数量进行估算,并将其记录下来。该数值能够通过INFO status命令的instantaneous_ops_per_sec域查看。

redis>INFO stats
# Stats
instantaneous_ops_per_sec:6

上面的命令结果显示,在最近的一秒钟内,服务器处理了大概6个命令。trackOperationsPerSecond函数和服务器状态中四个ops_sec开头的属性有关:

struct redisServer{
//上一次进行抽样的时间
long long ops_sec_last_sample_time;
//上一次抽样时,服务器已执行命令的数量
long long ops_sec_last_sample_ops;
//REDIS_OPS_SEC_SAMPLES大小(默认值为16)的环形数组,
//数组中的每个项都记录了一次抽样结果。
long long ops_sec_samples [REDIS_OPS_SEC_SAMPLES];
//ops_sec_samp1es数组的素引值,
//每次抽样后将值自增一,
//在值等于16时重置为0,
//让ops_sec_samples数组构成一个环形数组。
int ops_sec_idx;
  1. 每次执行trackOperationsPerSecond函数时,会依据ops_sec_last_sample_time记录的上次抽样时刻与服务器当前时间,以及ops_sec_last_sample_ops记录的上次抽样已执行命令数当前已执行命令数。算出两次函数调用期间服务器每毫秒处理的命令请求平均数。
  2. 将该平均值乘以1000,得出服务器每秒处理命令请求的估计值,并将此估计值作为新元素存入ops_sec_samples环形数组中。
getoperationsPerSecond

当客户端执行INFO命令时,服务器将触发getoperationsPerSecond函数。该函数依据ops_sec_samples环形数组内的抽样数据,完成对instantaneous_ops_per_sec属性值的计算。以下为getoperationsPerSecond函数的具体实现代码:

long long getoperationsPerSecond(void)(int j;long long sum 0// 计算所有取样值的总和for (j=0;j<REDIS_OPS_SEC_SAMPLES;j++)sum + = server.ops_sec_samples[j];//计算取样的平均值return sum / REDIS_OPS_SEC_SAMPLES;

getOperationsPerSecond函数的定义可知,instantaneous_ops_per_sec属性的值是通过对最近REDIS_OPS_SEC_SAMPLES次取样结果取平均值而得到的,这一数值属于估算值。

更新服务器内存峰值记录-stat_peak_memory

服务器状态中的stat_peak_memory属性记录了服务器的内存峰值大小:

struct redisServer{
//已使用内存峰值
size_t stat_peak_memory
}

每次serverCron函数执行时,程序都会查看服务器当前使用的内存数量,并与stat_peak_memory保存的数值进行比较,如果当前使用的内存数量比stat_peak_memory属性记录的值要大,那么程序就将当前使用的内存数量记录到stat_peak_memory属性里面。

INFO memory

INFO memory命令的used_memory_peakused_memory_peak_human两个域分别以两种格式记录了服务器的内存峰值:

redis > INFO memory
# Memory
used_memory_peak:541824
used_memory_peak_human:492.06K

处理SIGTERM信号

在启动服务器时,Redis会为服务器进程的SIGTERM信号关联处理器sigtermHandler函数,这个信号处理器负责在服务器接到SIGTERM信号时,打开服务器状态的shutdown_asap标识:

//SIGTERM信号的处理器
static void sigtermHandler(int sig){//打印日志redisLogFromHandler(REDIS WARNING,"Received SIGTERM,scheduling shutdown...");//打开关闭标识server.shutdown_asap = 1;
}

每次serverCron函数运行时,程序都会对服务器状态的shutdown_asap属性进行检查,并根据属性的值决定是否关闭服务器:

struct redisServer {//关闭服务器的标识://值为1时,关闭服务器,//值为0时,不做动作。int shutdown_asap;... ...
}

以下展示了服务器在接到SIGTERM信号之后,关闭服务器并打印相关日志的:

[6794 I signal handler](1644435690)Received SIGTERM,scheduling shutdown...
[6794] 14 Nov 21:28:10.108 User requested shutdown...
[6794] 14 Nov 21:28:10.108 Saving the final RDB snapshot before exiting.
[6794] 14 Nov 21:28:10.161 DB saved on disk
[6794] 14 Nov 21:28:10.161 Redisis now ready to exit,bye bye...

从日志里面可以看到,服务器在关闭自身之前会进行RDB持久化操作,这也是服务器拦截SIGTERM信号的原因,如果服务器一接到SIGTERM信号就立即关闭,那么它就没办法执行持久化操作了。

管理客户端资源

serverCron函数每次执行都会调用clientsCron函数,clientsCron函数会对一定数量的客户端进行以下两个检查:

  • 若客户端与服务器的连接超时(即长时间无任何交互),程序将释放该客户端。
  • 若客户端自上次执行命令请求后,输入缓冲区大小超出规定长度,程序会释放当前输入缓冲区,并重新创建默认大小的输入缓冲区,以此避免输入缓冲区过度占用内存。

执行被延迟的BGREWRITEAOF

在服务器执行BGSAVE命令的期间,如果客户端向服务器发来BGREWRITEAOF命令,那么服务器会将BGREWRITEAOF命令的执行时间延迟到BGSAVE命令执行完毕之后。

服务器的aof_rewrite_scheduled标识记录了服务器是否延迟了BGREWRITEAOF命令:

struct redisServer {// 如果值为1,那么表示有BGREWRITEAOF命令被延迟了int aof_rewrite_scheduled;
};

每次serverCron函数执行时,函数都会检查BGSAVE命令或者BGREWRITEAOF命令是否正在执行,如果这两个命令都没在执行,并且aof_rewrite_scheduled属性的值为1,那么服务器就会执行之前被推延的BGREWRITEAOF命令。

检查持久化操作的运行状态

服务器状态使用rdb_child_pid属性和aof_child_pid属性记录执行BGSAVE命令和BGREWRITEAOF命令的子进程的D,这两个属性也可以用于检查BGSAVE命令或者BGREWRITEAOF命令是否正在执行:

struct redisServer{//记录执行BGSAVE命令的子进程的ID://如果服务器没有在执行BGSAVE,//那么这个属性的值为-1。pid t rdb_child_pid;/*PID of RDB saving child *///记录执行BGREWRITEAOF命令的子进程的ID://如果限务器没有在执行BGREWRITEAOF,//那么这个属性的值为-1。pid_t aof_child_pid;/*PID if rewriting process */
};

每次serverCron函数执行时,程序都会检查rdb_child_pidaof_child_pid两个属性的值,只要其中一个属性的值不为-1,程序就会执行一次wait3函数,检查子进程是否有信号发来服务器进程:

  1. 如果有信号到达,那么表示新的RDB文件已经生成完毕(对于BGSAVE命令来说),或者AOF文件已经重写完毕(对于BGREWRITEAOF命令来说),服务器需要进行相应命令的后续操作,比如用新的RDB文件替换现有的RDB文件,或者用重写后的AOF文件替换现有的AOF文件。
  2. 如果没有信号到达,那么表示持久化操作未完成,程序不做动作。

http://www.hkcw.cn/article/bWsuxbICdQ.shtml

相关文章

ZIP Cracker版本更新了

废话不多说(也不能多说&#xff0c;原因都懂吧)&#xff0c;上图&#xff0c;阿修大佬已经更新了新的版本 参考原文&#xff1a;https://mp.weixin.qq.com/s/7ptu8tLR_2huivLJdcFBzQ

云南独龙江乡全部通信网络已抢通 紧急抢修保畅通

近日,受持续强降雨影响,怒江傈僳族自治州贡山县独龙江乡遭遇山洪和滑坡等自然灾害,导致通信网络严重受损。5月31日上午10时37分,全乡通信网络站点大面积中断,中国移动云南公司怒江分公司使用卫星传输基站保障独龙江乡政府所在地的通信正常。怒江移动分公司迅速启动防汛应急…

跨越时空的科学对话:现代科学解160年前的遗传学密码 科学家精神熠熠生辉

点滴故事中,领略科学家精神的熠熠光辉。通过讲述一个个科学家的故事,展现他们的风采,记录科技事业的发展历程,弘扬科学家的精神内涵。2025年5月31日是端午节,传统文化中有纪念屈原的习俗。两千三百年前,屈原在汨罗江畔仰观宇宙,以《天问》叩击苍穹:“日月安属?列星安陈…

美国民众开始不愿意花钱了 对现有经济存“潜在焦虑情绪” 多重经济压力交织

近期,一系列数据和调查显示,美国民众对本国经济前景的信心正处于低谷。美国密歇根大学公布的5月消费者信心指数初值降至50.8,连续第五个月下降,为2022年6月以来的最低水平。这种悲观情绪反映出美国经济深层次的矛盾与挑战。通货膨胀一直是困扰美国民众的主要问题。尽管美联…

【GESP真题解析】第 4 集 GESP 三级 2023 年 6 月编程题 1:春游

大家好,我是莫小特。 这篇文章给大家分享 GESP 三级 2023 年 6 月编程题第 1 题:春游。 题目链接 洛谷链接:B3842 春游 一、完成输入 根据输入格式的描述,输入包括两个正整数 N 和 M,N 是 N 位同学,M 是 M 次报出编号,数据范围: 2 ≤ N , M ≤ 1000 2\le N,M \le 10…

遭邻居多次持刀砍门当事人发声 精神疾病患者惹争议

近日,有大连网友在社交平台发布视频称,5月1日和5月28日,疑似患有精神疾病的邻居两次持刀上门,用刀砍其家门,并进行踢踹。网传视频截图显示了这一情况。该网友表示,他们一家才搬来一年,与这名邻居素不相识,没有正面交流过。记者多次尝试联系该网友,但未获回复。6月1日,…

攻防 FART 脱壳:特征检测识别 + 对抗绕过全解析

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ FART 对抗 某视频 app 的壳在启动的时候会检测 FART 特征&#xff0c;日志输出如下&#xff1a; 2025-05-29 02:16:25.612 2557-2557 ActivityThread …

Azure DevOps 管道部署系列之一本地服务器

Azure DevOps 是一个帮助改进 SDLC(软件开发生命周期)的平台。 在本文中,我们将使用 Azure Pipelines 创建自动化部署。 Azure DevOps 团队将 Azure Pipelines 定义为“使用 CI/CD 构建、测试和部署,适用于任何语言、平台和云平台”。 在这里,我将解释如何在 Azure Dev…

冤家路窄!萨巴伦卡谈再战郑钦文:这次我状态正佳期待复仇 罗马失利后渴望翻盘

在法网女单1/8决赛中,头号种子萨巴伦卡直落两盘晋级,接下来将对阵郑钦文。赛后,萨巴伦卡接受了采访。记者问她是否认为与郑钦文的比赛会是一场硬仗,萨巴伦卡表示,每次与郑钦文交手都很艰难,因为对方是一位出色的球员。她期待着一场精彩的较量,并且非常期待在1/4决赛中与…

遭邻居多次持刀砍门当事人发声: 她说我们是脑控组织, 入侵她大脑, 已被送精神鉴定 警方介入处理

近日,辽宁大连有网友发布视频称,疑似患有精神疾病的邻居多次持刀上门砍其家门。5月31日,当事人刘女士向媒体透露,楼下60多岁的邻居自去年10月搬入后,频繁上门滋扰,声称刘女士一家是“脑控组织”,意图入侵她的大脑。刘女士解释说,她们一家是外地人,去年才搬到这里,为了…

涉嫌歧视中国球迷!波多尔斯基向俱乐部作保证 社媒未回应照常更新 否认种族歧视指控

近日,德国名将波多尔斯基被指涉嫌对中国球迷进行种族歧视。据其所在俱乐部的消息,波多尔斯基否认了这一指控,并保证自己没有做出这种行为。昨日,欧冠决赛在德国举行,波多尔斯基到场观看了比赛。赛后,一位中国博主在酒吧外偶遇波多尔斯基并请求合影。博主称,波多尔斯基停…

热度直追世界杯!五台山上座率超过8成,多名领导冒雨看“苏超” 球迷热情不减

苏A对阵苏B的比赛吸引了15669名球迷涌入五台山体育场。考虑到最近多个苏超赛场都比较火爆,徐州对阵连云港的比赛有22000多名球迷到场;常州对阵扬州的比赛,在常州工学院体育场围栏外也围着一圈又一圈的球迷。五台山理论上只有18600个座位,本场上座率超过84%。即使南京下了一…

清理 pycharm 无效解释器

1. 起因&#xff0c; 目的: 经常使用 pycharm 来调试深度学习项目&#xff0c;每次新建虚拟环境&#xff0c;都是显示一堆不存在的名称&#xff0c;删也删不掉。 总觉得很烦&#xff0c;是个痛点。决定深入研究一下。 2. 先看效果 效果是能行&#xff0c;而且清爽多了。 3. …

c++面向对象第4天---拷贝构造函数与深复制

含有对象成员的构造函数深复制与浅复制拷贝&#xff08;复制&#xff09;构造函数 第一部分&#xff1a;含有对象成员的构造函数 以下是一个学生 类包含日期成员出生日期的代码 #include<iostream> using namespace std; class Date { public:Date(int year,int month…

【STM32F1标准库】理论——定时器/计数器中断

目录 一、定时器/计数器简介 1.通用定时器 2.基本定时器 二、时基单元 三、定时器/计数器结构框图 四、程序运行途中改变分频系数后的时序 1.缓冲器 2.预装器 3.RCC时钟树 五、计时计算方法 一、定时器/计数器简介 定时器可以对输入的时钟进行计数&#xff0c;并在计…

樊振东新球队夺欧冠冠军 萨尔布吕肯再创辉煌

北京时间6月1日晚,欧洲乒联冠军联赛男团决赛中,樊振东新赛季将加盟的萨尔布吕肯以3-1战胜杜塞尔多夫,第三次夺得欧冠冠军。比赛具体比分为:弗朗西斯卡2-3卡尔伯格、莫雷加德3-0邱党、达科约奇克3-2波尔、弗朗西斯卡3-2邱党。此前,德甲联赛萨尔布吕肯乒乓球甲级俱乐部宣布樊…

发明江苏足球联赛的人 一定是个天才 城市荣誉之战

江苏城市足球联赛的创立者堪称天才。江苏是一个由十三个地级市组成的省份,每个城市都有自己的特色和骄傲,彼此之间竞争激烈。此前,江苏省文旅部门制作了一个景点介绍视频,但网友们却开始计算各城市的出现时长,甚至有评论说“宿迁凭什么比扬州多三秒”。然而,在这样一个充…

韩国大选投票将开启 4位前总统发声 政坛局势扑朔迷离

韩国再次迎来大选季,选情充满变数。前总统朴槿惠突然发声,而现任总统尹锡悦则选择沉默。提前投票已经开始,民众排队等待投下自己的一票。最新民调显示,共同民主党的支持率逼近40%,而国民力量党则降至32%。执政党面临困境,主要是因为未能有效解决民生问题,年轻选民对此不…

高档烟酒“人情往来”暗藏权钱交易 违纪破法的开端

端午节临近,各级纪检监察机关针对这一节点部署了一系列纠治“四风”的明察暗访工作,重点查处违规吃喝、违规收送礼品礼金等问题,并对顶风违纪行为进行快速处理。近期,各地通报曝光了一批典型问题,相关人员均受到了严肃处理。从近年来各级纪检监察机关查处的腐败案件来看,…

C++输入与输出技术详解

文章目录 引言一、C标准输入输出流1.1 cin与cout1.2 cerr与clog 二、C风格输入输出函数2.1 scanf与printf2.2 fgets与puts 三、输入输出优化四、总结 引言 在C编程中&#xff0c;输入与输出&#xff08;I/O&#xff09;操作是程序与用户、文件或其他系统组件交互的核心环节。C…