原文出處 http://mysql.taobao.org/monthly/2015/10/04/mysql
PostgreSQL在9.0以後引入了主備流複製機制,經過流複製,備庫不斷的從主庫同步相應的數據,並在備庫apply每一個WAL record,這裏的流複製每次傳輸單位是WAL日誌的record。而PostgreSQL9.0以前提供的方法是主庫寫完一個WAL日誌文件後,才把WAL日誌文件傳送到備庫,這樣的方式致使主備延遲特別大。同時PostgreSQL9.0以後提供了Hot Standby,備庫在應用WAL record的同時也可以提供只讀服務,大大提高了用戶體驗。sql
PG主備流複製的核心部分由walsender,walreceiver和startup三個進程組成。
walsender進程是用來發送WAL日誌記錄的,執行順序以下:app
PostgresMain()->exec_replication_command()->StartReplication()->WalSndLoop()->XLogSendPhysical()
walreceiver進程是用來接收WAL日誌記錄的,執行順序以下:框架
sigusr1_handler()->StartWalReceiver()->AuxiliaryProcessMain()->WalReceiverMain()->walrcv_receive()
startup進程是用來apply日誌的,執行順序以下:ide
PostmasterMain()->StartupDataBase()->AuxiliaryProcessMain()->StartupProcessMain()->StartupXLOG()
下圖是PG主備整體框架圖:函數
walsender和walreceiver交互主要分爲如下幾個步驟:oop
startup進程進入standby模式和apply日誌主要過程:spa
對讀取的WAL record進行redo,經過record->xl_rmid
信息,調用相應的redo資源管理器進行redo操做。好比heap_redo的XLOG_HEAP_INSERT操做,就是經過record的信息在buffer page中增長一個record:日誌
MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData)); /* PG73FORMAT: get bitmap [+ padding] [+ oid] + data */ memcpy((char *) htup + offsetof(HeapTupleHeaderData, t_bits), (char *) xlrec + SizeOfHeapInsert + SizeOfHeapHeader, newlen); newlen += offsetof(HeapTupleHeaderData, t_bits); htup->t_infomask2 = xlhdr.t_infomask2; htup->t_infomask = xlhdr.t_infomask; htup->t_hoff = xlhdr.t_hoff; HeapTupleHeaderSetXmin(htup, record->xl_xid); HeapTupleHeaderSetCmin(htup, FirstCommandId); htup->t_ctid = xlrec->target.tid; offnum = PageAddItem(page, (Item) htup, newlen, offnum, true, true); if (offnum == InvalidOffsetNumber) elog(PANIC, "heap_insert_redo: failed to add tuple"); freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */ PageSetLSN(page, lsn); if (xlrec->flags & XLOG_HEAP_ALL_VISIBLE_CLEARED) PageClearAllVisible(page); MarkBufferDirty(buffer);
還有部分redo操做(vacuum產生的record)須要檢查在Hot Standby模式下的查詢衝突,好比某些tuples須要remove,而存在正在執行的query可能讀到這些tuples,這樣 就會破壞事務隔離級別。經過函數ResolveRecoveryConflictWithSnapshot檢測衝突,若是發生衝突,那麼就把這個query所在的進程kill掉。
5. 檢查一致性,若是一致了,Hot Standby模式能夠接受用戶只讀查詢;更新共享內存中XLogCtlData的apply位點和時間線;若是恢復到時間點,時間線或者事務id須要檢 查是否恢復到當前目標;
6. 回到步驟3,讀取next WAL record。code