結構圖如下:
Postgresql早在9.0版本開始支持物理復制,也稱為流復制,通過從實例級復制出一個與主庫一模一樣的備庫。流復制同步方式有同步,異步兩種,如果主節點和備節點不是很忙,通常異步模式下備庫和主庫的延遲時間能夠控制在毫秒級。物理復制只能復制整個實例。
邏輯復制也成為選擇性復制,可以做到基於表級別的復制,選擇需要邏輯復制的表,而不是復制實例上的所有數據庫的表,10版本不支持內置的邏輯復制,通常使用第三方邏輯復制。
WAL日志記錄數據庫變化,格式為二級制格式,盡管流復制都是基於WAL,但是兩者本質不同,流復制是基於WAL物理復制,邏輯復制是基於WAL邏輯解析,將WAL解析成一種清晰,易於理解的格式。
流復制和邏輯復制主要有以下差異:
- 流復制是物理復制
核心原理是主庫將預寫入日志WAL日志發給備庫,備庫接收到WAL日志后進行重做。
邏輯復制核心是基於WAL,邏輯復制會根據預先設置好的規則解析WAL日志,將二進制文件解析成一定格式的邏輯變化信息(有點像oracle的物理備庫和邏輯備庫)。
- 物理復制只能對實例級別,邏輯復制能夠對表級別進行復制
- 物理復制能夠對DDL進行操作,邏輯復制DDL主庫不能復制到備庫
- 物理復制必須大版本一致,邏輯復制支持跨大版本。
1. 物理復制
1. 異步流復制
環境情況:
主機 |
主機名 |
IP |
操作系統 |
Postgresql版本 |
master |
10pg1 |
192.168.10.41 |
Centos6.9 |
PostgreSQL 10.8 |
slave |
10pg2 |
192.168.10.51 |
Centos6.9 |
PostgreSQL 10.8 |
這種環境的部署包括兩種方式:
① 數據文件拷貝的方式
② pg_basebackup方式部署
本次將介紹pg_basebackup方式部署。
1. 兩台都要安裝postgresql
2. 主庫創建創建Replication用戶(以下都是主庫操作)
CREATE ROLE rep login replication password 'rep';
修改master的pg_hba.conf文件:
修改Master庫數據庫配置(postgresql.conf)
要使用流復制,一定要把wal_level = hot_standby設置成hot_standby,其中要開啟歸檔模式
wal_level = hot_standby # 這個是設置主為wal的主機
max_wal_senders = 5 # 這個設置了可以最多有幾個流復制連接
wal_keep_segments = 128 # 設置流復制保留的最多的xlog數目
wal_sender_timeout = 60s # 設置流復制主機發送數據的超時時間
max_connections = 100 # 這個設置要注意下,從庫的max_connections必須要大於主庫的
配置完后重啟主庫。
3. 以下都是備庫操作
修改master的pg_hba.conf文件:
host all all 192.168.10.0/24 md5
host replication rep 192.168.10.41/24 md5
host replication rep 192.168.10.51/24 md5
使用pg_basebackup建備庫
pg_basebackup -h 192.168.10.41 -Urep -Ft -Pv -Xf -z -Z5 -p 5432 -D /backup/20190629/
停止備庫進行恢復操作:
cd /pgsql/
mv pg_data/ pg_databak
mkdir -p /pgsql/pg_data
cd /pgsql/
chmod 700 pg_data
chown -R postgres:postgres /pgsql/
tar -zxvf /backup/20190629/base.tar.gz -C /pgsql/pg_data/
拷貝主庫的recovery.conf文件到備庫(主庫執行)
scp /usr/local/pgsql/share/recovery.conf.sample 192.168.10.51:/pgsql/pg_data/recovery.conf
備庫修改recovery.conf
standby_mode=on
primary_conninfo = 'user=rep password=rep host=192.168.10.41 port=5432'
recovery_target_timeline = 'latest'
啟動備庫后,會報錯,接下來修改postgresql.conf
vi postgresql.conf
max_connections = 200 # 一般查多於寫的應用從庫的最大連接數要比較大
hot_standby = on # 說明這台機器不僅僅是用於數據歸檔,也用於數據查詢
max_standby_streaming_delay = 30s # 數據流備份的最大延遲時間
wal_receiver_status_interval = 10s # 多久向主報告一次從的狀態,當然從每次數據復制都會向主報告狀態,這里只是設置最長的間隔時間
hot_standby_feedback = on # 如果有錯誤的數據復制,是否向主進行反饋
測試:
主庫操作:
備庫:
同步正常。
備庫只能執行查詢,與Oracle dg類似,且slave停掉后,主庫能夠正常的運行,wal日志不能傳向遠端。
啟動后,把主庫的歸檔日志傳向備庫,備庫繼續應用日志(不像ORACLE需要手動應用日志)。
備庫停庫后主庫delete操作:
備庫啟動后,主庫傳完歸檔日志操作:
主備庫一致性查詢操作:
主備一致,且主庫執行同步查詢:
select pid,state, client_addr,sync_priority,sync_state from pg_stat_replication;
select * from pg_stat_replication ;
檢查數據庫主從復制進度:
查看流復制的信息可以使用主庫上的視圖
select pid,state,client_addr,sync_priority,sync_state from pg_stat_replication;
查看備庫落后主庫多少字節
select pg_xlog_location_diff(pg_current_xlog_location(),replay_location)/1024/1024 as MB from pg_stat_replication;
select pg_xlog_location_diff(pg_current_xlog_location(),replay_location)/1024/1024/1024 as GB from pg_stat_replication;
級聯復制
select pg_xlog_location_diff(pg_last_xlog_replay_location(),replay_location)/1024/1024/1024 as GB from pg_stat_replication;
查看備庫因為沖突而被取消的SQL:
select * from pg_stat_database_conflicts;
顯示備庫詳細信息:pg_controldata
備庫wal 日志清理:
由於我的備庫WAL日志存在/pgsql/pg_data/pg_wal目錄。
vi /pgsql/pg_data/recovery.conf
archive_cleanup_command = 'pg_archivecleanup /pgsql/pg_data/pg_wal %r'
2. 同步流復制
異步流復制可以轉換成同步流復制。
主庫配置postgresql.conf:
synchronous_commit = on
synchronous_standby_names = 'standby1' --備庫設置節點別名
備庫配置recovery.conf
primary_conninfo = 'application_name=standby1 user=rep password=rep host=192.168.10.41 port=5432 sslmode=disable sslcompression=1'
recovery_target_timeline = 'latest'
配置完后重啟主備庫。
查看同步方式:
select pid,state,client_addr,sync_priority,sync_state from pg_stat_replication;
同步復制環境陷阱:
同步復制環境中,由於主庫提交事務至少需要一個備庫接收WAL,並返回確認信息后主庫才向客戶端返回成功,一方面保證了數據的完整性,另一方面對於一主一備的同步環境變現的陷阱是,如果備庫宕機,主庫上的寫操作即處於等待狀態(這點跟ORACLE不一樣,Oracle 有gap,主庫會向備庫傳送歸檔),讀操作不影響,需要手動的把歸檔同步到備庫,所以生產上,建議使用異步方式(一主一從架構)。
3.同步查看
查看延遲(wal延遲時間衡量):
select * from pg_stat_replication ;
通過WAL日志應用延遲量衡量:
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;
select * from pg_stat_wal_receiver;
查看恢復進程是否處於恢復模式:
SELECT PG_IS_IN_RECOVERY();
顯示備庫最近接收的WAL日志位置:
select pg_last_wal_receive_lsn();
顯示備庫最近應用的WAL日志位置:
select pg_last_wal_replay_lsn();
顯示備庫最近事務的應用時間:
select pg_last_xact_replay_timestamp();
顯示主庫WAL當前寫入位置:
select pg_current_wal_lsn();
2. 流復制備升主庫
建議主備庫事先做個快照
首先判斷主備庫
ps -ef | grep "wal"
可以查看有
主
備:
或者查看以下SQL 有內容的為主庫,沒有內容的為從庫。
select pid,state,client_addr,sync_priority,sync_state from pg_stat_replication;
或者查看
select pg_is_in_recovery(); -- t為備 f為主庫
pg_controldata 備庫Database cluster state參數 為 in archive recovery模式;主庫為in production 模式。
9.0之前切換需要文件出發方式,9.1開始,支持pg_ctlpromote出發方式,相比文件出發方式更方便。
Promote命令發出后,運行中的備庫將停止恢復模式,並切換成讀寫模式的主庫。步驟如下:
1.關閉主庫,建議使用-m fast模式關閉。
pg_ctl stop -D /pgsql/pg_data/ -m fast
2.備庫執行命令激活備庫
pg_ctl promote -D /pgsql/pg_data
查看備庫原備庫recovery.conf 變成recovery.done,表示切換完成(測試已切換完成)
查看新主庫:
測試新主庫可以進行讀寫操作,切換成功。
由於考錄到主庫宕機之后不可用,並沒有做主備互相切換,只做備庫升為主庫操作。
3. 流復制主備互換角色
Pg_rewind 是pgsql一個非常好的數據同步工具,如果主備互相切換的時候忘記關閉主庫,除了重新搭建備庫外,就會用到提供的pg_rewind工具。
pg_rewind:
主備庫設置參數 wal_log_hints = on ,如果數據庫初始化的時候是 --data-checksums選項可以不用設置此參數,由於--data-checksums會在數據塊上進行檢測,發現I/O錯誤,開啟后后性能損失。
設置號wal_log_hints = on 后,進行重啟生效。
① 激活備庫
參數設置好后,備庫提升為主庫
pg_ctl promote -D /pgsql/pg_data
提升成功。
② 主庫轉換為備庫
關閉原來的主庫。
pg_ctl stop -D /pgsql/pg_data/ -m fast
使用pg_rewind 工具增量同步10pg2到10pg1的數據。
pg_rewind --target-pgdata=/pgsql/pg_data/ --source-server='host=192.168.10.51 port=5432 user=postgres password=postgres dbname=postgres' -P
mv recovery.done recovery.conf
vi recovery.conf
把主庫信息修改一下
vi postgresql.conf
修改監聽地址。
后啟動成功后
pg_ctl start -D /pgsql/pg_data/
查看日志有報錯
把51的日志cp到41 wal日志目錄(由於我主庫有新的數據生成)
新備庫立馬同步正常。
延遲設置:
如果備庫不需要實時同步,設置此參數:
vi recovery.conf
recovery_min_apply_delay = 30s
默認是0 毫秒,支持ms,s,min,h,d(毫秒,秒,分鍾,小時,天),注意參數需要重啟生效;
如果設置時間過大,需要注意wal目錄的空間是否足夠大。
4. 流復制槽備庫高可用
很多時候在主庫產生xlog或者wal日志的時候,還沒有傳到從庫就被覆蓋了,為了保證xlog/wal日志不被覆蓋,postgres 就啟用流復制槽,讓沒有傳到從庫的xlog保存不被覆蓋,新的日志繼續產生。
配置流復制主備庫都需要進行參數設置。
主庫設置以下,並需要重啟
max_replication_slots = 4 # max number of replication slots
wal_level = hot_standby
- 在主庫上創建slot
select * from pg_create_physical_replication_slot('pg_5432');
查看是主庫否創建成功:
select * from pg_replication_slots ;
- 備庫recovery文件進行設置
vi /pgsql/pg_data/recovery.conf
primary_slot_name = 'pg_5432'
standby_mode = 'on'
recovery_target_timeline = 'latest'
primary_conninfo = 'user=rep password=rep host=192.168.10.41 port=5432
application_name=pg_5432 sslmode=disable sslcompression=1'
其他的都一樣,就是多了一個primary_slot_name 配置,以及primary_conninfo里面需要加上application_name=流復制槽名稱
備庫進行重啟。
備庫重啟后再次查看主庫流復制槽信息:
select * from pg_replication_slots ;