Setting up PostGresql Replication with Loadbalancing with PGPOOL II
Installation (on both Master and Slave Nodes):
yum install https://yum.postgresql.org/9.5/redhat/rhel-7-x86_64/pgdg-centos95-9.5-3.noarch.rpm yum install postgresql95 postgresql95-server postgresql-libs postgresql95-contrib rsync
Initialize the database and configure postgresql
/usr/pgsql-9.5/bin/postgresql95-setup initdb cd /var/lib/pgsql/9.5/data cp postgresql.conf postgresql.conf.orig chown postgres postgresql.conf.orig
On Master Node:
systemctl start postgresql-9.5 su - postgres psql create user repuser replication; \du+ (TO check if the replication user was created with right rule) \q
Configure Database Access:
Open pg_hba.conf for editing
vi /var/lib/pgsql/9.5/data/pg_hba.conf
If Doing Replication Manager:
#TYPE DATABASE USER ADDRESS METHOD host repmgr repmgr 192.168.202.101/32 trust host replication repmgr 192.168.202.101/32 trust host repmgr repmgr 192.168.202.102/32 trust host replication repmgr 192.168.202.102/32 trust host all pgpool 192.168.202.103/32 trust
Else if Using PGPOOL :
host all pgpool 192.168.100.0/24 trust host all pgpool ::1/128 trust host all pgpool 127.0.0.1/32 trust host replication repuser 192.168.100.43/32 trust host all all 192.168.100.0/24 md5
Else ( Plain Postgresql Replication)
host replication repuser 192.168.100.0/24 trust
Configure PostgreSQL
Open postgresql.conf for editing:
vi postgresql.conf
listen_addresses = '*' port = 5432 #write ahead log configuration (wal means write ahead logging, changes to data files must be written only after those changes have been logged) wal_level=hot_standby fsync = on wal_sync_method = open_sync synchronous_commit = on wal_keep_segments = 100 #(default size 16M , so 1600M) #replication max_wal_senders = 1 #no of slave servers synchronous_standby_names = 'postgresqlslave' # Enables synchronous replication. Will be used on slave instance configuration, can use anything #General max_connections = 100 # (change requires restart) shared_buffers = 128MB # min 128kB dynamic_shared_memory_type = posix # the default is the first option log_destination = 'stderr' # Valid values are combinations of logging_collector = on # Enable capturing of stderr and csvlog log_directory = 'pg_log' # directory where log files are written, log_filename = 'postgresql-%a.log' # log file name pattern, log_truncate_on_rotation = on # If on, an existing log file with the log_rotation_age = 1d # Automatic rotation of logfiles will log_rotation_size = 0 # Automatic rotation of logfiles will log_line_prefix = '< %m >' # special values: log_timezone = 'US/Eastern' datestyle = 'iso, mdy' timezone = 'US/Eastern' lc_messages = 'en_US.UTF-8' # locale for system error message lc_monetary = 'en_US.UTF-8' # locale for monetary formatting lc_numeric = 'en_US.UTF-8' # locale for number formatting lc_time = 'en_US.UTF-8' # locale for time formatting default_text_search_config = 'pg_catalog.english'
On the Slave Node:
systemctl stop postgresql-9.5 su - postgres cd /var/lib/pgsql/9.5/data/ rm -rf * pg_basebackup -D /var/lib/pgsql/9.5/data -h 192.168.100.57 -U repuser
vi recovery.conf #(provides information for replication, application_name is the synchronous_standby_names configured on master) standby_mode=on trigger_file='/tmp/promotedb' #(If this file exists the server will stop being a replication server and start being a primary server) primary_conninfo='host=192.168.100.57 port=5432 user=repuser application_name=postgresqlslave'
Now enable Slave to accept and read queries
vi /var/lib/pgsql/9.5/data/postgresql.conf hot_standby=on hot_standby_feedback = on
Restart Services and Set to auto start on boot:
systemctl restart postgresql-9.5 systemctl enable postgresql-9.5
CTRL+d systemctl restart postgresql-9.5
Install PGPOOL :
yum install postgresql95 pgpool-II-95 -y cd /etc/pgpool-II-95 cp /etc/pgpool-II-95/pgpool.conf.sample-stream /etc/pgpool-II-95/pgpool.conf sudo su - postgres psql CREATE ROLE pgpool SUPERUSER CREATEDB CREATEROLE INHERIT REPLICATION LOGIN ENCRYPTED PASSWORD 'secret'; \q exit
Configure pgpool configuration file (Note: Edit the settings , do not replace.
vi /etc/pgpool-II-95/pgpool.conf listen_addresses = '*' port = 5432 backend_hostname0 = 'pgdb1' backend_port0 = 5432 backend_weight0 = 1 backend_data_directory0 = '/var/lib/pgsql/9.5/data' backend_flag0 = 'ALLOW_TO_FAILOVER' backend_hostname1 = 'pgdb2' backend_port1 = 5432 backend_weight1 = 1 backend_data_directory1 = '/var/lib/pgsql/9.5/data' backend_flag1 = 'ALLOW_TO_FAILOVER' enable_pool_hba = on pid_file_name = '/var/run/pgpool-II-95/pgpool.pid' sr_check_user = 'pgpool' sr_check_password = 'secret' health_check_period = 10 health_check_user = 'pgpool' health_check_password = 'secret' failover_command = '/etc/pgpool-II-95/failover.sh %d %H' recovery_user = 'pgpool' recovery_password = 'secret' recovery_1st_stage_command = 'basebackup.sh'
Or if you would like to replace the whole file ( make sure you update your variables/settings)
listen_addresses = '*' port = 9999 socket_dir = '/tmp' pcp_listen_addresses = '*' pcp_port = 9898 pcp_socket_dir = '/tmp' listen_backlog_multiplier = 2 serialize_accept = off backend_hostname0 = 'localhost' backend_port0 = 5432 backend_weight0 = 1 backend_data_directory0 = '/var/lib/pgsql/9.5/data' backend_flag0 = 'ALLOW_TO_FAILOVER' enable_pool_hba = on pool_passwd = 'pool_passwd' authentication_timeout = 60 ssl = off num_init_children = 32 max_pool = 4 child_life_time = 300 child_max_connections = 0 connection_life_time = 0 client_idle_limit = 0 log_destination = 'syslog' log_line_prefix = '%t: pid %p: ' # printf-style string to output at beginning of each log line. log_connections = off log_hostname = off log_statement = off log_per_node_statement = off log_standby_delay = 'if_over_threshold' syslog_facility = 'LOCAL0' syslog_ident = 'pgpool' debug_level = 0 pid_file_name = '/var/run/pgpool-II-95/pgpool.pid' logdir = '/tmp' connection_cache = on reset_query_list = 'ABORT; DISCARD ALL' replication_mode = off replicate_select = off insert_lock = off lobj_lock_table = '' replication_stop_on_mismatch = off failover_if_affected_tuples_mismatch = off load_balance_mode = on ignore_leading_white_space = on white_function_list = '' black_function_list = 'currval,lastval,nextval,setval' database_redirect_preference_list = '' app_name_redirect_preference_list = '' allow_sql_comments = off master_slave_mode = on master_slave_sub_mode = 'stream' sr_check_period = 10 sr_check_user = 'pgpool' sr_check_password = 'secret' sr_check_database = 'postgres' delay_threshold = 10000000 follow_master_command = '' health_check_period = 10 health_check_timeout = 20 health_check_user = 'pgpool' health_check_password = 'secret' health_check_database = '' health_check_max_retries = 0 health_check_retry_delay = 1 connect_timeout = 10000 failover_command = '' failback_command = '' fail_over_on_backend_error = on search_primary_node_timeout = 300 recovery_user = 'pgpool' recovery_password = 'secret' recovery_1st_stage_command = '' recovery_2nd_stage_command = '' recovery_timeout = 90 client_idle_limit_in_recovery = 0 use_watchdog = off trusted_servers = '' ping_path = '/bin' wd_hostname = '' wd_port = 9000 wd_priority = 1 wd_authkey = '' wd_ipc_socket_dir = '/tmp' delegate_IP = '' if_cmd_path = '/sbin' if_up_cmd = 'ip addr add $_IP_$/24 dev eth0 label eth0:0' if_down_cmd = 'ip addr del $_IP_$/24 dev eth0' arping_path = '/usr/sbin' arping_cmd = 'arping -U $_IP_$ -w 1' clear_memqcache_on_escalation = on wd_escalation_command = '' wd_de_escalation_command = '' wd_monitoring_interfaces_list = '' # Comma separated list of interfaces names to monitor. wd_lifecheck_method = 'heartbeat' wd_interval = 10 wd_heartbeat_port = 9694 wd_heartbeat_keepalive = 2 wd_heartbeat_deadtime = 30 heartbeat_destination0 = 'host0_ip1' heartbeat_destination_port0 = 9694 heartbeat_device0 = '' wd_life_point = 3 wd_lifecheck_query = 'SELECT 1' wd_lifecheck_dbname = 'template1' wd_lifecheck_user = 'nobody' wd_lifecheck_password = '' relcache_expire = 0 relcache_size = 256 check_temp_table = on check_unlogged_table = on memory_cache_enabled = off memqcache_method = 'shmem' memqcache_memcached_host = 'localhost' memqcache_memcached_port = 11211 memqcache_total_size = 67108864 memqcache_max_num_cache = 1000000 memqcache_expire = 0 memqcache_auto_cache_invalidation = on memqcache_maxcache = 409600 memqcache_cache_block_size = 1048576 memqcache_oiddir = '/var/log/pgpool/oiddir' white_memqcache_table_list = '' black_memqcache_table_list = ''
If you would like pgpool to trigger failover script when failover happens :
vi /etc/pgpool-II-94/failover.sh: #!/bin/sh failed_node=$1 new_master=$2 ( date echo "Failed node: $failed_node" set -x /usr/bin/ssh -T -l postgres $new_master "/usr/pgsql-9.4/bin/repmgr -f /var/lib/pgsql/repmgr/repmgr.conf standby promote 2>/dev/null 1>/dev/null <&-" exit 0; ) 2>&1 | tee -a /tmp/pgpool_failover.log chmod 755 /etc/pgpool-II-94/failover.sh
We also specified in the configuration that we want to use pool_hba.conf so we need to create this file in /etc/pgpool-II-94/pool_hba.conf:
cp pool_hba.conf.sample pool_hba.conf
# TYPE DATABASE USER CIDR-ADDRESS METHOD local all all trust host all all 127.0.0.1/32 trust host all all ::1/128 trust host all all 0.0.0.0/0 md5
Every user that needs to connect via pgpool needs to be added in pool_passwd. First we need to create this file and let it be owned by postgres:
touch /etc/pgpool-II-95/pool_passwd chown postgres:postgres /etc/pgpool-II-95/pool_passwd
Add users to file :
su - postgres -c "pg_md5 -m -u pgpool secret"
Now we need to allow connection via PCP to manage the pgpool.
echo "pgpool:$(pg_md5 secret)"|sudo tee /etc/pgpool-II-95/pcp.conf pgpool:5ebe2294ecd0e0f08eab7690d2a6ee69
Now configure firewall if enabled
firewall-cmd --permanent --zone=public --add-service=postgresql systemctl reload firewalld
Configure Pgpool service to auto start on
systemctl enable pgpool-II-95 ( you can look for service name : /usr/lib/systemd/system/) systemctl start pgpool-II-95
Test PGPOOL :
psql -U pgpool --host pgpool --dbname postgres -c "\list"
To get status of nodes connected to pgpool :
psql -U pgpool --dbname=postgres --host pgpool -c "show pool_nodes"
Test Failover:
systemctl stop postgresql-9.5 psql -U pgpool --dbname=postgres --host pgpool -c "show pool_nodes"
Now you see former has become primary and other has become standby
For pgpool, we need to re-attach the failed node in order for it to be visible and usable as a standby-node:
pcp_detach_node 0 localhost 9898 pgpool secret 0
At this point, we’re back in a redundant status where the old standby (pgdb2) functions as the primary and the old primary (pgdb1) functions as a standby. If both machines are equal, you can leave the situation as is and continue to use it in this way.
Recover to the original situation
When the master (pgdb2) stopped, a failover was triggered and pgdb1 gets assigned as primary again:
psql -U pgpool --dbname=postgres --host pgpool -c "show pool_nodes"
Now, sync pgdb2 with the new primary (pgdb1) and start it:
su - postgres /usr/pgsql-9.4/bin/repmgr -D /var/lib/pgsql/9.4/data -d repmgr -p 5432 -U repmgr -R postgres --force standby clone pgdb1 systemctl start postgresql-9.5
Reattach another server as slave:
pcp_detach_node 1 localhost 9898 pgpool secret 1
Test Replication:::
\l or \list \dt all tables in current database \connect database_name Create database: create DATABASE test; CREATE TABLE data( id serial primary key not null, time timestamp not null default CURRENT_TIMESTAMP, number integer not null ); insert into data(id,number) values(2,10);
Check on Slave:
\connect test; SELECT * FROM data;
Extra Commands:
Applying changes on server:
pg_ctl -D /var/lib/pgsql/9.5/data reload pg_ctl -D /var/lib/pgsql/9.5/data/ start
If any changes are made to recovery file:
pg_ctl -D /var/lib/pgsql/data/ restart -m fast