1. 程式人生 > >postgresql主從實現之異步流復制

postgresql主從實現之異步流復制

postgresql主從實現之異步流復制

postgresql主從復制實現方式之一:
基於Standby的異步流復制,這是PostgreSQL9.x版本(2010.9)之後提供的一個很nice的功能,類似的功能在Oracle中是11g之後才提供的active dataguard和SQL Server 2012版本之後才提供的日誌傳送,此處再次為pg鼓掌,確實是一個很棒的開源數據庫。廢話不多說,本篇blog就詳細記錄一下在pg9.5中實現Hot Standby異步流復制的完整配置過程和註意事項。

Standby數據庫原理:
首先我們做主從同步的目的就是實現db服務的高可用性,通常是一臺主數據庫提供讀寫,然後把數據同步到另一臺從庫,然後從庫不斷apply從主庫接收到的數據,從庫不提供寫服務,只提供讀服務。在postgresql中提供讀寫全功能的服務器稱為primary database或master database,在接收主庫同步數據的同時又能提供讀服務的從庫服務器稱為hot standby server。


PostgreSQL在數據目錄下的pg_xlog子目錄中維護了一個WAL日誌文件,該文件用於記錄數據庫文件的每次改變,這種日誌文件機制提供了一種數據庫熱備份的方案,即:在把數據庫使用文件系統的方式備份出來的同時也把相應的WAL日誌進行備份,即使備份出來的數據塊不一致,也可以重放WAL日誌把備份的內容推到一致狀態。這也就是基於時間點的備份(Point-in-Time Recovery),簡稱PITR。而把WAL日誌傳送到另一臺服務器有兩種方式,分別是:

WAL日誌歸檔(base-file)
流復制(streaming replication)

第一種是寫完一個WAL日誌後,才把WAL日誌文件拷貝到standby數據庫中,簡言之就是通過cp命令實現遠程備份,這樣通常備庫會落後主庫一個WAL日誌文件。而第二種流復制是postgresql9.x之後才提供的新的傳遞WAL日誌的方法,它的好處是只要master庫一產生日誌,就會馬上傳遞到standby庫,同第一種相比有更低的同步延遲,所以我們肯定也會選擇流復制的方法。
在實際操作之前還有一點需要說明就是standby的搭建中最關鍵的一步——在standby中生成master的基礎備份。postgresql9.1之後提供了一個很方便的工具—— pg_basebackup,關於它的詳細介紹和參數說明可以在官網中查看(pg_basebackup tool).下面在搭建過程中再做相關具體說明,關於一些基礎概念和原理先介紹到這裏。
pg_basebackup tool官網介紹:
https://www.postgresql.org/docs/current/static/p-pgbasebackup.html


詳細配置環境:
下面開始實戰,首先準備兩臺服務器,我這裏開了2個虛機做測試,分別是:
主庫(master)CentOS release 6.5 (Final) 10.0.0.100 postgresql 9.5.9
從庫(standby)CentOS release 6.7 (Final) 10.0.0.110 postgresql 9.5.9

從主庫配置開始。
首先要提前在master機器10.0.0.100安裝好postgresql,采用的是二進制安裝包,具體參考本博文的postgresql二進制安裝過程。

主庫配置:
註意此處的操作都是在主庫(10.0.0.100)上進行的,首先打開數據目錄下的postgresql.conf文件然後做以下修改:

1.listen_address = ‘*’(默認localhost)
2.port = 10280 (默認是5432)
3.wal_level = hot_standby(默認是minimal)
4.max_wal_senders=2(默認是0)
5.wal_keep_segments=64(默認是0)
下面對上述參數稍作說明
第一個是監聽任何主機,wal_level表示啟動搭建Hot Standby,max_wal_senders則需要設置為一個大於0的數,它表示主庫最多可以有多少個並發的standby數據庫,而最後一個wal_keep_segments也應當設置為一個盡量大的值,以防止主庫生成WAL日誌太快,日誌還沒有來得及傳送到standby就被覆蓋,但是需要考慮磁盤空間允許,一個WAL日誌文件的大小是16M:
[postgres@localhost data]$ cd /data/pgsql100/data/pg_xlog/
[postgres@localhost pg_xlog]$ ls
000000010000000000000001 000000010000000000000002 000000010000000000000003 000000010000000000000004 000000010000000000000005 archive_status
[postgres@localhost pg_xlog]$ du -sh *
16M 000000010000000000000001
16M 000000010000000000000002
16M 000000010000000000000003
16M 000000010000000000000004
16M 000000010000000000000005
4.0K archive_status
如上,一個WAL日誌文件是16M,如果wal_keep_segments設置為64,也就是說將為standby庫保留64個WAL日誌文件,那麽就會占用16*64=1GB的磁盤空間,所以需要綜合考慮,在磁盤空間允許的情況下設置大一些,就會減少standby重新搭建的風險。接下來還需要在主庫創建一個超級用戶來專門負責讓standby連接去拖WAL日誌:
CREATE ROLE replica login replication encrypted password ‘replica‘;
接下來打開數據目錄下的pg_hba.conf文件然後做以下修改:
[postgres@localhost pg_xlog]$ tail -2 /data/pgsql100/data/pg_hba.conf
#host replication postgres ::1/128 trust
host replication replica 10.0.0.110/32 md5

如上,這行配置的意思是允許用戶replica從10.0.0.110/32網絡上發起到本數據庫的流復制連接,簡言之即允許從庫服務器連接主庫去拖WAL日誌數據。主庫配置很簡單,到此就算結束了,啟動主庫並繼續配置從庫
pg_ctl -D /data/pgsql100/data -l /data/pgsql100/log/postgres.log stop
pg_ctl -D /data/pgsql100/data -l /data/pgsql100/log/postgres.log start

從庫配置:
首先要說明的是從庫上一開始也是需要安裝postgresql數據庫服務的,應為需要pg_basebackup命令工具才能在從庫上生成的master主庫的基礎備份。但是還要強調一點的是:從庫上初始化數據庫時指定的數據目錄/data/psql110/data需要清空,才可以在從庫上使用pg_basebackup命令工具來生成master主庫的基礎備份數據。

從此處開始配置從庫(10.0.0.110),首先要通過pg_basebackup命令行工具在從庫上生成基礎備份:
[postgres@localhost data]$ pg_basebackup -h 10.0.0.100 -U replica -p 10280 -F p -x -P -R -D /data/psql110/data/ -l replbackup
Password: 密碼(replica)
46256/46256 kB (100%), 1/1 tablespace
[postgres@localhost data]$
簡單做一下參數說明(可以通過pg_basebackup --help進行查看),
-h指定連接的數據庫的主機名或IP地址,這裏就是主庫的ip。
-U指定連接的用戶名,此處是我們剛才創建的專門負責流復制的repl用戶。
-F指定了輸出的格式,支持p(原樣輸出)或者t(tar格式輸出)。
-x表示備份開始後,啟動另一個流復制連接從主庫接收WAL日誌。
-P表示允許在備份過程中實時的打印備份的進度。
-R表示會在備份結束後自動生成recovery.conf文件,這樣也就避免了手動創建。

-D指定把備份寫到哪個目錄,這裏尤其要註意一點就是做基礎備份之前從庫的數據目錄(/data/psql110/data/)目錄需要手動清空。
-l表示指定一個備份的標識。

[postgres@localhost data]$ cat /data/psql110/data/recovery.conf
standby_mode = ‘on‘
primary_conninfo = ‘user=replica password=replica host=10.0.0.100 port=10280 sslmode=prefer sslcompression=1 krbsrvname=postgres‘


