乐趣区

关于nosql:Redis配置文件补充

配置文件补充

昨天回去想了一想,配置文件还有一个十分重要的知识点没说到位,上面我在给大家补充补充这块,十分重要,十分重要。

int main(int argc , char* argv[])
{
    //...
     initServerConfig()
    //...
      loadServerConfig(server.configfile, config_from_stdin, options);
    //...
}

在执行 loadServerConfig 函数之前呢,还须要执行 initServerConfig 函数,该函数的作用如下:

initServerConfig()函数的作用是将 Redis 服务器的配置构造体 struct redisServer 的各个成员变量初始化为默认值。该函数在 Redis 服务器启动时被调用,以确保服务器的配置在开始时被正确设置。在该函数中,所有配置选项的默认值都被设置,例如服务器监听端口、日志文件名、长久化选项等等。

该函数代码我粘贴给大家看看:


void initServerConfig(void) {
    int j;
    char *default_bindaddr[CONFIG_DEFAULT_BINDADDR_COUNT] = CONFIG_DEFAULT_BINDADDR;

    initConfigValues();
    updateCachedTime(1);
    getRandomHexChars(server.runid,CONFIG_RUN_ID_SIZE);
    server.runid[CONFIG_RUN_ID_SIZE] = '\0';
    changeReplicationId();
    clearReplicationId2();
    server.hz = CONFIG_DEFAULT_HZ; /* Initialize it ASAP, even if it may get
                                      updated later after loading the config.
                                      This value may be used before the server
                                      is initialized. */
    server.timezone = getTimeZone(); /* Initialized by tzset(). */
    server.configfile = NULL;
    server.executable = NULL;
    server.arch_bits = (sizeof(long) == 8) ? 64 : 32;
    server.bindaddr_count = CONFIG_DEFAULT_BINDADDR_COUNT;
    for (j = 0; j < CONFIG_DEFAULT_BINDADDR_COUNT; j++)
        server.bindaddr[j] = zstrdup(default_bindaddr[j]);
   /*
   
           // 相干参数的初始化,我就不粘贴了
   
   
   */
   
    /* Client output buffer limits */
    for (j = 0; j < CLIENT_TYPE_OBUF_COUNT; j++)
        server.client_obuf_limits[j] = clientBufferLimitsDefaults[j];

    /* Linux OOM Score config */
    for (j = 0; j < CONFIG_OOM_COUNT; j++)
        server.oom_score_adj_values[j] = configOOMScoreAdjValuesDefaults[j];

    /* Double constants initialization */
    R_Zero = 0.0;
    R_PosInf = 1.0/R_Zero;
    R_NegInf = -1.0/R_Zero;
    R_Nan = R_Zero/R_Zero;

    /* Command table -- we initialize it here as it is part of the
     * initial configuration, since command names may be changed via
     * redis.conf using the rename-command directive. */
    server.commands = dictCreate(&commandTableDictType);
    server.orig_commands = dictCreate(&commandTableDictType);
    populateCommandTable();

    /* Debugging */
    server.watchdog_period = 0;
}

1 代码阐明 - 默认绑定

  char *default_bindaddr[CONFIG_DEFAULT_BINDADDR_COUNT] = CONFIG_DEFAULT_BINDADDR;

这行代码定义了一个指针数组default_bindaddr,其每个元素都是一个指向字符数组的指针,每个字符数组存储了 Redis 默认绑定的 IP 地址。

具体来说,CONFIG_DEFAULT_BINDADDR定义在 src/server.h 中,其内容如下:

#define CONFIG_DEFAULT_BINDADDR_COUNT 2
#define CONFIG_DEFAULT_BINDADDR {"*", "-::*"}

2 代码阐明 - initConfigValues

