PostgreSQL技術大講堂 - 第44講:pg流復制部署

2024年2月6日 19点热度 0人点赞

PostgreSQL從小白到專傢,是從入門逐漸能力提升的一個系列教程,內容包括對PG基礎的認知、包括安裝使用、包括角色權限、包括維護管理、、等內容,希望對熱愛PG、學習PG的同學們有幫助,歡迎持續關註CUUG PG技術大講堂。

第44講:流復制部署

PostgreSQL第44講:2月3日(周六)19:30,釘釘群(35822460)& 視頻號(數據庫老陳)直播“老陳和德哥pg流復制部署現場等你來...”

內容1:流復制部署

流復制部署手冊

一 主備機器規劃主機名

角色 主機名 ip

Maswer: Pg1 192.168.18.211

Slave: Pg2 192.168.18.212

PG版本:

用源碼編譯安裝的12.2版本

二 創建流復制

2.1 設置host

master,slave兩節點都要操作。

# vim /etc/hosts

#編輯內容如下:

192.168.18.211 pg1

192.168.18.212 pg2

2.2 在主庫設置

2.2.1先初始化新數據庫

$ initdb -D /usr/local/pg12.2/data -U postgres --data-checksums

2.2.2啟動數據庫並建立同步用戶

$pg_ctl -D /usr/local/ pg12.2/data start

創建用戶:create role 同步用的用戶名 login replication encrypted password '密碼';

postgres=# create role repl login replication encrypted password 'repl';

CREATE ROLE

postgres=#\q --退出psql

2.2.3配置$PGDATA/data/pg_hba.conf,添加下面內容:

格式:host replication 同步用的用戶名 備庫IP地址或域名/24 trust

2.2.4配置主備庫的postgres.con文件

因為以後要進行角色切換,所以現在都添加一樣的參數。

host replication repl pg2 trust

host replication repl 192.168.18.0/24 trust

host all all 192.168.18.0/24 trust

主庫配置~/data/postgres.conf 查找並修改成以下內容

listen_addresses = '*'

wal_level = replica --10以後的版本為replica 物理復制,有一定局限性,可以選擇邏輯復制logical

max_wal_senders=10 --流復制允許連接進程,主備庫這個參數值必須一樣

wal_keep_segments =64

archive_mode = on -- 設置歸檔模式

archive_command = 'cp %p /home/postgres/arch/%f' --設置歸檔cp命令

listen_addresses = '*'

port = 1922

wal_level = logical

max_wal_senders=20

wal_keep_segments =64

archive_mode = on

archive_command = 'cp %p /home/postgres/arch/%f'

restore_command = 'cp /home/postgres/arch/%f %p'

recovery_target_timeline = 'latest'

log_destination = 'csvlog'

logging_collector = on

log_directory = 'pg_log' ##$PGDATA/pg_log

log_filename = 'postgresql-%Y-%m-%d'

log_truncate_on_rotation = off

log_rotation_age = 1d

log_rotation_size = 0

log_error_verbosity = verbose

log_statement = all

2.2.5重啟主庫服務,以更新配置

$pg_ctl -D ~/data/ -l ~/log/pglog.log restart

2.3 在備庫設置

2.3.1不需要初始化,直接從主庫備份就行,如有DATA直接刪掉或改名掉:

$ pg_basebackup -h pg1 -p 1922 -U repl -R -F p -P -D $PGDATA

備註:

-h,主庫主機,-p,主庫服務端口;

-U,復制用戶;

-F,p是默認輸出格式,輸出數據目錄和表空間相同的佈局,t表示tar格式輸出;

-P,同--progress,顯示進度;

-D,輸出到指定目錄;

-R 創建一個recovery.conf文件,10版本後就沒有該文件,改為standby.signal文件,需要自己創建,所以該參數可以省略

如果報錯:

pg_basebackup: error: could not connect to server: could not connect to server: No route to host Is the server running on host "pg1" (192.168.18.211) and accepting TCP/IP connections on port 1922?

