Redis奇幻之旅(三)1.redis客戶端與服務(wù)端

1.redis客戶端與服務(wù)端

1.1 客戶端

1.1.1 客戶端種類

redis 客戶端主要分為三種,普通客戶端、發(fā)布訂閱客戶端、slave 客戶端。

  • 普通客戶端我們不用多說,也是我們用的最多的客戶端。

  • redis 客戶端可以訂閱任意數(shù)量的頻道,如果你訂閱了某個(gè)服務(wù)器頻道,那么你的客戶端就也是一個(gè)發(fā)布訂閱客戶端,當(dāng)頻道中有新消息,服務(wù)器會向你推送。

  • 當(dāng) redis 集群中部署了主從節(jié)點(diǎn)的時(shí)候,所有的從節(jié)點(diǎn)服務(wù)器又稱為 slave 客戶端,他們會向 master 定期拉取最新數(shù)據(jù)。

1.1.2 客戶端參數(shù)說明

直接來看redis中是如何定義client的

typedef struct client {
    uint64_t id;            /* Client incremental unique ID. */
    connection *conn;
    int resp;               /* RESP protocol version. Can be 2 or 3. */
    redisDb *db;            /* Pointer to currently SELECTed DB. */
    robj *name;             /* As set by CLIENT SETNAME. */
    sds querybuf;           /* Buffer we use to accumulate client queries. */
    size_t qb_pos;          /* The position we have read in querybuf. */
    sds pending_querybuf;   /* If this client is flagged as master, this buffer
                               represents the yet not applied portion of the
                               replication stream that we are receiving from
                               the master. */
    size_t querybuf_peak;   /* Recent (100ms or more) peak of querybuf size. */
    int argc;               /* Num of arguments of current command. */
    robj **argv;            /* Arguments of current command. */
    struct redisCommand *cmd, *lastcmd;  /* Last command executed. */
    user *user;             /* User associated with this connection. If the
                               user is set to NULL the connection can do
                               anything (admin). */
    int reqtype;            /* Request protocol type: PROTO_REQ_* */
    int multibulklen;       /* Number of multi bulk arguments left to read. */
    long bulklen;           /* Length of bulk argument in multi bulk request. */
    list *reply;            /* List of reply objects to send to the client. */
    unsigned long long reply_bytes; /* Tot bytes of objects in reply list. */
    size_t sentlen;         /* Amount of bytes already sent in the current
                               buffer or object being sent. */
    time_t ctime;           /* Client creation time. */
    time_t lastinteraction; /* Time of the last interaction, used for timeout */
    time_t obuf_soft_limit_reached_time;
    uint64_t flags;         /* Client flags: CLIENT_* macros. */
    int authenticated;      /* Needed when the default user requires auth. */
    int replstate;          /* Replication state if this is a slave. */
    int repl_put_online_on_ack; /* Install slave write handler on first ACK. */
    int repldbfd;           /* Replication DB file descriptor. */
    off_t repldboff;        /* Replication DB file offset. */
    off_t repldbsize;       /* Replication DB file size. */
    sds replpreamble;       /* Replication DB preamble. */
    long long read_reploff; /* Read replication offset if this is a master. */
    long long reploff;      /* Applied replication offset if this is a master. */
    long long repl_ack_off; /* Replication ack offset, if this is a slave. */
    long long repl_ack_time;/* Replication ack time, if this is a slave. */
    long long psync_initial_offset; /* FULLRESYNC reply offset other slaves
                                       copying this slave output buffer
                                       should use. */
    char replid[CONFIG_RUN_ID_SIZE+1]; /* Master replication ID (if master). */
    int slave_listening_port; /* As configured with: SLAVECONF listening-port */
    char slave_ip[NET_IP_STR_LEN]; /* Optionally given by REPLCONF ip-address */
    int slave_capa;         /* Slave capabilities: SLAVE_CAPA_* bitwise OR. */
    multiState mstate;      /* MULTI/EXEC state */
    int btype;              /* Type of blocking op if CLIENT_BLOCKED. */
    blockingState bpop;     /* blocking state */
    long long woff;         /* Last write global replication offset. */
    list *watched_keys;     /* Keys WATCHED for MULTI/EXEC CAS */
    dict *pubsub_channels;  /* channels a client is interested in (SUBSCRIBE) */
    list *pubsub_patterns;  /* patterns a client is interested in (SUBSCRIBE) */
    sds peerid;             /* Cached peer ID. */
    listNode *client_list_node; /* list node in client list */
    RedisModuleUserChangedFunc auth_callback; /* Module callback to execute
                                               * when the authenticated user
                                               * changes. */
    void *auth_callback_privdata; /* Private data that is passed when the auth
                                   * changed callback is executed. Opaque for
                                   * Redis Core. */
    void *auth_module;      /* The module that owns the callback, which is used
                             * to disconnect the client if the module is
                             * unloaded for cleanup. Opaque for Redis Core.*/

    /* If this client is in tracking mode and this field is non zero,
     * invalidation messages for keys fetched by this client will be send to
     * the specified client ID. */
    uint64_t client_tracking_redirection;
    rax *client_tracking_prefixes; /* A dictionary of prefixes we are already
                                      subscribed to in BCAST mode, in the
                                      context of client side caching. */
    /* In clientsCronTrackClientsMemUsage() we track the memory usage of
     * each client and add it to the sum of all the clients of a given type,
     * however we need to remember what was the old contribution of each
     * client, and in which categoty the client was, in order to remove it
     * before adding it the new value. */
    uint64_t client_cron_last_memory_usage;
    int      client_cron_last_memory_type;
    /* Response buffer */
    int bufpos;
    char buf[PROTO_REPLY_CHUNK_BYTES];
} client;

authenticated:身份驗(yàn)證,為0時(shí)只能接受AUTH命令,為1時(shí)則正常使用

從終端執(zhí)行“client list”獲取到的值

127.0.0.1:6379> client list
id=308 addr=127.0.0.1:51338 fd=7 name= age=4752555 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client
  • id:自增唯一id

  • addr:客戶端地址 + 端口

  • fd:套接字描述符(偽客戶端為-1,其他為正整數(shù))

  • name:客戶端的名字,默認(rèn)是空,可以用 “client setname“ 為客戶端命名

  • age:生命周期,以秒為單位

  • idle:空閑時(shí)長,以秒為單位

  • flags:客戶端的標(biāo)志值

  • db:指向客戶端正在使用的數(shù)據(jù)庫

  • sub:已訂閱頻道的數(shù)量

  • psub:已訂閱模式的數(shù)量

  • multi:在事務(wù)中被執(zhí)行的命令數(shù)量

  • qbuf:輸入緩沖區(qū)--已使用的緩沖區(qū)

  • qbuf-free:輸入緩沖區(qū)--空閑的緩沖區(qū)

  • obl:輸出緩沖區(qū)--固定緩沖區(qū)長度

  • oll:輸出緩沖區(qū)--動態(tài)緩沖區(qū)長度

  • omem:固定緩沖區(qū)和動態(tài)緩沖區(qū)總共占用了多少字節(jié)

  • events:文件描述符時(shí)間

  • cmd:最近一次執(zhí)行的命令

