Redis 设计与实现(第十三章) -- 客户端



概述

对于每个与服务器连接的客户端,服务器都为它创建相应的redisClient的数据结构,并保持了相应的状态。Redis Server通过一个链表来保存所有的客户端连接。

本章包括:

  • 客户端数据结构介绍;
  • 客户端的创建与关闭

数据结构

先来看下redisClient中的数据结构:

* With multiplexing we need to take per-client state.
 * Clients are taken in a linked list. */
typedef struct redisClient {
    uint64_t id;            /* Client incremental unique ID. */
    int fd;   //套接字描述符,大于1的整数,如果是伪客户端则为-1
    redisDb *db;  //redisDB
    int dictid;
    robj *name;             /* As set by CLIENT SETNAME 客户端名字*/
    sds querybuf;   //输入缓冲区,用于保存客户端发送的命令请求
    size_t querybuf_peak;   /* Recent (100ms or more) peak of querybuf size */
    int argc;   //命令参数长度
    robj **argv;  //要执行的命令及命令参数
    struct redisCommand *cmd, *lastcmd; //命令实现
    int reqtype;
    int multibulklen;       /* number of multi bulk arguments left to read */
    long bulklen;           /* length of bulk argument in multi bulk request */
    list *reply;
    unsigned long reply_bytes; /* Tot bytes of objects in reply list */
    int 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;
    int flags;              /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... 客户端角色,一些状态*/
    int authenticated;      /* when requirepass is non-NULL  认证*/
    int replstate;          /* replication state if this is a slave */
    int repl_put_online_on_ack; /* Install slave write handler on 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 reploff;      /* replication offset if this is our 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 replrunid[REDIS_RUN_ID_SIZE+1]; /* master run id if this is a master */
    int slave_listening_port; /* As configured with: SLAVECONF listening-port */
    int slave_capa;         /* Slave capabilities: SLAVE_CAPA_* bitwise OR. */
    multiState mstate;      /* MULTI/EXEC state */
    int btype;              /* Type of blocking op if REDIS_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. */

    /* Response buffer,输出缓冲区 */
    int bufpos;   //记录了buf目前已使用的字节数
    char buf[REDIS_REPLY_CHUNK_BYTES];
} redisClient;



客户端创建与关闭

创建普通客户端

当客户端连接服务器时,服务器就会调用相应的连接事件处理器,将连接的客户端状态添加到redisServer数据结构中clients链表的末尾。

如下:

redission RBlockingQueue 大小 redis blocked clients_数据库

 

关闭普通客户端

一个普通客户端可能因为多种原因被关闭:

1.如果客户端进程退出或杀死,那么客户端与服务器间的网络连接将会断开,造成客户端关闭;

2.如果客户端向服务器发送了不符合协议格式的命令请求,那么这个客户端也会被服务器关闭;

3.如果客户端成了client kill命令的目标,那么客户端也将会被关闭;

4.如果用户为服务器设置了超时时间,那么超时时间到后,客户端也将会被关闭,在主从服务器里面有一些例外;

5.如果客户端发送的命令超过了缓冲区的大小(默认为1GB),那么客户端也将被关闭;

6.如果要发送给客户端的回复命令超过了输出缓冲区的大学,那么这个客户端也将被服务器关闭。

伪客户端

 1.Lua脚本的伪客户端,在服务器运行期间一直存在,直到服务器关闭;

2.AOF加载的伪客户端,在AOF加载完成后,伪客户端就关闭连接。