Redis设计与实现第14章 -- 服务器 总结(命令执行器 serverCron函数 初始化)

14.1 命令请求的执行过程

一个命令请求从发送到获得回复的过程中,客户端和服务器都需要完成一系列操作。

14.1.1 发送命令请求

当用户在客户端中输入一个命令请求的时候,客户端会把这个命令请求转换为协议格式,然后通过连接到服务器的套接字,将协议格式的命令请求发送给服务器。

14.1.2 读取命令请求

当客户端与服务器之间的连接套接字因为客户端的写入而变得可读时,服务器将调用命令请求处理器来执行以下操作:
  • 读取套接字中协议格式的命令请求,并将其保存到客户端状态的输入缓冲区里面
  • 对输入缓冲区中的命令请求进行分析,提取出命令请求中包含的命令参数和个数,分别保存到argv/argc属性里面。
  • 调用命令执行器,执行客户端指定的命令

14.1.3 命令执行器1:查找命令实现

根据客户端状态的argv[0]参数,在命令表里查找参数所指定的命令,并将找到的命令保存到客户端状态的cmd属性里。

命令表是一个字典,字典的键是一个个命令名字,字典的值是一个个redisCommend结构。

主要属性有:name 名字、proc 函数指针、arity 命令参数的个数、sflags 字符串形式的标识值、flags 二进制标识、calls 服务器总共执行了多少次这个命令、millseconds 服务器执行这个命令耗费的总时长

sflags属性可以使用的标识值如下:

  • w:写入命令
  • r:只读命令
  • m:可能占用大量内存,内存紧张的话禁用
  • a:管理命令
  • p:发布订阅功能的命令
  • s:不可以在lua脚本执行
  • R:随机命令
  • S:排序
  • l:可以在服务器载入数据的过程中使用
  • t:允许从服务器在带有过期数据时使用的命令
  • M:监视器模式下不会自动被传播

14.1.4 命令执行器2:执行预备操作

+ 检查客户端状态的cmd指针是否指向NULL + 根据客户端cmd属性指向的redisCommand结构的arity属性,检查命令请求所给定的参数个数是否正确。 + 检查客户端是否通过了身份认证 + 如果服务器打开了maxmemory功能,执行命令前先检查服务器的内存占用情况,并在有需要时进行内存回收 + 如果服务器上一次执行BGSAVE命令时出错,并且服务器打开了stop-writes-on-bgsave-error功能,而且即将要执行的是写命令,那么服务器将拒绝执行 + 客户端正在用SUBSCRIBE命令订阅频道,或是正在用PSUBSCRIBE命令订阅模式,服务端只会执行客户端发来的SUBSCRIBE PSUBSCRIBE UNSUBSCRIBE PUNSUBSCRIBE 四个命令,其他命令都会被服务器拒绝 + 如果服务器正在进行数据载入,客户端发送的命令必须要带有l标识才会被执行 + 如果服务器因为执行Lua脚本而超时并进入阻塞状态,服务器只会执行客户端发来的SHUTDOWN nosave和SCRIPT KILL命令 + 如果客户端正在执行事务,只会执行EXEC DISCARD MULTI WATCH 四个命令 + 如果服务器打开了监视器功能,将要执行的命令和参数等信息发送给监视器

14.1.5 命令执行器3:调用命令实现函数

被调用的命令实现函数会执行指定的操作,并产生相应的命令回复,这些回复会被保存在客户端状态的输出缓冲区里,buf属性和reply属性。

14.1.6 命令执行器4:执行后续工作

+ 如果服务器开启了慢查询日志功能,会检查是否需要为刚刚执行完的命令请求添加一条新的慢查询日志 + 根据刚刚执行命令所耗费的时长,更新被执行命令的redisCommand结构的millseconds属性,并将命令的redisCommand结构的calls计数器的值加一 + 如果服务器开启了AOF持久化功能,会将刚刚执行的命令请求写入AOF缓冲区里 + 如果有其他从服务器正在复制当前这个服务器,那么服务器会将刚刚执行的命令传播给所有从服务器

