本文指的是源代码版本是
我们知道,公司有多个部门与各个部门合作,以支持整个公司的正常运作,如下图所示:
在类比方面,Redis也得到许多模块的支持。不同之处在于,Redis更像是一件竖井的工作。当然,每个模块都使用事件作为通信介质来维护轴的信息。(总线类型)实际上,这里的中央轴位于Redis中。每个模块要处理的任务通过事件的形式传递到主线程,然后将主线程一个接一个地处理。
此处的事件分为连接请求,IO阅读/写作,命令执行等;和定期任务,例如消除过期的密钥,rehash等。
REDIS服务器是典型的事件驱动程序,该事件分为两个类别:插座的可读/写作事件)和(定时任务)。无论是文件事件还是时间事件,都将其封装在结构中。
REDIS服务在最后阶段开始了Aemain方法,并真正启动了事件处理程序。一方面,必须处理它,以下是以下模式:
Redis的核心业务自然是客户的要求。我们称之为。当然,系统的正常操作需要许多辅助功能,例如定期检查,任务处理等。我们称之为。
一个主和一项补充在其各自的任务围绕中央轴(主线程)旋转。我们知道Redis使用单个线程执行命令。有一个很大的好处是,无需考虑多线程带来的并发问题,以及线程的切换带来的间接费用问题。
因此,例如Key的呼气淘汰策略,字典重新命名等都在同一单程中,但是将控制每种处理的数量以避免阻塞。
正是这种主要和辅助关系。REDIS将优先考虑主事件,然后处理辅助事件,如下所示:相应的源代码如下(外层的Aemain):
文件事件是REDIS的核心事件。
在上一篇文章中,我们了解Redis在单线程周围(主IO线程)围绕整个图片的单个线程执行详细介绍了用户请求的各个阶段。主要分析是文件事件。
关于文件事件,我们将看一张图片:
所有用户请求和后端任务处理将从此处开始。
绑定端口和对内核的注册文件描述符以收听新连接,并指定处理新连接的方法。
如上所述,在注册时,您需要指定新连接的处理方法。
继续下降,我们看到创建,并指定读取数据的方法:
最后,我们看到新连接的注册已通过ReadHandler注册给内核:
然后,您可以等待新连接的IO Ready活动。
关于内核提供的IO的恢复,我们需要积极检查注册文件描述符是否准备就绪,即:
不同系统内核提供的支持是不同的。因此,Redis还为不同系统写了几套支持。在这里,我们以系统为例:
可以看出,API是通过内核提供的。
当您通过IO Multi -Way Reuse听到它时,您可以处理前面指定的方法:先前的方法:
继续定位,并最终将一些由Redis封装的列定位。每个命令都有相应的实现。执行客户端命令的实现。
在每个处理结果之后,调用类似的方法来响应:
首先将数据输出到客户端缓冲区,然后在下一轮事件循环时统一返回客户端。特定的处理方法是。
REDIS服务器内部有许多定时任务要执行。例如,定时任务被封装为“时间事件” aetementevent对象。多个时间事件形成链接列表,并存储存储在AEEVentloop结构中的TimeEventhead字段,该字段指向链接列表的第一个节点。
让我们看看图片,时间事件做了什么:
每个字段的含义如下。
时间事件执行函数的处理逻辑相对简单,但是时间事件的链接列表用于确定当前时间事件是否已过期。
我们看到TE-> timeProc(EventLoop,id,te-> clientData)此行代码是真正执行时间事件的逻辑,呼叫方指定特定的处理逻辑。
如前所述,主线程是在事件周围进行的,并为事件(事件和其他操作)进行了包装。让我们看一下创建时间的时间:
可以看出,新添加的时间事件直接维持在结构时间的头部。我们从新事件开始,找到它,发现有几个地方可以通过AecReateTimeEventFunction创建时间事件:其中,ServerCron是我们稍后将主要引入的功能。
让我们首先谈论结论,时间事件主要在以下两个类别中:
其中,定期周期任务(ServerCron)分为(处理一次)和两个类别,根据投诉,源代码如下:
如果时间处理功能返回周期任务的值并指定下一个执行时间;否则,将其直接从时间事件列表中删除。
定期处理函数,每秒执行频率由全局参数控制,主要执行以下操作:
其中,我们选择了一些常见的治疗方法来看看:
这里的主要操作是用于DB的背景操作,例如密钥过期的清洁,磁盘碎片,字典调整大小 /重新设计。
在此步骤中,您应该很清楚。即使定期检测和清洁背景(与命令相同的线程),钥匙已过期的清理和逐渐重新操作。
它主要处理客户端的连接,释放客户端query_buffer和更新统计信息(info命令)。
在周期性任务中执行AOF重写是计划属性,关键参数的操作。
例如,当用户提交命令时,发现目前正在执行育儿过程。为了避免同时处理,Bgrewrite目前将提交定期任务,即修改。
当主线程询问处理时间的时间时,触发bgrewrite的执行。
触发周期性任务也是一个替代操作。当用户提交BGSAVE命令时,如果子过程正在执行操作,则不会暂时处理它。
实际上,这里类似于上面触发的AOF重新修饰原理。
STOPTHREADEDIOIFNEED实际上是一个用于它的多线程程序。REDIS6.0中的多线程线程主要是处理的请求,并且默认情况下仅处理操作。
我们知道多线程具有昂贵的上下文开销。因此,当要回复的客户端数量很少时,所有客户端的读写操作都可以完全负责,以便其余的线程将暂时进入休眠状态。
此时间事件用于处理与涉及的LRU相关的相关操作(消除)。通常,它将在Redis使用内存实现最大限制后进行处理。事件创建期间指定的处理方法是。
当Redis内存使用我们设置的最大值时,它将触发内存驱逐出境(消除)机制。执行入口是驱逐出境。执行每个命令后
从源代码可以看出,为了避免在一个操作中长期阻塞,redis通常会设置时间或单词限制;
本质
由于上一系列文章的大多数都是围绕内容旋转的,因此本文的重点是介绍的。
您可能会好奇的是,诸如周期性之类的任务不是启动一个新线程来处理它,并且仍将其移交给主线程。
然后,您会发现,如果我想定期在100毫米下执行一个周期任务,那就可以。例如,当命令的先前执行被阻止时,它将影响后续周期任务的处理时间点,依此类推。
此外,您可能还会注意到时间事件是按时间的形式串起的。每次都从一开始就插入,每个时间处理点都没有顺序,因此您需要每次遍历所有事件。
本质是因为到目前为止,只有两个或三个时间事件,例如servercron,evictionTimeProc,等等。也许在后来的迭代中,有更多的事件,结构可能会改变。
在上面,我称文档事件为“时间事件”,主要事件负责提供能力,辅助事件负责调整其内部条件。
参考:
原始:https://juejin.cn/post/710240207919222446