写点什么

Redis「5」事件处理模型与键过期策略

作者:Samson
  • 2022 年 5 月 16 日
  • 本文字数:1803 字

    阅读完需:约 6 分钟

Redis「5」事件处理模型与键过期策略

01-Redis 单线程模型

Redis 服务端是基于 Reactor 模式实现的事件驱动程序,并需要处理两类的事件:


  • 文件事件,简单来讲就是 Redis 客户端通过 Socket 发来的命令。

  • 时间事件,服务端中需要特定时间点执行的操作,例如serverCron函数。


Redis 的单线程模型实际指的是上述两类事件是在同一个线程内处理的。但是为了能同时处理多个客户端的连接,Redis 中用到了 IO 多路复用技术。《Redis 设计与实现》中对 Redis 中的多路复用介绍如下:


文件事件处理器以单线程方式运行,但通过 IO 多路复用程序来监听多个客户端套接字。既实现了高性能的网络通信模型,又可以很好地与 Redis 服务器中其他同样以单线程方式运行的模块进行对接,这保持了 Redis 内部线程模型的简单性。


Redis 中单线程的事件循环可以用如下伪代码表示:


def eventLoop():    while True:  # 处理文件事件,接受明令以及发送命令回复  processFileEvents()  # 处理时间事件  processTimeEvents()  # 其他操作  ...
复制代码

01.1-文件事件处理器


  • 当 Socket 变得可读时,会产生AE_READABLE事件

  • 当 Socket 变得可写时,会产生AE_WRITABLE事件


一次完整的客户端与服务端连接过程中,事件及处理器的过程如下:


  1. 服务端监听套接字AE_READABLE事件,且此时该事件对应的处理器为连接应答处理器;

  2. 当客户端发起连接后,监听套接字将产生AE_READABLE事件,连接应答处理器负责创建客户端套接字,并将客户端套接字的AE_READABLE事件与命令请求处理器绑定;

  3. 当客户端发送命令时,客户端套接字将发生AE_READABLE事件,命令请求处理器负责处理这些命令,并产生回复。

  4. 为了将命令回复传送到客户端,服务器会将客户端套接字的AE_WRITABLE事件与命令回复处理器绑定。

  5. 当客户端尝试读取命令回复时,会触发AE_WRITABLE事件,命令回复处理器会将回复写入套接字。之后,服务器会解除AE_WRITABLE事件与命令回复处理器的绑定。

01.2-时间事件处理器

Redis 中时间事件分为 2 类:


  • 定时事件,例如 30ms 后执行一次

  • 周期事件,例如每隔 30ms 执行一次


每隔时间事件,都包含如下三个要素:


  1. id,全局唯一 ID,且按照事件先后顺序递增。

  2. when,事件到达时间,毫秒精度 UNIX 时间戳。

  3. timeProc,事件处理器,用于处理响应的事件。其返回值决定事件是定时的(ae.h/AE_NOMORE),还是周期性的。


[1] Reactor pattern (Node.js Netty 等知名项目的线程模型也都基于 Reactor 模式)

02-键过期

Redis 中设置键过期的方式有如下几种:


  • expire key ttl,ttl 秒后过期

  • pexpire key ttl,ttl 毫秒后过期

  • pexpireat key timestamp,在 timestamp 时刻过期


无论上述哪种方式,最终都通过pexpireat方式实现。过期的实现原理如下:在redisDb中维护了一个 dict(过期字典),记录了哪些键在何时应当过期。


typedef struct redisDb {  ...  // 其键为 String 类型,其值为 long long类型  dict *expires;  ...}
复制代码


过期判定的原则就是,将过期字典中的键对应的值与当前系统时间相比,若小于系统时间,则认为键过期。

02.1-键过期删除策略

一般来说,键过期删除策略有三种:


  • 定时删除,在设置键的过期时间时,启动一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除。优缺点:对内存最友好,但对 CPU 最不友好。

  • 惰性删除,过期时并不删除,但是每次从键空间获取键时,都判断键是否过期。若过期则删除,否则返回该键的值。对内存不友好,但对 CPU 友好。

  • 定期删除,每隔一段时间就对数据库进行检查,删除里面的过期键。(前两种方式的混合)。

02.2-Redis 内存淘汰机制

虽然 Redis 通常采用惰性删除和定期删除的混合策略,但仍有可能有大量过期的键驻留在内存中,导致 OOM。Redis 是如何解决这个问题的呢?你可能需要了解如下几种 Redis 的内存淘汰机制:


  1. volatile-lru,从server.db[i].expires中挑选最近最少使用的淘汰;

  2. volatile-ttl,从server.db[i].expires中挑选将要过期的数据淘汰;

  3. volatile-random, 从server.db[i].expires中随机挑选数据淘汰;

  4. allkeys-lru,从server.db[i].dict中挑选最近最少使用的淘汰;

  5. allkeys-random,从server.db[i].dict中随机挑选数据淘汰;

  6. no-eviction,如果内存不足以写入新数据,拒绝淘汰,写入报错;

  7. volatile-lfu,从server.db[i].expires中挑选最不经常使用的淘汰;

  8. allkeys-lfu,从server.db[i].dict中挑选最不经常使用的淘汰;


历史文章

Redis「4」Redis 在秒杀系统中的应用

Redis「3」持久化

Redis「2」缓存一致性与异常处理

Redis「1」流水线、事务、Lua 脚本

发布于: 刚刚阅读数: 2
用户头像

Samson

关注

还未添加个人签名 2019.07.22 加入

还未添加个人简介

评论

发布
暂无评论
Redis「5」事件处理模型与键过期策略_学习笔记_Samson_InfoQ写作社区