客戶端 flag 可以由以下部分組成:

  • O:客戶端是 MONITOR 模式下的附屬節(jié)點(diǎn)(slave)
  • S:客戶端是一般模式下(normal)的附屬節(jié)點(diǎn)
  • M:客戶端是主節(jié)點(diǎn)(master)
  • x:客戶端正在執(zhí)行事務(wù)
  • b:客戶端正在等待阻塞事件
  • i:客戶端正在等待 VM I/O 操作(已廢棄)
  • d:一個(gè)受監(jiān)視(watched)的鍵已被修改, EXEC 命令將失敗
  • c:在將回復(fù)完整地寫出之后,關(guān)閉鏈接
  • u:客戶端未被阻塞(unblocked)
  • A:盡可能快地關(guān)閉連接
  • N:未設(shè)置任何 flag

文件描述符事件可以是:

  • r:客戶端套接字(在事件 loop 中)是可讀的(readable)
  • w:客戶端套接字(在事件 loop 中)是可寫的(writeable)

1.2 服務(wù)端

Redis: under the hood

1.2.1 Redis服務(wù)啟動流程

概要

? Redis通過初始化全局服務(wù)器狀態(tài)變量并讀取可選的配置文件以覆蓋所有默認(rèn)值來啟動。它建立了一個(gè)全局命令表,該表將命令名稱與實(shí)現(xiàn)該命令的實(shí)際功能連接起來。它使用最佳可用的基礎(chǔ)系統(tǒng)庫創(chuàng)建事件循環(huán),以進(jìn)行事件/就緒通知,并為有新客戶端套接字連接接受時(shí)注冊處理程序函數(shù)。它還注冊了一個(gè)定期的(即基于時(shí)間的)事件處理程序來處理cron密鑰到期之類的類似任務(wù),需要在常規(guī)客戶端處理路徑之外解決。一旦客戶端已連接,便在事件循環(huán)中注冊了一個(gè)功能,以便在客戶端具有要讀取的數(shù)據(jù)(即查詢命令)時(shí)得到通知。解析客戶端的查詢,并調(diào)用命令處理程序以執(zhí)行命令并將響應(yīng)寫回到客戶端(事件通知循環(huán)也處理向客戶端的數(shù)據(jù)寫入)??蛻舳藢ο蟊恢刂茫?wù)器準(zhǔn)備處理更多查詢。

開始全局服務(wù)器狀態(tài)初始化

? 首先會調(diào)用initServerConfig()初始化一個(gè)變量server,其類型為struct redisServer,用作全局服務(wù)器狀態(tài)。

源碼如下:

struct redisServer {
    /* General */
    pid_t pid;                  /* Main process pid. */
    char *configfile;           /* Absolute config file path, or NULL */
    char *executable;           /* Absolute executable file path. */
    char **exec_argv;           /* Executable argv vector (copy). */
    int dynamic_hz;             /* Change hz value depending on # of clients. */
    int config_hz;              /* Configured HZ value. May be different than
                                   the actual 'hz' field value if dynamic-hz
                                   is enabled. */
    int hz;                     /* serverCron() calls frequency in hertz */
    redisDb *db;
    dict *commands;             /* Command table */
    dict *orig_commands;        /* Command table before command renaming. */
    aeEventLoop *el;
    _Atomic unsigned int lruclock; /* Clock for LRU eviction */
    int shutdown_asap;          /* SHUTDOWN needed ASAP */
    int activerehashing;        /* Incremental rehash in serverCron() */
    int active_defrag_running;  /* Active defragmentation running (holds current scan aggressiveness) */
    char *pidfile;              /* PID file path */
    int arch_bits;              /* 32 or 64 depending on sizeof(long) */
    int cronloops;              /* Number of times the cron function run */
    char runid[CONFIG_RUN_ID_SIZE+1];  /* ID always different at every exec. */
    int sentinel_mode;          /* True if this instance is a Sentinel. */
    size_t initial_memory_usage; /* Bytes used after initialization. */
    int always_show_logo;       /* Show logo even for non-stdout logging. */
    /* Modules */
    dict *moduleapi;            /* Exported core APIs dictionary for modules. */
    dict *sharedapi;            /* Like moduleapi but containing the APIs that
                                   modules share with each other. */
    list *loadmodule_queue;     /* List of modules to load at startup. */
    int module_blocked_pipe[2]; /* Pipe used to awake the event loop if a
                                   client blocked on a module command needs
                                   to be processed. */
    pid_t module_child_pid;     /* PID of module child */
    /* Networking */
    int port;                   /* TCP listening port */
    int tls_port;               /* TLS listening port */
    int tcp_backlog;            /* TCP listen() backlog */
    char *bindaddr[CONFIG_BINDADDR_MAX]; /* Addresses we should bind to */
    int bindaddr_count;         /* Number of addresses in server.bindaddr[] */
    char *unixsocket;           /* UNIX socket path */
    mode_t unixsocketperm;      /* UNIX socket permission */
    int ipfd[CONFIG_BINDADDR_MAX]; /* TCP socket file descriptors */
    int ipfd_count;             /* Used slots in ipfd[] */
    int tlsfd[CONFIG_BINDADDR_MAX]; /* TLS socket file descriptors */
    int tlsfd_count;            /* Used slots in tlsfd[] */
    int sofd;                   /* Unix socket file descriptor */
    int cfd[CONFIG_BINDADDR_MAX];/* Cluster bus listening socket */
    int cfd_count;              /* Used slots in cfd[] */
    list *clients;              /* List of active clients */
    list *clients_to_close;     /* Clients to close asynchronously */
    list *clients_pending_write; /* There is to write or install handler. */
    list *clients_pending_read;  /* Client has pending read socket buffers. */
    list *slaves, *monitors;    /* List of slaves and MONITORs */
    client *current_client;     /* Current client executing the command. */
    rax *clients_timeout_table; /* Radix tree for blocked clients timeouts. */
    long fixed_time_expire;     /* If > 0, expire keys against server.mstime. */
    rax *clients_index;         /* Active clients dictionary by client ID. */
    int clients_paused;         /* True if clients are currently paused */
    mstime_t clients_pause_end_time; /* Time when we undo clients_paused */
    char neterr[ANET_ERR_LEN];   /* Error buffer for anet.c */
    dict *migrate_cached_sockets;/* MIGRATE cached sockets */
    _Atomic uint64_t next_client_id; /* Next client unique ID. Incremental. */
    int protected_mode;         /* Don't accept external connections. */
    int gopher_enabled;         /* If true the server will reply to gopher
                                   queries. Will still serve RESP2 queries. */
    int io_threads_num;         /* Number of IO threads to use. */
    int io_threads_do_reads;    /* Read and parse from IO threads? */
    int io_threads_active;      /* Is IO threads currently active? */
    long long events_processed_while_blocked; /* processEventsWhileBlocked() */