void initConfigValues() {configs = dictCreate(&sdsHashDictType);
    dictExpand(configs, sizeof(static_configs) / sizeof(standardConfig));
    for (standardConfig *config = static_configs; config->name != NULL; config++) {if (config->interface.init) config->interface.init(config);
        /* Add the primary config to the dictionary. */
        int ret = registerConfigValue(config->name, config, 0);
        serverAssert(ret);

        /* Aliases are the same as their primary counter parts, but they
         * also have a flag indicating they are the alias. */
        if (config->alias) {int ret = registerConfigValue(config->alias, config, ALIAS_CONFIG);
            serverAssert(ret);
        }
    }
}

configs是一个字典类型的全局变量,在 src/config.c 外面定义

dict *configs = NULL; /* Runtime config values *

configs 是一个 Redis 服务器配置项字典,用于存储 Redis 服务器的各种配置项。在 initConfigValues() 函数中,通过调用 dictCreate() 函数创立了这个字典,并且应用了 sizeof() 函数计算了动态配置项数组的长度,而后调用了 dictExpand() 函数进行了字典的扩容。

在之后的循环中,将动态配置项数组中的每个配置项增加到 configs 字典中,以便后续应用。同时,如果配置项具备别名,则还会将别名增加到字典中,并将它们的类型标记为 ALIAS_CONFIG。通过这种形式,能够不便地将别名配置项映射到其主配置项。

initConfigValues()函数用于初始化 Redis 的配置参数,并将这些参数退出到 Redis 的参数字典中,不便后续应用。具体实现过程如下:

  1. 首先创立了一个字典构造configs,用于存储配置参数。
  2. 而后通过 dictExpand() 函数扩大字典的大小,以包容所有动态配置参数(即在源码中间接定义的参数)。
  3. 接着遍历动态配置参数数组static_configs,对于每个配置参数,别离执行以下操作:

    1. 如果该参数的接口有初始化函数,则调用该函数进行初始化。
    2. 调用 registerConfigValue() 函数将该参数增加到参数字典中。
    3. 如果该参数有别名,则同样调用 registerConfigValue() 函数将别名也增加到参数字典中,并设置标记位 ALIAS_CONFIG 示意该参数为别名。
  4. 遍历完所有动态配置参数后,所有配置参数都曾经被增加到了参数字典中,初始化工作实现。

总之,initConfigValues()函数次要作用是初始化 Redis 的配置参数,并将这些参数增加到 Redis 的参数字典中,不便后续应用。

我给大家截了一张动态数组源码的图,大家能够看一看:

每一个元素的类型都为 standardConfig 类型,其定义如下:

struct standardConfig {
    const char *name; /* The user visible name of this config */
    const char *alias; /* An alias that can also be used for this config */
    unsigned int flags; /* Flags for this specific config */
    typeInterface interface; /* The function pointers that define the type interface */
    typeData data; /* The type specific data exposed used by the interface */
    configType type; /* The type of config this is. */
    void *privdata; /* privdata for this config, for module configs this is a ModuleConfig struct */
};

作用为:

  • name:该配置项的名称;
  • alias:该配置项的别名,也能够用来代替该配置项的名称;
  • flags:标记位,用于批示该配置项的个性;
  • interface:一个 typeInterface 构造体,定义了该配置项的操作接口;
  • data:该配置项的数据;
  • type:该配置项的数据类型;
  • privdata:公有数据,用于某些非凡的配置项,比方模块配置。

该构造体中的字段形容了一个 Redis 的配置项的各种属性,包含名称、别名、数据类型、操作接口等。在 Redis 的配置文件中,配置项就是由这个构造体来定义的。

int ret = registerConfigValue(config->name, config, 0);

这行代码调用了 registerConfigValue 函数,将一个配置项注册到 Redis 的全局配置字典中。其中,config->name是配置项的名称,config是该配置项对应的 standardConfig 构造体指针,0是该配置项的标记。这个函数返回一个整数值,代表配置项是否注册胜利。

serverAssert(ret);
#define serverAssert(_e) ((_e)?(void)0 : (_serverAssert(#_e,__FILE__,__LINE__),redis_unreachable()))

