背景
PostgreSQL 10 在高可用架構中提供了物理復制,也稱為流復制(Streaming Replication),用于實現實例級別的數據同步。PostgreSQL 復制機制主要包括物理復制和邏輯復制:物理復制依賴 WAL 日志進行物理塊級別的同步,能夠保證備庫與主庫的數據完全一致,適用于高可用、讀寫分離、災備切換等場景。相比之下,邏輯復制則更靈活,支持表級數據同步。在高并發業務中,物理復制因其高效、低延遲的特性,廣泛用于保障數據庫的高可用性。
流復制介紹
什么是流復制?
基于流復制協議的WAL日志從主節點到備節點實時復制傳輸與復用;
為了實現數據庫的容災備份,我們需要搭建主庫和備庫;
流復制是搭建主備庫的一種有效方式;
兩套數據庫之間的數據,通過WAL日志,后臺自動同步;
對外部的應用程序而言,可以看作是兩套數據庫,需要根據業務需要,顯示分別連接不同的數據庫;
獲取配合其他中間件使用,例如PGPOOL實現負載均很和故障自動切換。
流復制起源
PostgreSQL自從2010年推出的9.0版本開始,支持流式物理復制,用戶可以通過流式復制,構建只讀備庫(主備物理復制,塊級別一致)。流式物理復制可以做到極低的延遲(通常在毫秒以內)。
同步流復制
2011年推出的9.1版本,支持同步復制,當時只支持一個同步流復制備節點(例如配置了3個備,只有一個是同步模式的,其他都是異步模式)。
在同步復制模式下,當用戶提交事務時,需要等待這筆事務的WAL日志復制到同步流復制備節點,才會返回提交成功的ACK給客戶端。
同步模式下,可以確保數據的0丟失。(只要客戶端收到了事務提交成功的ACK,這筆事務的WAL就有兩份。)
級聯流復制
2012年推出的9.2版本,支持級聯流復制。意思是備庫還可以再連備庫。
級聯復制特別適合跨機房的使用,例如主庫在A機房,備庫在B機房,但是B機房需要建立多個備庫時,那么B機房只需要建立一個直連主庫的備庫,其他的備庫可以通過B機房的這個備庫級聯產生。從而減少網絡開銷。
流式虛擬備庫
2012年推出的9.2版本,除了支持級聯復制,還支持虛擬備庫,什么是虛擬備庫呢?就是只有WAL,沒有數據文件的備庫。
通過虛擬備庫,可以流式的接收WAL,進行實時的流式WAL歸檔。提高備份或歸檔的實時性。
邏輯復制的基礎
2014年推出的9.4版本,在WAL中增加了邏輯復制需要的基礎信息,通過插件,可以實現邏輯復制。
邏輯復制可以做到對主庫的部分復制,例如表級復制,而不是整個集群的塊級一致復制。邏輯復制的備庫不僅僅是只讀的,也可以執行寫操作。
WAL日志
WAL(Write-Ahead Logging,預寫式日志),保存了對數據庫的操作記錄,保證了PG的事務持久性和數據完整性,同時避免了頻繁的I/O對數據庫性能的影響。
WAL機制的理念是,對數據文件的操作,例如表和索引,都應該先將操作日志寫入磁盤中的WAL日志文件,而Data Buffer中的臟頁延遲至checkpoint發生的時候才刷新到磁盤中的數據文件。
-
刷新數據頁涉及大量的隨機I/O,即刷新臟頁需對硬盤中的多個分散的數據塊進行寫操作,這里會涉及硬盤磁頭的尋道操作,非常耗時;相比之下刷新WAL是把記錄追加到WAL文件上,屬于連續寫,效率要高得多。
-
日志先被持久化,即使數據庫發生宕機,即使Data Buffer存在未刷新到數據文件的數據頁,當數據庫重新啟動后,那些未刷新的數據頁上的變動可以根據WAL日志重做,保證數據的完整性。
流復制執行過程
- 發生DML(INSERT/UPDATE/DELETE)、DDL(表結果變更)等變更操作提交時,數據庫進程將WAL記錄先寫入內存的WAL Buffer中。
- WAL Buffer中的WAL記錄被刷新到硬盤的WAL日志文件中。
- 通知walsender進程。
- walsender進程讀取剛剛刷新到硬盤的WAL記錄。
- walsender進程負責WAL記錄發送給備庫的walreceiver進程。
- 備庫walreceiver接收到WAL記錄后會通知walwriter進程,walwriter負責把接收到的WAL記錄寫入硬盤的WAL日志文件。
- 通知數據庫startup進程。
- 備庫startup進程讀取剛剛刷新到硬盤的WAL記錄。
- 備庫startup進程重播WAL日志,并把數據寫入硬盤的數據文件。
經過以上步驟,實現主庫與備庫的數據一致性。
流復制同步級別
2016年推出的9.6版本,PG的流式復制,通過復制WAL達到同步的目的,因此同步級別也和WAL有關。通過synchronous_commit參數,可以配置事務的同步級別。
1、remote_apply,表示本地WAL fsync(fsync:內存持久化存儲),同步standby WAL 已恢復。這個帶來的RT最高。
2、on,表示本地WAL fsync,同步standby WAL fsync。即兩份持久化的WAL。
3、remote_write, 表示本地WAL fsync,同步standby WAL 異步write完成。一份持久化,備庫的WAL可能還在OS CACHE中。
4、local,表示本地WAL fsync。
5、off,表示本地WAL寫到WAL buffer中即返回客戶端事務提交成功的ACK,為異步提交(數據庫CRASH可能導致事務丟失,但不會導致數據庫不一致)。
RT影響,從低到高如下:off, local, remote_write, on, remote_apply。
同步等級 | 設定值 | 說明 | 保證范圍(流復制過程步驟保證) |
---|---|---|---|
同步 | remote_apply | 再備庫上應用WAL(更新數據)后,它將返回COMMIT響應,并且可以在備庫上進行引用。由于完全保證數據同步,因此它適用于需要備庫始終保持最新數據的負載分配場景。 | 1-9 |
同步 | on(默認) | 在備庫上寫入WAL之后,返回COMMIT響應。性能和可靠性之間平衡。 | 1-6 |
準同步 | remote_write | WAL已傳輸到備庫后,返回COMMIT響應。 | 1-5 |
異步 | local | 寫入主庫WAL之后,返回COMMIT響應。 | 1-2 |
異步 | off | WAL寫到WAL buffer中即返回COMMIT響應,無需等待主庫WAL完成寫入。該設置對現有業務效率無影響,相當于異步。 | 1 |
異步流復制和同步流復制的區別
流復制傳遞日志的兩種方式
- 異步流復制
- 同步流復制
兩者的主要區別
- 在異步流復制的情況下,事務被提交到master之后數據才會被復制。
slave就寫操作而言,通常滯后于master一些,此延遲(delay)被稱為滯后性。
- 同步復制較高的數據一致性規則
在同步流復制的情況下,系統必須確保通過事務寫入的數據至少事務同時在兩臺服務器上提交。
這意味著:slave不滯后于master,而且終端用戶在兩臺服務器上看到的數據是一致的。
考慮數據丟失
假設我們正在以異步復制方式同步數據:
- 事務發送到master
- 事務提交到master
- 在事務發送到slave之前,master宕機
- slave永遠都不會收到這個事務
在異步復制的情況下,有一個窗口(滯后),在滯后窗口期間數據會存在丟失
滯后窗口的大小因設置類型的不同而不同,它的大小非常短(幾毫秒)或非常長(幾分鐘、幾小時、幾天)。
一個重要的事實是:數據可能丟失,一個小的滯后指揮是數據丟失的可能性較小,但任務大于零的滯后都可能導致數據丟失。
考慮性能問題
通過網絡發送不必要的消息的開銷是相對昂貴和耗時的。
如果一個事務采用同步的方式復制,PostgreSQL必須確保數據到達第二個節點,這樣就會導致額外的延遲問題,業務的感知會有延遲。
在許多方面,同步復制比異步復制昂貴很多,因此如果這種消耗確實需要,應該三思而后行。(只在有特別需要的時候使用同步復制)
流式備份壓縮
2017年推出的10版本,pg_basebackup, pg_receivewal命令支持流式壓縮備份WAL。
quorum based 同步流復制
2017年推出的10版本,支持quorum based的同步流復制,例如有3個備節點,你可以告訴主庫,這個事務需要3份WAL副本,那么主庫需要等待至少2個備節點已將WAL同步過去的反饋,才會將事務提交成功的ACK返回給客戶端。
quorum based同步流復制,結合raft協議,可以實現零數據丟失的高可用、高可靠架構。
內置邏輯訂閱、復制
2017年推出的10版本,內置了邏輯訂閱的功能。
多master
2017年推出的10版本,通過邏輯訂閱的功能,可以實現多Master架構。
物理流復制
主庫執行操作
- 備份postgresql.conf
cp /data/xxx/pgsql/data/postgresql.conf /data/xxx/pgsql/data/postgresql.conf.backup
chown postgresql:postgresql postgresql.conf.backup
- 配置postgresql.conf
# - iuser數據庫主備配置 -
wal_level = replica
fsync = on
synchronous_commit = remote_write
synchronous_standby_names = 'ANY 1 (*)'
max_wal_senders = 10
wal_keep_segments = 1024
hot_standby = on
# - iuser數據庫主備配置 -
配置說明
max_wal_senders 設置為一個大于0的數,表示主庫最多可以有多少個并發的standby
wal_keep_segments 設置為一個盡量大的值,以防止主庫生成WAL日志太快,日志還沒有來得及傳送到standby就被覆蓋,但是需要考慮磁盤空間允許,一個WAL日志文件的大小通常是16M
postgresql.conf、pg_hba.conf配置調優
https://github.com/digoal/blog/blob/master/201707/20170711_01.md
- 備份pg_hba.conf
cp /data/xxx/pgsql/data/pg_hba.conf /data/xxx/pgsql/data/pg_hba.conf.backup
chown postgresql:postgresql pg_hba.conf.backup
- 配置pg_hba.conf
# - iuser數據庫主備配置 -
local replication all md5
host replication all 127.0.0.1/32 md5
host replication all ::1/128 md5
host replication all 0.0.0.0/0 md5
# - iuser數據庫主備配置 -
- 重啟主庫
service restart postgresql
- 創建流復制角色
創建replication角色的用戶來專門負責standby連接去獲取WAL日志
psql -h 127.0.0.1 -p 5432 -U postgres
PGPASSWORD=xxx psql -h 127.0.0.1 -p 5432 -U postgres
postgres=# set synchronous_commit = off;
postgres=# create role rep login replication encrypted password '123456';
備庫執行操作
- 備份備庫目錄
做基礎備份之前從庫的數據目錄需要手動清空
cd /data/xxx/pgsql
tar -cvf pg_data_backup.tar.gz /data/xxx/pgsql/data
rm -rf /data/xxx/pgsql/data/*
- 停止備庫
service stop postgresql
- 恢復備庫(備份主庫數據)
# 獲取整庫備份文件(支持自定義表空間)
# 注意:密碼也會被覆蓋成主機密碼、即主備機密碼需一致
./bin/pg_basebackup -D /data/xxx/pgsql/data -Ft -Pv -U rep -h 192.168.121.23-D 表示指定數據備份的位置
-F 表示備份文件格式,這里t表示是tar壓縮文件格式。
-Pv 表示顯示備份過程。
-U、-h、-p 表示數據庫連接相關設置------
# 生成基礎備份(如果自定義表空間沒有和默認表空間data目錄一起存儲可使用該命令)
./bin/pg_basebackup -h 192.168.121.23 -U rep -F p -P -R -D /data/xxx/pgsql/data -l repbackup20240304-X fetch:
當使用 -X fetch 選項時,pg_basebackup 將通過獲取和復制 WAL 日志文件的方式來進行備份。它會在備份完成后將 WAL 日志文件復制到備份目錄中,以確保備份的完整性。
優點是備份的完整性更高,因為它會將 WAL 日志文件復制到備份目錄中,以便在恢復時能夠恢復到特定的時間點。
缺點是備份過程可能會稍慢,特別是在網絡連接較慢或延遲較高的情況下。
-X stream:
當使用 -X stream 選項時,pg_basebackup 將通過流復制的方式來進行備份。它會在備份過程中直接從主服務器獲取 WAL 日志文件,并將它們應用到備份數據中。
優點是備份過程可能會更快,因為它直接從主服務器獲取 WAL 日志文件,并且不需要等待 WAL 日志文件復制完成。
缺點是由于備份數據中包含 WAL 日志的一部分,因此在恢復時可能無法恢復到特定的時間點,而是恢復到備份結束時的狀態。
綜上所述,-X fetch 和 -X stream 的區別在于備份時獲取 WAL 日志文件的方式不同,前者將 WAL 日志文件復制到備份目錄中以確保備份的完整性,而后者則直接從主服務器獲取 WAL 日志文件以提高備份速度。您可以根據實際需求選擇適合的方式進行備份。./bin/pg_basebackup -D /data/xxx/pgsql/data -F p -X stream -h 192.168.121.23 -p 5432 -U rep
密碼:123456
./bin/pg_basebackup -D /data/xxx/pgsql/data -F p -X fetch -h 192.168.121.23 -p 5432 -U rep
自定義表空間恢復注意事項
由于使用了自定義表空間恢復備份過程失敗參考:
https://cloud.tencent.com/developer/ask/sof/111519647
https://zhuanlan.zhihu.com/p/677427319
https://baijiahao.baidu.com/s?id=1708319850223764755&wfr=spider&for=pc
http://www.manongjc.com/detail/40-xpencvjhrnhytdn.html
- 恢復備庫(備庫執行恢復)
a.目錄解壓
數據目錄/data/xxx/pgsql/data下存在以下三個備份文件
# 第一個基礎信息包base.tar解壓(直接數據目錄下執行)
tar -xvf base.tar
# 第二個數據目錄包16385.tar解壓(解壓到data目錄下的pg_iuser目錄下)
tar -xvf 16385.tar -C pg_iuser/
# 第三個WAL日志包pg_wal.tar解壓(解壓到data目錄下的pg_iuser目錄下)
tar -xvf pg_wal.tar -C pg_wal/
b.配置備庫恢復配置文件recovery.conf
cp /data/xxx/postgresql/share/recovery.conf.sample recovery.conf
chown postgresql:postgresql recovery.conf
# 設置recovery.conf文件內容
recovery_target_timeline = 'latest'
standby_mode = on
primary_conninfo = 'host=192.168.121.23 port=5432 user=rep password=123456'
注意:recovery_target_timeline當設置為 ‘latest’ 時,PostgreSQL 將使用最新的時間線來進行恢復。這意味著在恢復數據庫時,將使用 WAL 日志中最新的時間線。這對于在流復制環境中進行故障切換時非常有用,因為您希望備庫能夠盡快地切換到主庫的最新時間線,以確保數據的一致性和完整性。這在進行 PITR(Point-In-Time Recovery)時特別有用,因為您可以確保將數據庫恢復到最新的狀態,而不是恢復到之前的某個時間點。‘immediate’ 該選擇只能恢復到備份的時間點,無法使用備份后生成的wal。
若recovery.conf文件存在,則進行PITR操作,根據recovery_target應用日志。
c.數據目錄賦權
# 備份過程中可能由于root用戶操作導致目錄權限被覆蓋
sudo chown -R postgresql:postgresql /data/xxx/pgsql/data
- 備份完成啟動備庫
service start postgresql
主從節點部署完成。
節點狀態監控
主庫查詢
# 擴展展示查詢
\x
Expanded display is on. # 查詢狀態
select pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn)) as sent_delay, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), write_lsn)) as write_delay, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), flush_lsn)) as flush_delay, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)) as replay_delay, *
from pg_stat_replication;# 結果查詢
-[ RECORD 1 ]----+------------------------------
sent_delay | 0 bytes
write_delay | 0 bytes
flush_delay | 0 bytes
replay_delay | 0 bytes
pid | 56584
usesysid | 24576
usename | rep
application_name | walreceiver
client_addr | 192.168.121.24
client_hostname |
client_port | 45564
backend_start | 2024-03-05 00:29:50.486627+08
backend_xmin |
state | streaming
sent_lsn | 0/F152118
write_lsn | 0/F152118
flush_lsn | 0/F152118
replay_lsn | 0/F152118
write_lag |
flush_lag |
replay_lag |
sync_priority | 1
sync_state | quorum
備庫查詢
-- 查看當前WAL應用是否暫停了 (navicat可執行)
iuser=# select pg_is_wal_replay_paused();pg_is_wal_replay_paused
------------------------- f -- 查看WAL接收到的位點
iuser=# select pg_last_wal_receive_lsn();pg_last_wal_receive_lsn
------------------------- 0/F152A88 -- 查看WAL的應用位點
iuser=# select pg_last_wal_replay_lsn();pg_last_wal_replay_lsn
------------------------
0/F152B30-- 查看wal receiver的統計信息
iuser=# \x
Expanded display is on.
iuser=# select * from pg_stat_get_wal_receiver();
-[ RECORD 1 ]---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
pid | 65235
status | streaming
receive_start_lsn | 0/F000000
receive_start_tli | 1
received_lsn | 0/F152B68
received_tli | 1
last_msg_send_time | 2024-03-05 11:41:32.810624+08
last_msg_receipt_time | 2024-03-05 11:41:33.591844+08
latest_end_lsn | 0/F152B68
latest_end_time | 2024-03-05 11:41:02.770438+08
slot_name |
conninfo | user=rep password=******** dbname=replication host=192.168.121.23 port=5432 fallback_application_name=walreceiver sslmode=prefer sslcompression=1 krbsrvname=postgres target_session_attrs=any-- 注意!!!執行暫停WAL的應用(例如要做一些排錯時)
iuser=# select pg_wal_replay_pause();
-[ RECORD 1 ]-------+-
pg_wal_replay_pause | -- 查詢是否暫停WAL - 結果t
postgres=# select pg_is_wal_replay_paused();
-[ RECORD 1 ]-----------+--
pg_is_wal_replay_paused | t -- 注意!!!執行繼續
postgres=# select pg_wal_replay_resume();
-[ RECORD 1 ]--------+-
pg_wal_replay_resume | -- 查詢是否暫停WAL - 結果f
postgres=# select pg_is_wal_replay_paused();
-[ RECORD 1 ]-----------+--
pg_is_wal_replay_paused | f
注:
– 刪除所有發布
SELECT pg_drop_replication_slot(slot_name) FROM pg_replication_slots;
– 刪除所有訂閱
SELECT pg_drop_subscription(subname) FROM pg_subscription;
注意事項
1、如果要防止日志主庫刪除,備庫還沒有接收的WAL文件。
使用slot,或者配置足夠大的wal keep。
但是這兩種方法都有一定的風險或問題,例如當備庫掛了,或者備庫不再使用了,而用戶忘記刪除對應的SLOT時,可能導致主庫WAL無限膨脹。
而wal keep則會導致主庫的WAL預留足夠的個數,默認一個wal文件大小16M,占用一定空間,例如配置wal_keep_segments=1024,那么磁盤最大存儲是16G。
相關參數
主 postgresql.conf
# max_replication_slots = 10
# wal_keep_segments = 1024 #保持至少 1024 個 WAL 文件可用,以確保數據庫的持續運行備 recovery.conf
# primary_slot_name = ''
2、如果不想通過以上方法預防備庫需要的WAL已被刪除,那么可以配置主庫的歸檔,同時備庫需要能獲取到已歸檔的WAL文件。
相關參數
主 postgresql.conf
#archive_mode = off # enables archiving; off, on, or always # (change requires restart)
#archive_command = '' # command to use to archive a logfile segment # placeholders: %p = path of file to archive # %f = file name only # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' 備 recovery.conf
# restore_command = '' # e.g. 'cp /mnt/server/archivedir/%f %p'
3、保護好recovery.conf文件中的密碼,因為配置的是明文。–源碼中是否可以配置密文?
在 recovery.conf 配置文件中配置的密碼通常是以明文形式存儲的,而不是加密存儲的。這是因為 recovery.conf 文件通常只能由數據庫管理員或具有足夠權限的用戶訪問,因此存儲密碼為明文通常被視為足夠安全。
然而,對于安全性要求較高的環境,您可能希望采取額外的措施來保護密碼的安全性。這可能包括:
1.使用操作系統權限限制訪問:確保只有具有足夠權限的用戶才能訪問 recovery.conf 文件。
2.定期更改密碼:定期更改密碼是一種通用的安全實踐,可以幫助減少密碼泄露的風險。
3.使用密碼管理工具:某些密碼管理工具允許您安全地存儲和管理密碼,并提供額外的安全功能,如加密存儲、訪問控制和審計日志等。
4.加密密碼:雖然 recovery.conf 文件本身不支持加密存儲密碼,但您可以使用加密技術來保護密碼。例如,您可以將密碼存儲在加密的配置文件中,并在數據庫啟動時使用腳本來解密密碼。
4、主備之間的帶寬請足夠大,否則可能導致主備延遲。
5、大數據量下磁盤空間占滿問題,預估一下一個大數據量項目的數據庫大小占存儲空間多少。查看數據庫的大小 :
postgres=# select round(sum(pg_database_size(oid))/1024/1024.0,2)||'MB' from pg_database;?column?
----------288.21MB
(1 row)
查看表空間和使用的數據庫
CREATE ROLE
iuser=# SHOW data_directory;data_directory
---------------------------/data/xxx/pgsql/data
(1 row)iuser=# SELECT * FROM pg_tablespace;spcname | spcowner | spcacl | spcoptions
------------+----------+--------+------------pg_default | 10 | | pg_global | 10 | | iuser | 10 | |
(3 rows)iuser=# \db+List of tablespacesName | Owner | Location | Access privileges | Options | Size | Description
------------+------------+----------------------------------+-------------------+---------+--------+-------------iuser | postgresql | /data/xxx/pgsql/data/pg_iuser | | | 11 MB | pg_default | postgresql | | | | 23 MB | pg_global | postgresql | | | | 574 kB |
同步壓測
連接主庫進行TPC-B的壓測
TPC-B 測試的結果通常以每秒完成的事務數(Transaction-per-Second, TPS)來衡量,即系統在單位時間內能夠完成的事務數量。這個指標越高,表示數據庫系統在處理事務型工作負載時的性能越好。
可通過正常部署的機器對比主從部署的機器性能測試。
- 創建測試數據庫
iuser=# create database test_db;
- 初始化數據庫
pgbench -i -U <user> -d <dbname> -h <host>
主庫執行
./bin/pgbench -i -s 10 -d test_db -h 127.0.0.1 -p 5432 -U iuser密碼:xxx-i:表示初始化數據庫。執行此命令后,pgbench 將創建必要的表和索引,并向數據庫中插入初始數據。-s:指定了插入的規模因子(Scale Factor)。Scale Factor 是一個用于控制測試數據規模的參數,它決定了插入的數據量。在這個例子中,規模因子為 10,表示將會插入約為預設規模的 10 倍的數據。這意味著將會插入較大規模的測試數據,以便進行性能測試。比例因子,將生成的行數乘以給定的數,例如,在默認情況下,比例因子為1,pgbench_accounts表會創建100,000行,當-s 10 即會創建1,000,000行。
./bin/pgbench -n -r -P 1 -d test_db -h 127.0.0.1 -p 5432 -U iuser -c 32 -j 32 -T 120這個命令使用 pgbench 工具對 PostgreSQL 數據庫執行性能測試,并輸出了一些關于測試結果的統計信息。具體的參數含義如下:
-n:表示不執行事務初始化階段。如果數據庫已經初始化過,可以通過這個選項跳過初始化步驟,直接執行測試。
-r:表示按照事務順序執行,而不是隨機順序。在這個例子中,使用的是 TPC-B 測試,它涉及到一系列按順序執行的事務。
-P 1:指定測試過程中的預熱時間。在執行正式的測試之前,通常需要一段時間來預熱數據庫緩存。這個選項表示預熱時間為 1 秒。
-c 32:指定測試過程中的并發客戶端數量為 32。即同時有 32 個客戶端連接到數據庫執行測試。
-j 32:指定測試過程中的線程數量為 32。即同時有 32 個線程執行測試。
-T 120:指定測試的持續時間為 120 秒。
測試結果
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 10
query mode: simple
number of clients: 32
number of threads: 32
duration: 120 s
number of transactions actually processed: 109736
latency average = 34.958 ms
latency stddev = 172.667 ms
tps = 913.754775 (including connections establishing)
tps = 914.944815 (excluding connections establishing)
script statistics:- statement latencies in milliseconds:0.027 \set aid random(1, 100000 * :scale)0.013 \set bid random(1, 1 * :scale)0.011 \set tid random(1, 10 * :scale)0.008 \set delta random(-5000, 5000)1.122 BEGIN;0.741 UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;0.916 SELECT abalance FROM pgbench_accounts WHERE aid = :aid;6.643 UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;17.218 UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;0.837 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);7.421 END;
結果分析
根據提供的測試結果,我們可以進行性能分析:平均延遲(Latency Average): 平均延遲約為 34.958 毫秒,這表示每個事務的平均執行時間。較低的延遲通常表示更好的性能。延遲標準偏差(Latency Stddev): 延遲標準偏差為 172.667 毫秒,表示延遲值的離散程度。較小的標準偏差通常表示延遲值分布較為集中。每秒事務數(TPS):在連接建立的情況下,TPS約為 913.75;不包括連接建立時,TPS約為 914.94。TPS 表示系統每秒鐘可以處理的事務數量。較高的 TPS 值通常表示更好的性能。各種語句的執行時間:在腳本統計中,每個語句的執行時間分別列出。可以看到,UPDATE 語句的執行時間較長,特別是 pgbench_branches 表的更新操作和 pgbench_tellers 表的更新操作。基于以上數據,性能評估如下:平均延遲較高:平均延遲較高,可能表示數據庫服務器的負載較重或者系統資源不足。需要進一步分析系統資源使用情況,優化數據庫配置或增加硬件資源以提高性能。TPS 較低:每秒處理的事務數量較低,可能會影響系統的并發處理能力。可以嘗試優化 SQL 查詢、調整連接池配置或者進行硬件升級等方式來提高 TPS。部分語句執行時間較長:特別是 UPDATE 語句的執行時間較長,可能會影響整體性能。可以通過優化表結構、添加索引或調整查詢計劃等方式來減少執行時間。綜上所述,需要進一步分析系統的資源使用情況,并針對性地進行優化,以提高系統的性能和穩定性。
觀察主備的延遲
iuser=# \x
iuser=# select pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn)) as sent_delay,pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), write_lsn)) as write_delay,pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), flush_lsn)) as flush_delay,pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)) as replay_delay, * from pg_stat_replication;iuser=# \watch 1
運行過程中測試結果
-[ RECORD 1 ]----+------------------------------
sent_delay | 0 bytes
write_delay | 0 bytes
flush_delay | 0 bytes
replay_delay | 1592 bytes
pid | 56584
usesysid | 24576
usename | rep
application_name | walreceiver
client_addr | 192.168.121.24
client_hostname |
client_port | 45564
backend_start | 2024-03-05 00:29:50.486627+08
backend_xmin |
state | streaming
sent_lsn | 0/2B1D7998
write_lsn | 0/2B1D7998
flush_lsn | 0/2B1D7998
replay_lsn | 0/2B1D7360
write_lag | 00:00:00.005352
flush_lag | 00:00:00.005363
replay_lag | 00:00:00.007701
sync_priority | 1
sync_state | quorum
運行過程中測試結果分析
根據提供的 pg_stat_replication 查詢結果,我們可以分析主從數據庫同步延遲情況如下:streaming 狀態:從結果中可以看到,狀態為 "streaming",這表示該從節點正在通過流復制(streaming replication)的方式與主節點同步數據。延遲信息:從結果中的 sent_delay、write_delay、flush_delay 和 replay_delay 等字段可以看出不同階段的延遲情況。這些字段表示從接收 WAL 日志到將其寫入磁盤、刷新到持久存儲、以及重放到從節點數據庫的延遲情況。延遲時間:從 write_lag、flush_lag 和 replay_lag 等字段可以看到相應的延遲時間。這些字段顯示了在不同階段的延遲時間,例如從接收到 WAL 日志到寫入磁盤的延遲、刷新到持久存儲的延遲以及重放到從節點數據庫的延遲。同步狀態:sync_state 字段顯示同步狀態,這里是 "quorum",表示同步狀態良好。綜合分析這些信息,可以得出以下結論:延遲情況分析:從結果中可以看出,從節點的 replay 延遲較大,為 7.701 毫秒。這表示從節點接收到 WAL 日志后,需要經過約 7.7 毫秒的時間才能將其重放到從節點數據庫中。其他階段的延遲時間較小,都在毫秒級別。同步狀態正常:從結果中的 sync_state 字段可以看出,同步狀態為 "quorum",表示同步狀態良好,從節點與主節點之間的數據同步工作正常。綜上所述,根據 pg_stat_replication 查詢結果分析,從節點的重放延遲較大,可能是由于從節點的資源負載較重或者網絡延遲等原因導致。建議進一步分析系統資源使用情況,并針對性地進行優化,以減少同步延遲,提高主從數據庫之間的同步性能。
空載運行時結果對比
-[ RECORD 1 ]----+------------------------------
sent_delay | 0 bytes
write_delay | 0 bytes
flush_delay | 0 bytes
replay_delay | 0 bytes
pid | 56584
usesysid | 24576
usename | rep
application_name | walreceiver
client_addr | 192.168.121.24
client_hostname |
client_port | 45564
backend_start | 2024-03-05 00:29:50.486627+08
backend_xmin |
state | streaming
sent_lsn | 0/2F103930
write_lsn | 0/2F103930
flush_lsn | 0/2F103930
replay_lsn | 0/2F103930
write_lag |
flush_lag |
replay_lag |
sync_priority | 1
sync_state | quorum
總結
物理流復制是 PostgreSQL 10 構建高可用架構的重要方案之一,適用于讀寫分離、數據容災、快速故障切換等場景。與邏輯復制相比,物理復制能保證主備庫的數據嚴格一致,但靈活性較低。通過合理配置同步復制或異步復制,可以在性能與一致性之間找到最佳平衡,確保業務的穩定運行。🚀 想讓你的 PostgreSQL 更高可用?物理流復制是必不可少的技術!💡