解決方法:發現是系統防火墻的問題:

# 查看防火墻狀態

service iptables status

systemctl stop firewalld --centos 7

systemctl disable firewalld --centos 7

# 停止防火墻

service iptables stop

# 永久關閉防火墻

chkconfig iptables off

2.3.2備庫修改配置文件(由於是從主庫備份過來的,配置文件也修改了)

postgres@NanoPI-006:~$vi ~/data/postgresql.conf

添加以下內容

listen_addresses = '*'

wal_level = replica

max_wal_senders=20

wal_keep_segments =64

archive_mode = on

archive_command = 'cp %p /home/postgres/arch/%f'

restore_command = 'cp /home/postgres/arch/%f %p'

recovery_target_timeline = 'latest'

full_page_writes = on

wal_log_hints = on

hot_standby = on #在同步的同時允許查詢,默認值


max_standby_streaming_delay = 30s #可選,流復制最大延遲


wal_receiver_status_interval = 10s #可選,從向主報告狀態的最大間隔時間

hot_standby_feedback = on #可選,查詢沖突時向主反饋

2.3.3配置~/data/pg_hba.conf

添加下面內容

host replication repl 192.168.18.0/24 trust

host all all 192.168.18.0/24 trust

#在備庫中維護的主庫IP地址是為了以後切換使用

2.3.4、創建備庫文件standby.signal

primary_conninfo = 'host=pg1 port=1922 user=repl password=repl options=''-c wal_sender_timeout=5000'''

restore_command = 'cp /home/postgres/arch/%f %p'

archive_cleanup_command = 'pg_archivecleanup /home/postgres/arch %r'

standby_mode = on

第一行參數:#連接到主庫信息

第二行參數:將來變成主庫時需要用到的參數。

第三行參數:變成主庫後需要清空的歸檔日志。

第四行參數:把備庫變成read-only transaction模式,不允許進行寫操作。允許查詢。這一點非常好。

2.3.5啟動備庫數據服務

$pg_ctl -D $PGDATA -l ~/log/pglog.log start

增加日志輸出設置,從而獲得更多的信息。

三、驗證

3.1、觀察主從兩庫的歸檔日志的位置,或者主庫兩邊的pg_wal目錄下的內容,發現主庫日志切換後,備庫pg_wal目錄下就會產生新的日志文件,但是在備庫的歸檔目錄下沒有內容,應該是主庫的歸檔日志傳遞到備庫的pg_wal目錄下了。

3.2、主庫修改後,日志沒有歸檔,但是備庫已經同步了,類似於oracle同步時用lgwr方式進行寫standby_logfile進行同步。

3.3、查看當前備庫狀態:

testdb=# select pg_is_in_recovery();

pg_is_in_recovery

-------------------

t

t :true,意味著處於recovery狀態

f :false,意味著處於正常服務狀態

主庫查詢:

testdb=# \x

testdb=# select * from pg_stat_replication;

-[ RECORD 1 ]---- ------------------------------

pid | 3711

usesysid | 16384

usename | repl

application_name | walreceiver

client_addr | 192.168.18.212

client_hostname | pg2

client_port | 49206

backend_start | 2020-03-03 22:08:47.924435-05

backend_xmin |

state | streaming

sent_lsn | 0/210000D8

write_lsn | 0/210000D8

flush_lsn | 0/210000D8

replay_lsn | 0/210000D8

write_lag |

flush_lag |

replay_lag |

sync_priority | 0

sync_state | async

reply_time | 2020-03-03 22:13:02.990258-05

#application_name 很重要,以後同步復制需要用到。

3.4、備庫數據庫日志內容:

cp: cannot stat `/home/postgres/arch/00000002.history': No such file or directory

cp: cannot stat `/home/postgres/arch/000000010000000000000009': No such file or directory