serverAssert(ret); 是 Redis 中的断言语句,用于在运行时查看程序逻辑是否正确。如果 ret 的值为 0,也就是注册配置项失败,serverAssert() 会抛出一个运行时谬误并终止程序的执行,用于帮忙开发人员疾速定位谬误并进行修复。

3 代码阐明 - updateCachedTime(1)

void updateCachedTime(int update_daylight_info) {const long long us = ustime();
    updateCachedTimeWithUs(update_daylight_info, us);
}
static inline void updateCachedTimeWithUs(int update_daylight_info, const long long ustime) {
    server.ustime = ustime;
    server.mstime = server.ustime / 1000;
    time_t unixtime = server.mstime / 1000;
    atomicSet(server.unixtime, unixtime);

    /* To get information about daylight saving time, we need to call
     * localtime_r and cache the result. However calling localtime_r in this
     * context is safe since we will never fork() while here, in the main
     * thread. The logging function will call a thread safe version of
     * localtime that has no locks. */
    if (update_daylight_info) {
        struct tm tm;
        time_t ut = server.unixtime;
        localtime_r(&ut,&tm);
        server.daylight_active = tm.tm_isdst;
    }
}

updateCachedTime(1)函数是用来更新服务器的外部工夫缓存的。该函数承受一个布尔值作为参数,批示是否应该将以后工夫设置为服务器的 unixtime,如果参数为 1,则设置为 unixtime。该函数的作用是确保服务器外部的工夫缓存始终与零碎工夫放弃同步,以便服务器可能正确地解决各种过期和定时事件。

4 代码阐明 - getRandomHexChars(server.runid,CONFIG_RUN_ID_SIZE)

void getRandomHexChars(char *p, size_t len) {
    char *charset = "0123456789abcdef";
    size_t j;

    getRandomBytes((unsigned char*)p,len);
    for (j = 0; j < len; j++) p[j] = charset[p[j] & 0x0F];
}
#define CONFIG_RUN_ID_SIZE 40

getRandomHexChars(server.runid, CONFIG_RUN_ID_SIZE) 是 Redis 在初始化时生成一个惟一的运行 ID。它的作用是为了让多个 Redis 实例在进行集群操作时进行辨别。

这个函数定义在 util.c 文件中。它应用 getRandomBytes() 函数生成一个随机数序列,而后将其转换成一个蕴含 40 个随机十六进制字符的字符串。

server.runid 是一个全局变量,示意 Redis 实例的运行 ID。它在 serverCron() 函数中被更新,以确保它始终保持最新状态。运行 ID 通常被用于构建集群中节点之间的通信,因为它是惟一的,能够用于标识每个 Redis 实例。

  server.runid[CONFIG_RUN_ID_SIZE] = '\0';

这行代码的作用是给 server.runid 字符数组的开端增加一个 null 字符,行将字符串的结尾标记为 '\0'。这是为了确保 server.runid 是一个以 null 字符结尾的 C 字符串,以便能够应用字符串处理函数对其进行操作。如果不增加 null 字符,那么在应用字符串处理函数时会呈现未定义行为。

  changeReplicationId();
  clearReplicationId2();

这两个函数是用于设置 Redis 复制的 ID 的。changeReplicationId()会生成一个新的 ID 并设置到 server.runid 中,而 clearReplicationId2() 会将 server.replid2 设置为空字符串。

在 Redis 复制中,每个主服务器都有一个惟一的复制 ID(replid),所有的从服务器会记录它们最初一次胜利复制的 replid。当从服务器从新连贯到主服务器时,它将发送本人的 replid,主服务器会查看它是否比它所记录的从服务器最初一次胜利复制的 replid 更新,如果是,主服务器会将缺失的数据同步到从服务器。这种形式能够确保从服务器与主服务器数据的一致性。

5 配置项阐明

server.hz = CONFIG_DEFAULT_HZ;

