Redis modules extend the functionality of Redis by allowing developers to add custom commands and data types. This module will guide you through the process of creating your own Redis module, from setting up the development environment to writing and deploying your custom module.

  1. Setting Up the Development Environment

Before you start creating a custom Redis module, you need to set up your development environment.

Prerequisites

  • Redis: Ensure you have Redis installed on your machine.
  • C Compiler: Redis modules are typically written in C, so you need a C compiler like gcc.
  • Redis Module SDK: Download the Redis Module SDK from the Redis Labs GitHub repository.

Steps

  1. Install Redis:

    sudo apt-get update
    sudo apt-get install redis-server
    
  2. Install GCC:

    sudo apt-get install build-essential
    
  3. Clone the Redis Module SDK:

    git clone https://github.com/RedisLabs/redis-module-sdk.git
    cd redis-module-sdk
    

  1. Writing Your First Redis Module

Creating the Module File

Create a new file named mymodule.c in the redis-module-sdk directory.

Basic Structure of a Redis Module

Here is a basic structure of a Redis module:

#include "redismodule.h"

// Function to be called when the command is executed
int MyCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (argc != 2) {
        return RedisModule_WrongArity(ctx);
    }
    RedisModule_ReplyWithString(ctx, argv[1]);
    return REDISMODULE_OK;
}

// Module initialization function
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (RedisModule_Init(ctx, "mymodule", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) {
        return REDISMODULE_ERR;
    }
    if (RedisModule_CreateCommand(ctx, "mymodule.mycommand", MyCommand_RedisCommand, "readonly", 1, 1, 1) == REDISMODULE_ERR) {
        return REDISMODULE_ERR;
    }
    return REDISMODULE_OK;
}

Explanation

  • Include the Redis Module API: #include "redismodule.h"
  • Define the Command Function: MyCommand_RedisCommand is the function that will be executed when the custom command is called.
  • Initialize the Module: RedisModule_OnLoad is the entry point of the module. It registers the module and the custom command.

Compiling the Module

Compile the module using gcc:

gcc -o mymodule.so -shared -fPIC mymodule.c -I/path/to/redis/src

Replace /path/to/redis/src with the path to the Redis source code.

  1. Loading and Testing the Module

Loading the Module

Start the Redis server with the module loaded:

redis-server --loadmodule ./mymodule.so

Testing the Module

Open the Redis CLI and test the custom command:

redis-cli
127.0.0.1:6379> mymodule.mycommand "Hello, Redis!"
"Hello, Redis!"

  1. Advanced Module Features

Adding Custom Data Types

Redis modules can define custom data types. Here is an example of how to define a custom data type:

// Define the custom data type
RedisModuleType *MyType;

typedef struct {
    long long value;
} MyTypeObject;

// Function to create a new object
void *MyType_RdbLoad(RedisModuleIO *rdb, int encver) {
    MyTypeObject *o = RedisModule_Alloc(sizeof(*o));
    o->value = RedisModule_LoadSigned(rdb);
    return o;
}

// Function to save the object to RDB
void MyType_RdbSave(RedisModuleIO *rdb, void *value) {
    MyTypeObject *o = value;
    RedisModule_SaveSigned(rdb, o->value);
}

// Function to free the object
void MyType_Free(void *value) {
    RedisModule_Free(value);
}

// Module initialization function
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (RedisModule_Init(ctx, "mymodule", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) {
        return REDISMODULE_ERR;
    }

    // Register the custom data type
    RedisModuleTypeMethods tm = {
        .version = REDISMODULE_TYPE_METHOD_VERSION,
        .rdb_load = MyType_RdbLoad,
        .rdb_save = MyType_RdbSave,
        .aof_rewrite = NULL,
        .mem_usage = NULL,
        .digest = NULL,
        .free = MyType_Free
    };

    MyType = RedisModule_CreateDataType(ctx, "mytype", 0, &tm);
    if (MyType == NULL) return REDISMODULE_ERR;

    return REDISMODULE_OK;
}

Explanation

  • Define the Custom Data Type: MyTypeObject is a simple structure with a single value field.
  • Implement RDB Load and Save Functions: These functions handle the serialization and deserialization of the custom data type.
  • Register the Custom Data Type: The RedisModule_CreateDataType function registers the custom data type with Redis.

  1. Practical Exercise

Exercise

Create a Redis module that defines a custom command mymodule.add which takes two integer arguments and returns their sum.

Solution

#include "redismodule.h"

int AddCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (argc != 3) {
        return RedisModule_WrongArity(ctx);
    }

    long long a, b;
    if (RedisModule_StringToLongLong(argv[1], &a) != REDISMODULE_OK ||
        RedisModule_StringToLongLong(argv[2], &b) != REDISMODULE_OK) {
        RedisModule_ReplyWithError(ctx, "ERR invalid integer");
        return REDISMODULE_ERR;
    }

    RedisModule_ReplyWithLongLong(ctx, a + b);
    return REDISMODULE_OK;
}

int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (RedisModule_Init(ctx, "mymodule", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) {
        return REDISMODULE_ERR;
    }
    if (RedisModule_CreateCommand(ctx, "mymodule.add", AddCommand_RedisCommand, "readonly", 1, 1, 1) == REDISMODULE_ERR) {
        return REDISMODULE_ERR;
    }
    return REDISMODULE_OK;
}

Compiling and Testing

  1. Compile the Module:

    gcc -o mymodule.so -shared -fPIC mymodule.c -I/path/to/redis/src
    
  2. Load the Module:

    redis-server --loadmodule ./mymodule.so
    
  3. Test the Command:

    redis-cli
    127.0.0.1:6379> mymodule.add 5 10
    (integer) 15
    

Conclusion

In this section, you learned how to create custom Redis modules, including setting up the development environment, writing a basic module, and adding custom commands and data types. You also practiced creating a simple module that adds two integers. With this knowledge, you can extend Redis to meet your specific needs and integrate it more deeply into your applications.

© Copyright 2024. All rights reserved