服务器

WBOY
WBOY원래의
2016-06-07 14:49:421238검색

redis服务器负责与多个客户端建立网络连接,处理客户端发送的命令请求,在数据库中保存客户端执行命令所才参数的数据,并通过资源管理来维持服务器自身的运转。 1. 命令请求的执行过程 以SET命令为例: redis SET key valueredis OK 1.1 发送命令请求 1.2读

redis服务器负责与多个客户端建立网络连接,处理客户端发送的命令请求,在数据库中保存客户端执行命令所才参数的数据,并通过资源管理来维持服务器自身的运转。

1. 命令请求的执行过程

以SET命令为例:

<code class=" hljs vbnet">redis> <span class="hljs-keyword">SET</span> <span class="hljs-keyword">key</span> value
redis> OK</code>

1.1 发送命令请求

这里写图片描述

1.2读取命令请求

当客户端与服务器之间的连接套接字因为客户端的写入而变的可读时,服务器将调用命令请求处理器来执行如下操作:
①读取套接字中协议格式的命令请求,保存到客户端状态的输入缓冲区。
这里写图片描述
②对缓冲区中的命令请求进行分析,提取命令参数及个数,保存到客户端状态的argv属性和argc属性。
这里写图片描述
③调用命令执行器执行客户端指定的命令。

1.3 命令执行器

(1)查找命令实现
根据客户端状态的 argv[0] 参数, 在命令表(command table)中查找参数所指定的命令, 并将找到的命令保存到客户端状态的 cmd 属性里面。
命令表是一个字典, 字典的键是一个个命令名字,比如 “set” 、 “get” 、 “del” ,等等; 而字典的值则是一个个 redisCommand 结构, 每个 redisCommand 结构记录了一个 Redis 命令的实现信息。
这里写图片描述
这里写图片描述
(2)执行预备操作
(3)调用命令的实现函数

<code class=" hljs haskell"><span class="hljs-title">client</span>->cmd-><span class="hljs-keyword">proc</span>(client);</code>

这里写图片描述
这里写图片描述
(4)执行后续工作

1.4 将命令回复发送给客户端

命令实现函数会将命令回复保存到客户端的输出缓冲区里面, 并为客户端的套接字关联命令回复处理器, 当客户端套接字变为可写状态时, 服务器就会执行命令回复处理器, 将保存在客户端输出缓冲区中的命令回复发送给客户端。
当命令回复发送完毕之后, 回复处理器会清空客户端状态的输出缓冲区, 为处理下一个命令请求做好准备。

1.5 客户端接收并打印命令回复

这里写图片描述

2. serverCron函数

redis服务器中的serverCron函数默认每隔100毫秒执行一次,这个函数负责管理服务器的资源,并保持服务器自身的良好运转。
主要工作包括:更新服务器状态信息,处理服务器接收的SIGTERM信号,管理客户端资源和数据库状态,检查并执行持久化操作等。

主要工作包括:
更新服务器的各类统计信息,比如时间,内存占用,数据库占用情况等。
清理数据库中过期键值对。
关闭和清理连接失效的客户端
尝试进行AOF或RDB持久化操作。
如果服务器是主服务器,对从服务器进行定期同步。
如果处理集群模式,对集群进行定期同步和连接测试。

redisServer结构/serverCron函数属性

<code class=" hljs axapta"><span class="hljs-comment">/* This is our timer interrupt, called server.hz times per second.
 *
 * 这是 Redis 的时间中断器,每秒调用 server.hz 次。
 *
 * Here is where we do a number of things that need to be done asynchronously.
 * For instance:
 *
 * 以下是需要异步执行的操作:
 *
 * - Active expired keys collection (it is also performed in a lazy way on
 *   lookup).
 *   主动清除过期键。
 *
 * - Software watchdog.
 *   更新软件 watchdog 的信息。
 *
 * - Update some statistic.
 *   更新统计信息。
 *
 * - Incremental rehashing of the DBs hash tables.
 *   对数据库进行渐增式 Rehash
 *
 * - Triggering BGSAVE / AOF rewrite, and handling of terminated children.
 *   触发 BGSAVE 或者 AOF 重写,并处理之后由 BGSAVE 和 AOF 重写引发的子进程停止。
 *
 * - Clients timeout of different kinds.
 *   处理客户端超时。
 *
 * - Replication reconnection.
 *   复制重连
 *
 * - Many more...
 *   等等。。。
 *
 * Everything directly called here will be called server.hz times per second,
 * so in order to throttle execution of things we want to do less frequently
 * a macro is used: run_with_period(milliseconds) { .... }
 *
 * 因为 serverCron 函数中的所有代码都会每秒调用 server.hz 次,
 * 为了对部分代码的调用次数进行限制,
 * 使用了一个宏 run_with_period(milliseconds) { ... } ,
 * 这个宏可以将被包含代码的执行次数降低为每 milliseconds 执行一次。
 */</span>