这行代码是在 Redis 服务器启动时初始化服务器的 hz 值,即 Redis 服务器每秒执行定时器事件的次数,它影响到 Redis 服务器的工夫精度。如果在配置文件中没有设置 hz 值,那么就应用默认值 CONFIG_DEFAULT_HZ(100),将其赋值给服务器的 hz 属性。

   for (j = 0; j < CONFIG_DEFAULT_BINDADDR_COUNT; j++)
        server.bindaddr[j] = zstrdup(default_bindaddr[j]);

这段代码是将默认的绑定地址配置复制到服务器实例的 server.bindaddr 数组中,这个数组是一个字符串数组,用于记录 Redis 服务器监听的地址和端口信息。具体来说,这个循环会遍历默认绑定地址数组 default_bindaddr,将其中的每个地址字符串复制到 server.bindaddr 数组的对应地位上,通过 zstrdup 函数来实现字符串的复制操作。

 server.ipfd.count = 0;
    server.tlsfd.count = 0;
    server.sofd = -1;
    server.active_expire_enabled = 1;
    server.skip_checksum_validation = 0;
    server.loading = 0;
    server.async_loading = 0;
    server.loading_rdb_used_mem = 0;
    server.aof_state = AOF_OFF;
    server.aof_rewrite_base_size = 0;
    server.aof_rewrite_scheduled = 0;
    server.aof_flush_sleep = 0;
    server.aof_last_fsync = time(NULL);
    server.aof_cur_timestamp = 0;
    atomicSet(server.aof_bio_fsync_status,C_OK);
    server.aof_rewrite_time_last = -1;
    server.aof_rewrite_time_start = -1;
    server.aof_lastbgrewrite_status = C_OK;
    server.aof_delayed_fsync = 0;
    server.aof_fd = -1;
    server.aof_selected_db = -1; /* Make sure the first time will not match */
    server.aof_flush_postponed_start = 0;
    server.aof_last_incr_size = 0;
    server.active_defrag_running = 0;
    server.notify_keyspace_events = 0;
    server.blocked_clients = 0;
    memset(server.blocked_clients_by_type,0,
           sizeof(server.blocked_clients_by_type));
    server.shutdown_asap = 0;
    server.shutdown_flags = 0;
    server.shutdown_mstime = 0;
    server.cluster_module_flags = CLUSTER_MODULE_FLAG_NONE;
    server.migrate_cached_sockets = dictCreate(&migrateCacheDictType);
    server.next_client_id = 1; /* Client IDs, start from 1 .*/
    server.page_size = sysconf(_SC_PAGESIZE);
    server.pause_cron = 0;

    server.latency_tracking_info_percentiles_len = 3;
    server.latency_tracking_info_percentiles = zmalloc(sizeof(double)*(server.latency_tracking_info_percentiles_len));
    server.latency_tracking_info_percentiles[0] = 50.0;  /* p50 */
    server.latency_tracking_info_percentiles[1] = 99.0;  /* p99 */
    server.latency_tracking_info_percentiles[2] = 99.9;  /* p999 */
  • server.ipfd.countserver.tlsfd.count 示意监听套接字的数量,初始化为 0;
  • server.sofd示意长久化过程的文件描述符,初始化为 -1;
  • server.active_expire_enabled示意是否启用过期键查看性能,初始化为 1;
  • server.skip_checksum_validation示意是否跳过对 AOF 文件和 RDB 文件的校验和验证,初始化为 0;
  • server.loadingserver.async_loading 示意是否正在加载长久化文件,初始化为 0;
  • server.aof_state示意 AOF 长久化状态,初始化为 AOF_OFF,示意未启用 AOF;
  • server.aof_last_fsync示意上次 AOF 缓冲区同步到磁盘的工夫戳,初始化为以后工夫;
  • server.aof_cur_timestamp示意 AOF 文件以后的工夫戳,初始化为 0;
  • server.aof_rewrite_time_lastserver.aof_rewrite_time_start 别离示意 AOF 重写上次执行的工夫和开始执行的工夫,初始化为 -1;
  • server.aof_fd示意 AOF 文件的文件描述符,初始化为 -1;
  • server.active_defrag_running示意是否正在进行被动内存碎片整顿,初始化为 0;
  • server.notify_keyspace_events示意订阅了哪些键空间告诉,初始化为 0;
  • server.blocked_clients示意以后阻塞的客户端数量,初始化为 0;
  • server.shutdown_asap示意是否立刻敞开服务器,初始化为 0;
  • server.shutdown_flags示意敞开服务器的标记,初始化为 0;
  • server.cluster_module_flags示意集群模块的标记,初始化为 CLUSTER_MODULE_FLAG_NONE;
  • server.migrate_cached_sockets示意缓存的迁徙套接字,初始化为一个空字典;
  • server.next_client_id示意下一个客户端的 ID,初始化为 1;
  • server.page_size示意操作系统的内存页大小,初始化为从操作系统获取的值;
  • server.pause_cron示意是否暂停定时工作,初始化为 0;
  • server.latency_tracking_info_percentiles示意提早跟踪的百分比值,初始化为 50、99 和 99.9 三个值。
 unsigned int lruclock = getLRUClock();

