Redis设计与实现之事件

目录

一、事件

1、文件事件

读事件

写事件

2、 时间事件

3、时间事件应用实例:服务器常规操作

4、事件的执行与调度

5、事件是否有重要性级别或优先级?需要立即处理还是可以延迟处理?

6、事件的类型是什么?是针对键的操作,还是集群的状态变化?

二、小结


一、事件

事件是 Redis 服务器的核心,它处理两项重要的任务:

  1. 处理文件事件:在多个客户端中实现多路复用,接受它们发来的命令请求,并将命令的执行结果返回给客户端。

  2. 时间事件:实现服务器常规操作(server cron job)。

本文以下内容就来介绍这两种事件,以及它们背后的运作模式。

1、文件事件

Redis 服务器通过在多个客户端之间进行多路复用,从而实现高效的命令请求处理:多个客户 端通过套接字连接到 Redis 服务器中,但只有在套接字可以无阻塞地进行读或者写时,服务器 才会和这些客户端进行交互。

Redis 将这类因为对套接字进行多路复用而产生的事件称为文件事件(file event),文件事件可 以分为读事件和写事件两类。

读事件

读事件标志着客户端命令请求的发送状态。

当一个新的客户端连接到服务器时,服务器会给为该客户端绑定读事件,直到客户端断开连接 之后,这个读事件才会被移除。读事件在整个网络连接的生命期内,都会在等待和就绪两种状态之间切换:

• 当客户端只是连接到服务器,但并没有向服务器发送命令时,该客户端的读事件就处于 等待状态。

• 当客户端给服务器发送命令请求,并且请求已到达时(相应的套接字可以无阻塞地执行读 操作),该客户端的读事件处于就绪状态。作为例子,下图展示了三个已连接到服务器、但并没有发送命令的客户端:

 这三个客户端的状态如下表:

之后,当客户端 X 向服务器发送命令请求,并且命令请求已到达时,客户端 X 的读事件状态 变为就绪:

 这时,三个客户端的状态如下表(只有客户端 X 的状态被更新了):

当事件处理器被执行时,就绪的文件事件会被识别到,相应的命令请求会被发送到命令执行 器,并对命令进行求值。

写事件

写事件标志着客户端对命令结果的接收状态。

和客户端自始至终都关联着读事件不同,服务器只会在有命令结果要传回给客户端时,才会为 客户端关联写事件,并且在命令结果传送完毕之后,客户端和写事件的关联就会被移除。

一个写事件会在两种状态之间切换:

• 当服务器有命令结果需要返回给客户端,但客户端还未能执行无阻塞写,那么写事件处 于等待状态。

• 当服务器有命令结果需要返回给客户端,并且客户端可以进行无阻塞写,那么写事件处 于就绪状态。

当客户端向服务器发送命令请求,并且请求被接受并执行之后,服务器就需要将保存在缓存内 的命令执行结果返回给客户端,这时服务器就会为客户端关联写事件。

作为例子,下图展示了三个连接到服务器的客户端,其中服务器正等待客户端 X 变得可写,从 而将命令的执行结果返回给它:

 此时三个客户端的事件状态分别如下表:

当客户端 X 的套接字可以进行无阻塞写操作时,写事件就绪,服务器将保存在缓存内的命令执 行结果返回给客户端: 此时三个客户端的事件状态分别如下表(只有客户端 X 的状态被更新了):

当命令执行结果被传送回客户端之后,客户端和写事件之间的关联会被解除(只剩下读事件), 至此,返回命令执行结果的动作执行完毕: 

Note: 同时关联写事件和读事件

前面提到过,读事件只有在客户端断开和服务器的连接时,才会被移除。

这也就是说,当客户端关联写事件的时候,实际上它在同时关联读/写两种事件。

因为在同一次文件事件处理器的调用中,单个客户端只能执行其中一种事件(要么读,要么写, 但不能又读又写),当出现读事件和写事件同时就绪的情况时,事件处理器优先处理读事件。

这也就是说,当服务器有命令结果要返回客户端,而客户端又有新命令请求进入时,服务器先 处理新命令请求。

2、 时间事件

