標籤:
原文地址:http://blog.sina.com.cn/s/blog_7530db6f0100vegl.html
一,  實現原理圖
(1)Slave伺服器串連到Master伺服器.
(2)Slave伺服器發送SYCN命令.
(3)Master伺服器備份資料庫到.rdb檔案.
(4)Master伺服器把.rdb檔案傳輸給Slave伺服器.
(5)Slave伺服器把.rdb檔案資料匯入到資料庫中.
 
上面的這5步是同步的第一階段, 接下來在Master伺服器上調用每一個命令都使用replicationFeedSlaves()來同步到Slave伺服器.
 
 二,  實現細節
(1) Slave伺服器串連到Master伺服器 / 發送SYNC命令:
Slave伺服器通過syncWithMaster()函數來串連Master伺服器(如果Master伺服器要求輸入密碼登陸的話, 先登陸), 並且發送SYNC命令請求同步, 接著開啟rdb檔案(用於儲存由Master發送過來的資料), 建立讀rdb的IO事件(readSyncBulkPayload). 代碼如下:
int syncWithMaster(void) {
......
//登陸master伺服器
if(server.masterauth) {
syncWrite(fd, "AUTH xxx\r\n", strlen(server.masterauth)+7, 5);
......
}
//發送SYNC命令
syncWrite(fd,"SYNC \r\n",7,5);
......
//開啟rdb檔案
dfd = open(tmpfile,O_CREAT|O_WRONLY|O_EXCL,0644);
......
//建立讀rdb的IO事件
aeCreateFileEvent(server.el, fd, AE_READABLE, readSyncBulkPayload, NULL);
......
return REDIS_OK;
}
 
(2) Master伺服器備份資料庫到.rdb檔案:
當Slave伺服器發送SYNC命令到Master伺服器時, Master伺服器便會調用syncCommand()函數來進行同步. 同步的第一步是把資料庫的資料存放區為rdb檔案, 儲存完畢後調用updateSlavesWaitingBgsave()函數來發送rdb檔案給所有的Slave伺服器.代碼如下:
void syncCommand(redisClient *c) {
    //如果正在儲存rdb檔案
if (server.bgsavechildpid != -1) {
    ......
    //主要判斷當前儲存rdb檔案是不是由SYNC命令觸發的
    //如果當前儲存rdb檔案不是由SYNC命令觸發, 則要等到下一次
    ......
} else {//否則調用rdbSaveBackground()儲存rdb檔案
    rdbSaveBackground(server.dbfilename);
}
}
 
當rdbSaveBackground()函數執行完畢, 就會調用updateSlavesWaitingBgsave()來發送rdb檔案到所有的Slave伺服器, 代碼如下:
void updateSlavesWaitingBgsave(int bgsaveerr) {
    listRewind(server.slaves,&li);
while((ln = listNext(&li))) {
    slave->repldbfd = open(server.dbfilename,O_RDONLY);
    .......
    aeCreateFileEvent(server.el,slave->fd,AE_WRITABLE, sendBulkToSlave,slave);
}
}
    updateSlavesWaitingBgsave()要做的事情是, 開啟rdb檔案, 建立發送rdb檔案IO事件(sendBulkToSlave). 而sendBulkToSlave()主要的工作就是把rdb檔案發送給Slave伺服器.
    而當Slave伺服器接收rdb檔案完畢之後(readSyncBulkPayload()函數處理), 會清空原來資料庫的資料, 然後把rdb檔案的資料匯入到資料庫中.
 
(3) 增量同步處理
完成上面的步驟之後, 同步基本完成. 接下來的工作就是增量同步處理, 也就是當Master伺服器有資料更新的時候, 會立刻
Redis主從實現原理分析 [轉]