getLRUClock()是 Redis 中的一个函数,它返回一个递增的时钟值,用于 LRU 算法中的工夫戳。这个时钟值会在 Redis 的每个操作中进行更新,用于记录最近一次拜访的工夫戳。在这段代码中,lruclock是一个无符号整数类型的变量,存储的是通过调用 getLRUClock() 函数获取的 LRU 时钟值。

 resetServerSaveParams();

    appendServerSaveParams(60*60,1);  /* save after 1 hour and 1 change */
    appendServerSaveParams(300,100);  /* save after 5 minutes and 100 changes */
    appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */

这段代码是 Redis 中对于长久化的参数配置,resetServerSaveParams()函数是用来清空 Redis 服务器以后已有的保留配置信息的。接下来,应用 appendServerSaveParams()函数对 Redis 服务器进行三次长久化配置设置:

  1. save after 1 hour and 1 change(1 小时 1 次变更后保留)。
  2. save after 5 minutes and 100 changes(5 分钟 100 次变更后保留)。
  3. save after 1 minute and 10000 changes(1 分钟 10000 次变更后保留)。

这三个配置参数定义了 Redis 服务器进行主动长久化的条件。在 Redis 运行过程中,每当满足其中一个条件时,Redis 服务器就会将以后内存中的数据保留到磁盘上,以防止数据在服务器解体时的失落。

/* Replication related */
    server.masterhost = NULL;
    server.masterport = 6379;
    server.master = NULL;
    server.cached_master = NULL;
    server.master_initial_offset = -1;
    server.repl_state = REPL_STATE_NONE;
    server.repl_transfer_tmpfile = NULL;
    server.repl_transfer_fd = -1;
    server.repl_transfer_s = NULL;
    server.repl_syncio_timeout = CONFIG_REPL_SYNCIO_TIMEOUT;
    server.repl_down_since = 0; /* Never connected, repl is down since EVER. */
    server.master_repl_offset = 0;

    /* Replication partial resync backlog */
    server.repl_backlog = NULL;
    server.repl_no_slaves_since = time(NULL);

    /* Failover related */
    server.failover_end_time = 0;
    server.force_failover = 0;
    server.target_replica_host = NULL;
    server.target_replica_port = 0;
    server.failover_state = NO_FAILOVER;

