两个比较有名的 redis 模块
- https://github.com/RedisBloom/RedisBloom
 - https://github.com/RedisGraph/RedisGraph
 
redis 模块文档:https://redis.io/docs/latest/develop/reference/modules/
1. 模块代码
文件 hello.cc
#include "redismodule.h"
#include <stdlib.h>
int HelloworldRand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    RedisModule_ReplyWithLongLong(ctx,rand());
    return REDISMODULE_OK;
}
const char * modulename = "helloworld";
const char * command = "helloworld.rand";
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (RedisModule_Init(ctx, modulename, 1, REDISMODULE_APIVER_1)
        == REDISMODULE_ERR) return REDISMODULE_ERR;
    if (RedisModule_CreateCommand(ctx, command,
        HelloworldRand_RedisCommand, "fast random",
        0, 0, 0) == REDISMODULE_ERR)
        return REDISMODULE_ERR;
    return REDISMODULE_OK;
}
- 模块的名字为 helloworld
 - 模块的命令为 helloworld.rand
 
2. CMakeLists.txt
PROJECT (redis-module)
INCLUDE_DIRECTORIES (
    ${CMAKE_CURRENT_SOURCE_DIR}/../redis-7.4.1/src # 目的是引用 "redismodule.h"
    )
LINK_DIRECTORIES (
    ${CMAKE_CURRENT_SOURCE_DIR}/target
    )
ADD_LIBRARY (htmlparser_shared SHARED src/hello.cc)
SET_TARGET_PROPERTIES(htmlparser_shared PROPERTIES OUTPUT_NAME "hello") # 输出文件名 libhello.so
SET_TARGET_PROPERTIES(htmlparser_shared PROPERTIES CLEAN_DIRECT_OUTPUT 1)
3. 加载模块
修改文件 redis.conf,增加一行
loadmodule /root/workspace/hello/target/libhello.so
或者在执行命令的时候增加参数 --loadmodule
./src/redis-server --loadmodule /root/workspace/hello/target/libhello.so
4. 使用 redis-cli 查看加载的模块 动态加载/卸载模块
- 加载模块
 
MODULE LOAD /path/to/mymodule.so
- 查看已经加载的模块列表
 
> MODULE LIST
- 卸载模块
 
MODULE UNLOAD mymodule
5. 模块中可以使用的 API
- 初始化
 
int RedisModule_Init(RedisModuleCtx *ctx, const char *modulename,
                     int module_version, int api_version);
- 注册命令
 
int RedisModule_CreateCommand(RedisModuleCtx *ctx, const char *name,
                              RedisModuleCmdFunc cmdfunc, const char *strflags,
                              int firstkey, int lastkey, int keystep);
- 执行命令的函数
 
int mycommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
- 返回值
 
int RedisModule_ReplyWithLongLong(RedisModuleCtx *ctx, long long integer);
- 清理模块
 
int RedisModule_OnUnload(RedisModuleCtx *ctx);
In most cases, there is no need for special cleanup. When a module is unloaded, Redis will automatically unregister commands and unsubscribe from notifications. However in the case where a module contains some persistent memory or configuration, a module may include an optional RedisModule_OnUnload function. If a module provides this function, it will be invoked during the module unload process. The following is the function prototype: The OnUnload function may prevent module unloading by returning REDISMODULE_ERR. Otherwise, REDISMODULE_OK should be returned.
- 数字转字符串/字符串转数字
 
RedisModuleString *mystr = RedisModule_CreateStringFromLongLong(ctx,10);
# --
long long myval;
if (RedisModule_StringToLongLong(ctx,argv[1],&myval) == REDISMODULE_OK) {
    /* Do something with 'myval' */
}
- 调用 redis 命令
 
RedisModuleCallReply *reply;
reply = RedisModule_Call(ctx,"INCRBY","sc",argv[1],"10");
- 返回值
 RedisModule_ReplyWithError(RedisModuleCtx *ctx, const char *err);REDISMODULE_ERRORMSG_WRONGTYPERedisModule_ReplyWithError(ctx,"ERR invalid arguments");RedisModule_ReplyWithLongLong(ctx,12345);RedisModule_ReplyWithSimpleString(ctx,"OK");int RedisModule_ReplyWithStringBuffer(RedisModuleCtx *ctx, const char *buf, size_t len);int RedisModule_ReplyWithString(RedisModuleCtx *ctx, RedisModuleString *str);RedisModule_ReplyWithArray(ctx,2);RedisModule_ReplyWithStringBuffer(ctx,"age",3);RedisModule_ReplyWithLongLong(ctx,22);- 
RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_LEN); - 
接收参数
 - 获取参数类型 
int keytype = RedisModule_KeyType(key); - REDISMODULE_KEYTYPE_EMPTY
 - REDISMODULE_KEYTYPE_STRING
 - REDISMODULE_KEYTYPE_LIST
 - REDISMODULE_KEYTYPE_HASH
 - REDISMODULE_KEYTYPE_SET
 - REDISMODULE_KEYTYPE_ZSET