<span class="hljs-keyword">int</span> serverCron(struct aeEventLoop *eventLoop, <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> id, <span class="hljs-keyword">void</span> *clientData) {
    <span class="hljs-keyword">int</span> j;
    REDIS_NOTUSED(eventLoop);
    REDIS_NOTUSED(id);
    REDIS_NOTUSED(clientData);

    <span class="hljs-comment">/* Software watchdog: deliver the SIGALRM that will reach the signal
     * handler if we don't return here fast enough. */</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">server</span>.watchdog_period) watchdogScheduleSignal(<span class="hljs-keyword">server</span>.watchdog_period);

    <span class="hljs-comment">/* Update the time cache. */</span>
    updateCachedTime();

    <span class="hljs-comment">// 记录服务器执行命令的次数</span>
    run_with_period(<span class="hljs-number">100</span>) trackOperationsPerSecond();

    <span class="hljs-comment">/* We have just REDIS_LRU_BITS bits per object for LRU information.
     * So we use an (eventually wrapping) LRU clock.
     *
     * Note that even if the counter wraps it's not a big problem,
     * everything will still work but some object will appear younger
     * to Redis. However for this to happen a given object should never be
     * touched for all the time needed to the counter to wrap, which is
     * not likely.
     *
     * 即使服务器的时间最终比 1.5 年长也无所谓,
     * 对象系统仍会正常运作,不过一些对象可能会比服务器本身的时钟更年轻。
     * 不过这要这个对象在 1.5 年内都没有被访问过,才会出现这种现象。
     *
     * Note that you can change the resolution altering the
     * REDIS_LRU_CLOCK_RESOLUTION define.
     *
     * LRU 时间的精度可以通过修改 REDIS_LRU_CLOCK_RESOLUTION 常量来改变。
     */</span>
    <span class="hljs-keyword">server</span>.lruclock = getLRUClock();

    <span class="hljs-comment">/* Record the max memory used since the server was started. */</span>
    <span class="hljs-comment">// 记录服务器的内存峰值</span>
    <span class="hljs-keyword">if</span> (zmalloc_used_memory() > <span class="hljs-keyword">server</span>.stat_peak_memory)
        <span class="hljs-keyword">server</span>.stat_peak_memory = zmalloc_used_memory();

    <span class="hljs-comment">/* Sample the RSS here since this is a relatively slow call. */</span>
    <span class="hljs-keyword">server</span>.resident_set_size = zmalloc_get_rss();

    <span class="hljs-comment">/* We received a SIGTERM, shutting down here in a safe way, as it is
     * not ok doing so inside the signal handler. */</span>
    <span class="hljs-comment">// 服务器进程收到 SIGTERM 信号,关闭服务器</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">server</span>.shutdown_asap) {

        <span class="hljs-comment">// 尝试关闭服务器</span>
        <span class="hljs-keyword">if</span> (prepareForShutdown(<span class="hljs-number">0</span>) == REDIS_OK) exit(<span class="hljs-number">0</span>);

        <span class="hljs-comment">// 如果关闭失败,那么打印 LOG ,并移除关闭标识</span>
        redisLog(REDIS_WARNING,<span class="hljs-string">"SIGTERM received but errors trying to shut down the server, check the logs for more information"</span>);
        <span class="hljs-keyword">server</span>.shutdown_asap = <span class="hljs-number">0</span>;
    }

    <span class="hljs-comment">/* Show some info about non-empty databases */</span>
    <span class="hljs-comment">// 打印数据库的键值对信息</span>
    run_with_period(<span class="hljs-number">5000</span>) {
        <span class="hljs-keyword">for</span> (j = <span class="hljs-number">0</span>; j < <span class="hljs-keyword">server</span>.dbnum; j++) {
            <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> size, used, vkeys;

            <span class="hljs-comment">// 可用键值对的数量</span>
            size = dictSlots(<span class="hljs-keyword">server</span>.db[j].dict);
            <span class="hljs-comment">// 已用键值对的数量</span>
            used = dictSize(<span class="hljs-keyword">server</span>.db[j].dict);
            <span class="hljs-comment">// 带有过期时间的键值对数量</span>
            vkeys = dictSize(<span class="hljs-keyword">server</span>.db[j].expires);

            <span class="hljs-comment">// 用 LOG 打印数量</span>
            <span class="hljs-keyword">if</span> (used || vkeys) {
                redisLog(REDIS_VERBOSE,<span class="hljs-string">"DB %d: %lld keys (%lld volatile) in %lld slots HT."</span>,j,used,vkeys,size);
                <span class="hljs-comment">/* dictPrintStats(server.dict); */</span>
            }
        }
    }

    <span class="hljs-comment">/* Show information about connected clients */</span>
    <span class="hljs-comment">// 如果服务器没有运行在 SENTINEL 模式下,那么打印客户端的连接信息</span>
    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">server</span>.sentinel_mode) {
        run_with_period(<span class="hljs-number">5000</span>) {
            redisLog(REDIS_VERBOSE,
                <span class="hljs-string">"%lu clients connected (%lu slaves), %zu bytes in use"</span>,
                listLength(<span class="hljs-keyword">server</span>.clients)-listLength(<span class="hljs-keyword">server</span>.slaves),
                listLength(<span class="hljs-keyword">server</span>.slaves),
                zmalloc_used_memory());
        }
    }

    <span class="hljs-comment">/* We need to do a few operations on clients asynchronously. */</span>
    <span class="hljs-comment">// 检查客户端,关闭超时客户端,并释放客户端多余的缓冲区</span>
    clientsCron();

    <span class="hljs-comment">/* Handle background operations on Redis databases. */</span>
    <span class="hljs-comment">// 对数据库执行各种操作</span>
    databasesCron();

    <span class="hljs-comment">/* Start a scheduled AOF rewrite if this was requested by the user while
     * a BGSAVE was in progress. */</span>
    <span class="hljs-comment">// 如果 BGSAVE 和 BGREWRITEAOF 都没有在执行</span>
    <span class="hljs-comment">// 并且有一个 BGREWRITEAOF 在等待,那么执行 BGREWRITEAOF</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">server</span>.rdb_child_pid == -<span class="hljs-number">1</span> && <span class="hljs-keyword">server</span>.aof_child_pid == -<span class="hljs-number">1</span> &&
        <span class="hljs-keyword">server</span>.aof_rewrite_scheduled)
    {
        rewriteAppendOnlyFileBackground();
    }

    <span class="hljs-comment">/* Check if a background saving or AOF rewrite in progress terminated. */</span>
    <span class="hljs-comment">// 检查 BGSAVE 或者 BGREWRITEAOF 是否已经执行完毕</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">server</span>.rdb_child_pid != -<span class="hljs-number">1</span> || <span class="hljs-keyword">server</span>.aof_child_pid != -<span class="hljs-number">1</span>) {
        <span class="hljs-keyword">int</span> statloc;
        pid_t pid;

        <span class="hljs-comment">// 接收子进程发来的信号,非阻塞</span>
        <span class="hljs-keyword">if</span> ((pid = wait3(&statloc,WNOHANG,NULL)) != <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">int</span> exitcode = WEXITSTATUS(statloc);
            <span class="hljs-keyword">int</span> bysignal = <span class="hljs-number">0</span>;

            <span class="hljs-keyword">if</span> (WIFSIGNALED(statloc)) bysignal = WTERMSIG(statloc);

            <span class="hljs-comment">// BGSAVE 执行完毕</span>
            <span class="hljs-keyword">if</span> (pid == <span class="hljs-keyword">server</span>.rdb_child_pid) {
                backgroundSaveDoneHandler(exitcode,bysignal);

            <span class="hljs-comment">// BGREWRITEAOF 执行完毕</span>
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (pid == <span class="hljs-keyword">server</span>.aof_child_pid) {
                backgroundRewriteDoneHandler(exitcode,bysignal);

            } <span class="hljs-keyword">else</span> {
                redisLog(REDIS_WARNING,
                    <span class="hljs-string">"Warning, detected child with unmatched pid: %ld"</span>,
                    (<span class="hljs-keyword">long</span>)pid);
            }
            updateDictResizePolicy();
        }
    } <span class="hljs-keyword">else</span> {

        <span class="hljs-comment">/* If there is not a background saving/rewrite in progress check if
         * we have to save/rewrite now */</span>
        <span class="hljs-comment">// 既然没有 BGSAVE 或者 BGREWRITEAOF 在执行,那么检查是否需要执行它们</span>

        <span class="hljs-comment">// 遍历所有保存条件,看是否需要执行 BGSAVE 命令</span>
         <span class="hljs-keyword">for</span> (j = <span class="hljs-number">0</span>; j < <span class="hljs-keyword">server</span>.saveparamslen; j++) {
            struct saveparam *sp = <span class="hljs-keyword">server</span>.saveparams+j;

            <span class="hljs-comment">/* Save if we reached the given amount of changes,
             * the given amount of seconds, and if the latest bgsave was
             * successful or if, in case of an error, at least
             * REDIS_BGSAVE_RETRY_DELAY seconds already elapsed. */</span>
            <span class="hljs-comment">// 检查是否有某个保存条件已经满足了</span>
            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">server</span>.dirty >= sp->changes &&
                <span class="hljs-keyword">server</span>.unixtime-<span class="hljs-keyword">server</span>.lastsave > sp->seconds &&
                (<span class="hljs-keyword">server</span>.unixtime-<span class="hljs-keyword">server</span>.lastbgsave_try >
                 REDIS_BGSAVE_RETRY_DELAY ||
                 <span class="hljs-keyword">server</span>.lastbgsave_status == REDIS_OK))
            {
                redisLog(REDIS_NOTICE,<span class="hljs-string">"%d changes in %d seconds. Saving..."</span>,
                    sp->changes, (<span class="hljs-keyword">int</span>)sp->seconds);
                <span class="hljs-comment">// 执行 BGSAVE</span>
                rdbSaveBackground(<span class="hljs-keyword">server</span>.rdb_filename);
                <span class="hljs-keyword">break</span>;
            }
         }

         <span class="hljs-comment">/* Trigger an AOF rewrite if needed */</span>
        <span class="hljs-comment">// 出发 BGREWRITEAOF</span>
         <span class="hljs-keyword">if</span> (<span class="hljs-keyword">server</span>.rdb_child_pid == -<span class="hljs-number">1</span> &&
             <span class="hljs-keyword">server</span>.aof_child_pid == -<span class="hljs-number">1</span> &&
             <span class="hljs-keyword">server</span>.aof_rewrite_perc &&
             <span class="hljs-comment">// AOF 文件的当前大小大于执行 BGREWRITEAOF 所需的最小大小</span>
             <span class="hljs-keyword">server</span>.aof_current_size > <span class="hljs-keyword">server</span>.aof_rewrite_min_size)
         {
            <span class="hljs-comment">// 上一次完成 AOF 写入之后,AOF 文件的大小</span>
            <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> base = <span class="hljs-keyword">server</span>.aof_rewrite_base_size ?
                            <span class="hljs-keyword">server</span>.aof_rewrite_base_size : <span class="hljs-number">1</span>;

            <span class="hljs-comment">// AOF 文件当前的体积相对于 base 的体积的百分比</span>
            <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> growth = (<span class="hljs-keyword">server</span>.aof_current_size*<span class="hljs-number">100</span>/base) - <span class="hljs-number">100</span>;

            <span class="hljs-comment">// 如果增长体积的百分比超过了 growth ,那么执行 BGREWRITEAOF</span>
            <span class="hljs-keyword">if</span> (growth >= <span class="hljs-keyword">server</span>.aof_rewrite_perc) {
                redisLog(REDIS_NOTICE,<span class="hljs-string">"Starting automatic rewriting of AOF on %lld%% growth"</span>,growth);
                <span class="hljs-comment">// 执行 BGREWRITEAOF</span>
                rewriteAppendOnlyFileBackground();
            }
         }
    }

    <span class="hljs-comment">// 根据 AOF 政策,</span>
    <span class="hljs-comment">// 考虑是否需要将 AOF 缓冲区中的内容写入到 AOF 文件中</span>
    <span class="hljs-comment">/* AOF postponed flush: Try at every cron cycle if the slow fsync
     * completed. */</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">server</span>.aof_flush_postponed_start) flushAppendOnlyFile(<span class="hljs-number">0</span>);

    <span class="hljs-comment">/* AOF write errors: in this case we have a buffer to flush as well and
     * clear the AOF error in case of success to make the DB writable again,
     * however to try every second is enough in case of 'hz' is set to
     * an higher frequency. */</span>
    run_with_period(<span class="hljs-number">1000</span>) {
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">server</span>.aof_last_write_status == REDIS_ERR)
            flushAppendOnlyFile(<span class="hljs-number">0</span>);
    }

    <span class="hljs-comment">/* Close clients that need to be closed asynchronous */</span>
    <span class="hljs-comment">// 关闭那些需要异步关闭的客户端</span>
    freeClientsInAsyncFreeQueue();

    <span class="hljs-comment">/* Clear the paused clients flag if needed. */</span>
    clientsArePaused(); <span class="hljs-comment">/* Don't check return value, just use the side effect. */</span>

    <span class="hljs-comment">/* Replication cron function -- used to reconnect to master and
     * to detect transfer failures. */</span>
    <span class="hljs-comment">// 复制函数</span>
    <span class="hljs-comment">// 重连接主服务器、向主服务器发送 ACK 、判断数据发送失败情况、断开本服务器超时的从服务器,等等</span>
    run_with_period(<span class="hljs-number">1000</span>) replicationCron();

    <span class="hljs-comment">/* Run the Redis Cluster cron. */</span>
    <span class="hljs-comment">// 如果服务器运行在集群模式下,那么执行集群操作</span>
    run_with_period(<span class="hljs-number">100</span>) {
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">server</span>.cluster_enabled) clusterCron();
    }

    <span class="hljs-comment">/* Run the Sentinel timer if we are in sentinel mode. */</span>
    <span class="hljs-comment">// 如果服务器运行在 sentinel 模式下,那么执行 SENTINEL 的主函数</span>
    run_with_period(<span class="hljs-number">100</span>) {
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">server</span>.sentinel_mode) sentinelTimer();
    }

    <span class="hljs-comment">/* Cleanup expired MIGRATE cached sockets. */</span>
    <span class="hljs-comment">// 集群。。。TODO</span>
    run_with_period(<span class="hljs-number">1000</span>) {
        migrateCloseTimedoutSockets();
    }

    <span class="hljs-comment">// 增加 loop 计数器</span>
    <span class="hljs-keyword">server</span>.cronloops++;

    <span class="hljs-keyword">return</span> <span class="hljs-number">1000</span>/<span class="hljs-keyword">server</span>.hz;
}</code>

