Swift51.com
麦子学院 头像
麦子学院  2017-08-22 22:03

Redis学习之外部扩展模块详解

回复:0  查看:2952  
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 提供加密的密码存储


来源:千里