1. 流復制和邏輯復制的差異
- 邏輯復制和流復制最直觀的不同是,邏輯復制支持表級別復制
- 區分點事原理不同
-
- 邏輯日志是在wal日志產生的數據庫上,由邏輯解析模塊對wal日志進行初步的解析,解析結果是ReorderBufferChange(理解為HeapTupleData),再由pgoutput plugin對中間結果進行過濾和消息化拼接,然后將其發送到訂閱端,訂閱端根據接受到的Heap TupleData重新對其執行insert、delete、udpate操作
- 流復制時將數據從walrecord拷貝到數據頁,
- 邏輯復制時將數據重新執行一次insert、update或delete
2. 流復制
- 流復制面對未提交的事務,事務沒有提交也會同步到備機,當主庫進行提交和回滾的時候,也會同步進行提交和回滾。對大事務相對友好
- 流復制會導致備機也會產生大量死元祖,需要做vacuum
- 流復制時將wal日志中記錄的內容按照確切的塊地址逐字節的拷貝到備庫,因此主備之間數據分布是一樣的,意味著主備機器上,同一條記錄的ctid是相同的
3. 流復制的實現原理
- 后端進程通過執行XLogInsert和XLogFlush函數,將wal數據寫入并刷新到WAL段文件中
- walsender進程將寫入wal段的wal數據發送給walreveiver進程
- 發送wal數據后,后端進程繼續等待備用服務器的ACK響應。更準確的說,后端進行通過執行內部函數SyncRepWaitForLSN獲得一個latch,并等待他被釋放
- 備用服務器上的walreveiver將接受到的wal數據寫入備用的wal段中,使用write系統調用,并向walsender返回一次ACK響應
- walreveiver使用如fsync等系統調用將wal數據刷新到wal段,向walsender返回另一個ACK響應,并通知啟動進程關于wal數據的刷新
- startup進程回訪已寫入wal段的wal數據
- 當walsender收到walreveiver的ack響應時,釋放后端進程的latch,然后后端進程的提交或中止操作將完成。latch釋放的時機取決于參數synchronous_commit,如果設置為on,當收到步驟5的ACK時釋放latch,如果設置為remote_wirte,則在收到步驟3的ACK時釋放latch
ACK的包括內容
- 寫入最新wal數據的lsn位置
- 刷新最新wal數據的lsn位置
- 在啟動過程中回放最新wal數據的lsn位置
- 發送此響應的時間戳
過程分析
- 主庫的進程進行寫操作
- 產生WAL record
- walsender感知到新的wal,發送給備庫
- 備庫接受,寫盤再回放
是否發送wal日志與主庫事務的提交與否沒有關系,但主庫是否能提交取決于備庫的wal日志寫入位置,默認是on的話需要落盤,備庫實時回放
注意點
- 流復制就是借助latch實現主從進程間的協作
- 流復制場景下,只讀事務、子事務的提交以及事務回滾,無需等待備庫的ACK