    /* RDB / AOF loading information */
    int loading;                /* We are loading data from disk if true */
    off_t loading_total_bytes;
    off_t loading_loaded_bytes;
    time_t loading_start_time;
    off_t loading_process_events_interval_bytes;
    /* Fast pointers to often looked up command */
    struct redisCommand *delCommand, *multiCommand, *lpushCommand,
                        *lpopCommand, *rpopCommand, *zpopminCommand,
                        *zpopmaxCommand, *sremCommand, *execCommand,
                        *expireCommand, *pexpireCommand, *xclaimCommand,
                        *xgroupCommand, *rpoplpushCommand;
    /* Fields used only for stats */
    time_t stat_starttime;          /* Server start time */
    long long stat_numcommands;     /* Number of processed commands */
    long long stat_numconnections;  /* Number of connections received */
    long long stat_expiredkeys;     /* Number of expired keys */
    double stat_expired_stale_perc; /* Percentage of keys probably expired */
    long long stat_expired_time_cap_reached_count; /* Early expire cylce stops.*/
    long long stat_expire_cycle_time_used; /* Cumulative microseconds used. */
    long long stat_evictedkeys;     /* Number of evicted keys (maxmemory) */
    long long stat_keyspace_hits;   /* Number of successful lookups of keys */
    long long stat_keyspace_misses; /* Number of failed lookups of keys */
    long long stat_active_defrag_hits;      /* number of allocations moved */
    long long stat_active_defrag_misses;    /* number of allocations scanned but not moved */
    long long stat_active_defrag_key_hits;  /* number of keys with moved allocations */
    long long stat_active_defrag_key_misses;/* number of keys scanned and not moved */
    long long stat_active_defrag_scanned;   /* number of dictEntries scanned */
    size_t stat_peak_memory;        /* Max used memory record */
    long long stat_fork_time;       /* Time needed to perform latest fork() */
    double stat_fork_rate;          /* Fork rate in GB/sec. */
    long long stat_rejected_conn;   /* Clients rejected because of maxclients */
    long long stat_sync_full;       /* Number of full resyncs with slaves. */
    long long stat_sync_partial_ok; /* Number of accepted PSYNC requests. */
    long long stat_sync_partial_err;/* Number of unaccepted PSYNC requests. */
    list *slowlog;                  /* SLOWLOG list of commands */
    long long slowlog_entry_id;     /* SLOWLOG current entry ID */
    long long slowlog_log_slower_than; /* SLOWLOG time limit (to get logged) */
    unsigned long slowlog_max_len;     /* SLOWLOG max number of items logged */
    struct malloc_stats cron_malloc_stats; /* sampled in serverCron(). */
    _Atomic long long stat_net_input_bytes; /* Bytes read from network. */
    _Atomic long long stat_net_output_bytes; /* Bytes written to network. */
    size_t stat_rdb_cow_bytes;      /* Copy on write bytes during RDB saving. */
    size_t stat_aof_cow_bytes;      /* Copy on write bytes during AOF rewrite. */
    size_t stat_module_cow_bytes;   /* Copy on write bytes during module fork. */
    uint64_t stat_clients_type_memory[CLIENT_TYPE_COUNT];/* Mem usage by type */
    long long stat_unexpected_error_replies; /* Number of unexpected (aof-loading, replica to master, etc.) error replies */
    long long stat_io_reads_processed; /* Number of read events processed by IO / Main threads */
    long long stat_io_writes_processed; /* Number of write events processed by IO / Main threads */
    _Atomic long long stat_total_reads_processed; /* Total number of read events processed */
    _Atomic long long stat_total_writes_processed; /* Total number of write events processed */
    /* The following two are used to track instantaneous metrics, like
     * number of operations per second, network traffic. */
    struct {
        long long last_sample_time; /* Timestamp of last sample in ms */
        long long last_sample_count;/* Count in last sample */
        long long samples[STATS_METRIC_SAMPLES];
        int idx;
    } inst_metric[STATS_METRIC_COUNT];
    /* Configuration */
    int verbosity;                  /* Loglevel in redis.conf */
    int maxidletime;                /* Client timeout in seconds */
    int tcpkeepalive;               /* Set SO_KEEPALIVE if non-zero. */
    int active_expire_enabled;      /* Can be disabled for testing purposes. */
    int active_expire_effort;       /* From 1 (default) to 10, active effort. */
    int active_defrag_enabled;
    int jemalloc_bg_thread;         /* Enable jemalloc background thread */
    size_t active_defrag_ignore_bytes; /* minimum amount of fragmentation waste to start active defrag */
    int active_defrag_threshold_lower; /* minimum percentage of fragmentation to start active defrag */
    int active_defrag_threshold_upper; /* maximum percentage of fragmentation at which we use maximum effort */
    int active_defrag_cycle_min;       /* minimal effort for defrag in CPU percentage */
    int active_defrag_cycle_max;       /* maximal effort for defrag in CPU percentage */
    unsigned long active_defrag_max_scan_fields; /* maximum number of fields of set/hash/zset/list to process from within the main dict scan */
    _Atomic size_t client_max_querybuf_len; /* Limit for client query buffer length */
    int dbnum;                      /* Total number of configured DBs */
    int supervised;                 /* 1 if supervised, 0 otherwise. */
    int supervised_mode;            /* See SUPERVISED_* */
    int daemonize;                  /* True if running as a daemon */
    clientBufferLimitsConfig client_obuf_limits[CLIENT_TYPE_OBUF_COUNT];
    /* AOF persistence */
    int aof_enabled;                /* AOF configuration */
    int aof_state;                  /* AOF_(ON|OFF|WAIT_REWRITE) */
    int aof_fsync;                  /* Kind of fsync() policy */
    char *aof_filename;             /* Name of the AOF file */
    int aof_no_fsync_on_rewrite;    /* Don't fsync if a rewrite is in prog. */
    int aof_rewrite_perc;           /* Rewrite AOF if % growth is > M and... */
    off_t aof_rewrite_min_size;     /* the AOF file is at least N bytes. */
    off_t aof_rewrite_base_size;    /* AOF size on latest startup or rewrite. */
    off_t aof_current_size;         /* AOF current size. */
    off_t aof_fsync_offset;         /* AOF offset which is already synced to disk. */
    int aof_flush_sleep;            /* Micros to sleep before flush. (used by tests) */
    int aof_rewrite_scheduled;      /* Rewrite once BGSAVE terminates. */
    pid_t aof_child_pid;            /* PID if rewriting process */
    list *aof_rewrite_buf_blocks;   /* Hold changes during an AOF rewrite. */
    sds aof_buf;      /* AOF buffer, written before entering the event loop */
    int aof_fd;       /* File descriptor of currently selected AOF file */
    int aof_selected_db; /* Currently selected DB in AOF */
    time_t aof_flush_postponed_start; /* UNIX time of postponed AOF flush */
    time_t aof_last_fsync;            /* UNIX time of last fsync() */
    time_t aof_rewrite_time_last;   /* Time used by last AOF rewrite run. */
    time_t aof_rewrite_time_start;  /* Current AOF rewrite start time. */
    int aof_lastbgrewrite_status;   /* C_OK or C_ERR */
    unsigned long aof_delayed_fsync;  /* delayed AOF fsync() counter */
    int aof_rewrite_incremental_fsync;/* fsync incrementally while aof rewriting? */
    int rdb_save_incremental_fsync;   /* fsync incrementally while rdb saving? */
    int aof_last_write_status;      /* C_OK or C_ERR */
    int aof_last_write_errno;       /* Valid if aof_last_write_status is ERR */
    int aof_load_truncated;         /* Don't stop on unexpected AOF EOF. */
    int aof_use_rdb_preamble;       /* Use RDB preamble on AOF rewrites. */
    /* AOF pipes used to communicate between parent and child during rewrite. */
    int aof_pipe_write_data_to_child;
    int aof_pipe_read_data_from_parent;
    int aof_pipe_write_ack_to_parent;
    int aof_pipe_read_ack_from_child;
    int aof_pipe_write_ack_to_child;
    int aof_pipe_read_ack_from_parent;
    int aof_stop_sending_diff;     /* If true stop sending accumulated diffs
                                      to child process. */
    sds aof_child_diff;             /* AOF diff accumulator child side. */
    /* RDB persistence */
    long long dirty;                /* Changes to DB from the last save */
    long long dirty_before_bgsave;  /* Used to restore dirty on failed BGSAVE */
    pid_t rdb_child_pid;            /* PID of RDB saving child */
    struct saveparam *saveparams;   /* Save points array for RDB */
    int saveparamslen;              /* Number of saving points */
    char *rdb_filename;             /* Name of RDB file */
    int rdb_compression;            /* Use compression in RDB? */
    int rdb_checksum;               /* Use RDB checksum? */
    int rdb_del_sync_files;         /* Remove RDB files used only for SYNC if
                                       the instance does not use persistence. */
    time_t lastsave;                /* Unix time of last successful save */
    time_t lastbgsave_try;          /* Unix time of last attempted bgsave */
    time_t rdb_save_time_last;      /* Time used by last RDB save run. */
    time_t rdb_save_time_start;     /* Current RDB save start time. */
    int rdb_bgsave_scheduled;       /* BGSAVE when possible if true. */
    int rdb_child_type;             /* Type of save by active child. */
    int lastbgsave_status;          /* C_OK or C_ERR */
    int stop_writes_on_bgsave_err;  /* Don't allow writes if can't BGSAVE */
    int rdb_pipe_write;             /* RDB pipes used to transfer the rdb */
    int rdb_pipe_read;              /* data to the parent process in diskless repl. */
    connection **rdb_pipe_conns;    /* Connections which are currently the */
    int rdb_pipe_numconns;          /* target of diskless rdb fork child. */
    int rdb_pipe_numconns_writing;  /* Number of rdb conns with pending writes. */
    char *rdb_pipe_buff;            /* In diskless replication, this buffer holds data */
    int rdb_pipe_bufflen;           /* that was read from the the rdb pipe. */
    int rdb_key_save_delay;         /* Delay in microseconds between keys while
                                     * writing the RDB. (for testings). negative
                                     * value means fractions of microsecons (on average). */
    int key_load_delay;             /* Delay in microseconds between keys while
                                     * loading aof or rdb. (for testings). negative
                                     * value means fractions of microsecons (on average). */
    /* Pipe and data structures for child -> parent info sharing. */
    int child_info_pipe[2];         /* Pipe used to write the child_info_data. */
    struct {
        int process_type;           /* AOF or RDB child? */
        size_t cow_size;            /* Copy on write size. */
        unsigned long long magic;   /* Magic value to make sure data is valid. */
    } child_info_data;
    /* Propagation of commands in AOF / replication */
    redisOpArray also_propagate;    /* Additional command to propagate. */
    /* Logging */
    char *logfile;                  /* Path of log file */
    int syslog_enabled;             /* Is syslog enabled? */
    char *syslog_ident;             /* Syslog ident */
    int syslog_facility;            /* Syslog facility */
    int crashlog_enabled;           /* Enable signal handler for crashlog.
                                     * disable for clean core dumps. */
    int memcheck_enabled;           /* Enable memory check on crash. */
    int use_exit_on_panic;          /* Use exit() on panic and assert rather than
                                     * abort(). useful for Valgrind. */
    /* Replication (master) */
    char replid[CONFIG_RUN_ID_SIZE+1];  /* My current replication ID. */
    char replid2[CONFIG_RUN_ID_SIZE+1]; /* replid inherited from master*/
    long long master_repl_offset;   /* My current replication offset */
    long long second_replid_offset; /* Accept offsets up to this for replid2. */
    int slaveseldb;                 /* Last SELECTed DB in replication output */
    int repl_ping_slave_period;     /* Master pings the slave every N seconds */
    char *repl_backlog;             /* Replication backlog for partial syncs */
    long long repl_backlog_size;    /* Backlog circular buffer size */
    long long repl_backlog_histlen; /* Backlog actual data length */
    long long repl_backlog_idx;     /* Backlog circular buffer current offset,
                                       that is the next byte will'll write to.*/
    long long repl_backlog_off;     /* Replication "master offset" of first
                                       byte in the replication backlog buffer.*/
    time_t repl_backlog_time_limit; /* Time without slaves after the backlog
                                       gets released. */
    time_t repl_no_slaves_since;    /* We have no slaves since that time.
                                       Only valid if server.slaves len is 0. */
    int repl_min_slaves_to_write;   /* Min number of slaves to write. */
    int repl_min_slaves_max_lag;    /* Max lag of <count> slaves to write. */
    int repl_good_slaves_count;     /* Number of slaves with lag <= max_lag. */
    int repl_diskless_sync;         /* Master send RDB to slaves sockets directly. */
    int repl_diskless_load;         /* Slave parse RDB directly from the socket.
                                     * see REPL_DISKLESS_LOAD_* enum */
    int repl_diskless_sync_delay;   /* Delay to start a diskless repl BGSAVE. */
    /* Replication (slave) */
    char *masteruser;               /* AUTH with this user and masterauth with master */
    char *masterauth;               /* AUTH with this password with master */
    char *masterhost;               /* Hostname of master */
    int masterport;                 /* Port of master */
    int repl_timeout;               /* Timeout after N seconds of master idle */
    client *master;     /* Client that is master for this slave */
    client *cached_master; /* Cached master to be reused for PSYNC. */
    int repl_syncio_timeout; /* Timeout for synchronous I/O calls */
    int repl_state;          /* Replication status if the instance is a slave */
    off_t repl_transfer_size; /* Size of RDB to read from master during sync. */
    off_t repl_transfer_read; /* Amount of RDB read from master during sync. */
    off_t repl_transfer_last_fsync_off; /* Offset when we fsync-ed last time. */
    connection *repl_transfer_s;     /* Slave -> Master SYNC connection */
    int repl_transfer_fd;    /* Slave -> Master SYNC temp file descriptor */
    char *repl_transfer_tmpfile; /* Slave-> master SYNC temp file name */
    time_t repl_transfer_lastio; /* Unix time of the latest read, for timeout */
    int repl_serve_stale_data; /* Serve stale data when link is down? */
    int repl_slave_ro;          /* Slave is read only? */
    int repl_slave_ignore_maxmemory;    /* If true slaves do not evict. */
    time_t repl_down_since; /* Unix time at which link with master went down */
    int repl_disable_tcp_nodelay;   /* Disable TCP_NODELAY after SYNC? */
    int slave_priority;             /* Reported in INFO and used by Sentinel. */
    int slave_announce_port;        /* Give the master this listening port. */
    char *slave_announce_ip;        /* Give the master this ip address. */
    /* The following two fields is where we store master PSYNC replid/offset
     * while the PSYNC is in progress. At the end we'll copy the fields into
     * the server->master client structure. */
    char master_replid[CONFIG_RUN_ID_SIZE+1];  /* Master PSYNC runid. */
    long long master_initial_offset;           /* Master PSYNC offset. */
    int repl_slave_lazy_flush;          /* Lazy FLUSHALL before loading DB? */
    /* Replication script cache. */
    dict *repl_scriptcache_dict;        /* SHA1 all slaves are aware of. */
    list *repl_scriptcache_fifo;        /* First in, first out LRU eviction. */
    unsigned int repl_scriptcache_size; /* Max number of elements. */
    /* Synchronous replication. */
    list *clients_waiting_acks;         /* Clients waiting in WAIT command. */
    int get_ack_from_slaves;            /* If true we send REPLCONF GETACK. */
    /* Limits */
    unsigned int maxclients;            /* Max number of simultaneous clients */
    unsigned long long maxmemory;   /* Max number of memory bytes to use */
    int maxmemory_policy;           /* Policy for key eviction */
    int maxmemory_samples;          /* Pricision of random sampling */
    int lfu_log_factor;             /* LFU logarithmic counter factor. */
    int lfu_decay_time;             /* LFU counter decay factor. */
    long long proto_max_bulk_len;   /* Protocol bulk length maximum size. */
    int oom_score_adj_base;         /* Base oom_score_adj value, as observed on startup */
    int oom_score_adj_values[CONFIG_OOM_COUNT];   /* Linux oom_score_adj configuration */
    int oom_score_adj;                            /* If true, oom_score_adj is managed */
    /* Blocked clients */
    unsigned int blocked_clients;   /* # of clients executing a blocking cmd.*/
    unsigned int blocked_clients_by_type[BLOCKED_NUM];
    list *unblocked_clients; /* list of clients to unblock before next loop */
    list *ready_keys;        /* List of readyList structures for BLPOP & co */
    /* Client side caching. */
    unsigned int tracking_clients;  /* # of clients with tracking enabled.*/
    size_t tracking_table_max_keys; /* Max number of keys in tracking table. */
    /* Sort parameters - qsort_r() is only available under BSD so we
     * have to take this state global, in order to pass it to sortCompare() */
    int sort_desc;
    int sort_alpha;
    int sort_bypattern;
    int sort_store;
    /* Zip structure config, see redis.conf for more information  */
    size_t hash_max_ziplist_entries;
    size_t hash_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;
    size_t stream_node_max_bytes;
    long long stream_node_max_entries;
    /* List parameters */
    int list_max_ziplist_size;
    int list_compress_depth;
    /* time cache */
    _Atomic time_t unixtime;    /* Unix time sampled every cron cycle. */
    time_t timezone;            /* Cached timezone. As set by tzset(). */
    int daylight_active;        /* Currently in daylight saving time. */
    mstime_t mstime;            /* 'unixtime' in milliseconds. */
    ustime_t ustime;            /* 'unixtime' in microseconds. */
    long long blocked_last_cron; /* Indicate the mstime of the last time we did cron jobs from a blocking operation */
    /* Pubsub */
    dict *pubsub_channels;  /* Map channels to list of subscribed clients */
    list *pubsub_patterns;  /* A list of pubsub_patterns */
    dict *pubsub_patterns_dict;  /* A dict of pubsub_patterns */
    int notify_keyspace_events; /* Events to propagate via Pub/Sub. This is an
                                   xor of NOTIFY_... flags. */
    /* Cluster */
    int cluster_enabled;      /* Is cluster enabled? */
    mstime_t cluster_node_timeout; /* Cluster node timeout. */
    char *cluster_configfile; /* Cluster auto-generated config file name. */
    struct clusterState *cluster;  /* State of the cluster */
    int cluster_migration_barrier; /* Cluster replicas migration barrier. */
    int cluster_slave_validity_factor; /* Slave max data age for failover. */
    int cluster_require_full_coverage; /* If true, put the cluster down if
                                          there is at least an uncovered slot.*/
    int cluster_slave_no_failover;  /* Prevent slave from starting a failover
                                       if the master is in failure state. */
    char *cluster_announce_ip;  /* IP address to announce on cluster bus. */
    int cluster_announce_port;     /* base port to announce on cluster bus. */
    int cluster_announce_bus_port; /* bus port to announce on cluster bus. */
    int cluster_module_flags;      /* Set of flags that Redis modules are able
                                      to set in order to suppress certain
                                      native Redis Cluster features. Check the
                                      REDISMODULE_CLUSTER_FLAG_*. */
    int cluster_allow_reads_when_down; /* Are reads allowed when the cluster
                                        is down? */
    int cluster_config_file_lock_fd;   /* cluster config fd, will be flock */
    /* Scripting */
    lua_State *lua; /* The Lua interpreter. We use just one for all clients */
    client *lua_client;   /* The "fake client" to query Redis from Lua */
    client *lua_caller;   /* The client running EVAL right now, or NULL */
    char* lua_cur_script; /* SHA1 of the script currently running, or NULL */
    dict *lua_scripts;         /* A dictionary of SHA1 -> Lua scripts */
    unsigned long long lua_scripts_mem;  /* Cached scripts' memory + oh */
    mstime_t lua_time_limit;  /* Script timeout in milliseconds */
    mstime_t lua_time_start;  /* Start time of script, milliseconds time */
    int lua_write_dirty;  /* True if a write command was called during the
                             execution of the current script. */
    int lua_random_dirty; /* True if a random command was called during the
                             execution of the current script. */
    int lua_replicate_commands; /* True if we are doing single commands repl. */
    int lua_multi_emitted;/* True if we already proagated MULTI. */
    int lua_repl;         /* Script replication flags for redis.set_repl(). */
    int lua_timedout;     /* True if we reached the time limit for script
                             execution. */
    int lua_kill;         /* Kill the script if true. */
    int lua_always_replicate_commands; /* Default replication type. */
    int lua_oom;          /* OOM detected when script start? */
    /* Lazy free */
    int lazyfree_lazy_eviction;
    int lazyfree_lazy_expire;
    int lazyfree_lazy_server_del;
    int lazyfree_lazy_user_del;
    /* Latency monitor */
    long long latency_monitor_threshold;
    dict *latency_events;
    /* ACLs */
    char *acl_filename;     /* ACL Users file. NULL if not configured. */
    unsigned long acllog_max_len; /* Maximum length of the ACL LOG list. */
    sds requirepass;        /* Remember the cleartext password set with the
                               old "requirepass" directive for backward
                               compatibility with Redis <= 5. */
    /* Assert & bug reporting */
    int watchdog_period;  /* Software watchdog period in ms. 0 = off */
    /* System hardware info */
    size_t system_memory_size;  /* Total memory in system as reported by OS */
    /* TLS Configuration */
    int tls_cluster;
    int tls_replication;
    int tls_auth_clients;
    redisTLSContextConfig tls_ctx_config;
    /* cpu affinity */
    char *server_cpulist; /* cpu affinity list of redis server main/io thread. */
    char *bio_cpulist; /* cpu affinity list of bio thread. */
    char *aof_rewrite_cpulist; /* cpu affinity list of aof rewrite process. */
    char *bgsave_cpulist; /* cpu affinity list of bgsave process. */
};