3. 初始化服务器

3.1 服务器状态结构

redis.h/redisServer结构,服务器状态:

<code class=" hljs cpp"><span class="hljs-keyword">struct</span> redisServer {

    <span class="hljs-comment">/* General */</span>

    <span class="hljs-comment">// 配置文件的绝对路径</span>
    <span class="hljs-keyword">char</span> *configfile;           <span class="hljs-comment">/* Absolute config file path, or NULL */</span>

    <span class="hljs-comment">// serverCron() 每秒调用的次数</span>
    <span class="hljs-keyword">int</span> hz;                     <span class="hljs-comment">/* serverCron() calls frequency in hertz */</span>

    <span class="hljs-comment">// 数据库</span>
    redisDb *db;

    <span class="hljs-comment">// 命令表(受到 rename 配置选项的作用)</span>
    dict *commands;             <span class="hljs-comment">/* Command table */</span>
    <span class="hljs-comment">// 命令表(无 rename 配置选项的作用)</span>
    dict *orig_commands;        <span class="hljs-comment">/* Command table before command renaming. */</span>

    <span class="hljs-comment">// 事件状态</span>
    aeEventLoop *el;

    <span class="hljs-comment">// 最近一次使用时钟</span>
    <span class="hljs-keyword">unsigned</span> lruclock:REDIS_LRU_BITS; <span class="hljs-comment">/* Clock for LRU eviction */</span>

    <span class="hljs-comment">// 关闭服务器的标识</span>
    <span class="hljs-keyword">int</span> shutdown_asap;          <span class="hljs-comment">/* SHUTDOWN needed ASAP */</span>

    <span class="hljs-comment">// 在执行 serverCron() 时进行渐进式 rehash</span>
    <span class="hljs-keyword">int</span> activerehashing;        <span class="hljs-comment">/* Incremental rehash in serverCron() */</span>

    <span class="hljs-comment">// 是否设置了密码</span>
    <span class="hljs-keyword">char</span> *requirepass;          <span class="hljs-comment">/* Pass for AUTH command, or NULL */</span>

    <span class="hljs-comment">// PID 文件</span>
    <span class="hljs-keyword">char</span> *pidfile;              <span class="hljs-comment">/* PID file path */</span>

    <span class="hljs-comment">// 架构类型</span>
    <span class="hljs-keyword">int</span> arch_bits;              <span class="hljs-comment">/* 32 or 64 depending on sizeof(long) */</span>

    <span class="hljs-comment">// serverCron() 函数的运行次数计数器</span>
    <span class="hljs-keyword">int</span> cronloops;              <span class="hljs-comment">/* Number of times the cron function run */</span>

    <span class="hljs-comment">// 本服务器的 RUN ID</span>
    <span class="hljs-keyword">char</span> runid[REDIS_RUN_ID_SIZE+<span class="hljs-number">1</span>];  <span class="hljs-comment">/* ID always different at every exec. */</span>

    <span class="hljs-comment">// 服务器是否运行在 SENTINEL 模式</span>
    <span class="hljs-keyword">int</span> sentinel_mode;          <span class="hljs-comment">/* True if this instance is a Sentinel. */</span>


    <span class="hljs-comment">/* Networking */</span>

    <span class="hljs-comment">// TCP 监听端口</span>
    <span class="hljs-keyword">int</span> port;                   <span class="hljs-comment">/* TCP listening port */</span>

    <span class="hljs-keyword">int</span> tcp_backlog;            <span class="hljs-comment">/* TCP listen() backlog */</span>

    <span class="hljs-comment">// 地址</span>
    <span class="hljs-keyword">char</span> *bindaddr[REDIS_BINDADDR_MAX]; <span class="hljs-comment">/* Addresses we should bind to */</span>
    <span class="hljs-comment">// 地址数量</span>
    <span class="hljs-keyword">int</span> bindaddr_count;         <span class="hljs-comment">/* Number of addresses in server.bindaddr[] */</span>

    <span class="hljs-comment">// UNIX 套接字</span>
    <span class="hljs-keyword">char</span> *unixsocket;           <span class="hljs-comment">/* UNIX socket path */</span>
    mode_t unixsocketperm;      <span class="hljs-comment">/* UNIX socket permission */</span>

    <span class="hljs-comment">// 描述符</span>
    <span class="hljs-keyword">int</span> ipfd[REDIS_BINDADDR_MAX]; <span class="hljs-comment">/* TCP socket file descriptors */</span>
    <span class="hljs-comment">// 描述符数量</span>
    <span class="hljs-keyword">int</span> ipfd_count;             <span class="hljs-comment">/* Used slots in ipfd[] */</span>

    <span class="hljs-comment">// UNIX 套接字文件描述符</span>
    <span class="hljs-keyword">int</span> sofd;                   <span class="hljs-comment">/* Unix socket file descriptor */</span>

    <span class="hljs-keyword">int</span> cfd[REDIS_BINDADDR_MAX];<span class="hljs-comment">/* Cluster bus listening socket */</span>
    <span class="hljs-keyword">int</span> cfd_count;              <span class="hljs-comment">/* Used slots in cfd[] */</span>

    <span class="hljs-comment">// 一个链表,保存了所有客户端状态结构</span>
    <span class="hljs-built_in">list</span> *clients;              <span class="hljs-comment">/* List of active clients */</span>
    <span class="hljs-comment">// 链表,保存了所有待关闭的客户端</span>
    <span class="hljs-built_in">list</span> *clients_to_close;     <span class="hljs-comment">/* Clients to close asynchronously */</span>

    <span class="hljs-comment">// 链表,保存了所有从服务器,以及所有监视器</span>
    <span class="hljs-built_in">list</span> *slaves, *monitors;    <span class="hljs-comment">/* List of slaves and MONITORs */</span>

    <span class="hljs-comment">// 服务器的当前客户端,仅用于崩溃报告</span>
    redisClient *current_client; <span class="hljs-comment">/* Current client, only used on crash report */</span>

    <span class="hljs-keyword">int</span> clients_paused;         <span class="hljs-comment">/* True if clients are currently paused */</span>
    mstime_t clients_pause_end_time; <span class="hljs-comment">/* Time when we undo clients_paused */</span>

    <span class="hljs-comment">// 网络错误</span>
    <span class="hljs-keyword">char</span> neterr[ANET_ERR_LEN];   <span class="hljs-comment">/* Error buffer for anet.c */</span>

    <span class="hljs-comment">// MIGRATE 缓存</span>
    dict *migrate_cached_sockets;<span class="hljs-comment">/* MIGRATE cached sockets */</span>


    <span class="hljs-comment">/* RDB / AOF loading information */</span>

    <span class="hljs-comment">// 这个值为真时,表示服务器正在进行载入</span>
    <span class="hljs-keyword">int</span> loading;                <span class="hljs-comment">/* We are loading data from disk if true */</span>

    <span class="hljs-comment">// 正在载入的数据的大小</span>
    off_t loading_total_bytes;

    <span class="hljs-comment">// 已载入数据的大小</span>
    off_t loading_loaded_bytes;

    <span class="hljs-comment">// 开始进行载入的时间</span>
    time_t loading_start_time;
    off_t loading_process_events_interval_bytes;

    <span class="hljs-comment">/* Fast pointers to often looked up command */</span>
    <span class="hljs-comment">// 常用命令的快捷连接</span>
    <span class="hljs-keyword">struct</span> redisCommand *delCommand, *multiCommand, *lpushCommand, *lpopCommand,
                        *rpopCommand;


    <span class="hljs-comment">/* Fields used only for stats */</span>

    <span class="hljs-comment">// 服务器启动时间</span>
    time_t stat_starttime;          <span class="hljs-comment">/* Server start time */</span>

    <span class="hljs-comment">// 已处理命令的数量</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> stat_numcommands;     <span class="hljs-comment">/* Number of processed commands */</span>

    <span class="hljs-comment">// 服务器接到的连接请求数量</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> stat_numconnections;  <span class="hljs-comment">/* Number of connections received */</span>

    <span class="hljs-comment">// 已过期的键数量</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> stat_expiredkeys;     <span class="hljs-comment">/* Number of expired keys */</span>

    <span class="hljs-comment">// 因为回收内存而被释放的过期键的数量</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> stat_evictedkeys;     <span class="hljs-comment">/* Number of evicted keys (maxmemory) */</span>

    <span class="hljs-comment">// 成功查找键的次数</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> stat_keyspace_hits;   <span class="hljs-comment">/* Number of successful lookups of keys */</span>

    <span class="hljs-comment">// 查找键失败的次数</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> stat_keyspace_misses; <span class="hljs-comment">/* Number of failed lookups of keys */</span>

    <span class="hljs-comment">// 已使用内存峰值</span>
    size_t stat_peak_memory;        <span class="hljs-comment">/* Max used memory record */</span>

    <span class="hljs-comment">// 最后一次执行 fork() 时消耗的时间</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> stat_fork_time;       <span class="hljs-comment">/* Time needed to perform latest fork() */</span>

    <span class="hljs-comment">// 服务器因为客户端数量过多而拒绝客户端连接的次数</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> stat_rejected_conn;   <span class="hljs-comment">/* Clients rejected because of maxclients */</span>

    <span class="hljs-comment">// 执行 full sync 的次数</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> stat_sync_full;       <span class="hljs-comment">/* Number of full resyncs with slaves. */</span>

    <span class="hljs-comment">// PSYNC 成功执行的次数</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> stat_sync_partial_ok; <span class="hljs-comment">/* Number of accepted PSYNC requests. */</span>

    <span class="hljs-comment">// PSYNC 执行失败的次数</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> stat_sync_partial_err;<span class="hljs-comment">/* Number of unaccepted PSYNC requests. */</span>


    <span class="hljs-comment">/* slowlog */</span>

    <span class="hljs-comment">// 保存了所有慢查询日志的链表</span>
    <span class="hljs-built_in">list</span> *slowlog;                  <span class="hljs-comment">/* SLOWLOG list of commands */</span>

    <span class="hljs-comment">// 下一条慢查询日志的 ID</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> slowlog_entry_id;     <span class="hljs-comment">/* SLOWLOG current entry ID */</span>

    <span class="hljs-comment">// 服务器配置 slowlog-log-slower-than 选项的值</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> slowlog_log_slower_than; <span class="hljs-comment">/* SLOWLOG time limit (to get logged) */</span>

    <span class="hljs-comment">// 服务器配置 slowlog-max-len 选项的值</span>
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> slowlog_max_len;     <span class="hljs-comment">/* SLOWLOG max number of items logged */</span>
    size_t resident_set_size;       <span class="hljs-comment">/* RSS sampled in serverCron(). */</span>
    <span class="hljs-comment">/* The following two are used to track instantaneous "load" in terms
     * of operations per second. */</span>
    <span class="hljs-comment">// 最后一次进行抽样的时间</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> ops_sec_last_sample_time; <span class="hljs-comment">/* Timestamp of last sample (in ms) */</span>
    <span class="hljs-comment">// 最后一次抽样时,服务器已执行命令的数量</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> ops_sec_last_sample_ops;  <span class="hljs-comment">/* numcommands in last sample */</span>
    <span class="hljs-comment">// 抽样结果</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> ops_sec_samples[REDIS_OPS_SEC_SAMPLES];
    <span class="hljs-comment">// 数组索引,用于保存抽样结果,并在需要时回绕到 0</span>
    <span class="hljs-keyword">int</span> ops_sec_idx;


    <span class="hljs-comment">/* Configuration */</span>

    <span class="hljs-comment">// 日志可见性</span>
    <span class="hljs-keyword">int</span> verbosity;                  <span class="hljs-comment">/* Loglevel in redis.conf */</span>

    <span class="hljs-comment">// 客户端最大空转时间</span>
    <span class="hljs-keyword">int</span> maxidletime;                <span class="hljs-comment">/* Client timeout in seconds */</span>

    <span class="hljs-comment">// 是否开启 SO_KEEPALIVE 选项</span>
    <span class="hljs-keyword">int</span> tcpkeepalive;               <span class="hljs-comment">/* Set SO_KEEPALIVE if non-zero. */</span>
    <span class="hljs-keyword">int</span> active_expire_enabled;      <span class="hljs-comment">/* Can be disabled for testing purposes. */</span>
    size_t client_max_querybuf_len; <span class="hljs-comment">/* Limit for client query buffer length */</span>
    <span class="hljs-keyword">int</span> dbnum;                      <span class="hljs-comment">/* Total number of configured DBs */</span>
    <span class="hljs-keyword">int</span> daemonize;                  <span class="hljs-comment">/* True if running as a daemon */</span>
    <span class="hljs-comment">// 客户端输出缓冲区大小限制</span>
    <span class="hljs-comment">// 数组的元素有 REDIS_CLIENT_LIMIT_NUM_CLASSES 个</span>
    <span class="hljs-comment">// 每个代表一类客户端:普通、从服务器、pubsub,诸如此类</span>
    clientBufferLimitsConfig client_obuf_limits[REDIS_CLIENT_LIMIT_NUM_CLASSES];


    <span class="hljs-comment">/* AOF persistence */</span>

    <span class="hljs-comment">// AOF 状态(开启/关闭/可写)</span>
    <span class="hljs-keyword">int</span> aof_state;                  <span class="hljs-comment">/* REDIS_AOF_(ON|OFF|WAIT_REWRITE) */</span>

    <span class="hljs-comment">// 所使用的 fsync 策略(每个写入/每秒/从不)</span>
    <span class="hljs-keyword">int</span> aof_fsync;                  <span class="hljs-comment">/* Kind of fsync() policy */</span>
    <span class="hljs-keyword">char</span> *aof_filename;             <span class="hljs-comment">/* Name of the AOF file */</span>
    <span class="hljs-keyword">int</span> aof_no_fsync_on_rewrite;    <span class="hljs-comment">/* Don't fsync if a rewrite is in prog. */</span>
    <span class="hljs-keyword">int</span> aof_rewrite_perc;           <span class="hljs-comment">/* Rewrite AOF if % growth is > M and... */</span>
    off_t aof_rewrite_min_size;     <span class="hljs-comment">/* the AOF file is at least N bytes. */</span>

    <span class="hljs-comment">// 最后一次执行 BGREWRITEAOF 时, AOF 文件的大小</span>
    off_t aof_rewrite_base_size;    <span class="hljs-comment">/* AOF size on latest startup or rewrite. */</span>

    <span class="hljs-comment">// AOF 文件的当前字节大小</span>
    off_t aof_current_size;         <span class="hljs-comment">/* AOF current size. */</span>
    <span class="hljs-keyword">int</span> aof_rewrite_scheduled;      <span class="hljs-comment">/* Rewrite once BGSAVE terminates. */</span>

    <span class="hljs-comment">// 负责进行 AOF 重写的子进程 ID</span>
    pid_t aof_child_pid;            <span class="hljs-comment">/* PID if rewriting process */</span>

    <span class="hljs-comment">// AOF 重写缓存链表,链接着多个缓存块</span>
    <span class="hljs-built_in">list</span> *aof_rewrite_buf_blocks;   <span class="hljs-comment">/* Hold changes during an AOF rewrite. */</span>

    <span class="hljs-comment">// AOF 缓冲区</span>
    sds aof_buf;      <span class="hljs-comment">/* AOF buffer, written before entering the event loop */</span>

    <span class="hljs-comment">// AOF 文件的描述符</span>
    <span class="hljs-keyword">int</span> aof_fd;       <span class="hljs-comment">/* File descriptor of currently selected AOF file */</span>

    <span class="hljs-comment">// AOF 的当前目标数据库</span>
    <span class="hljs-keyword">int</span> aof_selected_db; <span class="hljs-comment">/* Currently selected DB in AOF */</span>

    <span class="hljs-comment">// 推迟 write 操作的时间</span>
    time_t aof_flush_postponed_start; <span class="hljs-comment">/* UNIX time of postponed AOF flush */</span>

    <span class="hljs-comment">// 最后一直执行 fsync 的时间</span>
    time_t aof_last_fsync;            <span class="hljs-comment">/* UNIX time of last fsync() */</span>
    time_t aof_rewrite_time_last;   <span class="hljs-comment">/* Time used by last AOF rewrite run. */</span>

    <span class="hljs-comment">// AOF 重写的开始时间</span>
    time_t aof_rewrite_time_start;  <span class="hljs-comment">/* Current AOF rewrite start time. */</span>

    <span class="hljs-comment">// 最后一次执行 BGREWRITEAOF 的结果</span>
    <span class="hljs-keyword">int</span> aof_lastbgrewrite_status;   <span class="hljs-comment">/* REDIS_OK or REDIS_ERR */</span>

    <span class="hljs-comment">// 记录 AOF 的 write 操作被推迟了多少次</span>
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> aof_delayed_fsync;  <span class="hljs-comment">/* delayed AOF fsync() counter */</span>

    <span class="hljs-comment">// 指示是否需要每写入一定量的数据,就主动执行一次 fsync()</span>
    <span class="hljs-keyword">int</span> aof_rewrite_incremental_fsync;<span class="hljs-comment">/* fsync incrementally while rewriting? */</span>
    <span class="hljs-keyword">int</span> aof_last_write_status;      <span class="hljs-comment">/* REDIS_OK or REDIS_ERR */</span>
    <span class="hljs-keyword">int</span> aof_last_write_errno;       <span class="hljs-comment">/* Valid if aof_last_write_status is ERR */</span>
    <span class="hljs-comment">/* RDB persistence */</span>

    <span class="hljs-comment">// 自从上次 SAVE 执行以来,数据库被修改的次数</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> dirty;                <span class="hljs-comment">/* Changes to DB from the last save */</span>

    <span class="hljs-comment">// BGSAVE 执行前的数据库被修改次数</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> dirty_before_bgsave;  <span class="hljs-comment">/* Used to restore dirty on failed BGSAVE */</span>

    <span class="hljs-comment">// 负责执行 BGSAVE 的子进程的 ID</span>
    <span class="hljs-comment">// 没在执行 BGSAVE 时,设为 -1</span>
    pid_t rdb_child_pid;            <span class="hljs-comment">/* PID of RDB saving child */</span>
    <span class="hljs-keyword">struct</span> saveparam *saveparams;   <span class="hljs-comment">/* Save points array for RDB */</span>
    <span class="hljs-keyword">int</span> saveparamslen;              <span class="hljs-comment">/* Number of saving points */</span>
    <span class="hljs-keyword">char</span> *rdb_filename;             <span class="hljs-comment">/* Name of RDB file */</span>
    <span class="hljs-keyword">int</span> rdb_compression;            <span class="hljs-comment">/* Use compression in RDB? */</span>
    <span class="hljs-keyword">int</span> rdb_checksum;               <span class="hljs-comment">/* Use RDB checksum? */</span>

    <span class="hljs-comment">// 最后一次完成 SAVE 的时间</span>
    time_t lastsave;                <span class="hljs-comment">/* Unix time of last successful save */</span>

    <span class="hljs-comment">// 最后一次尝试执行 BGSAVE 的时间</span>
    time_t lastbgsave_try;          <span class="hljs-comment">/* Unix time of last attempted bgsave */</span>

    <span class="hljs-comment">// 最近一次 BGSAVE 执行耗费的时间</span>
    time_t rdb_save_time_last;      <span class="hljs-comment">/* Time used by last RDB save run. */</span>

    <span class="hljs-comment">// 数据库最近一次开始执行 BGSAVE 的时间</span>
    time_t rdb_save_time_start;     <span class="hljs-comment">/* Current RDB save start time. */</span>

    <span class="hljs-comment">// 最后一次执行 SAVE 的状态</span>
    <span class="hljs-keyword">int</span> lastbgsave_status;          <span class="hljs-comment">/* REDIS_OK or REDIS_ERR */</span>
    <span class="hljs-keyword">int</span> stop_writes_on_bgsave_err;  <span class="hljs-comment">/* Don't allow writes if can't BGSAVE */</span>


    <span class="hljs-comment">/* Propagation of commands in AOF / replication */</span>
    redisOpArray also_propagate;    <span class="hljs-comment">/* Additional command to propagate. */</span>


    <span class="hljs-comment">/* Logging */</span>
    <span class="hljs-keyword">char</span> *logfile;                  <span class="hljs-comment">/* Path of log file */</span>
    <span class="hljs-keyword">int</span> syslog_enabled;             <span class="hljs-comment">/* Is syslog enabled? */</span>
    <span class="hljs-keyword">char</span> *syslog_ident;             <span class="hljs-comment">/* Syslog ident */</span>
    <span class="hljs-keyword">int</span> syslog_facility;            <span class="hljs-comment">/* Syslog facility */</span>


    <span class="hljs-comment">/* Replication (master) */</span>
    <span class="hljs-keyword">int</span> slaveseldb;                 <span class="hljs-comment">/* Last SELECTed DB in replication output */</span>
    <span class="hljs-comment">// 全局复制偏移量(一个累计值)</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> master_repl_offset;   <span class="hljs-comment">/* Global replication offset */</span>
    <span class="hljs-comment">// 主服务器发送 PING 的频率</span>
    <span class="hljs-keyword">int</span> repl_ping_slave_period;     <span class="hljs-comment">/* Master pings the slave every N seconds */</span>

    <span class="hljs-comment">// backlog 本身</span>
    <span class="hljs-keyword">char</span> *repl_backlog;             <span class="hljs-comment">/* Replication backlog for partial syncs */</span>
    <span class="hljs-comment">// backlog 的长度</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> repl_backlog_size;    <span class="hljs-comment">/* Backlog circular buffer size */</span>
    <span class="hljs-comment">// backlog 中数据的长度</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> repl_backlog_histlen; <span class="hljs-comment">/* Backlog actual data length */</span>
    <span class="hljs-comment">// backlog 的当前索引</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> repl_backlog_idx;     <span class="hljs-comment">/* Backlog circular buffer current offset */</span>
    <span class="hljs-comment">// backlog 中可以被还原的第一个字节的偏移量</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> repl_backlog_off;     <span class="hljs-comment">/* Replication offset of first byte in the
                                       backlog buffer. */</span>
    <span class="hljs-comment">// backlog 的过期时间</span>
    time_t repl_backlog_time_limit; <span class="hljs-comment">/* Time without slaves after the backlog
                                       gets released. */</span>

    <span class="hljs-comment">// 距离上一次有从服务器的时间</span>
    time_t repl_no_slaves_since;    <span class="hljs-comment">/* We have no slaves since that time.
                                       Only valid if server.slaves len is 0. */</span>

    <span class="hljs-comment">// 是否开启最小数量从服务器写入功能</span>
    <span class="hljs-keyword">int</span> repl_min_slaves_to_write;   <span class="hljs-comment">/* Min number of slaves to write. */</span>
    <span class="hljs-comment">// 定义最小数量从服务器的最大延迟值</span>
    <span class="hljs-keyword">int</span> repl_min_slaves_max_lag;    <span class="hljs-comment">/* Max lag of <count> slaves to write. */</span>
    <span class="hljs-comment">// 延迟良好的从服务器的数量</span>
    <span class="hljs-keyword">int</span> repl_good_slaves_count;     <span class="hljs-comment">/* Number of slaves with lag <= max_lag. */</span>


    <span class="hljs-comment">/* Replication (slave) */</span>
    <span class="hljs-comment">// 主服务器的验证密码</span>
    <span class="hljs-keyword">char</span> *masterauth;               <span class="hljs-comment">/* AUTH with this password with master */</span>
    <span class="hljs-comment">// 主服务器的地址</span>
    <span class="hljs-keyword">char</span> *masterhost;               <span class="hljs-comment">/* Hostname of master */</span>
    <span class="hljs-comment">// 主服务器的端口</span>
    <span class="hljs-keyword">int</span> masterport;                 <span class="hljs-comment">/* Port of master */</span>
    <span class="hljs-comment">// 超时时间</span>
    <span class="hljs-keyword">int</span> repl_timeout;               <span class="hljs-comment">/* Timeout after N seconds of master idle */</span>
    <span class="hljs-comment">// 主服务器所对应的客户端</span>
    redisClient *master;     <span class="hljs-comment">/* Client that is master for this slave */</span>
    <span class="hljs-comment">// 被缓存的主服务器,PSYNC 时使用</span>
    redisClient *cached_master; <span class="hljs-comment">/* Cached master to be reused for PSYNC. */</span>
    <span class="hljs-keyword">int</span> repl_syncio_timeout; <span class="hljs-comment">/* Timeout for synchronous I/O calls */</span>
    <span class="hljs-comment">// 复制的状态(服务器是从服务器时使用)</span>
    <span class="hljs-keyword">int</span> repl_state;          <span class="hljs-comment">/* Replication status if the instance is a slave */</span>
    <span class="hljs-comment">// RDB 文件的大小</span>
    off_t repl_transfer_size; <span class="hljs-comment">/* Size of RDB to read from master during sync. */</span>
    <span class="hljs-comment">// 已读 RDB 文件内容的字节数</span>
    off_t repl_transfer_read; <span class="hljs-comment">/* Amount of RDB read from master during sync. */</span>
    <span class="hljs-comment">// 最近一次执行 fsync 时的偏移量</span>
    <span class="hljs-comment">// 用于 sync_file_range 函数</span>
    off_t repl_transfer_last_fsync_off; <span class="hljs-comment">/* Offset when we fsync-ed last time. */</span>
    <span class="hljs-comment">// 主服务器的套接字</span>
    <span class="hljs-keyword">int</span> repl_transfer_s;     <span class="hljs-comment">/* Slave -> Master SYNC socket */</span>
    <span class="hljs-comment">// 保存 RDB 文件的临时文件的描述符</span>
    <span class="hljs-keyword">int</span> repl_transfer_fd;    <span class="hljs-comment">/* Slave -> Master SYNC temp file descriptor */</span>
    <span class="hljs-comment">// 保存 RDB 文件的临时文件名字</span>
    <span class="hljs-keyword">char</span> *repl_transfer_tmpfile; <span class="hljs-comment">/* Slave-> master SYNC temp file name */</span>
    <span class="hljs-comment">// 最近一次读入 RDB 内容的时间</span>
    time_t repl_transfer_lastio; <span class="hljs-comment">/* Unix time of the latest read, for timeout */</span>
    <span class="hljs-keyword">int</span> repl_serve_stale_data; <span class="hljs-comment">/* Serve stale data when link is down? */</span>
    <span class="hljs-comment">// 是否只读从服务器?</span>
    <span class="hljs-keyword">int</span> repl_slave_ro;          <span class="hljs-comment">/* Slave is read only? */</span>
    <span class="hljs-comment">// 连接断开的时长</span>
    time_t repl_down_since; <span class="hljs-comment">/* Unix time at which link with master went down */</span>
    <span class="hljs-comment">// 是否要在 SYNC 之后关闭 NODELAY ?</span>
    <span class="hljs-keyword">int</span> repl_disable_tcp_nodelay;   <span class="hljs-comment">/* Disable TCP_NODELAY after SYNC? */</span>
    <span class="hljs-comment">// 从服务器优先级</span>
    <span class="hljs-keyword">int</span> slave_priority;             <span class="hljs-comment">/* Reported in INFO and used by Sentinel. */</span>
    <span class="hljs-comment">// 本服务器(从服务器)当前主服务器的 RUN ID</span>
    <span class="hljs-keyword">char</span> repl_master_runid[REDIS_RUN_ID_SIZE+<span class="hljs-number">1</span>];  <span class="hljs-comment">/* Master run id for PSYNC. */</span>
    <span class="hljs-comment">// 初始化偏移量</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> repl_master_initial_offset;         <span class="hljs-comment">/* Master PSYNC offset. */</span>


    <span class="hljs-comment">/* Replication script cache. */</span>
    <span class="hljs-comment">// 复制脚本缓存</span>
    <span class="hljs-comment">// 字典</span>
    dict *repl_scriptcache_dict;        <span class="hljs-comment">/* SHA1 all slaves are aware of. */</span>
    <span class="hljs-comment">// FIFO 队列</span>
    <span class="hljs-built_in">list</span> *repl_scriptcache_fifo;        <span class="hljs-comment">/* First in, first out LRU eviction. */</span>
    <span class="hljs-comment">// 缓存的大小</span>
    <span class="hljs-keyword">int</span> repl_scriptcache_size;          <span class="hljs-comment">/* Max number of elements. */</span>

    <span class="hljs-comment">/* Synchronous replication. */</span>
    <span class="hljs-built_in">list</span> *clients_waiting_acks;         <span class="hljs-comment">/* Clients waiting in WAIT command. */</span>
    <span class="hljs-keyword">int</span> get_ack_from_slaves;            <span class="hljs-comment">/* If true we send REPLCONF GETACK. */</span>
    <span class="hljs-comment">/* Limits */</span>
    <span class="hljs-keyword">int</span> maxclients;                 <span class="hljs-comment">/* Max number of simultaneous clients */</span>
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> maxmemory;   <span class="hljs-comment">/* Max number of memory bytes to use */</span>
    <span class="hljs-keyword">int</span> maxmemory_policy;           <span class="hljs-comment">/* Policy for key eviction */</span>
    <span class="hljs-keyword">int</span> maxmemory_samples;          <span class="hljs-comment">/* Pricision of random sampling */</span>


    <span class="hljs-comment">/* Blocked clients */</span>
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> bpop_blocked_clients; <span class="hljs-comment">/* Number of clients blocked by lists */</span>
    <span class="hljs-built_in">list</span> *unblocked_clients; <span class="hljs-comment">/* list of clients to unblock before next loop */</span>
    <span class="hljs-built_in">list</span> *ready_keys;        <span class="hljs-comment">/* List of readyList structures for BLPOP & co */</span>


    <span class="hljs-comment">/* Sort parameters - qsort_r() is only available under BSD so we
     * have to take this state global, in order to pass it to sortCompare() */</span>
    <span class="hljs-keyword">int</span> sort_desc;
    <span class="hljs-keyword">int</span> sort_alpha;
    <span class="hljs-keyword">int</span> sort_bypattern;
    <span class="hljs-keyword">int</span> sort_store;


    <span class="hljs-comment">/* Zip structure config, see redis.conf for more information  */</span>
    size_t hash_max_ziplist_entries;
    size_t hash_max_ziplist_value;
    size_t list_max_ziplist_entries;
    size_t list_max_ziplist_value;
    size_t set_max_intset_entries;
    size_t zset_max_ziplist_entries;
    size_t zset_max_ziplist_value;
    size_t hll_sparse_max_bytes;
    time_t unixtime;        <span class="hljs-comment">/* Unix time sampled every cron cycle. */</span>
    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> mstime;       <span class="hljs-comment">/* Like 'unixtime' but with milliseconds resolution. */</span>


    <span class="hljs-comment">/* Pubsub */</span>
    <span class="hljs-comment">// 字典,键为频道,值为链表</span>
    <span class="hljs-comment">// 链表中保存了所有订阅某个频道的客户端</span>
    <span class="hljs-comment">// 新客户端总是被添加到链表的表尾</span>
    dict *pubsub_channels;  <span class="hljs-comment">/* Map channels to list of subscribed clients */</span>

    <span class="hljs-comment">// 这个链表记录了客户端订阅的所有模式的名字</span>
    <span class="hljs-built_in">list</span> *pubsub_patterns;  <span class="hljs-comment">/* A list of pubsub_patterns */</span>

    <span class="hljs-keyword">int</span> notify_keyspace_events; <span class="hljs-comment">/* Events to propagate via Pub/Sub. This is an
                                   xor of REDIS_NOTIFY... flags. */</span>


    <span class="hljs-comment">/* Cluster */</span>

    <span class="hljs-keyword">int</span> cluster_enabled;      <span class="hljs-comment">/* Is cluster enabled? */</span>
    mstime_t cluster_node_timeout; <span class="hljs-comment">/* Cluster node timeout. */</span>
    <span class="hljs-keyword">char</span> *cluster_configfile; <span class="hljs-comment">/* Cluster auto-generated config file name. */</span>
    <span class="hljs-keyword">struct</span> clusterState *cluster;  <span class="hljs-comment">/* State of the cluster */</span>

    <span class="hljs-keyword">int</span> cluster_migration_barrier; <span class="hljs-comment">/* Cluster replicas migration barrier. */</span>
    <span class="hljs-comment">/* Scripting */</span>

    <span class="hljs-comment">// Lua 环境</span>
    lua_State *lua; <span class="hljs-comment">/* The Lua interpreter. We use just one for all clients */</span>

    <span class="hljs-comment">// 复制执行 Lua 脚本中的 Redis 命令的伪客户端</span>
    redisClient *lua_client;   <span class="hljs-comment">/* The "fake client" to query Redis from Lua */</span>

    <span class="hljs-comment">// 当前正在执行 EVAL 命令的客户端,如果没有就是 NULL</span>
    redisClient *lua_caller;   <span class="hljs-comment">/* The client running EVAL right now, or NULL */</span>

    <span class="hljs-comment">// 一个字典,值为 Lua 脚本,键为脚本的 SHA1 校验和</span>
    dict *lua_scripts;         <span class="hljs-comment">/* A dictionary of SHA1 -> Lua scripts */</span>
    <span class="hljs-comment">// Lua 脚本的执行时限</span>
    mstime_t lua_time_limit;  <span class="hljs-comment">/* Script timeout in milliseconds */</span>
    <span class="hljs-comment">// 脚本开始执行的时间</span>
    mstime_t lua_time_start;  <span class="hljs-comment">/* Start time of script, milliseconds time */</span>

    <span class="hljs-comment">// 脚本是否执行过写命令</span>
    <span class="hljs-keyword">int</span> lua_write_dirty;  <span class="hljs-comment">/* True if a write command was called during the
                             execution of the current script. */</span>

    <span class="hljs-comment">// 脚本是否执行过带有随机性质的命令</span>
    <span class="hljs-keyword">int</span> lua_random_dirty; <span class="hljs-comment">/* True if a random command was called during the
                             execution of the current script. */</span>

    <span class="hljs-comment">// 脚本是否超时</span>
    <span class="hljs-keyword">int</span> lua_timedout;     <span class="hljs-comment">/* True if we reached the time limit for script
                             execution. */</span>

    <span class="hljs-comment">// 是否要杀死脚本</span>
    <span class="hljs-keyword">int</span> lua_kill;         <span class="hljs-comment">/* Kill the script if true. */</span>


    <span class="hljs-comment">/* Assert & bug reporting */</span>

    <span class="hljs-keyword">char</span> *assert_failed;
    <span class="hljs-keyword">char</span> *assert_file;
    <span class="hljs-keyword">int</span> assert_line;
    <span class="hljs-keyword">int</span> bug_report_start; <span class="hljs-comment">/* True if bug report header was already logged. */</span>
    <span class="hljs-keyword">int</span> watchdog_period;  <span class="hljs-comment">/* Software watchdog period in ms. 0 = off */</span>
};</code>