时间事件记录着那些要在指定时间点运行的事件,多个时间事件以无序链表的形式保存在服务器状态中。 每个时间事件主要由三个属性组成:

• when :以毫秒格式的 UNIX 时间戳为单位,记录了应该在什么时间点执行事件处理函数。

• timeProc :事件处理函数。
• next 指向下一个时间事件,形成链表。

根据 timeProc 函数的返回值,可以将时间事件划分为两类:

  • 如果事件处理函数返回ae.h/AE_NOMORE,那么这个事件为单次执行事件:该事件会在指 定的时间被处理一次,之后该事件就会被删除,不再执行。

  • 如果事件处理函数返回一个非AE_NOMORE的整数值,那么这个事件为循环执行事件:该 事件会在指定的时间被处理,之后它会按照事件处理函数的返回值,更新事件的 when 属 性,让这个事件在之后的某个时间点再次运行,并以这种方式一直更新并运行下去。可以用伪代码来表示这两种事件的处理方式:

    def handle_time_event(server, time_event):# 执行事件处理器,并获取返回值# 返回值可以是 AE_NOMORE ,或者一个表示毫秒数的非符整数值 retval = time_event.timeProc()if retval == AE_NOMORE:# 如果返回 AE_NOMORE ,那么将事件从链表中删除,不再执行server.time_event_linked_list.delete(time_event) else:# 否则,更新事件的 when 属性# 让它在当前时间之后的 retval 毫秒之后再次运行 time_event.when = unix_ts_in_ms() + retval

    当时间事件处理器被执行时,它遍历所有链表中的时间事件,检查它们的到达事件(when 属 性),并执行其中的已到达事件:

    def process_time_event(server): # 遍历时间事件链表for time_event in server.time_event_linked_list: # 检查事件是否已经到达if time_event.when >= unix_ts_in_ms():# 处理已到达事件 handle_time_event(server, time_event)

    Note: 无序链表并不影响时间事件处理器的性能
    在目前的版本中,正常模式下的 Redis 只带有 serverCron 一个时间事件,而在 benchmark 模式下,Redis 也只使用两个时间事件。 在这种情况下,程序几乎是将无序链表退化成一个指针来使用,所以使用无序链表来保存时间事件,并不影响事件处理器的性能。

3、时间事件应用实例:服务器常规操作

对于持续运行的服务器来说,服务器需要定期对自身的资源和状态进行必要的检查和整理,从而让服务器维持在一个健康稳定的状态,这类操作被统称为常规操作(cron job)。 在 Redis 中,常规操作由 redis.c/serverCron 实现,它主要执行以下操作:

• 更新服务器的各类统计信息,比如时间、内存占用、数据库占用情况等。

• 清理数据库中的过期键值对。
• 对不合理的数据库进行大小调整。
• 关闭和清理连接失效的客户端。
• 尝试进行 AOF 或 RDB 持久化操作。
• 如果服务器是主节点的话,对附属节点进行定期同步。
• 如果处于集群模式的话,对集群进行定期同步和连接测试。

Redis 将 serverCron 作为时间事件来运行,从而确保它每隔一段时间就会自动运行一次,又 因为 serverCron 需要在 Redis 服务器运行期间一直定期运行,所以它是一个循环时间事件: serverCron 会一直定期执行,直到服务器关闭为止。

在 Redis 2.6 版本中,程序规定 serverCron 每隔 10 毫秒就会被运行一次。从 Redis 2.8 开始, 10 毫秒是 serverCron 运行的默认间隔,而具体的间隔可以由用户自己调整。

4、事件的执行与调度

既然 Redis 里面既有文件事件,又有时间事件,那么如何调度这两种事件就成了一个关键问题。 简单地说,Redis 里面的两种事件呈合作关系,它们之间包含以下三种属性:

  1. 一种事件会等待另一种事件执行完毕之后,才开始执行,事件之间不会出现抢占。

  2. 事件处理器先处理文件事件(处理命令请求),再执行时间事件(调用serverCron)

  3. 文件事件的等待时间(类poll函数的最大阻塞时间),由距离到达时间最短的时间事件 决定。

这些属性表明,实际处理时间事件的时间,通常会比时间事件所预定的时间要晚,至于延迟的 时间有多长,取决于时间事件执行之前,执行文件事件所消耗的时间。

