redis module模块简单使用

以往我们想给 Redis 加个功能或类似事务的东西只能用 Lua 脚本,这个东西没有实现真正的原子性,另外也无法使用底层的 API ,实质上比单纯的命令脚本提升有限。

Redis 4.0 终于加入了模块,暴露了必要的 API,并且有自动内存管理(大大减轻编写负担),基于 C99(C++ 或者其它语言的 C 绑定接口当然也可以)。

这东西有多灵活呢?不知道作者是不是为了突出这一点,直接编写了一个神经网络模块。

注意:

redis对布隆过滤器的支持就是通过第三方module来实现的,安装,使用都很简单

可以参考笔者的这篇博客:https://blog.csdn.net/yzf279533105/article/details/110873427

模块 Module 可以动态的载入和卸载,可以实现底层的数据结构也可以调用高层的指令,这一切都只需要包含头文件 redismodule.h ,和 Redis 本身一样简洁优雅。

基本入门

Hello World

// redis 4.0 以上源码可以找到头文件
#include "redismodule.h"
#include <stdlib.h>

int HelloworldRand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    RedisModule_ReplyWithLongLong(ctx,rand());
    return REDISMODULE_OK;
}

// 必须的函数
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
   // 最先调用初始化
    if (RedisModule_Init(ctx,"helloworld",1,REDISMODULE_APIVER_1)
        == REDISMODULE_ERR) return REDISMODULE_ERR;
   // 注册命令
    if (RedisModule_CreateCommand(ctx,"helloworld.rand",
        HelloworldRand_RedisCommand) == REDISMODULE_ERR)
        return REDISMODULE_ERR;

    return REDISMODULE_OK;
}

编译命令

g++ -fPIC -c mycal.cpp -o mycal.xo 
ld -o mycal.so mycal.xo -shared -lc

一般我更喜欢用 cmake,管理起来更容易

cmake_minimum_required(VERSION 2.8.11)
project(mycal)

set(mycal mycal.so)

add_library(${mycal} SHARED mycal.cpp)
set_target_properties(${mycal} PROPERTIES PREFIX "" SUFFIX "")  

加载命令

MODULE LOAD /path/to/mymodule.so   # 在 redis-cli 中执行,注意这里 mymodule.so 是文件名

执行命令

helloworld.rand   # 在 redis-cli 中执行

基础 API 一览

#include "redismodule.h" // 这个头文件在 > 4.0 的redis 源代码可以找到
#include <stdlib.h>

// redis API 和 argv 参数 都是 RedisModuleString 类型的
int HelloworldRand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    // 自动内存管理
    // 不需要 close keys/ free replies / free RedisModuleString
    // 注意为了及时处理内存,使用大内存应该手动 free (用redis对应函数)
    RedisModule_AutoMemory(ctx);

    // 错误调用可以使得 redis 直接崩溃,需要检查参数
    if (argc != 3) return RedisModule_WrongArity(ctx);

    // 从 redis 字符串获取数据
    const char *s = RedisModule_StringPtrLen(argv[0], NULL);

    // 字符串到数字
    long long myval;
    if (RedisModule_StringToLongLong(argv[1],&myval) == REDISMODULE_OK) {
        /* Do something with 'myval' */
    }

    // 数字到字符串
    RedisModuleString *mystr = RedisModule_CreateStringFromLongLong(ctx, 10);

    // 使用如下的函数而不是 malloc(对Redis透明,无法控制),保证和 redis 的内存分配器一致,默认是 jemalloc
    // void *RedisModule_Alloc(size_t bytes);
    // void* RedisModule_Realloc(void *ptr, size_t bytes);
    // void RedisModule_Free(void *ptr);
    // void RedisModule_Calloc(size_t nmemb, size_t size);
    // char *RedisModule_Strdup(const char *str);


    // 操作 Redis 原生类型底层API,通常是 RedisModule_TypeOperation 的格式命名函数
    RedisModuleKey *key;
    key = (RedisModuleKey*)RedisModule_OpenKey(ctx,argv[1],REDISMODULE_WRITE);
    if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) {
        RedisModule_StringSet(key,argv[2]);
    }

    // 高层 API 用 RedisModule_Call
    RedisModuleCallReply *reply;
    // sc 是格式化标志位,表示命令的多个参数各是什么类型,s 代表 argv[1] 是一个 RedisModuleString
    // c 代表 “10” 是以 \0 结尾的 C 字符串
    reply = RedisModule_Call(ctx,"INCR","sc",argv[1],"10");
    if (RedisModule_CallReplyType(reply) == REDISMODULE_REPLY_INTEGER) {
        long long myval = RedisModule_CallReplyInteger(reply);
        /* Do something with myval. */
    }

    // 返回一个数值给调用者
    RedisModule_ReplyWithLongLong(ctx, rand());
    return REDISMODULE_OK;
}

// 必须的函数
extern "C" int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    // 模块的名称在这里注册,可以跟编译后 so 名字不一样,推荐一样
    // RedisModule_Init 必须在调用其它API前最先被调用
    if (RedisModule_Init(ctx, "mycal", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR)
        return REDISMODULE_ERR;

    // 与其它模块命名冲突会导致命令注册失败,推荐采用 模块名.命令名 方式
    if (RedisModule_CreateCommand(ctx, "mycal", HelloworldRand_RedisCommand, "write", 1,1,1) == REDISMODULE_ERR)
        return REDISMODULE_ERR;
}

模块必须的函数只有 RedisModule_OnLoad,它是 redis 调用模块的入口函数。

上面的语言是 C++ ,为了编译成动态时函数的可见性加了 extern "C" 前缀。

用 C 语言开发是最简单的,但事实上任何语言都可以开发 Redis 模块。

 

在配置文件 redis.conf

增加: loadmoudule /path/module.so [argv0] [argv1] # 配置文件,后面可以加参数,这种方式需要重启redis

客户端工具 redis-cli

module load /path/module.so [argv0] [argv1] # 客户端指令,加载模块,不需要重启redis,但是如果redis关闭后这个module需要重新加载

module list # 列出所有模块

module unload module # 卸载模块,模块名是函数中注册的名称,不是文件名

API

大致可以分为三类:直接操作底层数据;redis 命令操作;内存分配、集群支持等

注意

模块如果有没有捕获或内存泄露出错等问题 Redis 本身是无法处理的,会导致程序整个挂掉,甚至很可能连日志都没有需要非常小心。

参考文献

  1. 开发简介 Redis Modules: an introduction to the API
  2. API 简介 Modules API reference - Redis
  3. 寻找灵感 Redis Labs Modules
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值