这段代码是 Redis 的复制(replication)和故障转移(failover)相干的配置。其中:

  • server.masterhostserver.masterport 指定了 Redis 主节点的地址和端口号。
  • server.master 是一个指向主节点状态的指针,指向 clusterNode 构造体。
  • server.cached_master 也是一个指向主节点状态的指针,指向 clusterNode 构造体。它在复制过程中被用来缓存主节点的信息,以防止频繁地拜访主节点状态。
  • server.master_initial_offset 指定了从节点初始同步时的偏移量,通常为 - 1 示意从头开始同步。
  • server.repl_state 记录了复制状态,有REPL_STATE_NONEREPL_STATE_CONNECTREPL_STATE_CONNECTINGREPL_STATE_RECEIVE_PONGREPL_STATE_SEND_AUTHREPL_STATE_RECEIVE_AUTHREPL_STATE_SEND_PORTREPL_STATE_RECEIVE_PORTREPL_STATE_SEND_CAPAREPL_STATE_RECEIVE_CAPAREPL_STATE_SEND_PSYNCREPL_STATE_RECEIVE_PSYNCREPL_STATE_SEND_FILEREPL_STATE_RECEIVE_FILEREPL_STATE_SEND_BULKREPL_STATE_RECEIVE_BULKREPL_STATE_ONLINEREPL_STATE_CATCHUPREPL_STATE_CONNECTEDREPL_STATE_WAIT_BGSAVE_STARTREPL_STATE_WAIT_BGSAVE_END 等状态。
  • server.repl_transfer_tmpfile 用于保留复制过程中传输的临时文件的文件名。
  • server.repl_transfer_fd 是传输文件的文件描述符。
  • server.repl_transfer_s 是传输文件的网络连接状态。
  • server.repl_syncio_timeout 是复制同步操作的超时工夫,默认值为 5 秒。
  • server.repl_down_since 记录了主节点生效的工夫戳,单位是秒。
  • server.master_repl_offset 是从节点以后的复制偏移量。

在这段代码中,还定义了与故障转移相干的变量,例如 server.failover_end_time 示意故障转移的完结工夫戳,server.failover_state 示意故障转移的状态,server.target_replica_hostserver.target_replica_port是新的主节点的地址和端口号。

/* Client output buffer limits */
    for (j = 0; j < CLIENT_TYPE_OBUF_COUNT; j++)
        server.client_obuf_limits[j] = clientBufferLimitsDefaults[j];

    /* Linux OOM Score config */
    for (j = 0; j < CONFIG_OOM_COUNT; j++)
        server.oom_score_adj_values[j] = configOOMScoreAdjValuesDefaults[j];

这段代码初始化了服务器中客户端输入缓冲区的限度以及 Linux OOM(Out-Of-Memory)Score 值的配置。

在第一个循环中,应用默认值初始化了客户端输入缓冲区的限度,CLIENT_TYPE_OBUF_COUNT 示意不同类型的客户端输入缓冲区,clientBufferLimitsDefaults 是默认的客户端输入缓冲区限度。

在第二个循环中,应用默认值初始化了服务器的 OOM Score 值,OOM Score 是 Linux 内核的一个性能,用于依据零碎内存应用状况调整过程的优先级。CONFIG_OOM_COUNT 是不同类型的 OOM Score 的数量,configOOMScoreAdjValuesDefaults 是默认的 OOM Score 值。

   server.commands = dictCreate(&commandTableDictType);
    server.orig_commands = dictCreate(&commandTableDictType);
    populateCommandTable();

这段代码创立了两个字典构造 server.commandsserver.orig_commands,用于存储 Redis 命令。而后通过调用 populateCommandTable() 函数来填充 Redis 命令表,将命令增加到字典中。其中,命令表的定义是通过 struct redisCommand 构造体实现的,构造体中蕴含命令名、命令函数等信息

6 填充 redis 命令表

void populateCommandTable(void) {
    int j;
    struct redisCommand *c;

    for (j = 0;; j++) {
        c = redisCommandTable + j;
        if (c->declared_name == NULL)
            break;

        int retval1, retval2;

        c->fullname = sdsnew(c->declared_name);
        if (populateCommandStructure(c) == C_ERR)
            continue;

        retval1 = dictAdd(server.commands, sdsdup(c->fullname), c);
        /* Populate an additional dictionary that will be unaffected
         * by rename-command statements in redis.conf. */
        retval2 = dictAdd(server.orig_commands, sdsdup(c->fullname), c);
        serverAssert(retval1 == DICT_OK && retval2 == DICT_OK);
    }
}