運行命令後看到如下進度提示就說明生成基礎備份成功:
[postgres@localhost data]$ pg_basebackup -h 10.0.0.100 -U replica -p 10280 -F p -x -P -R -D /data/psql110/data/ -l replbackup
Password: 密碼(replica)
46256/46256 kB (100%), 1/1 tablespace
[postgres@localhost data]$
如上由於我們在pg_hba.conf中指定的md5認證方式,所以需要輸入密碼。最後還需要修改一下從庫數據目錄下的postgresql.conf文件,將hot_standby改為啟用狀態,即hot_standby=on。到此為止就算配置結束了,我們現在可以啟動從庫,
[postgres@localhost data]$ egrep -v ‘^#|^$‘ /data/psql110/data/postgresql.conf|grep "hot_standby"
wal_level = hot_standby # minimal, archive, hot_standby, or logical
hot_standby = on # "on" allows queries during recovery

[postgres@localhost data]$ pg_ctl -D /data/psql110/data -l /data/psql110/log/postgres.log start
server starting

從庫上查看到流復制進程:

[postgres@localhost data]$ ss -lntup|grep postgres
tcp LISTEN 0 128 :::10280 :::* users:(("postgres",23161,4))
tcp LISTEN 0 128 *:10280 *:* users:(("postgres",23161,3))
[postgres@localhost data]$ ps -ef|grep postgres
root 5663 4716 0 18:12 pts/0 00:00:00 su - postgres
postgres 5664 5663 0 18:12 pts/0 00:00:00 -bash
postgres 5855 5664 0 18:13 pts/0 00:00:00 /bin/bash /usr/local/pgsql/bin/psql
postgres 5857 5855 0 18:13 pts/0 00:00:00 /usr/local/pgsql/bin/psql.bin
root 12406 7244 0 18:34 pts/1 00:00:00 su - postgres
postgres 12407 12406 0 18:34 pts/1 00:00:00 -bash
root 13861 13810 0 18:47 pts/3 00:00:00 su - postgres
postgres 13862 13861 0 18:47 pts/3 00:00:00 -bash
root 21768 21736 0 19:54 pts/2 00:00:00 su - postgres
postgres 21769 21768 0 19:54 pts/2 00:00:00 -bash
postgres 23161 1 0 20:05 pts/2 00:00:00 /usr/local/pgsql/bin/postgres -D /data/psql110/data
postgres 23164 23161 0 20:05 ? 00:00:00 postgres: startup process recovering 000000010000000000000007
postgres 23165 23161 0 20:05 ? 00:00:00 postgres: checkpointer process
postgres 23166 23161 0 20:05 ? 00:00:00 postgres: writer process
postgres 23167 23161 0 20:05 ? 00:00:00 postgres: stats collector process
postgres 23168 23161 0 20:05 ? 00:00:00 postgres: wal receiver process streaming 0/7000140
postgres 23240 21769 0 20:06 pts/2 00:00:00 ps -ef
postgres 23241 21769 0 20:06 pts/2 00:00:00 grep postgres

主庫上查看到流復制進程:

[postgres@localhost pg_xlog]$ ps -ef|grep postgres
root 2904 2642 0 00:40 pts/0 00:00:00 su - postgres
postgres 2905 2904 0 00:40 pts/0 00:00:00 -bash
postgres 2939 1 0 00:42 pts/0 00:00:00 /usr/local/pgsql/bin/postgres -D /data/pgsql100/data
postgres 2941 2939 0 00:42 ? 00:00:00 postgres: checkpointer process
postgres 2942 2939 0 00:42 ? 00:00:00 postgres: writer process
postgres 2943 2939 0 00:42 ? 00:00:00 postgres: wal writer process
postgres 2944 2939 0 00:42 ? 00:00:00 postgres: autovacuum launcher process
postgres 2945 2939 0 00:42 ? 00:00:00 postgres: stats collector process
root 3109 3064 0 00:58 pts/2 00:00:00 su - postgres
postgres 3110 3109 0 00:58 pts/2 00:00:00 -bash
postgres 3151 3110 0 00:59 pts/2 00:00:00 /bin/bash /usr/local/pgsql/bin/psql -p10280
postgres 3153 3151 0 00:59 pts/2 00:00:00 /usr/local/pgsql/bin/psql.bin -p10280
root 3189 3087 0 01:07 pts/3 00:00:00 su - postgres
postgres 3190 3189 0 01:07 pts/3 00:00:00 -bash
postgres 3272 2939 0 01:25 ? 00:00:00 postgres: postgres testdb01 [local] idle
postgres 3415 2939 0 02:16 ? 00:00:00 postgres: wal sender process replica 10.0.0.110(34021) streaming 0/7000140
postgres 3422 3190 0 02:17 pts/3 00:00:00 ps -ef
postgres 3423 3190 0 02:17 pts/3 00:00:00 grep postgres

