Redis源码分析:主从复制

源码版本:Redis 2.4.4

redis的主从复制实现简单却功能强大,其具有以下特点:
1. 一个master支持多个slave连接,slave可以接受其他slave的连接
2. 主从同步时,master和slave都是非阻塞的

redis主从复制可以用来:
1. data redundancy
2. slave作为master的扩展,提供一些read-only的服务
3. 可以将数据持久化放在slave做,从而提升master性能

通过简单的配置slave(master端无需配置),用户就能使用redis的主从复制
相关配置(redis.conf):
slaveof <masterip> <masterport>
表示该redis服务作为slave,masterip和masterport分别为master 的ip和port

masterauth
<master-password>
如果master设置了安全密码,则此处设置为相应的密码

slave-serve-stale-data yes
当slave丢失master或者同步正在进行时,如果发生对slave的服务请求:
slave-serve-stale-data设置为yes则slave依然正常提供服务
slave-serve-stale-data设置为no则slave返回client错误:"SYNC with master in progress"

repl-ping-slave-period 10
slave发送PINGS到master的时间间隔

repl-timeout 60
IO超时时间


代码:
slave端
slave状态:
/* Slave replication state - slave side */
#define REDIS_REPL_NONE 0 /* No active replication */
#define REDIS_REPL_CONNECT 1 /* Must connect to master */
#define REDIS_REPL_CONNECTING 2 /* Connecting to master */
#define REDIS_REPL_TRANSFER 3 /* Receiving .rdb from master */
#define REDIS_REPL_CONNECTED 4 /* Connected to master */
初始化时设置
server.replstate = REDIS_REPL_CONNECT
即slave需要连接master
slave周期性调用replicationCron,查看slave状态:

[cpp]

void replicationCron(void) {       /*判断是否IO超时*/       if (server.masterhost && server.replstate == REDIS_REPL_TRANSFER &&           (time(NULL)-server.repl_transfer_lastio) > server.repl_timeout)       {           redisLog(REDIS_WARNING,"Timeout receiving bulk data from MASTER...");           replicationAbortSyncTransfer(); //终止连接,并设置server.replstate = REDIS_REPL_CONNECT;        }          /* Timed out master when we are an already connected slave? */       if (server.masterhost && server.replstate == REDIS_REPL_CONNECTED &&           (time(NULL)-server.master->lastinteraction) > server.repl_timeout)       {           redisLog(REDIS_WARNING,"MASTER time out: no data nor PING received...");           freeClient(server.master);       }          /* Check if we should connect to a MASTER */       if (server.replstate == REDIS_REPL_CONNECT) {           redisLog(REDIS_NOTICE,"Connecting to MASTER...");           if (connectWithMaster() == REDIS_OK) { //连接master                redisLog(REDIS_NOTICE,"MASTER <-> SLAVE sync started");           }       }              /* If we have attached slaves, PING them from time to time.       * So slaves can implement an explicit timeout to masters, and will       * be able to detect a link disconnection even if the TCP connection       * will not actually go down. */       if (!(server.cronloops % (server.repl_ping_slave_period*10))) {           listIter li;           listNode *ln;              listRewind(server.slaves,&li);           while((ln = listNext(&li))) {               redisClient *slave = ln->value;                  /* Don't ping slaves that are in the middle of a bulk transfer               * with the master for first synchronization. */               if (slave->replstate == REDIS_REPL_SEND_BULK) continue;               if (slave->replstate == REDIS_REPL_ONLINE) {                   /* If the slave is online send a normal ping */                   addReplySds(slave,sdsnew("PING\r\n"));               } else {                   /* Otherwise we are in the pre-synchronization stage.                   * Just a newline will do the work of refreshing the                   * connection last interaction time, and at the same time                   * we'll be sure that being a single char there are no                   * short-write problems. */                   if (write(slave->fd, "\n", 1) == -1) {                       /* Don't worry, it's just a ping. */                   }               }           }       }   }  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/pxwgp.html