14.1.7 将命令回复发送给客户端

命令实现函数将命令回复保存到客户端的输出缓冲区里面,并为客户端的套接字关联命令回复处理器。

当客户端套接字变成可写状态的时候,服务器就会执行命令回复处理器,将保存在客户端输出缓冲区的命令回复发送给客户端

14.1.8 客户端接收并打印命令回复

客户端收到协议格式的命令回复后,会转化为人类可读的格式。

14.2 serverCron函数

每隔100ms执行一次

14.2.1 更新服务器时间缓存

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

这两个属性是100ms更新一次的,所以精确度不高

  • 当打印日志、更新服务器的LRU时钟、决定是否执行持久化任务、计算服务器上线时间这种对时间精确度要求不高的功能上才会用
  • 对于为键设置过期时间、添加慢查询日志这种需要高精度时间的功能来说,服务器还是会再次执行系统调用

14.2.2 更新LRU时钟

服务器的lruclock属性保存了服务器的LRU时钟,每个redis对象都会有一个lru属性,保存了对象最后一次被命令访问的时间。当服务器计算数据库键的空转时间的时候,会用服务器的lruclock属性记录的时间减去对象lru属性记录的时间。

serverCron函数默认以10秒一次的频率更新lruclock属性的值

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

trackOperationsPerSecond函数以每100ms一次的频率执行,功能是以抽样计算的方式,估算并记录服务器在最后一秒钟处理的命令请求数量。

可以通过INFO status命令的instantaneous_ops_per_sec域查看

14.2.4 更新服务器内存峰值记录

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

每次serverCron函数执行时,服务器都会查看当前使用的内存数量

14.2.5 处理SIGTERM信号

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

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

服务器在关闭自身前会进行RDB持久化操作,这也就是服务器拦截SIGTERM信号的原因

14.2.6 管理客户端资源

调用clientsCron函数,对一定数量的客户端进行检查:
  • 连接超时,很久没互动
  • 上一次执行请求命令后,输入缓冲区的大小超过了一定长度,程序会释放客户端当前的输入缓冲区,重新创建一个默认大小的输入缓冲区

14.2.7 管理数据库资源

databasesCron函数,对服务器中的一部分数据库进行检查,1删除过期键,收缩字典等,详情见第9章

14.2.8 执行被延迟的BGREWRITEAOF

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

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

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

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

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

  • 如果有信号到达,那么表示新的RDB文件已经生成完成或是AOF文件已经重写完毕,服务器进行后续的替换操作
  • 如果没有信号,不做动作

如果两个属性的值都是-1,说明没有进行持久化操作,检查:

  • 查看是否有BGREWRITEAOF被延迟了
  • 检查服务器的自动保存条件是否已经被满足,如果条件满足,而且服务器没有在执行其他持久化操作,那么服务器开始一次新的BGSAVE操作
  • 检查服务器设置的AOF重写条件是否满足,如果满足并且没有进行其他持久化操作,服务器开始一次新的BHREWRITEAOF操作

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

14.2.10 将AOF缓冲区文件的内容写入AOF文件

详情见11章

14.2.11 关闭异步客户端

输出缓冲区大小超出限制的客户端,详情见13章

14.2.12 增加cronloops计数器的值

cronloops属性记录了serverCron函数执行的次数,目前唯一的作用就是在复制模块中实现:每执行serverCron函数N次就执行一次指定代码的功能

14.3 初始化服务器

14.3.1 初始化服务器状态结构

创建一个redisServer类型的实例变量server作用服务器的状态,并为结构里的各个属性设置默认值,初始化函数为initServerConfig函数完成,主要工作为:设置服务器的运行ID、默认运行频率、默认配置文件路径、运行架构、默认端口号、默认RDB/AOF持久化条件、LRU时钟、创建命令表

14.3.2 载入配置选项

载入用户给定的配置参数和配置文件,并根据用户设定的配置,对server变量相关属性的值进行修改