2020-02-29 04:48:45.734 EST [4938] FATAL: could not connect to the primary server: could not connect to server: Connection refused

Is the server running on host "pg1" (192.168.18.211) and accepting

TCP/IP connections on port 1922?

cp: cannot stat `/home/postgres/arch/00000002.history': No such file or directory

cp: cannot stat `/home/postgres/arch/000000010000000000000009': No such file or directory

2020-02-29 04:48:50.747 EST [4941] LOG: started streaming WAL from primary at 0/9000000 on timeline 1

如果主庫關閉,備庫數據庫日志內容:

cp: cannot stat `/home/postgres/arch/00000002.history': No such file or directory

cp: cannot stat `/home/postgres/arch/00000001000000000000000C': No such file or directory

2020-02-29 05:22:55.757 EST [5048] FATAL: could not connect to the primary server: could not connect to server: Connection refused

Is the server running on host "pg1" (192.168.18.211) and accepting

TCP/IP connections on port 1922?

cp: cannot stat `/home/postgres/arch/00000002.history': No such file or directory

3.5、主庫後臺進程:

ps -ef|grep "wal"

postgres 3753 3749 0 21:21 ? 00:00:00 postgres: walwriter

postgres 3844 3749 0 21:49 ? 00:00:00 postgres: walsender repl 192.168.18.212(33595) streaming 0/8000148

3.6、備庫後臺進程,一個進程負責接收,一個負責recovery:

ps -ef|grep postgres

postgres 3472 3471 0 21:49 ? 00:00:00 postgres: startup recovering 000000010000000000000008

postgres 3475 3471 0 21:49 ? 00:00:00 postgres: checkpointer

postgres 3476 3471 0 21:49 ? 00:00:00 postgres: background writer

postgres 3478 3471 0 21:49 ? 00:00:00 postgres: stats collector

postgres 3479 3471 0 21:49 ? 00:00:00 postgres: walreceiver streaming 0/8000148

四、主從切換

4.1、停掉主庫

pg_ctl stop -m fast

4.2、執行以下命令進行主從切換,把備庫改成主庫,執行之後發現standby.signal被刪除了:

pg_ctl promote

查看最新狀態:

pg_controldata | grep cluster

Database cluster state: in production

4.3、這一步非常關鍵,註意原來的備庫的postgresql.auto.conf文件中會自動添加一行primary_conninfo的信息,要把這一行給註釋掉,否則雖然現在是主庫了,但是配置還是當作備庫,自相矛盾,且在跟蹤日志中會報“background worker "logical replication launcher" (PID 6304) exited with exit code 1”錯誤。這可能是PG12.2的bug。

postgresql.auto.conf文件內容如下,註意下面內容隻是一行數據,/home/postgres/.pgpass其實沒有沒有這個文件,不需要創建:

primary_conninfo = 'user=repl passfile=''/home/postgres/.pgpass'' host=pg1 port=1922 sslmode=disable sslcompression=0 gssencmode=disable krbsrvname=postgres target_session_attrs=any'

重啟數據庫,查看後臺進程,實驗發現walsender進程要等備庫正常啟動後才會啟動,備庫關閉時該進程也自動中斷:

ps -ef|grep postgres |grep -v sshd |grep -v bash

postgres 3215 3164 0 Feb29 pts/3 00:00:00 tail -f pg_log

postgres 6329 1 0 07:08 ? 00:00:00 /usr/local/pg12.2/bin/postgres

postgres 6331 6329 0 07:08 ? 00:00:00 postgres: checkpointer

postgres 6332 6329 0 07:08 ? 00:00:00 postgres: background writer

postgres 6333 6329 0 07:08 ? 00:00:00 postgres: walwriter

postgres 6334 6329 0 07:08 ? 00:00:00 postgres: autovacuum launcher

postgres 6335 6329 0 07:08 ? 00:00:00 postgres: archiver

postgres 6336 6329 0 07:08 ? 00:00:00 postgres: stats collector

postgres 6337 6329 0 07:08 ? 00:00:00 postgres: logical replication launcher

postgres 6353 6329 0 07:12 ? 00:00:00 postgres: walsender repl 192.168.18.212(33609) streaming 0/1A01C7F8

4.4、在新備庫上創建一個standby.signal文件,添加如下內容:

primary_conninfo = 'host=pg2 port=1922 user=repl password=repl options=''-c wal_sender_timeout=5000'''

restore_command = 'cp /home/postgres/arch/%f %p'

archive_cleanup_command = 'pg_archivecleanup /home/postgres/arch %r'

standby_mode = on

4.5、在新備庫的postgresql.auto.conf文件中添加如下內容,這一步非常關鍵,第一次搭建備庫的時候會自動添加,但是切換後卻不能:

primary_conninfo = 'user=repl passfile=''/home/postgres/.pgpass'' host=pg2 port=1922 sslmode=disable sslcompression=0 gssencmode=disable krbsrvname=postgres target_session_attrs=any'

註意/home/postgres/.pgpass其實沒有沒有這個文件,不需要創建。

4.6、啟動新備庫:

pg_ctl start -l pg_log

4.7、查看後臺進程:

ps -ef|grep postgre |grep -v ssh |grep -v bash

postgres 3274 3237 0 Feb29 pts/3 00:00:00 tail -f pg_log

postgres 6441 1 0 07:12 ? 00:00:00 /usr/local/pg12.2/bin/postgres

postgres 6442 6441 0 07:12 ? 00:00:00 postgres: startup recovering 00000003000000000000001A

postgres 6447 6441 0 07:12 ? 00:00:00 postgres: checkpointer

postgres 6448 6441 0 07:12 ? 00:00:00 postgres: background writer

postgres 6450 6441 0 07:12 ? 00:00:00 postgres: stats collector

postgres 6451 6441 0 07:12 ? 00:00:05 postgres: walreceiver streaming 0/1A01C7F8

4.8、驗證主備庫是否能夠同步

在主庫進行dml操作,發現備庫能夠正常同步,切換成功。

4.9、主庫變成備庫時,有時候啟動會失敗,日志顯示找不到xxx.history日志文件,解決辦法,在postgresql.conf中指定明確的timeline,把原來的latest替換掉:

recovery_target_timeline = '3'

有時需要把缺少的文件復制到備庫的歸檔目錄下,比如xxxx.history文件。

總結:

經過實驗,發現主備切換不太靈活和智能,需要後續進行手動修改,特別是postgresql.auto.conf文件中自動添加的一行,在主備切換的時候不會自動刪除,沒有相關文檔,造成了隱性的問題,給DBA造成了很大的麻煩,不容易故障排除。

主庫在正常運行中,備庫可以隨意切換為主庫,沒有一個制約機制,感覺不嚴謹,此時變成兩個主庫,數據無法同步。如果此時兩邊的數據庫都各自發生變化,將來想把一臺主庫當作備庫,則需要在備庫上對當前的數據進行同步,然後就可以變成備庫,用以下的命令進行同步:

pg_rewind --target-pgdata $PGDATA --source-server='host=192.168.18.211 port=1922 user=postgres dbname=testdb'

pg_rewind: servers diverged at WAL location 0/1C01F280 on timeline 5

pg_rewind: rewinding from last common checkpoint at 0/1C01F1D0 on timeline 5

pg_rewind: Done!

五、pg_rewind工具

如果備庫是意外崩潰,如果新的主庫修改了數據,經過的時間很長,歸檔日志又刪除了,無法同步,原來的數據庫如果想變成備庫,需要對數據庫做一次同步,那麼就可以用到pg_rewind工具進行同步。

pg_rewind—使一個PostgreSQL數據目錄與另一個數據目錄(該目錄從第一個PostgreSQL數據目錄創建而來)一致。

描述

pg_rewind是一個在集群的時間線參數偏離之後,用於使一個PostgreSQL集群與另一個相同集群的拷貝同步的工具。一個典型的場景是在故障轉移之後,讓一個老的主服務器重新在線作為一個standby跟隨新主服務器。

其結果相當於使用源數據目錄替換目標數據目錄。所有的文件都被拷貝,包括配置文件。與做一個基礎備份或者像rsync這樣的工具相比,pg_rewind的優勢是pg_rewind不需要讀取所有集群中沒有更改的文件。當數據庫很大,並且隻有一小部分不同的集群之間,使它的速度快得多。

pg_rewind檢查源集群與目標集群的時間線歷史來檢測它們產生分歧的點,並希望在目標集群的pg_xlog目錄找到WAL回到分歧點的所有方式。在典型的故障轉移場景:目標集群在分歧之後立即被關閉,那是沒有問題的,但是,如果目標集群在分歧之後運行了很長一段時間,老的WAL文件可能不存在了。在這種情況下,它們可以手動從WAL歸檔復制到pg_xlog目錄。目前不支持從一個WAL歸檔中自動獲取丟失的文件。

在運行pg_rewind之後,當目標服務器第一次被啟動,它將進入恢復模式並重放從分歧點之後源服務器產生的所有WAL。當pg_rewind被運行時,如果一些 WAL在源服務器上不再可用,因此不能用pg_rewind回話復制,當目標服務器被啟動時時可以的。這可以通過在目標數據目錄創建一個帶有合適的restore_command命令的recovery.conf文件來實現。

選項

pg_rewind 接受下列命令行參數:

-D 目錄

--target-pgdata=目錄

該選項指定與源同步的目標數據目錄。

--source-pgdata=目錄

指定源服務器的數據目錄的路徑,以使目標數據目錄與之同步。當—source-pgdata被使用時,源服務器必須被關閉。

--source-server=連接字符串

指定一個libpq連接字符串以連接到源PostgreSQL服務器來使目標同步。服務器必須開啟並允許,並且不能處於恢復模式。

-n

--dry-run

做除了修改目標目錄的所有事情。

-P

--progress

開啟進程報告。在從源集群復制數據時,打開這個功能將提供一個近似的進 度報告。

--debug

打印詳細的調試輸出對開發者調試pg_rewind來說是非常有用的。

-V

--version

顯示版本信息並退出。

-?

--help

顯示幫助,然後退出

環境

當—source-server選項被使用時,pg_rewind也使用libpq支持的環境變量 (見31.14節)。

註意

pg_rewind需要啟用postgresql.conf中的wal_log_hints 選項,或者當集群被使用initdb初始化時啟用數據校驗。full_page_writes也必須啟用。

pg_rewind是如何工作的

基本的思想是從新的集群拷貝所有的東西到老的集群,除了我們知道的相同的(數據)塊。

1.從最後一個檢查點開始掃描老集群的WAL日志,在該檢查點之前,新集群的時間線歷史從老集群被創建出來。對於每一個WAL記錄,做一個數據塊被觸及的記錄。在新的集群被創建出來以後,這產生所有在老集群中被更改的數據塊的列表。

2.從新集群復制所有這些被更改的數據塊到老集群。

3.從新集群復制所有其它像clog,conf這樣的文件等等到老集群。每個文件,除了表文件。

4.從新集群應用WAL,從故障轉移創建的檢查點開始。(嚴格的說,pg_rewind不應用WAL,它隻是創建一個備份標簽文件以表明PostgreSQL被啟動了,它會從檢查點重放並應用所有需要的WAL)

2020-02-28 01:58:35.974 EST [16990] LOG: received promote request

2020-02-28 01:58:35.974 EST [16990] LOG: redo done at 0/50000028

2020-02-28 01:58:35.977 EST [16990] LOG: last completed transaction was at log time 2020-02-27 21:40:31.673922-05

cp: cannot stat `/home/postgres/arch/000000090000000000000050': No such file or directory