比如说,以下图表就展示了,虽然时间事件 TE 1 预定在 t1 时间执行,但因为文件事件 FE 1 正在运行,所以 TE 1 的执行被延迟了:

另外,对于像 serverCron 这类循环执行的时间事件来说,如果事件处理器的返回值是 t ,那 么 Redis 只保证:

  • 如果两次执行时间事件处理器之间的时间间隔大于等于t,那么这个时间事件至少会被 处理一次。

  • 而并不是说,每隔 t 时间,就一定要执行一次事件——这对于不使用抢占调度的 Redis 事件处理器来说,也是不可能做到的

    举个例子,虽然 serverCron (sC)设定的间隔为 10 毫秒,但它并不是像如下那样每隔 10 毫

    秒就运行一次:

在实际中,serverCron 的运行方式更可能是这样子的: 

根据情况,如果处理文件事件耗费了非常多的时间,serverCron 被推迟到一两秒之后才能执 行,也是有可能的。整个事件处理器程序可以用以下伪代码描述:

def process_event():# 获取执行时间最接近现在的一个时间事件te = get_nearest_time_event(server.time_event_linked_list)# 检查该事件的执行时间和现在时间之差# 如果值 <= 0 ,那么说明至少有一个时间事件已到达 # 如果值 > 0 ,那么说明目前没有任何时间事件到达 nearest_te_remaind_ms = te.when - now_in_ms()if nearest_te_remaind_ms <= 0:# 如果有时间事件已经到达# 那么调用不阻塞的文件事件等待函数 poll(timeout=None)else:# 如果时间事件还没到达# 那么阻塞的最大时间不超过 te 的到达时间 poll(timeout=nearest_te_remaind_ms)# 处理已就绪文件事件 process_file_events()# 处理已到达时间事件 process_time_event()

通过这段代码,可以清晰地看出:
• 到达时间最近的时间事件,决定了poll的最大阻塞时长。 • 文件事件先于时间事件处理。

将这个事件处理函数置于一个循环中,加上初始化和清理函数,这就构成了 Redis 服务器的主 函数调用:

def redis_main(): # 初始化服务器init_server()# 一直处理事件,直到服务器关闭为止 while server_is_not_shutdown():process_event()# 清理服务器 clean_server()

5、事件是否有重要性级别或优先级?需要立即处理还是可以延迟处理?

Redis事件没有定义重要性级别或优先级。所有的事件都会按照发生的顺序进行处理,没有特定的顺序要求。因此,Redis事件可以根据需要进行立即处理,也可以延迟处理。

6、事件的类型是什么?是针对键的操作,还是集群的状态变化?

Redis事件的类型有两种,分别是针对键的操作事件和集群的状态变化事件。

  1. 针对键的操作事件(Key Event):这些事件与键的操作相关,包括以下几种类型:

    • SET:当一个键被设置或修改时触发。
    • GET:当一个键被获取时触发。
    • DEL:当一个键被删除时触发。
    • EXPIRE:当一个键的过期时间被设置时触发。
    • EXPIRED:当一个键的过期时间到达时触发。
    • RENAME:当一个键被重命名时触发。
    • PERSIST:当一个键的过期时间被移除时触发。
    • ...
  2. 集群的状态变化事件(Cluster Event):这些事件与Redis集群的状态变化相关,包括以下几种类型:

    • NODE ADDED:当一个新的节点加入集群时触发。
    • NODE REMOVED:当一个节点被移除集群时触发。
    • NODE UPDATED:当一个节点的状态或信息发生变化时触发。
    • SLOT ASSIGNED:当一个槽位被指派给一个节点时触发。
    • SLOT UNASSIGNED:当一个槽位从一个节点上移除时触发。
    • ... 

二、小结

  • Redis 的事件分为时间事件和文件事件两类。

  • 文件事件分为读事件和写事件两类:读事件实现了命令请求的接收,写事件实现了命令 结果的返回。

  • 时间事件分为单次执行事件和循环执行事件,服务器常规操作serverCron就是循环事 件。

  • 文件事件和时间事件之间是合作关系:一种事件会等待另一种事件完成之后再执行,不 会出现抢占情况。

  • 时间事件的实际执行时间通常会比预定时间晚一些。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

