從一個群友問題看流複製實現原理
來源:PostgreSQL學徒
前言
這個問題是前幾天②群一位群友問的
問個問題,未提交得事務,WAL也會同步到從節點嗎?
當時我的回覆是:"嗯,然後根據commit和rollback,我下來確認一下"。藉著這個問題,我又重新思考了一下流複製的原理🤔,又有了一些新的思考,甚好甚好。
分析
首先這個問題的答案無疑,是肯定會同步到從節點,這一點和邏輯複製有所不同,之前也寫過一篇邏輯複製處理大事務的演進,在14版本邏輯複製才正式引入了"流式"傳輸,即未提交的事務也會流式傳輸到訂閱端,以前都是直到事務提交時才會一股腦傳送至訂閱端,所以碰到大事務就歇菜。
但是,流複製和邏輯複製有所不同,這一點其實很好驗證 (以下截圖左邊是主庫,右邊是備庫):
主庫在事務內做建表、插入等操作,但是事務還未提交。👆🏻可以看到,備庫中pg_waldump可以解析到mytest表的oid,以及插入操作。最後,隨著主庫的提交或者回滾以決定元組的可見性,主庫提交備庫也提交,主庫回滾備庫也相應回滾。
現在我們新插入一條資料,各位可以看到,備庫 startup 也"及時"回放到頁面上了。但是主庫上由於事務還未提交,因此備庫不可見,但是底層資料塊上已經有這條資料了,說明startup程式已經及時回放了這條WAL。
因此,備庫也會產生死元組 (update、delete、事務回滾等),也需要相應進行 VACUUM,移除死元組,從而導致流複製場景中一個很常見的衝突——snapshot conflict,即快照衝突,備庫查詢需要的行版本被 VACUUM 移除了,從而報錯:User query might have needed to see row versions that must be removed.
所以,一環扣一環,從很多平時細節,我們就可以倒推出這個原理。我們不如通俗地理解成:備庫按部就班,原模原樣復刻主庫的操作。主庫回滾我就回滾,主庫刪除我就刪除,也正是這種資料塊級別的物理複製機制,使得流複製有著其獨特的優勢——一致性。
深入剖析
作為一名鹹魚DBA,需要有打破砂鍋問到底的精神,我們不妨思考一下,PostgreSQL的流複製原理,底層是如何實現的?此處站在巨人的肩膀上——SUZUKI,內幕指南已經更新了流複製章節,我也很早就看了,,其中也有介紹流複製的傳輸細節:
(1) The backend process writes and flushes WAL data to a WAL segment file by executing the functions XLogInsert() and XLogFlush(). (2) The walsender process sends the WAL data written into the WAL segment to the walreceiver process. (3) After sending the WAL data, the backend process continues to wait for an ACK response from the standby server. More precisely, the backend process gets a latch by executing the internal function SyncRepWaitForLSN(), and waits for it to be released. (4) The walreceiver on the standby server writes the received WAL data into the standby's WAL segment using the write() system call, and returns an ACK response to the walsender. (5) The walreceiver flushes the WAL data to the WAL segment using the system call such as fsync(), returns another ACK response to the walsender, and informs the startup process about WAL data updated. (6) The startup process replays the WAL data, which has been written to the WAL segment. (7) The walsender releases the latch of the backend process on receiving the ACK response from the walreceiver, and then, the backend process's commit or abort action will be completed. The timing for latch-release depends on the parameter synchronous_commit. It is 'on' (default), the latch is released when the ACK of step (5) received, whereas it is 'remote_write', the latch is released when the ACK of step (4) is received.
翻譯一下
後端程式透過執行XLogInsert和XLogFlush函式,將WAL資料寫入並重新整理到WAL段檔案中。 walsender程式將寫入WAL段的WAL資料傳送給walreceiver程式。 傳送WAL資料後,後端程式繼續等待備用伺服器的ACK響應。更準確地說,後端程式透過執行內部函式SyncRepWaitForLSN獲得一個latch,並等待它被釋放。 備用伺服器上的walreceiver將接收到的WAL資料寫入備用的WAL段中,使用write系統呼叫,並向walsender返回一個ACK響應。 walreceiver使用如fsync等系統呼叫將WAL資料重新整理到WAL段,向walsender返回另一個ACK響應,並通知啟動程式關於WAL資料的更新。 startup程式回放已寫入WAL段的WAL資料。 當walsender收到來自walreceiver的ACK響應時,釋放後端程式的 latch,然後後端程式的提交或中止操作將完成。latch釋放的時機取決於引數synchronous_commit。如果設為on (預設值),當收到步驟(5)的ACK時釋放latch;如果設為remote_write,則在收到步驟(4)的ACK時釋放latch。
每一個ACK都包括
The LSN location where the latest WAL data has been written. The LSN location where the latest WAL data has been flushed. The LSN location where the latest WAL data has been replayed in the startup process. The timestamp when this response has be sent.
根據上述傳輸細節,我們便可以對這個案例進行理解剖析了:
主庫上的程式寫操作 產生WAL record walsender感知到新的WAL,傳送給備庫, 備庫接受,寫盤,再回放
因此準確來說,是否傳送WAL與主庫的事務是否提交與否沒有關係,但主庫的事務能否提交卻取決於備庫的WAL寫到了哪裡(預設是on的話,就需要落盤),即同步級別,備庫會實時回放。
至於latch,此次PostgreSQL生態大會上,文一也做了介紹,流複製就是藉助latch實現主從程式間的協作。
小結
不難理解,流複製以低延時(相對)著稱,是否傳送WAL與主庫的事務是否提交與否沒有關係,但主庫的事務能否提交取決於備庫的WAL寫到了哪裡(synchronous_commit),假如還要等待事務提交的時候,才將所有的WAL傳送,那麼無疑延遲會很大,這也體現不了物理複製的優勢。
不過值得注意的是,流複製場景下,只讀事務、子事務的提交以及事務回滾,無需等待備庫的ACK。
Read-only transactions and transaction rollbacks need not wait for replies from standby servers. Subtransaction commits do not wait for responses from standby servers, only top-level commits. Long running actions such as data loading or index building do not wait until the very final commit message. All two-phase commit actions require commit waits, including both prepare and commit.
最後,再次推薦各位閱讀一下SUZUKI大師的最新流複製章節,相信會有更多理解。
參考
文一 PostgreSQL Latch 簡介:一種事件實現機制
Streaming Replication
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024923/viewspace-2999652/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Mysql實現主從複製(一主雙從)MySql
- mysql的主從複製延遲問題--看這一篇就夠了MySql
- MYSQL一個裝置上的主從複製實現-windowsMySqlWindows
- mysql實現主從複製MySql
- redis 主從複製實現Redis
- MySQL主從複製問題解決一例MySql
- MySQL主從複製原理MySql
- Redis 主從複製原理Redis
- docker實現mysql主從複製DockerMySql
- MySQL叢集之 主從複製 主主複製 一主多從 多主一叢 實現方式MySql
- MySQL之 從複製延遲問題排查MySql
- Linux實現MySql資料庫的主從複製(一主一從)LinuxMySql資料庫
- 面試官:請講一下Redis主從複製的功能及實現原理面試Redis
- Redis主從複製原理剖析Redis
- MySQL全面瓦解27:主從複製(原理 + 實踐)MySql
- mysql主從複製配置與問題解決MySql
- redis-25.主從複製-常見問題Redis
- 主從複製是啥或者主從複製的原理是什麼?
- 簡單實踐實現 MySQL 主從複製MySql
- 從 MySQL 到 ClickHouse 實時複製與實現MySql
- golang拾遺:實現一個不可複製型別Golang型別
- ZeroClipboard 多個複製按鈕,多個複製連結 實現方式
- 詳談Redis主從複製原理Redis
- redis的主從複製的原理Redis
- Mysql主從複製原理及搭建MySql
- MySQL 主從複製原理不再難MySql
- Redis 主從複製技術原理Redis
- MySQL(13)---MYSQL主從複製原理MySql
- mysql資料庫實現主從複製MySql資料庫
- 如何解決MySQL主從複製太慢的問題MySql
- js 實現深複製/深複製JS
- mysql的主從複製 原理講解MySql
- 深入挖崛:mysql主從複製原理MySql
- Redis replication主從複製原理及配置Redis
- mysql 5.7 主從複製搭建及原理MySql
- mysql 複製原理與實踐MySql
- 【PG流複製】Postgresql流複製主備切換SQL
- 實現一個可定製化的FlowLayout -- 原理篇