README.MD中有對類型進(jìn)行簡單解釋:

All the server configuration and in general all the shared state is
defined in a global structure called `server`, of type `struct redisServer`.
A few important fields in this structure are:

* `server.db` is an array of Redis databases, where data is stored.
* `server.commands` is the command table.
* `server.clients` is a linked list of clients connected to the server.
* `server.master` is a special client, the master, if the instance is a replica.

There are tons of other fields. Most fields are commented directly inside
the structure definition.
設(shè)置命令表

? 接下來要做的是對Redis命令表進(jìn)行排序。它們在redisCommandTable數(shù)組的全局變量中定義struct redisCommand。

? 只讀表按源代碼排序,以便按類別將命令分組,例如字符串命令,列表命令,設(shè)置命令等,以使程序員更容易掃描表中的類似命令。排序后的命令表由全局變量指向,用于通過 commandTable標(biāo)準(zhǔn)二進(jìn)制搜索(lookupCommand(),返回指向a的指針redisCommand)查找Redis命令。

加載配置文件

? 1.2.1.1 中會全局初始化一份配置,而這個(gè)動作是用Redis.conf文件中用戶配置的值覆蓋之前初始化出來的配置。Redis將加載配置文件并調(diào)用initServerConfig()覆蓋已經(jīng)設(shè)置的任何默認(rèn)值loadServerConfig()。此函數(shù)非常簡單,它遍歷配置文件中的每一行,并將與指令名稱匹配的值轉(zhuǎn)換為server結(jié)構(gòu)中匹配成員的適當(dāng)類型 。此時(shí),Redis將被守護(hù)并從控制終端分離(如果已配置)。