项目验收材料整合流程

目标&#xff1a;多份word整合成一份项目验收材料 第一步&#xff1a;编写好word&#xff1b;准备好一份验收材料的封面与目录word 第二步&#xff1a;用WPS的word转PDF&#xff0c;批量转成PDF&#xff1b; 第三步&#xff1a;用Adobe Acrobat DC 合并转成的多个PDF成为一个…

[译]Kube Router Documentation

体系结构 Kube路由器是围绕观察者和控制器的概念而建立的。 观察者使用Kubernetes监视API来获取与创建&#xff0c;更新和删除Kubernetes对象有关的事件的通知。 每个观察者获取与特定API对象相关的通知。 在从API服务器接收事件时&#xff0c;观察者广播事件。 控制器注册以获…

windows11 22H2资源管理器开启多标签页

效果 步骤 windows11 22H2后续可能会推送该功能&#xff0c;现在是隐藏的&#xff0c;需要借助工具把这个隐藏功能开启 工具&#xff1a;vivetool 下载&#xff1a;Releases thebookisclosed/ViVe GitHub 步骤1&#xff1a;右键开始菜单&#xff0c;选择“终端&#xff08;…

遇到“我觉得行才算行”的业主怎么办?

目录 案例 分析 案例 项目初期UI设计需求不确定,我们设计了几稿,业主还是不满意,没有确定最终稿。后来呢,业主安排了一位内部的美工A过来。美工A给出了很多修改意见,我们根据美工A的意见进行了修改,又反反复复改了好几版,最后业主不算满意地确定了。 后来项目要收尾…

ceph安装配置

简介 ceph是一个开源分布式存储系统&#xff0c;支持PB级别的存储&#xff0c;支持对 象存储&#xff0c;块存储和文件存储&#xff0c;高性能&#xff0c;高可用&#xff0c;可扩展。 部署网络建议架构图 部署 部署架构图&#xff0c;本次实验部署jewel版本 实验环境的Vagrant…

推荐好用的JavaScript模块

2019独角兽企业重金招聘Python工程师标准>>> 译者按&#xff1a; 作者将自己常用的JavaScript模块分享给大家。 原文&#xff1a;? JavaScript Modules Worth Using ?译者: Fundebug为了保证可读性&#xff0c;本文采用意译而非直译。另外&#xff0c;本文版权归原…

select函数_SQL高级功能:窗口函数

一、窗口函数有什么用&#xff1f;在日常生活中&#xff0c;经常会遇到需要在每组内排名&#xff0c;比如下面的业务需求&#xff1a;排名问题&#xff1a;每个部门按业绩来排名topN问题&#xff1a;找出每个部门排名前N的员工进行奖励面对这类需求&#xff0c;就需要使用sql的…

发挥项目“临时性”威力,让项目顺利实施

所谓临时性,就是要有明确的“开始”和“结束”。虽然大家都知道项目一定会有开始和结束的,但要更多地关注“明确“。 问题1:问商务(售前)或业主,这个项目什么时候结束? 答:商务或业主他们有时候也不知道,因为国内的项目大多数是提前开始交付,是一边交付,一边把里程…

上拉加载更多后台数据_6-7【微信小程序全栈开发课程】记录页面(七)--分页加载记录数据...

现在是一次性加载所有的记录数据&#xff0c;数据多的时候&#xff0c;会加载比较慢&#xff0c;所以我们改成分页加载&#xff0c;一次最多加载15条数据每次拉倒底部都会自动加载下一页的数据&#xff0c;知道所有的数据加载完成1、添加data变量编辑record.vue文件&#xff0c…

spring cloud eureka服务注册和调用

SPRING INITIALIZR构建工程 spring boot 可通过SPRING INITIALIZR构建项目访问SPRING INITIALIZR官网&#xff0c;填写项目相关信息后&#xff0c;生成项目。将下载的项目解压&#xff0c;打开idea&#xff0c;file-->new-->project from existing sources。import proje…

打印工资条怎么做到每个人都有表头明细_朋友说:能不能用python,帮我写一个“制作工资条”的自动化程序?...