===========================================
初始化服务器的第一步:创建一个struct redisServer 类型的实例变量server作为服务器状态,并为各个属性设置默认值。

<code class=" hljs cs"><span class="hljs-comment">//redis.h</span>
<span class="hljs-keyword">extern</span> <span class="hljs-keyword">struct</span> redisServer server;</code>

初始化server变量由redis.c/initServerConfig函数完成:

<code class=" hljs axapta"><span class="hljs-keyword">void</span> initServerConfig() {
    <span class="hljs-keyword">int</span> j;

    <span class="hljs-comment">// 服务器状态</span>

    <span class="hljs-comment">// 设置服务器的运行 ID</span>
    getRandomHexChars(<span class="hljs-keyword">server</span>.runid,REDIS_RUN_ID_SIZE);
    <span class="hljs-comment">// 设置默认配置文件路径</span>
    <span class="hljs-keyword">server</span>.configfile = NULL;
    <span class="hljs-comment">// 设置默认服务器频率</span>
    <span class="hljs-keyword">server</span>.hz = REDIS_DEFAULT_HZ;
    <span class="hljs-comment">// 为运行 ID 加上结尾字符</span>
    <span class="hljs-keyword">server</span>.runid[REDIS_RUN_ID_SIZE] = <span class="hljs-string">'\0'</span>;
    <span class="hljs-comment">// 设置服务器的运行架构</span>
    <span class="hljs-keyword">server</span>.arch_bits = (sizeof(<span class="hljs-keyword">long</span>) == <span class="hljs-number">8</span>) ? <span class="hljs-number">64</span> : <span class="hljs-number">32</span>;
    <span class="hljs-comment">// 设置默认服务器端口号</span>
    <span class="hljs-keyword">server</span>.port = REDIS_SERVERPORT;
    <span class="hljs-keyword">server</span>.tcp_backlog = REDIS_TCP_BACKLOG;
    <span class="hljs-keyword">server</span>.bindaddr_count = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">server</span>.unixsocket = NULL;
    <span class="hljs-keyword">server</span>.unixsocketperm = REDIS_DEFAULT_UNIX_SOCKET_PERM;
    <span class="hljs-keyword">server</span>.ipfd_count = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">server</span>.sofd = -<span class="hljs-number">1</span>;
    <span class="hljs-keyword">server</span>.dbnum = REDIS_DEFAULT_DBNUM;
    <span class="hljs-keyword">server</span>.verbosity = REDIS_DEFAULT_VERBOSITY;
    <span class="hljs-keyword">server</span>.maxidletime = REDIS_MAXIDLETIME;
    <span class="hljs-keyword">server</span>.tcpkeepalive = REDIS_DEFAULT_TCP_KEEPALIVE;
    <span class="hljs-keyword">server</span>.active_expire_enabled = <span class="hljs-number">1</span>;
    <span class="hljs-keyword">server</span>.client_max_querybuf_len = REDIS_MAX_QUERYBUF_LEN;
    <span class="hljs-keyword">server</span>.saveparams = NULL;
    <span class="hljs-keyword">server</span>.loading = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">server</span>.logfile = zstrdup(REDIS_DEFAULT_LOGFILE);
    <span class="hljs-keyword">server</span>.syslog_enabled = REDIS_DEFAULT_SYSLOG_ENABLED;
    <span class="hljs-keyword">server</span>.syslog_ident = zstrdup(REDIS_DEFAULT_SYSLOG_IDENT);
    <span class="hljs-keyword">server</span>.syslog_facility = LOG_LOCAL0;
    <span class="hljs-keyword">server</span>.daemonize = REDIS_DEFAULT_DAEMONIZE;
    <span class="hljs-keyword">server</span>.aof_state = REDIS_AOF_OFF;
    <span class="hljs-keyword">server</span>.aof_fsync = REDIS_DEFAULT_AOF_FSYNC;
    <span class="hljs-keyword">server</span>.aof_no_fsync_on_rewrite = REDIS_DEFAULT_AOF_NO_FSYNC_ON_REWRITE;
    <span class="hljs-keyword">server</span>.aof_rewrite_perc = REDIS_AOF_REWRITE_PERC;
    <span class="hljs-keyword">server</span>.aof_rewrite_min_size = REDIS_AOF_REWRITE_MIN_SIZE;
    <span class="hljs-keyword">server</span>.aof_rewrite_base_size = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">server</span>.aof_rewrite_scheduled = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">server</span>.aof_last_fsync = time(NULL);
    <span class="hljs-keyword">server</span>.aof_rewrite_time_last = -<span class="hljs-number">1</span>;
    <span class="hljs-keyword">server</span>.aof_rewrite_time_start = -<span class="hljs-number">1</span>;
    <span class="hljs-keyword">server</span>.aof_lastbgrewrite_status = REDIS_OK;
    <span class="hljs-keyword">server</span>.aof_delayed_fsync = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">server</span>.aof_fd = -<span class="hljs-number">1</span>;
    <span class="hljs-keyword">server</span>.aof_selected_db = -<span class="hljs-number">1</span>; <span class="hljs-comment">/* Make sure the first time will not match */</span>
    <span class="hljs-keyword">server</span>.aof_flush_postponed_start = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">server</span>.aof_rewrite_incremental_fsync = REDIS_DEFAULT_AOF_REWRITE_INCREMENTAL_FSYNC;
    <span class="hljs-keyword">server</span>.pidfile = zstrdup(REDIS_DEFAULT_PID_FILE);
    <span class="hljs-keyword">server</span>.rdb_filename = zstrdup(REDIS_DEFAULT_RDB_FILENAME);
    <span class="hljs-keyword">server</span>.aof_filename = zstrdup(REDIS_DEFAULT_AOF_FILENAME);
    <span class="hljs-keyword">server</span>.requirepass = NULL;
    <span class="hljs-keyword">server</span>.rdb_compression = REDIS_DEFAULT_RDB_COMPRESSION;
    <span class="hljs-keyword">server</span>.rdb_checksum = REDIS_DEFAULT_RDB_CHECKSUM;
    <span class="hljs-keyword">server</span>.stop_writes_on_bgsave_err = REDIS_DEFAULT_STOP_WRITES_ON_BGSAVE_ERROR</code>
성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.