Redis模块开发,由Redis来触发RocketMQ Client进行发布消息

Redis有pubsub功能,我感觉用起来不方便,达不到我的要求,于是打算给Redis开发一个第三方模块,当key超时时自动通知RocketMQ超时的key,RocketMQ的消费者在消费消息,做响应的业务逻辑处理。

首先要做的就是github上下载RocketMQ的C++客户端源码:

https://github.com/apache/rocketmq-client-cpp

然后编译,编译总体来说还是比较顺利的,就碰到一个错误:

libboost_iostreams.a for lack of <pbin.v2/libs/iostreams/build/gcc-4.8.5/release/link-static/runtime

只需要安装一下bzip2包即可:yum install bzip2-devel

下来就是开发Redis的模块了。

模块也很简单,我就直接贴代码了 :


#define REDISMODULE_EXPERIMENTAL_API
#include "../../redismodule.h"

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <unistd.h>
#include <memory.h>

#include "CProducer.h"
#include "CCommon.h"
#include "CMessage.h"
#include "CSendResult.h"



static CProducer *producer = NULL;
static char* MQAddr  = NULL;
static char* MQTopic = NULL;
static char* MQTag   = NULL;


static int SendTOMQ (RedisModuleCtx *ctx, const char* expirekey)
{
    CMessage *msg = CreateMessage(MQTopic);
    SetMessageTags(msg, MQTag);
    SetMessageKeys(msg, expirekey);

    CSendResult result;

    SetMessageBody(msg,  "Redis Key Timeout\n");
    SendMessageSync(producer, msg, &result);
    if (result.sendStatus == E_SEND_OK) {
        printf ("Notify MQ successn: %s\n", expirekey);
        return REDISMODULE_OK;
    }
    
    else {
        printf ("Notify MQ fail: %s\n", expirekey);
        return  RedisModule_ReplyWithError(ctx,"Send to MQ fail\n");
    }

}


//int (*RedisModuleNotificationFunc)(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key);
extern "C" int KeyExpireEventCallback (RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key)
{
    REDISMODULE_NOT_USED(type);
    REDISMODULE_NOT_USED(event);

    size_t  keylen = 0;
    const char *expireKey = RedisModule_StringPtrLen(key, &keylen);

    printf ("RocketmqMoudle callback exe: %s\n", expireKey);

    //const char* topic = "FOREGROUND_CONSUMER";//
    //const char* tag   = "EXPIRE";//
    if (MQAddr == NULL || MQTopic == NULL || MQTag == NULL) {
        return  RedisModule_ReplyWithError(ctx,"You haven't set the parameters of MQ yet.");
    }

    return SendTOMQ(ctx, expireKey);

    
}




extern "C" int PublishKey(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (argc != 2) 
        return RedisModule_WrongArity(ctx);

    const char *expirekey = RedisModule_StringPtrLen(argv[1], NULL);
    

    return SendTOMQ (ctx, expirekey);

}

/*
write readonly admin deny-oom deny-script allow-loading pubsub random allow-stale no-monitor fast getkeys-api no-cluster
*/
extern "C" int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) 
{
    if (RedisModule_Init(ctx,"rocketmq",1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) 
		return REDISMODULE_ERR;

    size_t len;
    /* Log the list of parameters passing loading the module. */
    for (int j = 0; j < argc; j++) {
        const char *s = RedisModule_StringPtrLen(argv[j], &len);
        printf("Module loaded with ARGV[%d] = %s\n", j, s);
    }

    if (argc != 3) {
        return RedisModule_WrongArity(ctx);
    }

    
    MQAddr  = strdup(RedisModule_StringPtrLen(argv[0], &len));
    MQTopic = strdup(RedisModule_StringPtrLen(argv[1], &len));
    MQTag   = strdup(RedisModule_StringPtrLen(argv[2], &len));


    if (RedisModule_CreateCommand(ctx,"rocketmq.pubfun", PublishKey,"readonly",1,1,1) == REDISMODULE_ERR)
        return REDISMODULE_ERR;
 

    RedisModule_SubscribeToKeyspaceEvents (ctx, REDISMODULE_NOTIFY_EXPIRED, KeyExpireEventCallback);
    producer = CreateProducer("redis_producer");
    SetProducerNameServerAddress(producer, MQAddr);
    if (StartProducer(producer)) {
        printf("Module loaded StartProducer fail\n");
        return REDISMODULE_ERR;
    }
        

    return REDISMODULE_OK;
}



# Compile flags for linux / osx

SHOBJ_CFLAGS ?= -W -Wall -fno-common -g -ggdb -std=c99 -O2
SHOBJ_LDFLAGS ?= -shared

M_R_FLAGS  = -Wall -Wno-deprecated -fPIC -fno-strict-aliasing -O3 -DNDEBUG 
M_D_FLAGS  = -Wno-deprecated -fPIC -fno-strict-aliasing -O0 -DDEBUG  
M_INCLUDES = -I/root/rocketmq-client-cpp-master/bin/include -I/root/rocketmq-client-cpp-master/bin/include/jsoncpp -I/root/rocketmq-client-cpp-master/include 
LIBPATH    = -L/root/rocketmq-client-cpp-master/bin
LDFLAGS   =  -lrocketmq


.SUFFIXES: .c .so .xo .o

all: rocketmq.so

.cpp.xo:
	$(CC) -I. $(CFLAGS) $(SHOBJ_CFLAGS) $(M_D_FLAGS) $(M_INCLUDES) $(LIBPATH) -fPIC -c $< -o $@

rocketmq.xo: ../../redismodule.h

rocketmq.so: rocketmq.xo
	$(LD) -o $@ $< $(SHOBJ_LDFLAGS) $(LDFLAGS) $(LIBS) -lc

clean:
	rm -rf *.xo *.so

模块开发需要注意的小地方:RedisModule_OnLoad 函数中第一个执行的函数必须是 RedisModule_Init,否则就报 segmentfalt

再下来就是配置 redis.conf的配置文件

增加一行:

loadmodule   /opt/redis-unstable/src/modules/rocketmq.so    你RocketMQ的IP和端口     你的TOPIC      你的TAG

修改一行:

notify-keyspace-events Ex
 

也可以开发 kafka的通知消息, MQTT的通知消息, 也可以用一个第三方的模块来做 秒杀 的业务逻辑 或者分布式锁相关的业务逻辑。

猜你喜欢

转载自blog.csdn.net/langeldep/article/details/85692948
今日推荐