本文说明今天和一个朋友吃饭&#xff0c;她说我经常使用Excel制作工资条&#xff0c;但是每个月都要做一遍&#xff0c;你能不能用python写一个代码&#xff0c;能够自动化完成这个工作。这当然可以啦&#xff0c;就是这么牛逼&#xff01;我们先来看看原始数据是什么样子的。那…

做优化的数据库工程师请参考!CynosDB的计算层设计优化揭秘

本文由云社区发表本文作者&#xff1a;孙旭&#xff0c;腾讯数据库开发工程师&#xff0c;9年数据库内核开发经验&#xff1b;熟悉数据库查询处理&#xff0c;并发控制&#xff0c;日志以及存储系统&#xff1b;熟悉PostgreSQL&#xff08;Greenplum&#xff0c;PGXC等&#xf…

netty发送数据_看完这篇还不清楚Netty的内存管理,那我就哭了

说明在学习Netty的时候&#xff0c;ByteBuf随处可见&#xff0c;但是如何高效分配ByteBuf还是很复杂的&#xff0c;Netty的池化内存分配这块还是比较难的&#xff0c;很多人学习过&#xff0c;看过但是还是云里雾里的&#xff0c;本篇文章就是主要来讲解&#xff1a;Netty分配池…

数字化改革体系架构“152”两次迭代升级为“1612”

数字化改革体系架构已经完成两次迭代&#xff0c;152-1512-1612。 2021年&#xff0c;浙江在全国率先启动一项关系全局、影响深远、制胜未来的重大集成改革——数字化改革&#xff0c;并确定为全面深化改革的总抓手。 2021年2月18日&#xff0c;数字化改革大会“152”工作体系…

python 40位的数减个位数_Python数据分析入门教程(五):数据运算

作者 | CDA数据分析师进行到这一步就可以算是开始正式的烹饪了&#xff0c;在这部分之前的数据操作部分我们列举了一些不同维度的分析指标&#xff0c;这一章我们主要看看这些指标都是怎么计算出来的。一、算术运算算术运算就是基本的加减乘除&#xff0c;在Excel或者Python中数…

数字化改革“152”体系详解

架构图 “1” 即一体化智能化公共数据平台&#xff08;平台大脑&#xff09;&#xff0c;按照“统一规划、统一支撑、统一架构、统一平台、统一标准、统一建设、统一管理、统一运维"的要求&#xff0c;建设省市县三级公共数据平台&#xff0c;叠加三级“大脑功能&#xf…

数字化改革“141”体系

县级以上是“152”大框架&#xff0c;县以下是“141”体系。 141体系是&#xff1a;县级社会治理中心、乡镇&#xff08;街道&#xff09;基层治理“四个平台”、村社网格。 “1” 第一个“1”指县级社会治理中心。 “4” 第二个“4”指乡镇&#xff08;街道&#xff09;基…

接口做的好怎么形容_淘宝直播预告怎么做才合格?如何做好?

很多淘宝商家在直播前没有做淘宝直播预告&#xff0c;或者不知道怎么去做直播预告&#xff0c;这对直播的效果会有很大的影响&#xff0c;那么直播前如何做好直播预告呢?怎样的直播预告才是合格的&#xff0c;下面来了解一下。1.必须去淘宝直播中控台发布。因为手机上发布目前…

“1+7+N”改革工作体系介绍

2021年&#xff0c;浙江省确定了“17N”的改革工作体系&#xff0c;要求以全面深化改革新成效再创体制机制新优势。&#xff08;2022年已经升级为“1612N”&#xff0c;点击阅读&#xff09; “1” 数字化改革&#xff0c;这是浙江全面深化改革的总抓手。将聚焦打造全球数字变…

浙江省数字化改革回顾(2022年5月)

事业的伟大在于目标的壮丽&#xff0c;也在于过程的壮丽&#xff1b;改革的成果在于享有的丰富&#xff0c;也在于经历的丰富。2021年2月18日&#xff0c;春节假期后首个工作日&#xff0c;浙江省委召开全省数字化改革大会&#xff0c;在全国率先开启数字化改革探索实践。此后&…