作者:张仕华module的作用Redis通过对外提供一套API和一些数据类型, 可以供开发者开发自己的模块并且加载到redis中.通过API可以直接操作redis中的数据,也可以通过调用redis命令来操作数据(类似lua script).通过编写模块可以注册自己的命令到redis中.编写一个module我们通过编写一个简单的module来体验一下该功能.该module对外提供两个命令,一个是启动一个定时任务,每隔5s将redis持久化相关的信息发送到pinfo这个channel中,另一个是关闭该定时任务.注册该模块后,我们可以通过"subscribe pinfo"来订阅该渠道,然后就可以定时收到redis持久化相关的信息,以便做一些监控或相应的应对措施注册命令到redis中//每个模块都必须有该函数.该函数是redis加载模块的入口,我们通过该函数可以注册相关的命令进去int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { REDISMODULE_NOT_USED(argv); REDISMODULE_NOT_USED(argc); //注册模块,模块名称为’pushpersistenceinfo’ if (RedisModule_Init(ctx,“pushpersistenceinfo”,1,REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; //在redis中创建命令.第二部分为命令名称,第三部分为执行该命令时的回调函数 if (RedisModule_CreateCommand(ctx,“pushpersistenceinfo.timer”, TimerCommand_RedisCommand,“readonly”,0,0,0) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_CreateCommand(ctx,“pushpersistenceinfo.stop”, TimerStopCommand_RedisCommand,“readonly”,0,0,0) == REDISMODULE_ERR) return REDISMODULE_ERR; return REDISMODULE_OK;}如上函数类似一个模板,只需要填充自己的模块名称和相应的命令即可.重点是调用RedisModule_CreateCommand时的第三个参数-即回调函数.定义回调函数#define REDISMODULE_EXPERIMENTAL_API#include “../redismodule.h”#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <string.h>#include <errno.h>RedisModuleString *infoStr;int off=0 ;//定时器开关void getPersistenceStatus(RedisModuleCtx *ctx,RedisModuleString **infoStr);void publishPersistenceStatus(RedisModuleCtx *ctx,RedisModuleString *infoStr);/ Timer callback. *///时间任务的回调函数void timerHandler(RedisModuleCtx *ctx,void *data) { if(off == 1) return;//如果关闭了定时器,则返回退出 REDISMODULE_NOT_USED(ctx); getPersistenceStatus(ctx,&infoStr);//获取redis持久化相关的信息并放入infoStr中 publishPersistenceStatus(ctx,&infoStr);//publish redis持久化相关的信息到pinfo渠道 RedisModule_CreateTimer(ctx,5000,timerHandler,NULL);//创建定时任务,5s后执行}int TimerCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { off = 0; REDISMODULE_NOT_USED(argv); REDISMODULE_NOT_USED(argc); RedisModule_AutoMemory(ctx);//开启内存的自动管理 getPersistenceStatus(ctx,&infoStr);//获取redis持久化相关的信息并放入infoStr中 publishPersistenceStatus(ctx,&infoStr);//publish redis持久化相关的信息到pinfo渠道 RedisModule_CreateTimer(ctx,5000,timerHandler,NULL);//创建定时任务,5s后执行.回调函数为timerHandler return RedisModule_ReplyWithSimpleString(ctx, “OK”);//给客户端返回字符串"OK"}int TimerStopCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { off = 1;//关闭定时任务 return RedisModule_ReplyWithSimpleString(ctx, “OK”);//给客户端返回字符串"OK"}void getPersistenceStatus(RedisModuleCtx *ctx,RedisModuleString **infoStr){ RedisModuleCallReply *reply;//调用info Persistence获取redis持久化相关的信息 reply = RedisModule_Call(ctx,“info”,“c”,“Persistence”); *infoStr = RedisModule_CreateStringFromCallReply(reply);}void publishPersistenceStatus(RedisModuleCtx *ctx,RedisModuleString **infoStr){ //调用publish pinfo xxxxx将持久化信息推送到pinfo渠道 RedisModule_Call(ctx,“publish”,“cs”,“pinfo”,*infoStr);}执行pushpersistenceinfo.timer和pushpersistenceinfo.stop命令后会分别回调TimerCommand_RedisCommand和TimerStopCommand_RedisCommand这两个回调函数.前者会创建一个定时任务,定时任务回调函数为timerHandler,如果off不为1,则回调函数中会再次创建定时任务;后者会将off置为1,不再执行定时任务.演示将模块置于redis源码目录的src/modules/目录中,然后执行如下命令编译模块gcc -fPIC -std=gnu99 -c -o pushpersistenceinfo.o pushpersistenceinfo.cld -o pushpersistenceinfo.so pushpersistenceinfo.o -shared -Bsymbolic -lc加载模块127.0.0.1> module load $RedisSourcePath/src/modules/pushpersistenceinfo.soOK127.0.0.1> module list1) 1) “name” 2) “pushpersistenceinfo” 3) “ver” 4) (integer)执行命令(首先订阅pinfo渠道)redis-cli subscribe pinfoReading messages… (press Ctrl-C to quit)1) “subscribe"2) “pinfo"3) (integer) 1执行模块中的命令127.0.0.1> PUSHPERSISTENCEINFO.timerOK查看输出(可以看到,每隔5s会输出一次)1) “message"2) “pinfo"3) “# Persistence\r\nloading:0\r\nrdb_changes_since_last_save:15\r\nrdb_bgsave_in_progress:0\r\nrdb_last_save_time:1555494610\r\nrdb_last_bgsave_status:ok\r\nrdb_last_bgsave_time_sec:-1\r\nrdb_current_bgsave_time_sec:-1\r\nrdb_last_cow_size:0\r\naof_enabled:1\r\naof_rewrite_in_progress:0\r\naof_rewrite_scheduled:0\r\naof_last_rewrite_time_sec:-1\r\naof_current_rewrite_time_sec:-1\r\naof_last_bgrewrite_status:ok\r\naof_last_write_status:ok\r\naof_last_cow_size:0\r\naof_current_size:631\r\naof_base_size:631\r\naof_pending_rewrite:0\r\naof_buffer_length:0\r\naof_rewrite_buffer_length:0\r\naof_pending_bio_fsync:0\r\naof_delayed_fsync:0\r\n"1) “message"2) “pinfo"3) “# Persistence\r\nloading:0\r\nrdb_changes_since_last_save:15\r\nrdb_bgsave_in_progress:0\r\nrdb_last_save_time:1555494610\r\nrdb_last_bgsave_status:ok\r\nrdb_last_bgsave_time_sec:-1\r\nrdb_current_bgsave_time_sec:-1\r\nrdb_last_cow_size:0\r\naof_enabled:1\r\naof_rewrite_in_progress:0\r\naof_rewrite_scheduled:0\r\naof_last_rewrite_time_sec:-1\r\naof_current_rewrite_time_sec:-1\r\naof_last_bgrewrite_status:ok\r\naof_last_write_status:ok\r\naof_last_cow_size:0\r\naof_current_size:631\r\naof_base_size:631\r\naof_pending_rewrite:0\r\naof_buffer_length:0\r\naof_rewrite_buffer_length:0\r\naof_pending_bio_fsync:0\r\naof_delayed_fsync:0\r\n"停止定时器127.0.0.1> PUSHPERSISTENCEINFO.stopOK卸载模块127.0.0.1> module unload pushpersistenceinfoOK该模块代码地址:https://github.com/erpeng/red…参考文档https://redislabs.com/blog/wr…https://redis.io/topics/modul...https://redis.io/topics/modul...https://redis.io/topics/modul