14.3.3 初始化服务器数据结构

initServerConfig函数初始化server状态时,只创建了命令表一个数据结构,还有其他数据结构,比如:
  • server.clients链表,记录了和服务端相连的客户端的状态结构
  • server.db数组,包含了服务器的所有数据库
  • 保存频道订阅信息的pubsub_channels字典 保存模式订阅信息的pubsub_patterns链表
  • 执行lua脚本的lua环境
  • 用户保存慢查询日志的slowlog属性

这些都是在initServer函数里执行的,该函数负责初始化数据结构和设置操作,比如

  • 设置进行信号处理器
  • 设置共享对象,比如OK回复的字符串对象
  • 打开服务器的监听端口,并为监听套接字关联连接应答事件处理器,等待服务器正式运行时接受客户端的连接
  • 为serverCron函数创建时间事件,等待服务器正式运行时执行serverCron函数
  • 如果AOF持久化功能打开,创建/打开AOF文件
  • 初始化后台IO模块,bio

14.3.4 还原数据库状态

完成对服务器状态server变量的初始化之后,服务器需要载入RDB文件或AOF文件并根据文件记录的内容来还原服务器的数据库状态。
  • 如果开启了AOF持久化功能,用AOF文件还原
  • 否则,用RDB文件还原

14.3.5 执行事件循环

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/923446.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】字符串左旋的三种解题方法详细分析

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 💯前言💯题目描述💯方法一:逐字符移动法💯方法二:使用辅助空间法💯方法三:三次反转法💯方法对…

【AI绘画】Midjourney进阶:色调详解(上)

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AI绘画 | Midjourney 文章目录 💯前言💯Midjourney中的色彩控制为什么要控制色彩?为什么要在Midjourney中控制色彩? 💯色调白色调淡色调明色调 &#x1f4af…

零基础学安全--云技术基础

目录 学习连接 前言 云技术历史 云服务 公有云服务商 云分类 基础设施即服务(IaaS) 平台即服务(PaaS) 软件即服务(SaaS) 云架构 虚拟化 容器 云架构设计 组件选择 基础设施即代码 集成部署…

【Linux】网络通信

TCP协议是一个安全的、面向连接的、流式传输协议,所谓的面向连接就是三次握手,对于程序猿来说只需要在客户端调用connect()函数,三次握手就自动进行了。先通过下图看一下TCP协议的格式,然后再介绍三次握手的具体流程。 TCP的三次握…

Pgsql:json字段查询与更新

