0%

redis的非阻塞网络模型

redis的非阻塞网络模型

建立连接时:

    // 非阻塞
    anetNonBlock(NULL,fd);
    // 禁用 Nagle 算法
    anetEnableTcpNoDelay(NULL,fd);
    // 设置 keep alive
    if (server.tcpkeepalive)
        anetKeepAlive(NULL,fd,server.tcpkeepalive);
    // 绑定读事件到事件 loop (开始接收命令请求)
    if (aeCreateFileEvent(server.el,fd,AE_READABLE,
        readQueryFromClient, c) == AE_ERR)
    {
        close(fd);
        zfree(c);
        return NULL;
    }

1、redis会将fd设置为非阻塞

2、redis默认不设置TCP链接的KEEPLIVE(心跳保活)选项

加入监听时:

/*
* 关联给定事件到 fd
*/
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
aeApiState *state = eventLoop->apidata;
struct epoll_event ee;

/* If the fd was already monitored for some event, we need a MOD
 * operation. Otherwise we need an ADD operation. 
 *
 * 如果 fd 没有关联任何事件,那么这是一个 ADD 操作。
 *
 * 如果已经关联了某个/某些事件,那么这是一个 MOD 操作。
 */
int op = eventLoop->events[fd].mask == AE_NONE ?
        EPOLL_CTL_ADD : EPOLL_CTL_MOD;

// 注册事件到 epoll
ee.events = 0;
mask |= eventLoop->events[fd].mask; /* Merge old events */
if (mask & AE_READABLE) ee.events |= EPOLLIN;
if (mask & AE_WRITABLE) ee.events |= EPOLLOUT;
ee.data.u64 = 0; /* avoid valgrind warning */
ee.data.fd = fd;

if (epoll_ctl(state->epfd,op,fd,&ee) == -1) return -1;

return 0;
}

1、redis没有设置触发方式,故为默认的LT触发

读取数据时

// 读入内容到查询缓存
nread = read(fd, c->querybuf+qblen, readlen);

// 读入出错
if (nread == -1) {
    if (errno == EAGAIN) {
        nread = 0;
    } else {
        redisLog(REDIS_VERBOSE, "Reading from client: %s",strerror(errno));
        freeClient(c);
        return;
    }
// 遇到 EOF
} else if (nread == 0) {
    redisLog(REDIS_VERBOSE, "Client closed connection");
    freeClient(c);
    return;
}

if (nread) {
    // 根据内容,更新查询缓冲区(SDS) free 和 len 属性
    // 并将 '\0' 正确地放到内容的最后
    sdsIncrLen(c->querybuf,nread);
    // 记录服务器和客户端最后一次互动的时间
    c->lastinteraction = server.unixtime;
    // 如果客户端是 master 的话,更新它的复制偏移量
    if (c->flags & REDIS_MASTER) c->reploff += nread;
} else {
    // 在 nread == -1 且 errno == EAGAIN 时运行
    server.current_client = NULL;
    return;
}

1、redis没有进行循环读取
2、在read返回-1后,并且errno == EAGAIN,不做任何处理。
3、如果在while循环中不断读取的话,read将会一直读取,导致无法处理其他client的请求