Skip to content

Redis client

CLIENT_SLAVECLIENT_MASTER

在master中为client添加上 CLIENT_SLAVE 标识

slave instance向master instance发送SYNC或者PSYNC到master instance,所以master需要执行这两个command,这两个command的执行函数是:replication.c:syncCommand

replication.c:masterTryPartialResynchronization

当master执行对slave的full resynchronize的时候

如何缓存用户发送过来的command

具体的实现在networking.c:processMultibulkBuffer

其实在阅读了Redis Protocol specification后,知道在redis server中,一个非常重要的问题就是要将用户发送过来的command给保存起来,那在struct client中所采用的data structure是什么呢?以下是对这个问题的分析:

Redis Protocol specification中描述了,client发送过来的command是以RESP Arrays的方式打包的,以下是一个example:

*5\r\n
:1\r\n
:2\r\n
:3\r\n
:4\r\n
$6\r\n
foobar\r\n

可以看到,它其实非常类似于一个二维数组;

与此对应的是在struct client中也使用一个二维array来保存,在struct client中使用如下字段来保存:

robj **argv;            /* Arguments of current command. */

struct client字段int multibulklen; /* Number of multi bulk arguments left to read. */对应的是RESP Arrays中所指定的 number of elements in the array,所以据此就可以知道了argv中的元素的个数了;

由于底层的网络实现,client发送过来的command是可能需要多次调用read系统调用才能够完整地读取的,然后才能够准确地理解command的含义;所以我们需要一个cache来保存用户发送过来的stream,保存这个stream的就是struct client字段sds querybuf; struct client字段size_t qb_pos;则记录的是querybuf空闲空间的起点,也就是说read得到的数据从querybuf开始写入到querybuf中。

qb_pos记录的是已经处理的数据的长度

struct client字段sds querybuf

千万不要小看了querybuf,其实它涉及到了非常多的问题,稍有不慎就会导致严重后果:

struct client字段robj **argv

该字段其实和querybuf非常类似,本质上都是由于缓存;

如何判断与client之间的网络连接已经被对方断开?

今天在阅读redis的代码的时候,看到了如下这段让我感到非常疑惑的代码:

void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
    ......

    nread = read(fd, c->querybuf+qblen, readlen);
    if (nread == -1) {
        if (errno == EAGAIN) {
            return;
        } else {
            serverLog(LL_VERBOSE, "Reading from client: %s",strerror(errno));
            freeClientAsync(c);
            return;
        }
    } else if (nread == 0) {
        serverLog(LL_VERBOSE, "Client closed connection");
        freeClientAsync(c);
        return;
    } else if (c->flags & CLIENT_MASTER) {
        /* Append the query buffer to the pending (not applied) buffer
         * of the master. We'll use this buffer later in order to have a
         * copy of the string applied by the last command executed. */
        c->pending_querybuf = sdscatlen(c->pending_querybuf,
                                        c->querybuf+qblen,nread);
    }

    ......

}

为什么没有再读到数据了,就表示这个client已经close了connection?难道redis要每次在client没有数据可读的情况下,就将这个client给关闭掉?这样岂不是会导致这个client下一次进行IO的时候又要重新连接到redis server?

if (nread == 0) {
        serverLog(LL_VERBOSE, "Client closed connection");
        freeClientAsync(c);
        return;
    }

how to judge whether a socket peer close the connection in linux

how redis server judge client has close the network connection

https://github.com/andymccurdy/redis-py/issues/1140

https://redis.io/topics/clients

https://github.com/antirez/redis/issues/2948