RedisModule剖析 - RedisTimer

RedisTimer 是一款基于 Redis 的时间事件来实现的计时器的模块,通过时间事件机制来实现延迟/循环执行对应的脚本(函数),由于该模块执行脚本(函数)的命令为 FCALL,因此要求Redis版本最低为7.0.0,该模块也支持数据的持久化,用于保证计时器的信息不丢失。

一、简介

二、架构设计

2.1、相关命令

  • timer.new : 创建一个新的计时器,会在指定的时间之后执行对应的脚本(函数),会直接覆盖同名的已经存在的计时器;
  • timer.kill : 删除之前创建的计时器,并且删除对应的计时器key;
  • timer.info : 查看特定的计时器的信息;

2.2、数据结构

// 计时器的数据结构
typedef struct TimerData {
RedisModuleString *key; // 对应计时器key对象
RedisModuleString *function; // 需要执行的脚本
mstime_t interval; // 被调用的时间间隔,单位毫秒
int datalen; // 脚本及其参数的数量
int numkeys; // 参数中key的个数
bool loop; // 是否循环执行,每次执行之后间隔 interval 后会再次执行
bool deleted; // 计时器key是否已经从db中删除的标记
RedisModuleTimerID tid; // 内部创建计时器时的id
RedisModuleString *data[]; // 脚本及其参数对象
} TimerData;

2.3、持久化

2.3.1、RDB的持久化

RDB 的存储过程比较简单,直接把对应结构体的所有信息持久化到 RDB 文件中,相关函数 timer_RDBSaveCallBack

2.3.2、AOF的持久化

数据 AOF 的持久化会在 AofRewrite 的时候会用到,这里是将对应的数据结构转换为 timer.new 命令进行存储;

2.4、其他细节

  • 创建新的计时器时使用了 RedisModule 的 RM_CreateTimer 接口来注册了一个时间事件,从而实现在指定的时间之后执行对应的自定义的回调函数;
  • 执行完成单次回调函数之后,依据 loop 字段判断是否需要循环执行,则选择是否再次增加一个时间事件,或者调用 timer.kill 删除计时器;
  • 使用一个全局静态变量 timers 来记录当前现存的计时器数量,比便于在卸载该模块时进行判断;
  • 计时器的脚本(函数)调用使用 FCALL 命令,因此对 Redis 版本有一些要求(最低版本7.0.0);
作者: bugwz
链接: https://bugwz.com/2022/09/29/redismodule-redistimer/
声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 咕咕