基於docker容器的Postgresql 11主從複製搭建 及切換
基於docker容器的Postgresql 11主從複製搭建 及切換
1、背景
由於新專案要用到postgresql,且要求高可用功能,因此做可行性測試研究,並記錄過程,以備查。
映象採用官方postgresl11映象,本地映象只是為了加快部署進度.並無特殊之處。
首次應用,難免有疏漏錯誤之處,歡迎批評指正。
2、環境
192.168.200.153 部署主資料庫
資料盤掛載在 /home目錄
192.168.205.72 部署從資料庫
資料盤掛載在 /data目錄
3、安裝部署
3.1 主伺服器
利用 docker 搭建 postgres 伺服器
mkdir -p /home/postgresql/data docker run --name test_pg --restart=always -v /home/postgresql/data:/var/lib/postgresql/data -e POSTGRES_PASSWORD=123456 -p 5432:5432 -d 192.168.200.153:5000/test_pg:0.2
-v : 建立資料卷,將 docker 內的檔案系統掛載到宿主機上, linux 目錄:/home/postgresql/data, docker 容器對應的路徑 /var/lib/postgresql/data
-
- 進入啟動的 docker 容器內部
docker exec -it test_pg /bin/bash
-
- 進入 postgres 客戶端,新建用於同步資料的使用者
# 切換到 postgres 使用者
su postgres
# 進去 postgres 客戶端
psql
進入 postgres 客戶端
CREATE ROLE replica login replication encrypted password 'replica';
注:注意語句最後新增分號
建立使用者成功之後,控制檯會顯示 “CREATE ROLE”,利用 \du 命令可以檢視 postgres 的使用者列表
postgres=# \du List of roles Role name | Attributes | Member of -----------+------------------------------------------------------------+----------- postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {} replica | Replication | {}
檢視使用者列表
通過 \q 退出 postgres 控制檯,並通過 exit 退出 postgres 使用者
-
- 修改 pg_hba.conf 檔案
修改 pg_hba.conf 檔案,允許剛建立的 replica 使用者從 192.168.205.72 從伺服器上連線主伺服器。
vi /var/lib/postgresql/data/pg_hba.conf
vi 未安裝
如上顯示 vi 命令沒有安裝,通過如下命令進行安裝
apt-get update
apt-get install vim
安裝成功之後,再次修改 pg_hba.conf 檔案,進入最後部分,新增如下:
host replication replica 192.168.205.72/32 trust #允許 205.72 機器使用 replica 使用者來複制
-
- 修改 postgresql.conf
listen_addresses = '*' # 監聽所有IP
archive_mode = on # 允許歸檔
archive_command = '/bin/date' # 用該命令來歸檔logfile segment,這裡取消歸檔。
wal_level = replica #開啟熱備
max_wal_senders = 32 # 這個設定了可以最多有幾個流複製連線,差不多有幾個從,就設定幾個
wal_keep_segments = 64 # 設定流複製保留的最多的xlog數目,一份是 16M,注意機器磁碟 16M*64 = 1G
wal_sender_timeout = 60s # 設定流複製主機發送資料的超時時間
max_connections = 200 # 這個設定要注意下,從庫的max_connections必須要大於主庫的
-
- 重啟容器
通過 exit 命令退出容器,並重啟啟動容器
- 重啟容器
docker restart test_pg
從伺服器
-
- 啟動從節點資料庫:
mkdir -p /data/postgresql/data
docker run --name test_pg --restart=always -v /data/postgresql/data:/var/lib/postgresql/data -e POSTGRES_PASSWORD=123456 -p 5432:5432 -d 192.168.200.153:5000/test_pg:0.2
- 2 通過 docker exec -it test_pg /bin/bash 進入容器內部,拷貝主伺服器資料進入從節點容器並同步(注意按實際情況修改master節點ip地址)
docker exec -it test_pg /bin/bash
su postgres
rm -rf /var/lib/postgresql/data/*
pg_basebackup -h 192.168.200.153 -U replica -D /var/lib/postgresql/data -X stream -P
執行完上述命令之後,容器自動退出
切換到宿主機的 root 賬戶,進入 /data/postgresql/data目錄。
-
- 新增 recovery.conf 檔案
通過 vi /data/postgresql/data/recovery.conf新增恢復檔案 (注意按實際情況修改master節點ip地址)。
- 新增 recovery.conf 檔案
cd /data/postgresql/data
vi recovery.conf
standby_mode = on
primary_conninfo = 'host=192.168.200.153 port=5432 user=replica password=replica'
recovery_target_timeline = 'latest'
- 4.修改 postgresql.conf
vi /data/postgresql/data/postgresql.conf
wal_level = replica
max_connections = 1000
hot_standby = on
max_standby_streaming_delay = 30s
wal_receiver_status_interval = 10s
hot_standby_feedback = on
-
- 啟動容器
執行docker ps -a
如果 test_pg容器已經啟動
則先執行:
- 啟動容器
docker stop test_pg
否則
通過 docker start test_pg再次啟動容器
4. 校驗主從部署
- 驗證方法一:
到 192.168.200.153 主伺服器地址上校驗主從是否部署成功
通過 docker exec -it test_pg /bin/bash 進入容器內部
su postgres
psql
通過上訴命令進入 postgres 控制檯,然後執行:
select client_addr,sync_state from pg_stat_replication;
得到如下結果:
postgres=# select client_addr,sync_state from pg_stat_replication;
client_addr | sync_state
----------------+------------
192.168.205.72 | async
(1 row)
主從配置成功
- 驗證方法二:
主庫上:
postgres@be0f0d5e17f9:/$ ps -ef | grep wal
postgres 50 28 0 14:03 ? 00:00:00 postgres: walwriter
postgres 8760 28 0 16:04 ? 00:00:00 postgres: walsender replica 192.168.205.72(35476) streaming 0/B000060
postgres 13535 11320 0 16:44 pts/0 00:00:00 grep wal
備庫上:
root@61e3c16652eb:/# ps -ef | grep wal
postgres 51 28 0 16:01 ? 00:00:01 postgres: walreceiver
root 91 82 0 16:44 pts/0 00:00:00 grep wal
5.測試同步狀態
當然,穩妥起見,嘗試在主庫上建立並插入資料,觀察備庫上是否同步這些操作,我們再主庫上建立一張表:
postgres=# create table test_ms(id int4);
CREATE TABLE
postgres=# insert into test_ms values(6);
INSERT 0 1
主庫上,我們建立test_ms表,並插入了一條資料,我們就可以在備庫上進行查詢觀察是否同步成功:
postgres=# select * from test_ms;
id
----
6
(1 row)
接下來,我們再主庫上,再操作
postgres=# insert into test_ms values(9);
INSERT 0 1
postgres=# delete from test_ms where id=6;
DELETE 1
這個時候,我們發現備庫的資料也都正常同步上了:
postgres=# select * from test_ms;
id
----
9
(1 row)
那麼我們如果在備份上進行資料操作,情況會怎樣呢?我們再備份上執行:
postgres=# insert into test_ms values(6);
ERROR: cannot execute INSERT in a read-only transaction
STATEMENT: insert into test_ms values(6);
ERROR: cannot execute INSERT in a read-only transaction
觀察這些錯誤日誌,我們可以瞭解到,非同步流主從結構中,作為從節點的備庫目前處於的是隻讀狀態,它不能進行任何寫入操作。
6. 主備切換測試
-
- 在主伺服器上執行
docker stop test_pg;
關閉主庫
-
- 在備庫上執行pg_ctl promote命令**備庫,如果recovery.conf變成recovery.done表示備庫已切換成主庫
docker exec -it test_pg /bin/bash
su postgres
/usr/lib/postgresql/11/bin/pg_ctl promote -D $PGDATA promote -D $PGDATA
waiting for server to promote.... done
server promoted
命令執行後,如果原來的 recovery.conf 更名為 recovery.done, 表示切換成功
-
- 這時如果需要將老的主庫切換成備庫,在老的主庫的$PGDATA目錄下也建立recovery.conf檔案(建立方式跟之前介紹的一樣,內容可以和原從庫pghost2的一樣,只是primary_conninfo的IP換成對端pghost2的IP)
例如,主庫上的 recovery.conf 設定為:
recovery_target_timeline = 'latest'
standby_mode = on
primary_conninfo = 'host=192.168.205.72 port=5432 user=replica password=replica'
-
- 啟動老的主庫pghost1,這時觀察主、備進行是否正常,嚴格點可以在新的主庫上對剛才的test_ms表進行操作,觀察資料是否同步成功。
pg_ctl start
我們在新主庫(pghost2)上執行:
postgres=# select pg_is_in_recovery();
pg_is_in_recovery
-------------------
f
(1 row)
發現它目前的角色已經是主庫了, 在新備庫(pghost1)上繼續執行:
postgres=# select pg_is_in_recovery();
pg_is_in_recovery
-------------------
t
(1 row)
發現它目前的角色也已經切換為備庫了
我們再pghost2上,執行資料插入操作:
postgres=# insert into test_ms values(11);
INSERT 0 1
這時,pghost1上也觀察到資料同步成功:
postgres=# select * from test_ms;
id
----
9
11
(2 rows)
到這裡為止,主從切換的演練基本完成了
參考文件:
https://www.codeleading.com/article/6741340817/
基於 docker 的 postgres 主從流複製部署
Postgresql主從非同步流複製方案的深入探究