cp: cannot stat `/home/postgres/arch/0000000A.history': No such file or directory

2020-02-28 01:58:35.987 EST [16990] LOG: selected new timeline ID: 10

2020-02-28 01:58:36.090 EST [16990] LOG: archive recovery complete

cp: cannot stat `/home/postgres/arch/00000009.history': No such file or directory

2020-02-28 01:58:36.112 EST [16989] LOG: database system is ready to accept connections

五、實時同步

上面的配置是異步同步,對於主庫的性能影響是最小的,但是會丟數據,我們可以把復制配置成實時同步。

當設置同步復制時,盡量記住以下幾點:

最小化延遲

確保您有冗餘延遲

同步復制比異步復制代價更高

同步時是通過一個關鍵的參數application_name來實現的。

5.1、配置主庫postgres.conf,添加如下內容:

synchronous_standby_names = 'standby_pg2'

synchronous_commit = on --默認值,可以設置為remote_write,對主庫性能有利

5.2、重啟主庫

5.3、修改備庫standby.signal配置文件,在原來的內容中添加application_name內容:

primary_conninfo = 'host=pg1 application_name=standby_pg2 port=1922 user=repl password=oracle options=''-c wal_sender_timeout=5000'''

restore_command = 'cp /home/postgres/arch/%f %p'

