Replikace
Vestavěná (a)synchronní replikace - postup pro 9.1 a vyšší
Zde popsaný postup platí pro streaming replikaci. Streaming replikace vylepšuje Warm Standby a Hot Standby replikaci, tak že mezi master a standby databází otevře síťové spojení po kterém se předávají záznamy Write-Ahead Logů (WAL) z masteru na standby ihned poté, co jsou na master DB zpracovány. Na DB serveru v operačním systému jsou vidět běžící procesy walsender resp. walreceiver.
Warm Standby a Hot Standby replikace taky využívá WAL logy pro synchronizaci dat, ale v tomto případě je potřeba logy doručit z master na slave (např. přes scp). Tato konfigurace zde není popsána.
Master běží na 10.0.0.1, replika na 10.0.0.4
Pozn: Slave serverů může být několik - slave (replika) je read-only, master pouze jeden. Podmínkou je stejná verze PostgreSQL na replikovaném serveru a na replikách. Replikují se veškeré změny v databázi. Repliky mohou mít vlastní konfiguraci - podmínkou je soubor recovery.conf.
Příprava serveru, který poběží jako master
- vytvoření účtu pod kterým poběží replikace (pro 9.0 je nutné použít účet postgres)
postgres=# CREATE ROLE replikator LOGIN REPLICATION; CREATE ROLE postgres=# ALTER USER replikator PASSWORD 'heslo'; ALTER ROLE
- úpravy konfigurace postgresql.conf
listen_addresses = '*' # what IP address(es) to listen on; wal_level = hot_standby # minimal, archive, or hot_standby archive_mode = on # allows archiving to be done archive_command = '/bin/true' # command to use to archive a logfile segment max_wal_senders = 1 # max number of walsender processes wal_keep_segments = 64 # in logfile segments, 16MB each; 0 disables
- zpřístupnění masteru z repliky - zásah do pg_hba.conf
host replication replikator 10.0.0.4/32 md5
- (nepovinné) aktivace synchronní replikace v postgresql.conf
synchronous_standby_names = '*'
Příprava serveru, který poběží jako slave
- z repliky se přihlásit jako uživatel postgres a vymazat adresář ve kterém bude umístěn cluster repliky
- z repliky pomocí pg_basebackup provést online zálohu masteru - (na 9.0 ručně)
[postgres@nemesis data]$ pg_basebackup -D /usr/local/pgsql/data/ -U replikator -h 10.0.0.1 Password: NOTICE: pg_stop_backup complete, all required WAL segments have been archived
- v postgresql.conf povolit hot standby režim
hot_standby = on
- v případě, že na replice budete volat pomalé dotazy, nastavte aktivní hot_standby_feedback
hot_standby_feedback = on
- do clusteru repliky nakopírovat soubor recovery.conf
standby_mode='on' primary_conninfo='host=10.0.0.1 user=replikator password=heslo' trigger_file='/usr/local/pgsql/data/failover'
- vymazat serverlog z clusteru repliky
- nastartovat repliku
- log by měl obsahovat zhruba:
LOG: database system was interrupted; last known up at 2011-09-04 17:59:03 CEST LOG: creating missing WAL directory "pg_xlog/archive_status" LOG: entering standby mode LOG: streaming replication successfully connected to primary LOG: redo starts at 0/23000020 LOG: consistent recovery state reached at 0/24000000
Pozn: Pokud je takto nakonfigurován server, tak velice snadno - s použitím pg_basebackup můžeme provádět online full backup.V tom případě je nutné zvýšit max_wal_senders.
Monitoring běžící replikace
Master server
- Výpis procesů OS
[root@testdb1 data]# ps -ef |grep sender postgres 1818 1687 0 13:53 ? 00:00:00 postgres: wal sender process replikator 10.0.0.4(35948) streaming 0/130009A0
- DB dotaz
postgres=# SELECT pg_current_xlog_location() ; pg_current_xlog_location -------------------------- 0/13000A38 (1 row)
Standby server
- Výpis procesů OS
[root@testdb2 data]# ps -ef |grep receiver postgres 2837 2831 0 13:53 ? 00:00:02 postgres: wal receiver process streaming 0/130009A0
- DB dotaz
postgres=# select pg_last_xlog_receive_location() ; pg_last_xlog_receive_location ------------------------------- 0/13000A38 (1 row) postgres=# select pg_last_xlog_replay_location() ; pg_last_xlog_replay_location ------------------------------ 0/13000A38 (1 row) postgres=# SELECT pg_is_in_recovery(); pg_is_in_recovery ------------------- t (1 row)
Failover
V případě, že v souboru recovery.conf použijeme parametr trigger_file (v našem případě trigger_file='/usr/local/pgsql/data/failover') stačí vytvořit prázdný soubor na který tento parametr ukazuje a DB provede recovery automaticky.
- Provedení failoveru pomocí trigger file
[root@testdb2 ~]# su - posgres -c "touch /usr/local/pgsql/data/failover" Výpis logu: LOG: trigger file found: /usr/local/pgsql/data/failover FATAL: terminating walreceiver process due to administrator command LOG: record with zero length at 0/13000C00 LOG: redo done at 0/13000BA0 LOG: selected new timeline ID: 2 LOG: archive recovery complete LOG: database system is ready to accept connections LOG: autovacuum launcher started
Další možností je použít příkaz pg_ctl promote
Obnovení replikace po proceduře failover znamená vytvoření nové kopie standby DB a nastavení nové replikace jak je popsáno výše.
V pg_bench tj. při maximálním vytížení (výchozí konfigurace a IO s zablokovanou write cache (obyčejný disk v notebooku)) je režie asynchronní replikace cca 6-10%, a režie synchronní replikace cca 40% - v běžném provozu bych očekával režii znatelně nižší - pravděpodobně budete mít na svém serveru jištěné IO s aktivní write cache.
V případě, že potřebujeme automatické HA řešení existují různé projekty, které používají výše popsaný princip streaming replikace.
Pro Pacemaker + Corosync existuje projekt PAF. Je to v perlu napsaný OCF resource agent pomocí kterého je Pacemaker schopný rozpoznat stav jednotlivých PostgreSQL instancí na každém nodu: master, slave, stopped, catching up, apod. V případě, že na masteru nastane chyba, která je neopravitelná PAF provede promote vybrané standby DB jako nový master. PAF vyžaduje verzi PostgreSQL 9.3 a vyšší
Další projekt, který umožnuje postavení HA řešení je repmgr. Popis konfigurace viz níže, nebo v aktuálním taháku
Replikace a HA založená na repmgr (nutno zrevidovat)
Fakticky se jedná o nadstavbu nad vestavěnou podporou replikací v PostgreSQL 9.0 a vyšší. Tu rozšiřuje o podporu fail-over. Pracnost spojená s tímto systémem je větší než vestavěná replikace v 9.1 - naopak tento systém je možné použít i s PostgreSQL 9.1.
Master je na 10.0.0.1, slave je na 10.0.0.4.
Předpoklady: běžící sshd, možnost kopírování pomocí rsync mezi jednotlivými uzlu prostřednictvím učtu postgres.
- nastavení hesla pro uživatele postgres, vytvoření certifikátu a jeho zkopírování na slave
[root@nemesis pavel]# passwd postgres Changing password for user postgres. New password: Retype new password: passwd: all authentication tokens updated successfully. [root@nemesis pavel]# su - postgres [postgres@nemesis ~]$ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/postgres/.ssh/id_rsa): Created directory '/home/postgres/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/postgres/.ssh/id_rsa. Your public key has been saved in /home/postgres/.ssh/id_rsa.pub. The key fingerprint is: b6:84:3c:e2:e0:53:49:59:35:a9:53:9d:ca:f5:e8:ab postgres@nemesis The key's randomart image is: +--[ RSA 2048]----+ | ..oo . | | o o.+ | | o + o o | | . oo.o . . | | . + +.S. | | . + . + .. | | o . . . | | . . | | E. | +-----------------+ [postgres@10.0.0.1 ~]$ ssh-copy-id -i ~/.ssh/id_rsa.pub 10.0.0.4 The authenticity of host '10.0.0.4 (10.0.0.4)' can't be established. RSA key fingerprint is b2:25:50:34:3f:93:da:60:e8:f2:36:88:51:a8:1a:ce. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '10.0.0.4' (RSA) to the list of known hosts. postgres@10.0.0.4's password: Permission denied, please try again. postgres@10.0.0.4's password: Now try logging into the machine, with "ssh '10.0.0.4'", and check in: .ssh/authorized_keys to make sure we haven't added extra keys that you weren't expecting. [postgres@nemesis ~]$ ssh 10.0.0.4
- výše zmíněný login (ssh 10.0.0.4) by měl projít bez požadavků na heslo
- předchozí dva body se zopakují na počítači, který má sloužit jako slave
su - postgres ssh-keygen -t rsa ssh-copy-id -i ~/.ssh/id_rsa.pub 10.0.0.1 ssh 10.0.0.1
- uzavřeme všechny ssh spojení
- na masteru připravíme počáteční konfiguraci PostgreSQL
listen_addresses = "*" wal_level = hot_standby archive_mode=on archive_command='/bin/true' max_wal_senders=2 wal_keep_segments=100 hot_standby=on
- primární server zpřístupníme replice - zásah do pg_hba.conf
host repmgr repmgr 10.0.0.4/32 md5 host replication all 10.0.0.4/32 md5 host repmgr repmgr 10.0.0.1/32 md5 host replication all 10.0.0.1/32 md5
- heslo uživatele uloží v dalším kroku do .pgpass
- restart masteru
- na replice odstraníme obsah clusteru
/etc/init.d/postgresql stop cd /var/lib/pgsql/data rm -rf *
- na slavu přeložíme repmgr. K dispozici musí být devel knihovny PostgreSQL. Tento krok je nutné zopakovat i na primárném serveru (masteru)
tar xvfz repmgr-1.1.0.tar.gz cd repmgr-1.1.0 make USE_PGXS=1 su make USE_PGXS=1 install
- zpět na master - založíme db repmgr a uživatele repmgr - uživatel repmgr musí být superuser
[postgres@10.0.0.1]$ createdb repmgr; [postgres@10.0.0.1]$ createuser repmgr Shall the new role be a superuser? (y/n) y postgres=# ALTER USER repmgr PASSWORD 'heslo'; ALTER ROLE
- ověříme přístup ze slave na master
su postgres echo '10.0.0.1:5432:repmgr:repmgr:heslo' >> .pgpass chmod 0600 ~/.pgpass psql -h 10.0.0.1 -U repmgr repmgr
- klonujeme master na slave (pozor - je nutne zadat port, přestože je standardní)
[postgres@10.0.0.4]$ repmgr -D /usr/local/pgsql/data -U repmgr -p 5432 -d repmgr -R postgres --verbose standby clone 10.0.0.1 ... reomgr standby clone complete
- na všech uzlech vytvoříme konfigurační soubor /usr/local/pgsql/repmgr/repmgr.conf podle vzoru:
[root@10.0.0.1]# cat /usr/local/pgsql/repmgr/repmgr.conf cluster=test node=1 conninfo='host=10.0.0.1 user=repmgr dbname=repmgr password=heslo'
- registrace masteru
[root@10.0.0.1]# repmgr -f /usr/local/pgsql/repmgr/repmgr.conf --verbose master register Opening configuration file: /usr/local/pgsql/repmgr/repmgr.conf repmgr connecting to master database repmgr connected to master, checking its state master register: creating database objects inside the repmgr_test schema NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "repl_nodes_pkey" for table "repl_nodes" Master node correctly registered for cluster test with id 1 (conninfo: host=10.0.0.1 user=repmgr dbname=repmgr password=heslo)
- na slave je nutné do souboru recovery.conf dopsat přihlašovací údaje pro login na master
standby_mode = 'on' primary_coninfo = 'host=10.0.0.1 port=5432 user=repmgr password=heslo'
- registrace slave
[root@nemesis data]# /etc/init.d/pgsql start Starting PostgreSQL: ok [root@10.0.0.4 data]# repmgr -f /usr/local/pgsql/repmgr/repmgr.conf --verbose standby register Opening configuration file: /usr/local/pgsql/repmgr/repmgr.conf repmgr connecting to standby database repmgr connected to standby, checking its state repmgr connecting to master database finding node list for cluster 'test' checking role of cluster node 'host=10.0.0.1 user=repmgr dbname=repmgr password=heslo' repmgr connected to master, checking its state repmgr registering the standby repmgr registering the standby complete
- na slave nastartujeme repmgrd
[root@10.0.0.4]# repmgrd -f /usr/local/pgsql/repmgr/repmgr.conf --verbose > /usr/local/pgsql/repmgr/repmgr.log 2>&1 [root@10.0.0.4 pavel]# tail -f /usr/local/pgsql/repmgr/repmgr.log repmgrd Connecting to database 'host=10.0.0.4 user=repmgr dbname=repmgr password=heslo' repmgrd Connected to database, checking its state repmgrd Connecting to primary for cluster 'test' finding node list for cluster 'test' checking role of cluster node 'host=10.0.0.1 user=repmgr dbname=repmgr password=heslo' repmgrd Checking cluster configuration with schema 'repmgr_test' repmgrd Checking node 2 in cluster 'test' repmgrd Starting continuous standby node monitoring
- na slave se lze dotázat na stav replikace
repmgr=# select * from repmgr_test.repl_status ; ─[ RECORD 1 ]─────────────┬────────────────────────────── primary_node │ 1 standby_node │ 2 last_monitor_time │ 2011-09-05 18:00:44.277306+02 last_wal_primary_location │ 0/5B186764 last_wal_standby_location │ 0/5B186764 replication_lag │ 0 bytes apply_lag │ 0 bytes time_lag │ 00:00:02.639117