1.查询json字段的值 SELECT attribute_data->>设施类别 mycol, * FROM gis_coord_data WHERE attribute_data->>设施类别阀门井 查询结果如下: 2.更新json字段中的某个属性值 UPDATE gis_coord_data SET attribute_data(attribute_data::jsonb ||{&quo…

对于GC方面,在使用Elasticsearch时要注意什么?

大家好,我是锋哥。今天分享关于【对于GC方面,在使用Elasticsearch时要注意什么?】面试题。希望对大家有帮助; 对于GC方面,在使用Elasticsearch时要注意什么? 1000道 互联网大厂Java工程师 精选面试题-Java…

基于Netty实现聊天室

前言 了解了Netty的基本功能和相关概念,使用基于Netty实现多人聊天的功能。 需求 1.服务端能够接收客户端的注册,并且接受用户的信息注册 2.服务端能够处理客户端发送的消息,并且根据消息类型进行私发或者广播发送消 3.服务端能够私发消…

Linux -日志 | 线程池 | 线程安全 | 死锁

文章目录 1.日志1.1日志介绍1.2策略模式1.3实现日志类 2.线程池2.1线程池介绍2.2线程池的应用场景2.3线程池的设计2.4代码实现2.5修改为单例模式 3.线程安全和函数重入问题3.1线程安全和函数重入的概念3.2总结 4.死锁4.1什么是死锁4.2产生死锁的必要条件4.3避免死锁 1.日志 1.…

【博主推荐】C#的winfrom应用中datagridview常见问题及解决方案汇总

文章目录 1.datagridview绘制出现鼠标悬浮数据变空白2.datagridview在每列前动态添加序号2.1 加载数据集完成后绘制序号2.2 RowPostPaint事件绘制 3.datagridview改变行样式4.datagridview后台修改指定列数据5.datagridview固定某个列宽6.datagridview某个列的显示隐藏7.datagr…

【设计模式】创建型模式之单例模式(饿汉式 懒汉式 Golang实现)

定义 一个类只允许创建一个对象或实例,而且自行实例化并向整个系统提供该实例,这个类就是一个单例类,它提供全局访问的方法。这种设计模式叫单例设计模式,简称单例模式。 单例模式的要点: 某个类只能有一个实例必须…

Vivado程序固化到Flash

在上板调试FPGA时,通常使用JTAG接口下载程序到FPGA芯片中,FPGA本身是基于RAM工艺的器件,因此掉电后会丢失芯片内的程序,需要重新烧写程序。但是当程序需要投入使用时不能每一次都使用JTAG接口下载程序,一般FPGA的外围会…

技术文档,they are my collection!

工作 今天这篇文章,献给一直撰写技术文档的自己。我自认为是公司中最爱写文档的人了,我们是一个不到40人的小公司,公司作风没有多么严谨,领导也不会要求我们写技术文档。但是从入职初至今,我一直保持着写技术文档…

微信小程序学习指南从入门到精通

🗽微信小程序学习指南从入门到精通🗽 🔝微信小程序学习指南从入门到精通🔝✍前言✍💻微信小程序学习指南前言💻一、🚀文章列表🚀二、🔯教程文章的好处🔯1. ✅…

JavaWeb——SpringBoot原理

10.1. 配置优先级 10.1.1. 配置文件 properties > yml(推荐) > yaml 10.1.2. Java系统属性、命令行参数 命令行参数 > Java系统属性 > 配置文件 10.2. Bean管理 10.2.1. 手动获取bean ApplicationContext,IOC容器对象 10.2.2. bean作用域 10.2.3.…

如何在Python中进行数学建模?

数学建模是数据科学中使用的强大工具,通过数学方程和算法来表示真实世界的系统和现象。Python拥有丰富的库生态系统,为开发和实现数学模型提供了一个很好的平台。本文将指导您完成Python中的数学建模过程,重点关注数据科学中的应用。 数学建…

OCR技术详解:从基础到应用

OCR技术详解:从基础到应用 引言 OCR技术的定义 OCR(Optical Character Recognition,光学字符识别)是一种将印刷或手写文本转换为机器可读文本的技术。通过OCR技术,计算机可以自动识别图像中的文字,并将其…

webrtc视频会议学习(三)

文章目录 关联:源码搭建coturn服务器nginx配置ice配置需服务器要开放的端口 效果 关联: webrtcP2P音视频通话(一) webrtcP2P音视频通话(二) webrtc视频会议学习(三) 源码 WebRTC…

【从零开始的LeetCode-算法】43. 网络延迟时间

有 n 个网络节点,标记为 1 到 n。 给你一个列表 times,表示信号经过 有向 边的传递时间。 times[i] (ui, vi, wi),其中 ui 是源节点,vi 是目标节点, wi 是一个信号从源节点传递到目标节点的时间。 现在,…

数据结构--AVL树(平衡二叉树)

✅博客主页:爆打维c-CSDN博客​​​​​​ 🐾 🔹分享c、c知识及代码 🐾 🔹Gitee代码仓库 五彩斑斓黑1 (colorful-black-1) - Gitee.com 一、AVL树是什么?(含义、性质) 1.AVL树的概念 AVL树是最…

sunshine和moonlight串流网络丢失帧高的问题(局域网)

注:此贴结果仅供参考 场景环境:单身公寓 路由器:2016年的路由器 开始:电脑安装sunshine软件,手机安装moonlight软件开始串流发现网络丢失帧发现巨高 一开始怀疑就是路由器问题,因为是局域网,而…