Q & A
Master 在向 Slave传 rdb文件的过程,收到客户端发来的写请求。Master是怎么处理呢?
在代码中,作者有提及这过程。在同步完成前,写请求都先放到output buffer。
/* Feed slaves that are waiting for the initial SYNC (so these commands * are queued in the output buffer until the initial SYNC completes), * or are already in sync with the master. */
output buffer 又分为两个区域。当写请求长度小于 16k时,都往buf写。
/* Response buffer(In redisClient/redis.h) */
int bufpos;
char buf[REDIS_REPLY_CHUNK_BYTES]; // 16k output buffer
当长度大于16K时,往redisClient 的reply 写。
//In addReply/networking.c
if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK)
_addReplyObjectToList(c,obj);
当然,不能无休止地往reply写。达到上限时,会断开连接。上限可配置,对应的配置选项是client-output-buffer-limit
//in networking.c
void asyncCloseClientOnOutputBufferLimitReached(redisClient *c) {
redisAssert(c->reply_bytes < ULONG_MAX-(1024*64));
if (c->reply_bytes == 0 || c->flags & REDIS_CLOSE_ASAP) return;
if (checkClientOutputBufferLimits(c)) {
sds client = catClientInfoString(sdsempty(),c);
freeClientAsync(c);
redisLog(REDIS_WARNING,"Client %s scheduled to be closed ASAP for overcoming of output buffer limits.", client);
sdsfree(client);
}
}
当rdb文件发送完毕,Master向Slave转发这段期间的请求
//finishing send rdb file
if (slave->repldboff == slave->repldbsize) {
close(slave->repldbfd);
slave->repldbfd = -1;
aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
slave->replstate = REDIS_REPL_ONLINE;
slave->repl_ack_time = server.unixtime;
if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE,
sendReplyToClient, slave) == AE_ERR) {//send cached requests to slave
redisLog(REDIS_WARNING,"Unable to register writable event for slave bulk transfer: %s", strerror(errno));
freeClient(slave);
return;
}
refreshGoodSlavesCount();
redisLog(REDIS_NOTICE,"Synchronization with slave succeeded");
}