PostgreSQL Streaming Replication 是一種高可用性解決方案,可以將資料從主伺服器即時複製到一個或多個從伺服器。本文將詳細介紹如何在 Ubuntu 22.04 上設定 PostgreSQL Streaming Replication。
Streaming Replication 概述
Streaming Replication(串流複製)是 PostgreSQL 提供的原生複製功能,自 PostgreSQL 9.0 版本開始引入。它透過將 WAL(Write-Ahead Log)記錄從主伺服器串流傳輸到從伺服器來實現資料同步。
主要特點
- 即時同步:資料變更幾乎可以即時複製到從伺服器
- 讀取擴展:從伺服器可以處理唯讀查詢,分散讀取負載
- 高可用性:當主伺服器發生故障時,可以將從伺服器提升為新的主伺服器
- 多從伺服器支援:一個主伺服器可以同時複製到多個從伺服器
- 級聯複製:從伺服器也可以作為其他從伺服器的來源
同步與非同步複製
PostgreSQL Streaming Replication 支援兩種複製模式:
非同步複製(Asynchronous)
- 預設模式:主伺服器不等待從伺服器確認即提交事務
- 效能較佳:不會因等待從伺服器而影響主伺服器效能
- 資料延遲:可能存在短暫的資料延遲,故障時可能遺失少量資料
同步複製(Synchronous)
- 資料一致性:主伺服器等待至少一個從伺服器確認後才提交事務
- 零資料遺失:確保從伺服器與主伺服器資料完全同步
- 效能影響:會增加事務提交的延遲
環境準備
本教學假設您有兩台 Ubuntu 22.04 伺服器:
| 角色 | 主機名稱 | IP 位址 |
|---|
| 主伺服器(Primary) | pg-primary | 192.168.1.10 |
| 從伺服器(Standby) | pg-standby | 192.168.1.11 |
安裝 PostgreSQL
在兩台伺服器上都安裝 PostgreSQL:
1
2
| sudo apt update
sudo apt install postgresql postgresql-contrib -y
|
確認安裝版本:
主伺服器設定
1. 修改 postgresql.conf
編輯主伺服器的設定檔:
1
| sudo nano /etc/postgresql/14/main/postgresql.conf
|
修改以下參數:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # 監聽所有網路介面
listen_addresses = '*'
# WAL 設定
wal_level = replica
max_wal_senders = 10
wal_keep_size = 1GB
# 可選:啟用同步複製
# synchronous_commit = on
# synchronous_standby_names = 'pg-standby'
# 歸檔設定(建議啟用)
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/14/archive/%f'
|
參數說明:
wal_level:設為 replica 以支援串流複製max_wal_senders:允許的最大 WAL sender 程序數量wal_keep_size:保留的 WAL 檔案大小archive_mode:啟用 WAL 歸檔
2. 建立歸檔目錄
1
2
| sudo mkdir -p /var/lib/postgresql/14/archive
sudo chown postgres:postgres /var/lib/postgresql/14/archive
|
建立複製使用者
1. 建立專用複製帳號
在主伺服器上建立複製專用的使用者:
1
| CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'your_secure_password';
|
2. 設定存取權限
編輯 pg_hba.conf 允許從伺服器連線:
1
| sudo nano /etc/postgresql/14/main/pg_hba.conf
|
加入以下設定:
1
2
| # 允許複製連線
host replication replicator 192.168.1.11/32 scram-sha-256
|
3. 重新啟動主伺服器
1
| sudo systemctl restart postgresql
|
4. 驗證主伺服器設定
1
2
| sudo -u postgres psql -c "SHOW wal_level;"
sudo -u postgres psql -c "SHOW max_wal_senders;"
|
從伺服器設定
1. 停止 PostgreSQL 服務
1
| sudo systemctl stop postgresql
|
2. 清除現有資料目錄
1
| sudo rm -rf /var/lib/postgresql/14/main/*
|
使用 pg_basebackup
1. 執行基礎備份
使用 pg_basebackup 從主伺服器複製資料:
1
| sudo -u postgres pg_basebackup -h 192.168.1.10 -U replicator -D /var/lib/postgresql/14/main -Fp -Xs -P -R
|
參數說明:
-h:主伺服器 IP 位址-U:複製使用者名稱-D:目標資料目錄-Fp:使用 plain 格式-Xs:使用串流方式傳輸 WAL-P:顯示進度-R:自動建立 standby.signal 和設定複製連線
2. 驗證複製設定檔
pg_basebackup 會自動建立 standby.signal 檔案和更新 postgresql.auto.conf:
1
2
| cat /var/lib/postgresql/14/main/standby.signal
cat /var/lib/postgresql/14/main/postgresql.auto.conf
|
postgresql.auto.conf 應包含類似以下內容:
1
| primary_conninfo = 'user=replicator password=your_secure_password host=192.168.1.10 port=5432 sslmode=prefer'
|
3. 設定從伺服器參數(可選)
編輯從伺服器的 postgresql.conf:
1
| sudo nano /etc/postgresql/14/main/postgresql.conf
|
可選設定:
1
2
3
4
5
| # 允許從伺服器處理唯讀查詢
hot_standby = on
# 回饋主伺服器的複製進度
hot_standby_feedback = on
|
4. 啟動從伺服器
1
| sudo systemctl start postgresql
|
驗證複製狀態
在主伺服器上檢查
查看 WAL sender 程序
1
| sudo -u postgres psql -c "SELECT * FROM pg_stat_replication;"
|
重要欄位說明:
pid:WAL sender 程序 IDusename:複製使用者名稱client_addr:從伺服器 IPstate:連線狀態(應為 streaming)sent_lsn:已發送的 WAL 位置write_lsn:從伺服器已寫入的 WAL 位置flush_lsn:從伺服器已刷新的 WAL 位置replay_lsn:從伺服器已重播的 WAL 位置
查看複製延遲
1
2
3
4
5
6
7
8
| SELECT client_addr,
state,
sent_lsn,
write_lsn,
flush_lsn,
replay_lsn,
pg_wal_lsn_diff(sent_lsn, replay_lsn) AS replay_lag_bytes
FROM pg_stat_replication;
|
在從伺服器上檢查
確認複製狀態
1
| sudo -u postgres psql -c "SELECT * FROM pg_stat_wal_receiver;"
|
確認是否處於復原模式
1
| sudo -u postgres psql -c "SELECT pg_is_in_recovery();"
|
回傳 t 表示從伺服器正處於復原模式(正常運作中)。
測試資料同步
在主伺服器建立測試資料
1
2
3
4
| CREATE DATABASE testdb;
\c testdb
CREATE TABLE test_replication (id SERIAL PRIMARY KEY, data TEXT, created_at TIMESTAMP DEFAULT NOW());
INSERT INTO test_replication (data) VALUES ('Hello from Primary!');
|
在從伺服器驗證資料
1
| sudo -u postgres psql -d testdb -c "SELECT * FROM test_replication;"
|
故障轉移
當主伺服器發生故障時,需要將從伺服器提升為新的主伺服器。
手動故障轉移
1. 確認主伺服器無法使用
確認主伺服器確實無法存取後再進行故障轉移。
2. 提升從伺服器
在從伺服器上執行:
1
| sudo -u postgres pg_ctl promote -D /var/lib/postgresql/14/main
|
或使用 SQL 命令:
1
| sudo -u postgres psql -c "SELECT pg_promote();"
|
3. 驗證提升成功
1
| sudo -u postgres psql -c "SELECT pg_is_in_recovery();"
|
回傳 f 表示已不再處於復原模式,成為獨立的主伺服器。
4. 更新應用程式連線
將應用程式的資料庫連線指向新的主伺服器。
重新建立複製(原主伺服器恢復後)
當原主伺服器恢復後,可以將其轉換為從伺服器:
1
2
3
4
5
6
7
8
9
| # 在原主伺服器上
sudo systemctl stop postgresql
sudo rm -rf /var/lib/postgresql/14/main/*
# 從新主伺服器複製資料
sudo -u postgres pg_basebackup -h 192.168.1.11 -U replicator -D /var/lib/postgresql/14/main -Fp -Xs -P -R
# 啟動服務
sudo systemctl start postgresql
|
監控與維護
監控複製延遲
建立監控查詢:
1
2
3
4
5
6
| SELECT
client_addr,
state,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS lag_bytes,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) / 1024 / 1024 AS lag_mb
FROM pg_stat_replication;
|
設定警報
可搭配 Nagios、Zabbix 或 Prometheus 等監控工具,當複製延遲超過閾值時發出警報。
常見問題排除
複製連線失敗
- 檢查防火牆設定:
1
| sudo ufw allow 5432/tcp
|
確認 pg_hba.conf 設定正確
測試網路連通性:
1
| telnet 192.168.1.10 5432
|
WAL 檔案遺失
如果從伺服器落後太多,可能需要重新執行 pg_basebackup。建議適當調整 wal_keep_size 參數。
參考資料