-- postgresql.conf on standby serverhot_standby=onmax_standby_streaming_delay=30smax_standby_archive_delay=30swal_receiver_timeout=60shot_standby_feedback=on#Recoveryconfigurationrecovery_target_timeline='latest'
-- Create replication user on primaryCREATEUSERreplicatorWITHREPLICATIONLOGINPASSWORD'replication_password';-- Grant necessary privilegesGRANTCONNECTONDATABASEproductionTOreplicator;GRANTUSAGEONSCHEMApublicTOreplicator;
-- Enable logical replication on publisherALTERSYSTEMSETwal_level=logical;ALTERSYSTEMSETmax_replication_slots=10;ALTERSYSTEMSETmax_wal_senders=10;SELECTpg_reload_conf();-- Create publicationCREATEPUBLICATIONproduction_pubFORALLTABLES;-- Or for specific tablesCREATEPUBLICATIONuser_pubFORTABLEusers,user_profiles;CREATEPUBLICATIONorder_pubFORTABLEorders,order_items;-- Add tables to existing publicationALTERPUBLICATIONproduction_pubADDTABLEnew_table;
# monitoring/replication_monitor.pyimportpsycopg2importtimeimportloggingfromdatetimeimportdatetime,timedeltaclassPostgreSQLReplicationMonitor:def__init__(self,primary_config,standby_configs):self.primary_config=primary_configself.standby_configs=standby_configsself.setup_logging()defsetup_logging(self):"""Setup logging."""logging.basicConfig(level=logging.INFO)self.logger=logging.getLogger(__name__)defcheck_primary_status(self):"""Check primary server status."""try:conn=psycopg2.connect(**self.primary_config)withconn.cursor()ascur:# Check if primary is accepting connectionscur.execute("SELECT 1")result=cur.fetchone()# Check replication slotscur.execute(""" SELECT slot_name, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) as lag FROM pg_replication_slots; """)slots=cur.fetchall()# Check WAL sender processescur.execute(""" SELECT count(*) FROM pg_stat_replication; """)replication_count=cur.fetchone()[0]return{'status':'healthy','replication_slots':slots,'replication_count':replication_count}exceptExceptionase:self.logger.error(f"Primary check failed: {e}")return{'status':'unhealthy','error':str(e)}defcheck_standby_status(self,standby_config):"""Check standby server status."""try:conn=psycopg2.connect(**standby_config)withconn.cursor()ascur:# Check if standby is in recovery modecur.execute("SELECT pg_is_in_recovery();")in_recovery=cur.fetchone()[0]ifnotin_recovery:return{'status':'not_standby','error':'Server is not in recovery mode'}# Check replication lagcur.execute(""" SELECT pg_wal_lsn_diff(pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn()) as lag_bytes, pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn() """)lag_info=cur.fetchone()# Check last activitycur.execute(""" SELECT pg_last_xact_replay_timestamp(), pg_last_wal_replay_timestamp() """)activity_info=cur.fetchone()return{'status':'healthy','lag_bytes':lag_info[0],'receive_lsn':lag_info[1],'replay_lsn':lag_info[2],'last_xact_replay':activity_info[0],'last_wal_replay':activity_info[1]}exceptExceptionase:self.logger.error(f"Standby check failed: {e}")return{'status':'unhealthy','error':str(e)}defcheck_replication_lag(self,threshold_mb=100):"""Check replication lag across all standbys."""lag_alerts=[]forstandby_name,standby_configinself.standby_configs.items():status=self.check_standby_status(standby_config)ifstatus['status']=='healthy':lag_mb=status['lag_bytes']/(1024*1024)iflag_mb>threshold_mb:lag_alerts.append({'standby':standby_name,'lag_mb':lag_mb,'threshold_mb':threshold_mb})returnlag_alertsdefmonitor_replication(self):"""Monitor replication health."""# Check primaryprimary_status=self.check_primary_status()self.logger.info(f"Primary status: {primary_status['status']}")# Check standbysforstandby_name,standby_configinself.standby_configs.items():standby_status=self.check_standby_status(standby_config)self.logger.info(f"Standby {standby_name} status: {standby_status['status']}")ifstandby_status['status']=='healthy':lag_mb=standby_status['lag_bytes']/(1024*1024)self.logger.info(f"Standby {standby_name} lag: {lag_mb:.2f} MB")# Check for lag alertslag_alerts=self.check_replication_lag()iflag_alerts:foralertinlag_alerts:self.logger.warning(f"High replication lag on {alert['standby']}: {alert['lag_mb']:.2f} MB")return{'primary':primary_status,'standbys':{name:self.check_standby_status(config)forname,configinself.standby_configs.items()},'lag_alerts':lag_alerts}# Usageif__name__=="__main__":primary_config={'host':'192.168.1.10','database':'production','user':'monitor_user','password':'monitor_password'}standby_configs={'standby-1':{'host':'192.168.1.11','database':'production','user':'monitor_user','password':'monitor_password'},'standby-2':{'host':'192.168.1.12','database':'production','user':'monitor_user','password':'monitor_password'}}monitor=PostgreSQLReplicationMonitor(primary_config,standby_configs)whileTrue:status=monitor.monitor_replication()time.sleep(30)
# Complete PostgreSQL replication and HA setupdefsetup_postgresql_replication_ha():# 1. Streaming replication# 2. Logical replication# 3. High availability with Patroni# 4. Load balancing# 5. Monitoring and health checks# 6. Automated failover# 7. Disaster recovery# 8. Testing proceduresprint("PostgreSQL replication and HA setup complete!")