REDIS 阿里云压测(redis-benchmark源码解读与修改)

REDIS 阿里云压测(redis-benchmark源码解读与修改)_第1张图片

开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 (加他微信) ,在新加的朋友会分到3群(共1000人左右 1 + 2 + 3) 

本篇非本人撰写,在本人后面有一个强大的DBA TEAM,本篇来自于本TEAM 中的 REDIS DBA 小闫,如想和他讨论REDIS 数据库的使用和理解以及更深的使用,可以加群。

阿里云的redis集群架构压测时候,会有Proxy,压测的时候,我们需要带着proxy压测,好在redis-benchmark压测工具最新版本支持了—cluster参数,能够支持集群的压测。但是有个坏消息是由于带有了proxy,redis-benchmark不能获取槽位信息,这就导致了在进行压测的时候,所有的请求仍然都是发送到集群中的一个节点,就会出现压测的时候出现一个节点cpu报表,但是其他cpu仍然在0附近徘徊。

首先需要了解redis-benchmark加了—cluster之后做了什么。

加了—cluster参数以后,cluster模式被打开,然后写入和读取的时候key会被加上hashtag,也就是Key中的一部分被{}包裹,这内部的东西会被计算哈希值,然后根据这个哈希值确定槽位,然后确定这个请求发送到某个node。简单来说,具有相同hashtag的key会被分到同一个node上。

加上了—cluster以后,redis-benchmark通过获取槽位信息,确定有多少个节点,就会选择有几个不同的hashtag,然后将请求分发到这些节点上。

然而上面说了,加了阿里云加了proxy的redis集群无法获取节点和槽位信息,我们只能看到一个节点。

那么,需要对redis-benchmark的源码做一些小改动。

改动不多

首先,如果直接开启—cluster并运行redis-benchmark的话,会直接报错提示:

"Invalid cluster: 1 node(s).

也就是只获取到了一个节点,正常的cluster是不可能只有1个节点的。

找到这行代码

if (config.cluster_node_count <= 1) {

            fprintf(stderr, "Invalid cluster: %d node(s).\n",

                    config.cluster_node_count);

            exit(1);

        }

这里直接将小于等于换成<即可,或者这几行直接注释掉。

然后我们如果有四个节点,则需要将再复制出三个节点的配置信息。

继续向下

printf("Cluster has %d master nodes:\n\n", config.cluster_node_count);

        int i = 0;

        //这里开始是添加的代码

        config.cluster_nodes[0]->myflag=0;

        config.cluster_nodes[1] = malloc(sizeof(clusterNode));

        memcpy(config.cluster_nodes[1], config.cluster_nodes[0], sizeof(clusterNode));

        config.cluster_nodes[2] = malloc(sizeof(clusterNode));

        memcpy(config.cluster_nodes[2], config.cluster_nodes[0], sizeof(clusterNode));

        config.cluster_nodes[3] = malloc(sizeof(clusterNode));

        memcpy(config.cluster_nodes[3], config.cluster_nodes[0], sizeof(clusterNode));

        config.cluster_nodes[1]->myflag=1;

        config.cluster_nodes[2]->myflag=2;

        config.cluster_nodes[3]->myflag=3;

        config.cluster_node_count=4;

        //到这里结束

        for (; i < config.cluster_node_count; i++) {

            clusterNode *node = config.cluster_nodes[i];

            if (!node) {

                fprintf(stderr, "Invalid cluster node #%d\n", i);

                exit(1);

            }

            printf("Master %d: ", i);

            if (node->name) printf("%s ", node->name);

            printf("%s:%d\n", node->ip, node->port);

            node->redis_config = getRedisConfig(node->ip, node->port, NULL);

            if (node->redis_config == NULL) {

                fprintf(stderr, "WARNING: Could not fetch node CONFIG %s:%d\n",

                        node->ip, node->port);

            }

        }

        printf("\n");

这里添加了注释段的几行代码,其实就是强行修改config.cluster_nodes数组,原本是就有1个,我们复制出3个,这时候就有4个节点了,虽然他们连接地址都一样,但是后面我们需要通过手动构造tag来将他们区分开来。而通过什么来区分,需要有个标记,这里我添加了一个myflag属性作为一个标识。

这个需要在

/* Cluster. */

typedef struct clusterNode {

    char *ip;

    int port;

    sds name;

    int flags;

    sds replicate;  /* Master ID if node is a slave */

    int *slots;

    int slots_count;

    int current_slot_index;

    int *updated_slots;         /* Used by updateClusterSlotsConfiguration */

    int updated_slots_count;    /* Used by updateClusterSlotsConfiguration */

    int replicas_count;

    sds *migrating; /* An array of sds where even strings are slots and odd

                     * strings are the destination node IDs. */

    sds *importing; /* An array of sds where even strings are slots and odd

                     * strings are the source node IDs. */

    int migrating_count; /* Length of the migrating array (migrating slots*2) */

    int importing_count; /* Length of the importing array (importing slots*2) */

    struct redisConfig *redis_config;

    int myflag;

} clusterNode;

这个结构体最后添加一个int类型的字段,myflag。

然后通过分析代码,我们可以找到一个函数,函数名字叫做setClusterKeyHashTag,通过名字我们也能知道,这个就是设置hashtag的地方。

修改这个函数为下面的函数即可

static void setClusterKeyHashTag(client c) {

    assert(c->thread_id >= 0);

    clusterNode *node = c->cluster_node;

    assert(node);

    assert(node->current_slot_index < node->slots_count);

    int is_updating_slots = 0;

    atomicGet(config.is_updating_slots, is_updating_slots);

    /* If updateClusterSlotsConfiguration is updating the slots array,

     * call updateClusterSlotsConfiguration is order to block the thread

     * since the mutex is locked. When the slots will be updated by the

     * thread that's actually performing the update, the execution of

     * updateClusterSlotsConfiguration won't actually do anything, since

     * the updated_slots_count array will be already NULL. */

    if (is_updating_slots) updateClusterSlotsConfiguration();

    int slot = node->slots[node->current_slot_index];

    const char *tag;

    int taglen;

    if (node->myflag == 1) {

        // 根据 myflag 的值设置特定的标签

        tag = "g1";

        taglen = strlen(tag);

    } else if (node->myflag == 2) {

        // 根据 myflag 的值设置特定的标签

        tag = "a2";

        taglen = strlen(tag);

    } else if (node->myflag==3){

        tag = "a3";

        taglen = strlen(tag);

    }else {

        // 使用默认的标签

        tag = "a5";

        taglen = strlen(tag);

    }

    size_t i;

    for (i = 0; i < c->staglen; i++) {

        char *p = c->stagptr[i] + 1;

        p[0] = tag[0];

        p[1] = (taglen >= 2 ? tag[1] : '}');

        //p[2] = (taglen == 3 ? tag[2] : '}');

    }

}

这里的g1,a2,a3,a5,其实都是我自己试出来的,因为我们也看不到具体某个节点有哪个槽,所以只能通过压测以后查看cpu上升情况或者阿里云监测上面的key个数来获取这个信息。

修改完成以后make&&make install即可。

运行命令的时候开启—cluster即可看到命令被平均发送到每个节点了,cpu的计算压力和内存的存储压力已经被分散到四个节点上面了。

REDIS 阿里云压测(redis-benchmark源码解读与修改)_第2张图片

你可能感兴趣的:(redis,阿里云,数据库,缓存,云计算)