initServer()

? initServer()完成初始化由server開始的結(jié)構(gòu)的工作 initServerConfig()。首先,它設(shè)置了信號處理(SIGHUP并且 SIGPIPE信號被忽略了—有機(jī)會通過添加在接收到SIGHUP時(shí)以其他守護(hù)程序的方式重新加載其配置文件的功能來改進(jìn)Redis ),包括在服務(wù)器接收到時(shí)打印stacktrace a SIGSEGV(以及其他相關(guān)信號),請參閱segvHandler()。

? 創(chuàng)建了許多雙向鏈接列表(請參閱參考資料adlist.h)來跟蹤客戶端,從屬設(shè)備,監(jiān)視器(發(fā)送MONITOR命令的客戶端 )和無對象列表。

共享對象

? 很多人都知道 Redis內(nèi)部維護(hù)[0-9999]的整數(shù)對象池。創(chuàng)建大量的整數(shù)類型redisObject 存在內(nèi)存開銷,每個(gè)redisObject內(nèi)部結(jié)構(gòu)至少占16字節(jié),甚至超過了整數(shù)自身空間消耗。所以Redis內(nèi)存維護(hù)一個(gè)[0-9999]的整數(shù)對象池,用于節(jié)約內(nèi)存。 除了整數(shù)值對象,其他類型如list,hash,set,zset內(nèi)部元素也可以使用整數(shù)對象池。

