非同步流複製模式如何保證不丟資料?

德哥發表於2017-05-04

標籤

PostgreSQL , 流複製 , 非同步 , 2PC , 3PC


背景

PostgreSQL支援多種事務commit模式,以一主多備的同步流複製為例,事務的REDO資訊持久化是怎樣的呢?

配置synchronous_commit引數如下,以及對應的含義:

local:表示REDO本地持久化。

on:表示本地持久化,以及一個備庫持久化。

remote_write:表示本地持久化,以及備庫非同步WRITE完成。

off:表示本地寫wal buffer完成。

quorum:表示本地持久化,同時加上備庫已持久化的個數,需要超過半數節點。

很顯然,如果只有一個備庫,並且synchronous_commit使用local模式的話,在發生HA時,不能保證不丟資料。

但是有什麼方法能做到只有一個備庫,並且synchronous_commit使用local模式,還能不丟資料呢?

2PC與LSN柵欄

兩階段提交(2PC),在很多分散式資料庫中,被用於確保分散式事務的一致性。

在單個資料庫中,也可以被業務用於多個事務之間的依賴保證。

實際上,如果你要保證事務提交後,在非同步的備庫也提交,也可以使用2PC來實現。

備庫延遲的判斷

首先我們要了解如何判斷備庫的延遲.

檢視當前資料庫的LSN位置。

# select pg_current_xlog_insert_location();  
 pg_current_xlog_insert_location   
---------------------------------  
 3F7/517DE940  
(1 row)  

檢視備庫接收並持久化的WAL LSN位置。

# select flush_location from pg_stat_replication ;  
 flush_location   
----------------  
 3F7/51EAE058  
(1 row)  

當 “備庫的LSN >= 當前主庫的LSN” 時,說明你前面提交的事務都已經同步到備庫了。

例子

主庫

產生一個2PC事務

postgres=# create table test(id int);  
CREATE TABLE  
postgres=# begin;  
BEGIN  
postgres=# insert into test values (1);  
INSERT 0 1  
postgres=# prepare transaction `2pctest`;  
PREPARE TRANSACTION  

檢視備庫LSN是否大於等於主庫當前的LSN

postgres=# select flush_location from pg_stat_replication ;  
 flush_location   
----------------  
 81/A601E170  
(1 row)  
  
postgres=# select pg_current_xlog_insert_location();  
 pg_current_xlog_insert_location   
---------------------------------  
 81/A601E170  
(1 row)  

確保 備庫LSN是否大於等於主庫當前的LSN 後,關閉主庫(模擬主庫DOWN機)

pg_ctl stop -m fast  
waiting for server to shut down.... done  
server stopped  

檢視備庫現在有沒有未結束的2pc事務,當前還沒有啟用,所以看不到

postgres=# select * from pg_prepared_xacts ;  
 transaction | gid | prepared | owner | database   
-------------+-----+----------+-------+----------  
(0 rows)  

啟用備庫

pg_ctl promote  
server promoting  

再次檢視備庫,未提交的2PC出現了。

psql  
psql (9.4.1)  
Type "help" for help.  
  
postgres=# select * from pg_prepared_xacts ;  
 transaction |   gid   |           prepared           |  owner   | database   
-------------+---------+------------------------------+----------+----------  
   115258352 | 2pctest | 2017-05-04 19:42:51.32323+08 | postgres | postgres  
(1 row)  

你要做的是提交或回滾這些2PC事務即可。

使用這種方式,我們在非同步的流複製節點中,也可以做到不丟事務。(雖然這麼做比較繁瑣。)

對於非常關鍵的事務,你可以通過以上方式來實現非同步複製也不丟資料。

事務級同步級別

實際上PostgreSQL的同步級別(synchronous_commit)可以配置在事務中,也就是說,可以對可靠性要求高的事務,設定為同步模式。

對於可靠性要求低的事務,設定為非同步模式。

例子,設定事務為同步模式。

begin;  
set local synchronous_commit=on;  -- 同步模式  
....  
end;  

例子,設定事務為非同步模式。

begin;  
set local synchronous_commit=local;  -- 非同步模式  
....  
end;  

參考

《PostgreSQL 10.0 preview 功能增強 – slave支援WAITLSN `lsn`, time;用於設定安全replay柵欄》

https://www.postgresql.org/docs/9.6/static/sql-prepare-transaction.html

https://www.postgresql.org/docs/9.6/static/sql-commit-prepared.html

https://www.postgresql.org/docs/9.6/static/sql-rollback-prepared.html

https://www.postgresql.org/docs/9.6/static/view-pg-prepared-xacts.html


相關文章