bigpyer 360雲計算 redis
在上一篇文章《pika主從複製原理之binlog》中介紹了主從複製binlog的元信息、日誌的格式及對應的api,本篇介紹下主從複製有關的線程、全量複製過程、增量複製過程。本文一樣出自小米的公司的bigpyer,感謝他的分享!
PS:豐富的一線技術、多元化的表現形式,盡在「HULK一線技術雜談」,點關注哦!api
pika 是 360 Web 平臺部 DBA 與基礎架構組合做開發的大容量類 Redis 存儲,pika 的出現並非爲了替代 Redis,而是 Redis 的場景補充。pika 力求在徹底兼容 Redis 協議、繼承 Redis 便捷運維設計的前提下經過持久化存儲的方式解決 Redis 在大容量場景下的問題,如恢復時間慢、主從同步代價高、單線程相對脆弱、承載數據較有限、內存成本高昂等。架構
PikaBinlogReceiverThread: 系統啓動時初始化,佔用端口port+1000,做爲Slave接收Master同步過來的Redis命令。併發
PikaHeartbeatThread: 系統啓動時初始化,佔用端口port+2000,做爲Master接收Slave發送的ping、spci指令,對全部Slave進行存活檢測。運維
PikaTrysyncThread: 系統啓動時初始化,無角色,執行slaveof host port命令對應的後臺任務包括按期檢查是否須要跟某個Master創建鏈接、db替換、啓動或關閉rsync任務等,當啓動rsync服務時,佔用端口port+3000。ide
PikaSlavepingThread: 成爲某個Master的Slave後,做爲Slave的一方初始化,定時向Master發送ping、spci指令,若是超時超過30秒,生成之後關閉Master的後臺任務,由PikaBinlogReceiverThread來執行。函數
BinlogBGWorker: 系統啓動時初始化,每一個BinlogBGWorker包含一個binlogbg_thread,做爲Slave的後臺執行模塊,接收PikaBinlogReceiverThread的調度、執行具體的redis命令。雲計算
PikaBinlogSenderThread: 成爲某個Slave的Master後,做爲Master的一方初始化,根據slave傳過來的filenum、offset消費日誌,併發送到PikaBinlogReceiverThread所在的服務端口。線程
//初始化 int Thread::InitHandle() //執行線程內的定時任務 void Thread::CronHandle() //建立線程,調用RunThread() int Thread::StartThread() //處理邏輯入口函數 void *Thread::RunThread(void *arg)
virtual int InitHandle()設計
virtual void *ThreadMain()
//執行後臺任務,PikaSlavepingThread檢測到應該退出或者主掛掉時,添加Kill PikaBinlogSenderThread後臺任務。 void PikaBinlogReceiverThread::CronHandle()
int PikaMasterConn::DealMessage()
void Schedule()
void BinlogBGWorker::DoBinlogBG(void* arg)
1.若是是slaveof no one,中止rsync服務,刪除master,replstate = PIKA_REPL_NO_CONNECT,role=master
2.若是slaveof ip port filenum offset,則將filenum以前的binlog刪除,同時若是filenum存在,則將offset以前的文件內容填充空格。
3.role更新爲slave,repl_state更新爲PIKA_REPL_CONNECT,應答成功。
//後臺任務部分
4.PikaTrysyncThread檢測到repl_state==PIKA_REPL_CONNECT,在端口port+3000啓動rsync服務,準備接受master的db內容。
5.slave創建與master的鏈接,若是有auth,則主動發送auth命令。
6.發送trysync命令,主動要求master進行數據同步。
7.若是master應答結果爲kInnerReplWait,則replstate = PIKA_REPL_WAIT_DBSYNC。
8.slave會一直等待,直到db_sync_path目錄下存在info文件時,用新的db替換以前的db,根據info中的filenum、offset更新slave對應的filenum、offset,重置replstate = PIKA_REPL_CONNECT
9.再次執行3-6步驟,master應答kInnerReplOk,更新replstate = PIKA_REPL_CONNECTING,停掉rsync服務,建立PikaSlavepingThread,在PikaSlavepingThread ping master成功之後更新replstate = PIKA_REPL_CONNECTED,主從同步正式創建。
1.根據slave的ip、port構造slave的惟一標識,stage=SLAVE_ITEM_STAGE_ONE。
2.若是master沒有找到slave傳過來的filenum,則執行bgsave,生成一份db鏡像和info信息,經過rsync傳給slave,並清理掉master的臨時文件
3.根據slave的ip、port,bgsave的filenum、offset構建PikaBinlogSenderThread
4.過濾binlog中可能已經損壞的內容(什麼場景可能會用到?可能主從數據不一致嗎?)
5.更新role_ = PIKA_ROLE_MASTER,PikaSlavepingThread第二次存活檢測時發送spci命令,主根據PikaBinlogSenderThread,更新stage=SLAVE_ITEM_STAGE_TWO,主從同步正式創建。
我的認爲主從複製是pika裏面體量最大也是最複雜的一個模塊,經過採用了相似LevelDB的WAL日誌的方式,固然因爲redis命令的問題,這個日誌非冪等的,不是爲了在啓動時重放,而是解決了redis中增量複製buffer被打滿的問題。
原文地址:
http://www.jianshu.com/p/d969b6f6ae42?utm_campaign=hugo&utm_medium=reader_share&utm_content=note&utm_source=qq