? 除了整數(shù)對象池,還可以共享許多不同命令,響應(yīng)字符串和錯(cuò)誤消息所需要的通用Redis對象,而不必每次都分配它們,從而節(jié)省了內(nèi)存。例如:

shared.crlf = createObject(REDIS_STRING,sdsnew("\r\n"));
shared.ok = createObject(REDIS_STRING,sdsnew("+OK\r\n"));
shared.err = createObject(REDIS_STRING,sdsnew("-ERR\r\n"));
shared.emptybulk = createObject(REDIS_STRING,sdsnew("$0\r\n\r\n"));
事件循環(huán)

? initServer()會創(chuàng)建核心事件循環(huán),即調(diào)用aeCreateEventLoop()函數(shù)(參閱ae.c)。

? ae.h提供了一個(gè)獨(dú)立于平臺的包裝程序,用于設(shè)置I / O事件通知循環(huán),該循環(huán)程序epoll在Linuxkqueue上,BSD上使用,并在各自的首選不可用時(shí)返回select。Redis的事件循環(huán)輪詢新連接和I/O事件(從套接字讀取請求并向套接字寫入響應(yīng)),在新事件到達(dá)時(shí)觸發(fā)。這就是Redis如此快速響應(yīng)的原因,它可以同時(shí)為成千上萬的客戶端提供服務(wù),而不會阻塞單個(gè)請求的處理和響應(yīng)。

Databases

? initServer()初始化了一些redisDb對象,這些對象封裝了特定Redis數(shù)據(jù)庫的詳細(xì)信息,包括跟蹤即將到期的密鑰,正在阻止的密鑰(來自B{L,R}POP命令或I / O的密鑰)以及正在受檢查檢查的密鑰和設(shè)置。(默認(rèn)情況下,有16個(gè)獨(dú)立的數(shù)據(jù)庫,可以將它們視為Redis服務(wù)器中的名稱空間。)

TCP socket