此時從庫上可以看到流復制的進程,同樣的主庫也能看到該進程。表明主從流復制配置成功。


同步測試演示:
創建庫和建表做測試,在master服務器(10.0.0.100)中的創建testdb02庫並且建一張表並添加幾條數據:


master上操作:
postgres=# create database testdb02;
CREATE DATABASE
檢查:
[postgres@localhost pg_xlog]$ psql -p10280 -c ‘\list‘|grep testdb02
testdb02 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |

testdb01=# \c testdb02
You are now connected to database "testdb02" as user "postgres".
testdb02=# \d
No relations found.
創建表:
CREATE TABLE weather ( city varchar(80), temp_lo int, temp_hi int, prcp real,date date);
testdb02=# \d
List of relations
Schema | Name | Type | Owner
--------+---------+-------+----------
public | weather | table | postgres
(1 row)

testdb02=# \d weather
Table "public.weather"
Column | Type | Modifiers
---------+-----------------------+-----------
city | character varying(80) |
temp_lo | integer |
temp_hi | integer |
prcp | real |
date | date |

testdb02=#
testdb02=# INSERT INTO weather (city, temp_lo, temp_hi, prcp, date) VALUES (‘China05‘, ‘47‘, ‘59‘, ‘1.0‘, ‘1994-12-15‘);
INSERT 0 1
testdb02=# INSERT INTO weather (city, temp_lo, temp_hi, prcp, date) VALUES (‘China04‘, ‘46‘, ‘58‘, ‘2.0‘, ‘1994-12-14‘);\
INSERT 0 1
testdb02=# select * from weather;
city | temp_lo | temp_hi | prcp | date
---------+---------+---------+------+------------
China05 | 47 | 59 | 1 | 1994-12-15
China04 | 46 | 58 | 2 | 1994-12-14
(2 rows)
testdb02=#

從庫上檢查:
[postgres@localhost data]$ psql -p10280 -c ‘\list‘|grep testdb02
testdb02 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |

postgres=# \c testdb02;
You are now connected to database "testdb02" as user "postgres".
testdb02=# \d
List of relations
Schema | Name | Type | Owner
--------+---------+-------+----------
public | weather | table | postgres
(1 row)

testdb02=# \d weather;
Table "public.weather"
Column | Type | Modifiers
---------+-----------------------+-----------
city | character varying(80) |
temp_lo | integer |
temp_hi | integer |
prcp | real |
date | date |

testdb02=# select * from weather;
city | temp_lo | temp_hi | prcp | date
---------+---------+---------+------+------------
China05 | 47 | 59 | 1 | 1994-12-15
China04 | 46 | 58 | 2 | 1994-12-14
(2 rows)

testdb02=#
可以看到完美同步,那麽從庫是否能刪除呢?測試一下:
從庫上測試刪除數據庫testdb02;
postgres=# drop database testdb02;
ERROR: cannot execute DROP DATABASE in a read-only transaction
postgres=# drop database testdb01;
ERROR: cannot execute DROP DATABASE in a read-only transaction

standby的數據無法刪除,正如我們之前說的,standby只提供只讀服務,而只有master才能進行讀寫操作,所以master才有權限刪除數據。master刪除的同時standby中的數據也將同步刪除,

查看復制狀態

主庫中執行

技術分享

關於異步流復制的內容到這裏.

參考博文:

http://blog.csdn.net/wzyzzu/article/details/53331206

本文出自 “10931853” 博客,請務必保留此出處http://wujianwei.blog.51cto.com/10931853/1977210

postgresql主從實現之異步流復制