命令表局部截图如下:

redisCommand构造如下所示:

struct redisCommand {
    /* Declarative data */
    const char *declared_name; /* A string representing the command declared_name.
                                * It is a const char * for native commands and SDS for module commands. */
    const char *summary; /* Summary of the command (optional). */
    const char *complexity; /* Complexity description (optional). */
    const char *since; /* Debut version of the command (optional). */
    int doc_flags; /* Flags for documentation (see CMD_DOC_*). */
    const char *replaced_by; /* In case the command is deprecated, this is the successor command. */
    const char *deprecated_since; /* In case the command is deprecated, when did it happen? */
    redisCommandGroup group; /* Command group */
    commandHistory *history; /* History of the command */
    const char **tips; /* An array of strings that are meant to be tips for clients/proxies regarding this command */
    redisCommandProc *proc; /* Command implementation */
    int arity; /* Number of arguments, it is possible to use -N to say >= N */
    uint64_t flags; /* Command flags, see CMD_*. */
    uint64_t acl_categories; /* ACl categories, see ACL_CATEGORY_*. */
    keySpec key_specs_static[STATIC_KEY_SPECS_NUM]; /* Key specs. See keySpec */
    /* Use a function to determine keys arguments in a command line.
     * Used for Redis Cluster redirect (may be NULL) */
    redisGetKeysProc *getkeys_proc;
    /* Array of subcommands (may be NULL) */
    struct redisCommand *subcommands;
    /* Array of arguments (may be NULL) */
    struct redisCommandArg *args;

    /* Runtime populated data */
    long long microseconds, calls, rejected_calls, failed_calls;
    int id;     /* Command ID. This is a progressive ID starting from 0 that
                   is assigned at runtime, and is used in order to check
                   ACLs. A connection is able to execute a given command if
                   the user associated to the connection has this command
                   bit set in the bitmap of allowed commands. */
    sds fullname; /* A SDS string representing the command fullname. */
    struct hdr_histogram* latency_histogram; /*points to the command latency command histogram (unit of time nanosecond) */
    keySpec *key_specs;
    keySpec legacy_range_key_spec; /* The legacy (first,last,step) key spec is
                                     * still maintained (if applicable) so that
                                     * we can still support the reply format of
                                     * COMMAND INFO and COMMAND GETKEYS */
    int num_args;
    int num_history;
    int num_tips;
    int key_specs_num;
    int key_specs_max;
    dict *subcommands_dict; /* A dictionary that holds the subcommands, the key is the subcommand sds name
                             * (not the fullname), and the value is the redisCommand structure pointer. */
    struct redisCommand *parent;
    struct RedisModuleCommand *module_cmd; /* A pointer to the module command data (NULL if native command) */
};

这是一个 Redis 命令构造体的定义,它蕴含了 Redis 命令的各种属性和信息。具体来说,这个构造体蕴含了以下属性:

  • declared_name:一个字符串,示意该命令的名称,对于原生命令来说是 const char * 类型,对于模块命令来说是 SDS 类型。
  • summary:命令的摘要信息(可选)。
  • complexity:命令的复杂度形容(可选)。
  • since:命令的起始版本号(可选)。
  • doc_flags:用于文档的标记位(见 CMD_DOC_*)。
  • replaced_by:在命令被弃用的状况下,示意其后继命令。
  • deprecated_since:在命令被弃用的状况下,示意它被弃用的工夫。
  • group:命令所属的组别。
  • history:命令的历史记录。
  • tips:一个字符串数组,用于提醒客户端或代理无关该命令的信息。
  • proc:命令的实现函数。
  • arity:命令的参数个数,能够应用 -N 来示意 >= N。
  • flags:命令的标记位,见 CMD_*。
  • acl_categories:ACL 类别,见 ACL_CATEGORY_*。
  • key_specs_static:keySpec 类型的数组,用于形容键值对的信息,详见 keySpec 构造体的定义。
  • getkeys_proc:一个函数指针,用于在命令行中确定键参数,用于 Redis Cluster 重定向(可能为空)。
  • subcommands:子命令的构造体指针数组(可能为空)。
  • args:命令的参数构造体指针数组(可能为空)。