archive_cleanup_command = 'pg_archivecleanup /home/postgres/arch %r'

standby_mode = on

5.4、修改備庫postgresql.auto.conf,添加application_name內容,實際上備庫是以這個文件為主,上面修改的standby.signal並不生效:

primary_conninfo = 'user=repl passfile=''/home/postgres/.pgpass'' host=pg1 application_name=standby_pg2 port=1922 sslmode=disable sslcompression

=0 gssencmode=disable krbsrvname=postgres target_session_attrs=any'

5.5、重啟備庫,查看後臺日志信息:

consistent recovery state reached at 0/21000188

invalid record length at 0/210001C0: wanted 24, got 0

database system is ready to accept read only connections

started streaming WAL from primary at 0/21000000 on timeline 6

5.6、在主庫查看同步狀態:

postgres=# \x --以行形式顯示,類似於mysql的\G

postgres=# SELECT * FROM pg_stat_replication;

-[ RECORD 1 ]---- ------------------------------

pid | 3732

usesysid | 16384

usename | repl

application_name | standby_pg2

client_addr | 192.168.18.212

client_hostname | pg2

client_port | 49207

backend_start | 2020-03-03 22:14:24.010759-05

backend_xmin |

state | streaming

sent_lsn | 0/210001C0

write_lsn | 0/210001C0