? initServer()這是Redis偵聽連接的套接字(默認(rèn)情況下綁定到端口6379)的位置。另一個(gè)Redis本地包裝器anet.h定義anetTcpServer()了許多其他功能,這些功能簡化了設(shè)置新套接字,綁定和偵聽端口的通常復(fù)雜性。

serverCron

? initServer()進(jìn)一步為數(shù)據(jù)庫和pub / sub分配各種字典和列表,重置統(tǒng)計(jì)信息和各種標(biāo)志,并記下服務(wù)器啟動時(shí)間的UNIX時(shí)間戳。serverCron() 向事件循環(huán)注冊為時(shí)間事件,每100毫秒執(zhí)行一次該功能。(這并不完全,因?yàn)樽畛?serverCron()將其設(shè)置為在1毫秒內(nèi)運(yùn)行,以使該功能隨服務(wù)器啟動立即開始,但隨后將其設(shè)置為100毫秒執(zhí)行一次。)

? serverCron() 為Redis執(zhí)行許多定期任務(wù),包括詳細(xì)記錄數(shù)據(jù)庫大?。ㄊ褂玫逆I和內(nèi)存的數(shù)量)和已連接的客戶端,調(diào)整哈希表的大小,關(guān)閉空閑/超時(shí)的客戶端連接,執(zhí)行任何后臺保存或AOF重寫,如果已滿足所配置的保存條件(在這么多秒內(nèi)更改了很多鍵),則啟動后臺保存。

在事件循環(huán)中注冊連接處理器

? initServer()通過注冊套接字的描述符,并在acceptHandler()接受新連接時(shí)注冊要調(diào)用的函數(shù),從而將事件循環(huán)與服務(wù)器的TCP套接字掛鉤。

打開AOF

? initServer()會創(chuàng)建AOF文件,如果文件已存在,則直接打開。

備份主進(jìn)程id

? 如果服務(wù)器配置為守護(hù)進(jìn)程,則Redis現(xiàn)在將嘗試寫出一個(gè)pid文件(其路徑是可配置的,但默認(rèn)為 /var/run/redis.pid)。

? 此時(shí),服務(wù)器已啟動,Redis會將這個(gè)事實(shí)記錄到其日志文件中。

恢復(fù)AOF/RDB數(shù)據(jù)

? 如果存在AOF或數(shù)據(jù)庫轉(zhuǎn)儲文件(例如dump.rdb),則會將其加載,從而將服務(wù)器數(shù)據(jù)恢復(fù)到上一個(gè)會話。如果兩者都存在,則AOF優(yōu)先。

事件循環(huán)設(shè)置

? 最后,Redis在每次進(jìn)入事件循環(huán)時(shí)都會注冊一個(gè)要調(diào)用的函數(shù)beforeSleep()(因?yàn)樵撨^程實(shí)際上在等待通知事件的過程中進(jìn)入睡眠狀態(tài))。

進(jìn)入事件循環(huán)

? Redis通過調(diào)用aeMain()帶有參數(shù)的進(jìn)入主事件循環(huán)server.el(請記住,該成員包含指向的指針aeEventLoop)。如果每次循環(huán)都有任何時(shí)間或文件事件要處理,則將調(diào)用它們各自的處理程序函數(shù)。aeProcessEvents()封裝此邏輯-時(shí)間事件由定制邏輯來處理,而文件事件是由底層處理epoll或 kqueue或select I/O事件通知系統(tǒng)。

? 由于Redis需要響應(yīng)時(shí)間事件及文件I/O事件,因此它實(shí)現(xiàn)了自定義事件/輪詢循環(huán)aeMain()。通過檢查是否需要處理事件,并利用文件事件通知,事件循環(huán)可以有效地進(jìn)入睡眠狀態(tài),直到有工作要做為止,并且不會使CPU陷入緊張的while循環(huán)中。

處理新連接

? 當(dāng)有一個(gè)I/O事件與服務(wù)器正在偵聽的套接字的文件描述符相關(guān)聯(lián)時(shí)(即套接字具有等待讀取或?qū)懭氲臄?shù)據(jù)),Redis注冊為被調(diào)用。acceptHandler()創(chuàng)建一個(gè)客戶端對象-指向中redisClient定義的結(jié)構(gòu)的指針,表示新的客戶端連接。

? 調(diào)用createClient()以分配和初始化客戶端對象。默認(rèn)情況下,它選擇數(shù)據(jù)庫0(因?yàn)槊總€(gè)服務(wù)器必須至少有一個(gè)Redis db),并將acceptHandler()生成的客戶端文件描述符與客戶端對象相關(guān)聯(lián)。最后將客戶端附加到所跟蹤的客戶端的全局列表server.clients中。事件循環(huán)中注冊一個(gè)處理程序,該函數(shù)readQueryFromClient()用于何時(shí)從客戶端連接讀取數(shù)據(jù)。

從客戶端讀取命令

? 當(dāng)客戶端發(fā)出命令請求時(shí),由主事件循環(huán)調(diào)用。它會盡可能多地讀取命令(最多1024個(gè)字節(jié))到臨時(shí)緩沖區(qū),然后將其附加到特定于客戶端的緩沖區(qū)中,即:查詢緩沖區(qū)。這使Redis可以處理有效載荷大于1024字節(jié)的命令,或者由于I/O原因而被拆分為多個(gè)讀取事件的命令。然后調(diào)用processInputBuffer(),將客戶端對象作為參數(shù)傳遞。

? processInputBuffer()將來自客戶端的原始查詢解析為用于執(zhí)行Redis命令的參數(shù)。首先必須解決客戶機(jī)被B{L,R}POP 命令阻塞的可能性,并且在這種情況下盡早解救。然后,該函數(shù)將原始查詢緩沖區(qū)解析為參數(shù),創(chuàng)建每個(gè)的Redis字符串對象并將它們存儲在客戶端對象的數(shù)組中。該查詢采用Redis協(xié)議的形式,processInputBuffer()實(shí)際上是一個(gè)協(xié)議解析器,processCommand()來完全解析查詢。

? processCommand()從客戶端獲取命令的參數(shù)并執(zhí)行。在實(shí)際執(zhí)行命令之前,它會執(zhí)行許多檢查-如果任何檢查失敗,它將錯(cuò)誤消息附加到客戶端對象的答復(fù)列表中并返回給調(diào)用方processInputBuffer()。在特殊情況QUIT下處理了 命令后(為了安全地關(guān)閉客戶端),請將processCommand()設(shè)置在commandTable,這是在Redis的啟動周期中先前設(shè)置的。如果這是一個(gè)未知命令,或者客戶端錯(cuò)誤地認(rèn)為該命令是錯(cuò)誤的。雖然不常用,但是Redis可以配置為在接受命令之前要求密碼來認(rèn)證客戶端,這是Redis檢查客戶端是否經(jīng)過認(rèn)證的階段,否則將設(shè)置錯(cuò)誤。如果將Redis配置為使用最大內(nèi)存量,那么它會在此時(shí)嘗試釋放內(nèi)存(如果可能的話)(從空閑列表中釋放對象并刪除過期的密鑰),否則,如果服務(wù)器超出限制,它不會處理命令REDIS_CMD_DENYOOM標(biāo)志設(shè)置(主要是寫,像SET,INCR,RPUSH, ZADD等),再次出現(xiàn)錯(cuò)誤。Redis的最后一項(xiàng)檢查是,只有在訂閱了未解決的頻道時(shí),客戶端才能發(fā)出SUBSCRIBE或 UNSUBSCRIBE命令,否則,這是一個(gè)錯(cuò)誤。如果所有檢查均已通過,則將通過call()使用客戶端對象和命令對象作為參數(shù)調(diào)用來執(zhí)行命令。