除此之外,这个构造体还蕴含了一些运行时须要的信息,例如:

  • microseconds:命令的总执行工夫(单位为微秒)。
  • calls:命令被调用的次数。
  • rejected_calls:命令被拒绝执行的次数。
  • failed_calls:命令执行失败的次数。
  • id:命令的 ID,用于查看 ACL。
  • fullname:命令的残缺名称(SDS 字符串类型)。
  • latency_histogram:指向命令提早直方图的指针(工夫单位为纳秒)。
  • key_specs:keySpec 类型的指针数组,用于形容键值对的信息。
  • legacy_range_key_spec:用于反对 COMMAND INFO 和 COMMAND GETKEYS 的回复格局。
  • num_args:参数个数。
  • num_history:历史记录个数。
  • num_tips:提醒个数。
  • key_specs_num:keySpec 的数量。
  • key_specs_max:keySpec 的最大数量。
  • subcommands_dict:一个字典,用于存储子命令的 SDS 名称和 redisCommand 构造体指针。
  • parent:父命令的构造体指针。
  • module_cmd:指向模块命令数据的指针(如果是原生命令则为 NULL)。
  if (populateCommandStructure(c) == C_ERR)

populateCommandStructure(c) 函数的作用是初始化 Redis 命令构造体 redisCommand,该构造体定义了 Redis 反对的所有命令的信息,包含命令名、参数个数、参数类型、命令实现函数、命令标识等。Redis 的命令注册是在 Redis 启动时进行的,这个过程会解析 Redis 配置文件中定义的命令以及 Redis 模块中定义的命令,并将它们注册到 Redis 服务器的命令表中,使得 Redis 服务器可能响应客户端发来的命令申请。

populateCommandStructure(c) 函数承受一个 redisCommand 构造体指针 c 作为参数,依据 c 中申明的命令名、命令参数、命令实现函数等信息,初始化 redisCommand 构造体,这些信息能够在 Redis 启动时从配置文件和模块中读取。函数执行胜利时返回 C_OK,否则返回 C_ERR

该函数是 Redis 命令注册过程中的一个重要环节,确保 Redis 服务器可能正确地辨认并响应客户端的申请。

7 redis 看们狗

“Watchdog” 一词源于狗的畛域。在过来,人们经常训练一些狗来守卫家园、家畜或其余财产。这些狗通常是十分警惕和虔诚的,能够爱护客人的财产免受入侵和损坏。因而,当计算机系统呈现故障或意外敞开时,相似于这些狗的软件程序会被称为 ” 看门狗 ”,以暗示它们的工作是监视系统并在必要时采取行动来爱护零碎的完整性和稳定性。

server.watchdog_period = 0;

这行代码的作用是将 Redis 服务器的看门狗(watchdog)定期检查的工夫距离设置为 0。看门狗是 Redis 中的一个后盾线程,用于检测 Redis 服务器是否处于失常运行状态。当看门狗检测到 Redis 服务器未响应时,它将尝试主动重启服务器,以保障 Redis 服务器的可用性。

通常状况下,看门狗定期检查的工夫距离是 1 秒钟。将该工夫距离设置为 0 意味着禁用了看门狗的主动重启性能。这通常在某些状况下很有用,比方在进行调试时,咱们可能会频繁地重启 Redis 服务器,此时禁用看门狗能够防止不必要的麻烦。然而须要留神的是,禁用看门狗可能会对 Redis 服务器的可用性产生潜在的危险,因而在生产环境下不应该将看门狗齐全禁用。

退出移动版