flush_lsn | 0/210001C0

replay_lsn | 0/210001C0

write_lag |

flush_lag |

replay_lag |

sync_priority | 1

sync_state | sync

reply_time | 2020-03-03 22:14:44.126791-05

狀態顯示為實時同步。

5.7、驗證:

在同步過程中,如果把備庫給關閉,然後在主庫進行數據操作,會發現無法操作,該事務會掛起,處於等待狀態。此時對主庫會造成很大的影響,跟oracle的最大保護模式一樣。

5.8、如果我們配置了多個備庫,而且進行實時同步,假如隻要保證前面的備庫能夠實時就可以,那麼可以進行如下設置:

synchronous_standby_names = 'FIRST 2 (s1, s2, s3)'

5.9、如果隻要保證其中任何的備庫同步成功,可以進行如下設置:

synchronous_standby_names = 'ANY 2 (s1, s2, s3)'

六、添加節點

6.1、添加新的節點跟第二個節點添加方式一樣,修改standby.signal和postgres.auto.conf文件,然後啟動節點三。

6.2、修改主庫的postgres.conf,添加如下一行:

synchronous_standby_names = 'FIRST 2 (standby_pg2,standby_pg3)'

6.3、重啟主庫,查看復制狀態:

testdb=# \x

Expanded display is on.

