Redis从4.0版本开始加入了对外部扩展模块的支持。外部扩展模块可以实现新的Redis命令,新的Redis数据结构,总之基本上可以做到所有Redis内核可以做的事情。本文和大家分享的就是redis外部扩展模块相关内容,一起来看看吧,希望对待学习redis有所帮助。
我个人认为这是迄今为止,Redis最重要的一个改进。友好的API、完善的文档和健壮的基础结构,会快速吸引大量的第三方开发者不断贡献新的内容,Redis的用途必然会更加广泛,用户群也会随之扩大。
模块的实现
Redis模块需要引入 redismodule.h ,用C、C++或其他提供C binding的开发语言实现,并编译成动态库 .so 文件。基于 redismodule.h 提供的API实现的模块,在API不变的情况下(API版本号相同),可以兼容不同Redis版本而不需要重新编译。
在开发模块的时候并不需要依赖Redis的源代码或开发库,只需要把 redismodule.h 拷贝到工程下边引用,实现并导出方法 RedisModule_OnLoad 即可。
模块可以做什么
访问Redis数据空间
Redis提供了两套数据访问的API,一套是较高层的,类似于Lua脚本的API,往往用来调用API没有提供支持的Redis命令。另一套是底层API,速度很快,基本和Redis原生命令一样快,也提供了一些对各种数据结构的进行处理的函数,是推荐的数据访问方式。
高层API使用 RedisModule_Call 调用Redis命令,如:
RedisModuleCallReply *reply;reply = RedisModule_Call(ctx,"INCR","sc",argv[1],"10");
底层API使用 RedisModule_OpenKey 打开并获取Key指针继而进行后续处理,如:
RedisModuleKey *key;key = RedisModule_OpenKey(ctx,"somekey",REDISMODULE_READ);
实现新的数据结构
对于简单的数据结构,可以使用DMA(direct memory access)将结构编码保存到Redis的String类型中,如:
// 获取字符串内存指针继而修改其内容
size_t len;
char *myptr = RedisModule_StringDMA(key,&len,REDISMODULE_WRITE);
// 增大,减少或创建字符串
RedisModule_StringTruncate(key,1024);
也可以使用API注册并实现新的数据结构,可以控制内存的分配与释放,RDB序列化,AOF重写等。 这里 是Redis官方的一个例子,好奇的同学可以自己点进去看看。
实现阻塞命令
阻塞命令(Blocking commands)会阻塞客户端,直到某个期望的事件发生才会返回,比如List的 BLPOP 命令。模块API也提供了实现阻塞命令的功能,在写这篇文章的时候,Blocking Command的相关API还处于试验阶段,其设计还没有最终确定,所以这里就不详细说明了,以后再将这部分补全。
加载模块
模块有两种加载方式,一是在配置文件 redis.conf 中使用 loadmodule /path/to/mymodule.so在Redis启动时加载。另一种方式在运行时使用命令 MODULE LOAD /path/to/mymodule.so 加载。加载的模块可以使用命令 MODULE LIST 查看,使用 MODULE UNLOAD mymodule 卸载。
在载入的模块的时候可以传入参数,如: loadmodule mymodule.so foo bar 1234 ,参数会被传入模块的 OnLoad 方法中。
对Redis Cluster的支持
模块是可以支持Redis Cluster的,但是目前还找不到相关的介绍,只是在官方文档里提到两个相关的API函数: RedisModule_IsKeysPositionRequest(ctx) 与 RedisModule_KeyAtPos(ctx,pos)。于是仔细的看了一下官方API文档中的相关部分,并对照了一下其他模块的实现,猜了一下大概的实现方式。
首先,在创建Redis模块的命令时,需要调用API方法:
int RedisModule_CreateCommand(RedisModuleCtx *ctx,const char*name, RedisModuleCmdFunc cmdfunc,const char*strflags,intfirstkey,intlastkey,intkeystep);
其中的 strflags 参数的一个flag为 getkeys-api ,意思是这个方法是否支持返回参数中key。一个方法接收的参数有多个,但并不是每一个都是key,比如 LRANGE key start stop 中,只有第一个参数是key。而Redis需要知道一个命令涉及到哪些key,才能在集群中找到对应的服务器并执行命令。
如果一个命令支持 getkeys-api ,那么在集群环境下, RedisModule_IsKeysPositionRequest(ctx) 方法就会返回true,就是说需要方法标出参数中的key,这就用到了 RedisModule_KeyAtPos(ctx,pos) 方法,其中 pos 是参数的位置。下边是 rxzsets 中相关的代码:
int ZUnionTopKCommand(RedisModuleCtx *ctx, RedisModuleString **argv,intargc){
...
if (RedisModule_IsKeysPositionRequest(ctx)) {
for (int i = 0; i < numkeys; i++) {
RedisModule_KeyAtPos(ctx, 3 + i);
}
return REDISMODULE_OK;
}
...
}
int RedisModule_OnLoad(RedisModuleCtx *ctx){
...
if (RedisModule_CreateCommand(ctx, "zuniontop", ZUnionTopKCommand,
"readonly getkeys-api", 1, 1,
1) == REDISMODULE_ERR)
...
}
Redis Module Hub
Redis Module Hub 是Redis官方的模块仓库,目前已经有将近二十个模块,其中一大半是Redis Labs自己贡献的,算是抛砖引玉吧,下边随便拿出几个做一下简单的介绍:
· 对现有数据结构功能的扩展,如:
· rxkeys 提供了按正则表达式批量获取与删除条目的功能
· rxhashes 提供了在Hash中改变现有条目的值并返回原值的原子操做
· rxlists 提供了7个新的列表操作方法。
· 新数据结构,如:
· rejson 提供了对原生JSON格式支持,允许对JSON数据内的值进行获取与修改
· Redis Graph 添加了对图数据库的支持
· redisearch 实现了全文搜索,使用特殊的压缩数据结构,加快了搜索的速度,并且减少了内存占用
· redis-ml 实现了多个机器学习常用的数据结构及相关方法
· 对功能的扩展,如:
· graphicsmagick 提供类似GraphicsMagick的图片处理功能,从此生成缩略图,打水印都可以在Redis里做了
· redablooms 基于RedisString的Bloom filter,可以用于ID生成
· password 提供加密的密码存储
来源:千里