Base: Redis 2.8.7
Redis的Replication有一个配置“repl-disable-tcp-nodelay”,如下
# Disable TCP_NODELAY on the slave socket after SYNC?
#
# If you select "yes" Redis will use a smaller number of TCP packets and
# less bandwidth to send data to slaves. But this can add a delay for
# the data to appear on the slave side, up to 40 milliseconds with
# Linux kernels using a default configuration.
#
# If you select "no" the delay for data to appear on the slave side will
# be reduced but more bandwidth will be used for replication.
#
# By default we optimize for low latency, but in very high traffic conditions
# or when the master and slaves are many hops away, turning this to "yes" may
# be a good idea.
repl-disable-tcp-nodelay no
解释:
在slave和master同步后(发送psync/sync),后续的同步是否设置成TCP_NODELAY
假如设置成yes,则redis会合并小的TCP包从而节省带宽,但会增加同步延迟(40ms),造成master与slave数据不一致
假如设置成no,则redis master会立即发送同步数据,没有延迟
前者关注性能,后者关注一致性
代码分析:
命令配置,sync&psync都配置响应为syscCommand:
Redis.c
{"sync",syncCommand,1,"ars",0,NULL,0,0,0,0,0},
{"psync",syncCommand,3,"ars",0,NULL,0,0,0,0,0},
syscCommand函数:
Replication.c
void syncCommand(redisClient *c) { ...... if (!strcasecmp(c->argv[0]->ptr,"psync")) {//增量同步 if (masterTryPartialResynchronization(c) == REDIS_OK) { server.stat_sync_partial_ok++; return; /* No full resync needed, return. */ } else { char *master_runid = c->argv[1]->ptr; if (master_runid[0] != '?') server.stat_sync_partial_err++; } } else {//全量同步 c->flags |= REDIS_PRE_PSYNC; } /* Full resynchronization. */ server.stat_sync_full++; /* check是否需要生成rdb文件*/ if (server.rdb_child_pid != -1) { ...... } else { //fork子进程生成RDB文件 ...... } //调用setsockopt设置TCP_NODELAY if (server.repl_disable_tcp_nodelay) anetDisableTcpNoDelay(NULL, c->fd); /* Non critical if it fails. */ ...... }TCP_NODELAY
40ms是Nagle和TCP确认延迟机制共同作用的结果
TCP确认延迟机制:当Server端收到数据之后,它并不会马上向client端发送ACK,而是会将ACK的发送延迟一段时间,这个时间大概为40ms
A向B发送消息,B延迟40ms发送ACK(TCP确认延迟),由于B没有回复ACK,A不能发送下一条(Nagle),此时带来延迟
想深入理解Nagle和Tcp确认延迟的同学,推荐一篇非常好的文章,再探linux下的tcp延迟确认机制