執(zhí)行命令并響應(yīng)

? call(),struct redisCommandProc從對象的proc成員獲取類型為的函數(shù)的指針。

? 像SET和ZADD這樣的寫命令會使服務(wù)器“變臟”,換句話說,服務(wù)器被標(biāo)記為內(nèi)存中的頁面已更改。這對于自動保存過程非常重要,該過程可跟蹤在一定時(shí)期內(nèi)已更改了多少個(gè)Key寫入AOF。feedAppendOnlyFile()如果啟用了AOF的使用,該函數(shù)將調(diào)用 ,這會將命令緩沖區(qū)從客戶端寫到AOF,以便可以重播命令。(它將將相對密鑰有效期設(shè)置為絕對有效期的命令轉(zhuǎn)換為命令,但是否則,它基本上會復(fù)制從客戶端傳入的命令,請參見catAppendOnlyGenericCommand()。如果連接了任何從屬,call()則將命令發(fā)送給每個(gè)從屬以便從屬在本地執(zhí)行,可參閱replicationFeedSlaves()。同樣,如果連接了任何客戶端并發(fā)出了 MONITOR命令,Redis將發(fā)送該命令的表示形式,并帶有時(shí)間戳,請參見 replicationFeedMonitors()。

? 控制權(quán)返回給調(diào)用方,該調(diào)用方processCommand()將客戶端對象重置為后續(xù)命令。

? 如前所述,每個(gè)Redis命令過程本身負(fù)責(zé)設(shè)置要發(fā)送到客戶端的響應(yīng)。后readQueryFromClient()退出,并返回Redis的在以事件循環(huán)aeMain(),aeProcessEvents()將搭載在寫緩沖區(qū)中等待響應(yīng),并將其復(fù)制到客戶端連接的插座中。

? 客戶端和服務(wù)器都返回到可以分別發(fā)出和處理更多Redis命令的狀態(tài)。

1.3 INFO命令

通過給定可選的參數(shù) section ,可以讓命令只返回某一部分的信息:

  • server : 一般 Redis 服務(wù)器信息,包含以下域:

    • redis_version : Redis 服務(wù)器版本
    • redis_git_sha1 : Git SHA1
    • redis_git_dirty : Git dirty flag
    • os : Redis 服務(wù)器的宿主操作系統(tǒng)
    • arch_bits : 架構(gòu)(32 或 64 位)
    • multiplexing_api : Redis 所使用的事件處理機(jī)制
    • gcc_version : 編譯 Redis 時(shí)所使用的 GCC 版本
    • process_id : 服務(wù)器進(jìn)程的 PID
    • run_id : Redis 服務(wù)器的隨機(jī)標(biāo)識符(用于 Sentinel 和集群)
    • tcp_port : TCP/IP 監(jiān)聽端口
    • uptime_in_seconds : 自 Redis 服務(wù)器啟動以來,經(jīng)過的秒數(shù)
    • uptime_in_days : 自 Redis 服務(wù)器啟動以來,經(jīng)過的天數(shù)
    • lru_clock : 以分鐘為單位進(jìn)行自增的時(shí)鐘,用于 LRU 管理
  • clients : 已連接客戶端信息,包含以下域:

    • connected_clients : 已連接客戶端的數(shù)量(不包括通過從屬服務(wù)器連接的客戶端)
    • client_longest_output_list : 當(dāng)前連接的客戶端當(dāng)中,最長的輸出列表
    • client_longest_input_buf : 當(dāng)前連接的客戶端當(dāng)中,最大輸入緩存
    • blocked_clients : 正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客戶端的數(shù)量
  • memory : 內(nèi)存信息,包含以下域:

    • used_memory : 由 Redis 分配器分配的內(nèi)存總量,以字節(jié)(byte)為單位
    • used_memory_human : 以人類可讀的格式返回 Redis 分配的內(nèi)存總量
    • used_memory_rss : 從操作系統(tǒng)的角度,返回 Redis 已分配的內(nèi)存總量(俗稱常駐集大?。_@個(gè)值和 top 、 ps 等命令的輸出一致。
    • used_memory_peak : Redis 的內(nèi)存消耗峰值(以字節(jié)為單位)
    • used_memory_peak_human : 以人類可讀的格式返回 Redis 的內(nèi)存消耗峰值
    • used_memory_lua : Lua 引擎所使用的內(nèi)存大?。ㄒ宰止?jié)為單位)
    • mem_fragmentation_ratio : used_memory_rss 和 used_memory 之間的比率
    • mem_allocator : 在編譯時(shí)指定的, Redis 所使用的內(nèi)存分配器??梢允?libc 、 jemalloc 或者 tcmalloc 。

    在理想情況下, used_memory_rss 的值應(yīng)該只比 used_memory 稍微高一點(diǎn)兒。

    當(dāng) rss > used ,且兩者的值相差較大時(shí),表示存在(內(nèi)部或外部的)內(nèi)存碎片。

    內(nèi)存碎片的比率可以通過 mem_fragmentation_ratio 的值看出。

    當(dāng) used > rss 時(shí),表示 Redis 的部分內(nèi)存被操作系統(tǒng)換出到交換空間了,在這種情況下,操作可能會產(chǎn)生明顯的延遲。

    當(dāng) Redis 釋放內(nèi)存時(shí),分配器可能會,也可能不會,將內(nèi)存返還給操作系統(tǒng)。

    如果 Redis 釋放了內(nèi)存,卻沒有將內(nèi)存返還給操作系統(tǒng),那么 used_memory 的值可能和操作系統(tǒng)顯示的 Redis 內(nèi)存占用并不一致。

    查看 used_memory_peak 的值可以驗(yàn)證這種情況是否發(fā)生。

  • persistence : RDB 和 AOF 的相關(guān)信息

  • stats : 一般統(tǒng)計(jì)信息

  • replication : 主/從復(fù)制信息

  • cpu : CPU 計(jì)算量統(tǒng)計(jì)信息

  • commandstats : Redis 命令統(tǒng)計(jì)信息

  • cluster : Redis 集群信息

  • keyspace : 數(shù)據(jù)庫相關(guān)的統(tǒng)計(jì)信息

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容