zoukankan      html  css  js  c++  java
  • redis 事件

    事件是 Redis 服务器的核心,它处理两项重要的任务:
    • 文件事件
      • 在多个客户端中实现多路复用,接受它们发来的命令请求,并将命令的执行结果返回给客户端。
    • 时间事件
      • 实现服务器常规操作(server cron job)。
     
    文件事件

     
    • 读事件
    • 写事件
     
    读写事件的定义,是服务器对客户端的套接字操作;
    当服务器有数据返回给客户端,此时需要写套接字则是写事件;
    当服务器从客户端读取命令,来执行,此时需要读取套接字则是读事件;
     
    读事件
    读事件标志着客户端命令请求的发送状态。
     
    当一个新的客户端连接到服务器时,服务器会给为该客户端绑定读事件,直到客户端断开连接之后,这个读事件才会被移除。
     
    读事件在整个网络连接的生命期内,都会在等待和就绪两种状态之间切换:
    • 当客户端只是连接到服务器,但并没有向服务器发送命令时,该客户端的读事件就处于等待状态
    • 当客户端给服务器发送命令请求,并且请求已到达时(相应的套接字可以无阻塞地执行读 操作),该客户端的读事件处于就绪状态
     
    写事件
    写事件标志着客户端对命令结果的接收状态
     
    和客户端自始至终都关联着读事件不同,服务器只会在有命令结果要传回给客户端时,才会为
    客户端关联写事件,并且在命令结果传送完毕之后,客户端和写事件的关联就会被移除
     
    一个写事件会在两种状态之间切换:
    • 当服务器有命令结果需要返回给客户端,但客户端还未能执行无阻塞写,那么写事件处于等待状态
    • 当服务器有命令结果需要返回给客户端,并且客户端可以进行无阻塞写,那么写事件处于就绪状态。
     
    当客户端向服务器发送命令请求,并且请求被接受并执行之后,服务器就需要将保存在缓存内
    的命令执行结果返回给客户端,这时服务器就会为客户端关联写事件
     
     
    注意:同时关联写事件和读事件
    因为半双工的原因,要么执行读事件,要么执行写事件
    读事件的优先级高。
     
    事件时间

     
    时间事件记录着那些要在指定时间点运行的事件,
    多个时间事件以无序链表的形式保存在服务器状态中
     
    时间事件主要由三个属性组成:
    • when :以毫秒格式的 UNIX 时间戳为单位,记录了应该在什么时间点执行事件处理函数。
    • timeProc:事件处理函数。
    • next指向下一个时间事件,形成链表
     
    根据 timeProc 函数的返回值,可以将时间事件划分为两类
    • 如果事件处理函数返回 ae.h/AE_NOMORE ,那么这个事件为单次执行事件:
      • 该事件会在指定的时间被处理一次,之后该事件就会被删除,不再执行。
    • 如果事件处理函数返回一个非AE_NOMORE的整数值,那么这个事件为循环执行事件:
      • 该事件会在指定的时间被处理,之后它会按照事件处理函数的返回值,
      • 更新事件的when属性,让这个事件在之后的某个时间点再次运行,并以这种方式一直更新并运行
     
    当时间事件处理器被执行时,它遍历所有链表中的时间事件,检查它们的到达事件(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)
     
    

      

    时间事件应用:服务器常规操作
     
    服务器需要定期对自身的资源和状态进行必要的检查和整理,
    从而让服务器维持在一个健康稳定的状态,这类操作被统称为常规操作(cron job)
     
    在 Redis 中,常规操作由 redis.c/serverCron 实现,它主要执行以下操作:
    • 更新服务器的各类统计信息,比如时间、内存占用、数据库占用情况等
    • 清理数据库中的过期键值对。
    • 对不合理的数据库进行大小调整。
    • 关闭和清理连接失效的客户端。
    • 尝试进行AOF或RDB持久化操作。
    • 如果服务器是主节点的话,对附属节点进行定期同步。
    • 如果处于集群模式的话,对集群进行定期同步和连接测试
     
    在 Redis 2.6 版本中,程序规定 serverCron 每隔 10 毫秒就会被运行一次。从 Redis 2.8 开始,
    10 毫秒是 serverCron 运行的默认间隔,而具体的间隔可以由用户自己调整。
     
    事件的执行与调度

     
    Redis里面的两种事件呈合作关系,它们之间包含以下三种属性:
    •  一种事件会等待另一种事件执行完毕之后,才开始执行,事件之间不会出现抢占。
    • 事件处理器先处理文件事件(处理命令请求),再执行时间事件(调用 serverCron)
    • 文件事件的等待时间(类 poll 函数的最大阻塞时间),由距离到达时间最短的时间事件决定。
     
    这些属性表明,实际处理时间事件的时间,通常会比时间事件所预定的时间要晚,至于延迟的
    时间有多长,取决于时间事件执行之前,执行文件事件所消耗的时间
     
    根据情况,如果处理文件事件耗费了非常多的时间,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 的事件分为时间事件和文件事件两类。
    • 文件事件分为读事件和写事件两类:读事件实现了命令请求的接收,写事件实现了命令结果的返回。
    • 时间事件分为单次执行事件和循环执行事件,服务器常规操作 serverCron 就是循环事件。
    • 文件事件和时间事件之间是合作关系:一种事件会等待另一种事件完成之后再执行,不会出现抢占情况。
    • 时间事件的实际执行时间通常会比预定时间晚一些
     
     
  • 相关阅读:
    176. Second Highest Salary
    175. Combine Two Tables
    172. Factorial Trailing Zeroes
    171. Excel Sheet Column Number
    169. Majority Element
    168. Excel Sheet Column Title
    167. Two Sum II
    160. Intersection of Two Linked Lists
    个人博客记录
    <meta>标签
  • 原文地址:https://www.cnblogs.com/Aiapple/p/7249469.html
Copyright © 2011-2022 走看看