testdb=# select * from pg_stat_replication;

-[ RECORD 1 ]---- ------------------------------

pid | 8604

usesysid | 16384

usename | repl

application_name | standby_pg3

client_addr | 192.168.18.213

client_hostname | pg3

client_port | 34436

backend_start | 2020-03-06 05:46:23.01908-05

backend_xmin |

state | streaming

sent_lsn | 0/2A00FA38

write_lsn | 0/2A00FA38

flush_lsn | 0/2A00FA38

replay_lsn | 0/2A00FA38

write_lag |

flush_lag |

replay_lag |

sync_priority | 2

sync_state | sync

reply_time | 2020-03-06 05:46:33.088474-05

-[ RECORD 2 ]---- ------------------------------

pid | 4716

usesysid | 16384

usename | repl

application_name | standby_pg2

client_addr | 192.168.18.212

client_hostname | pg2

client_port | 50026

backend_start | 2020-03-06 03:13:46.966522-05

backend_xmin |

state | streaming

sent_lsn | 0/2A00FA38

write_lsn | 0/2A00FA38

flush_lsn | 0/2A00FA38

replay_lsn | 0/2A00FA38

write_lag |

flush_lag |

replay_lag |

sync_priority | 1

sync_state | sync

reply_time | 2020-03-06 05:46:27.970934-05

6.4、驗證同步

主要備庫的任何一個節點無法同步,都會影響主庫的事務操作。但是發現正常的一個備庫節點能夠同步,即使主庫處於停留狀態,由此證明主庫已經把事務傳遞到備庫了,隻是有備庫沒有同步,所以處於等待狀態。

6.5、如果把主庫的參數修改如下:

synchronous_standby_names = 'FIRST 1 (standby_pg2,standby_pg3)'

6.6、實驗證明,如果第二個備庫節點發生故障無法同步,不會影響主庫事務操作。

七、其它配置

7.1、正常情況下備庫會盡快恢復來自於主服務器的 WAL 記錄。但是有時候備庫的復制延遲一段時間,它能提供機會糾正數據丟失錯誤。雖然這種需求比較少見,但是也有個別的需求,recovery_min_apply_delay參數允許你將復制延遲一段時間,默認時間單位則為毫秒。例如,如果你設置這個參數為10min,對於一個事務提交,隻有備庫的系統時間超過主庫的提交時間至少 5分鐘時,備庫才會應用該事務。

在備庫的postgresql.auto.conf添加如下參數,備庫延遲recovery:

recovery_min_apply_delay = 1min

重啟數據庫生效,就會發現備庫延遲一分鐘recovery,註意這個參數隻是控制備庫延遲應用日志,不影響主庫傳輸日志到備庫,即使主備庫配置成實時同步,不會影響主庫事務操作。

7.2、如果設置了synchronous_commit=remote_apply,然後再設置recovery_min_apply_delay = 1min,會發現生產庫的事務會發生等待,直到備庫過一分鐘recovery結束後才完成,所以要避免這種情況發生。

7.3、如果把如果pg數據庫的歸檔日志都存放在一個目錄下,那麼將來主從切換的時候會造成錯誤,導致啟動失敗。

八、提高主庫的可用性和故障處理

處於同步復制的備用服務器發生故障並且不再能夠返回ACK響應,主服務器仍將繼續永遠等待響應。因此,無法提交正在運行的事務,也無法啟動後續查詢處理。流式復制不支持通過超時自動還原到異步模式的功能。

兩種解決辦法:

使用多個備用服務器來提高系統可用性

通過手動執行從同步模式切換到異步模式

(1) 將參數synchronous_standby_names設置為空字符串。

(2) 使用reload選項執行pg_ctl命令。

postgres> pg_ctl -D $PGDATA reload

我們討論第一種解決辦法:使用多個備用服務器來提高系統可用性。

1、配置主庫postgres.conf文件:

synchronous_standby_names = 'standby_pg2,standby_pg3'

--此時pg2的優先級比pg3的要高

2、查看流復制狀態:

testdb=# SELECT application_name AS host, sync_priority, sync_state FROM pg_stat_replication;

host | sync_priority | sync_state

------------- --------------- ------------

standby_pg2 | 1 | sync

standby_pg3 | 2 | potential

2、把standby_pg2數據庫關閉,則standby_pg3就會變成sync,而生產庫進行dml操作不受到影響,因為此時standby_pg3替代了standby_pg2,成為第一備庫。

testdb=# SELECT application_name AS host, sync_priority, sync_state FROM pg_stat_replication;

host | sync_priority | sync_state

------------- --------------- ------------

standby_pg3 | 2 | sync

3、如果此時把standby_pg3也關閉,則主庫的ddl和dml操作就會處於等待狀態,因為當前沒有可用的備庫來進行實時同步。

4、接下來隻要啟動任一的備庫,就會立刻成為第一備庫,則生產庫就能夠繼續進行數據操作。

註意:

根據故障類型的不同,通常可以在故障發生後立即檢測到故障,而有時在故障發生和檢測到故障之間可能有一個時間間隔。特別是,如果同步備用服務器中發生這一種類型的故障(硬件和網絡的故障檢測),則主服務器上的所有事務處理都將停止,直到檢測到備用服務器的故障為止,即使多個潛在的備用服務器可能已在工作。

把pg數據庫的日志功能打開,可以查看更多的信息:

postgres.conf添加參數如下:

log_destination = 'csvlog'

logging_collector = on

log_directory = 'pg_log'

log_filename = 'postgresql-%Y-%m-%d'

log_truncate_on_rotation = off

log_rotation_age = 1d

log_rotation_size = 0

log_error_verbosity = verbose

log_statement = all

經過測試,發現把日志目錄存放在$PGDATA/pg_log下,能夠記錄的內容很多,經過觀察發現pg的很多自身的命令其實在數據庫裡面都轉換成sql語句。

比如:

\l

日志信息如下:

2020-04-29 04:53:23.367 EDT,"postgres","testdb",4655,"[local]",5ea93fed.122f,2,"idle",2020-04-29 04:50:53 EDT,4/9,0,LOG,00000,"statement: SELECT d.datname as ""Name"",

pg_catalog.pg_get_userbyid(d.datdba) as ""Owner"",

pg_catalog.pg_encoding_to_char(d.encoding) as ""Encoding"",

d.datcollate as ""Collate"",

d.datctype as ""Ctype"",

pg_catalog.array_to_string(d.datacl, E'\n') AS ""Access privileges""

FROM pg_catalog.pg_database d

ORDER BY 1;",,,,,,,,"exec_simple_query, postgres.c:1045","psql"

查看主備庫同步的差異情況:

select client_addr,application_name, pg_wal_lsn_diff(pg_current_wal_lsn(), flush_lsn) as diff,

sync_state from pg_stat_replication;

client_addr | application_name | diff | sync_state

------------- ------------------ ------ ------------

172.21.0.6 | 172.21.0.6:11000 | 0 | async

查看主備同步狀態:

select

postgres-# current_setting('synchronous_commit') as synchronous_commit,

current_setting('synchronous_standby_names') as synchronous_standby_names,

array((select client_addr||'-'||application_name||'-'||sync_state from pg_stat_replication )) as sync_state;

synchronous_commit | synchronous_standby_names | sync_state

-------------------- --------------------------- ----------------------------------------

on | | {172.21.0.6/32-172.21.0.6:11000-async}

新建一個表空間,然後把create的權限授權給某個用戶,停止不動,原因是其它備庫上沒有創建新表空間的所在的目錄/home/postgres/newtbl。

CUUG PostgreSQL技術大講堂系列公開課第44講-流復制部署,往期視頻及文檔,請聯系CUUG。