pgraft Tutorial: Complete Setup and Usage Guide (pgElephant Suite)¶
This tutorial will walk you through setting up a complete pgraft cluster from scratch, including installation, configuration, and advanced usage scenarios. All steps, scripts, and best practices are up to date and consistent with the unified pgElephant suite.
Table of Contents¶
- Prerequisites
- Installation
- Basic Cluster Setup
- Advanced Configuration
- Cluster Operations
- Monitoring and Maintenance
- Troubleshooting
- Best Practices
Prerequisites¶
System Requirements¶
- Operating System: Linux, macOS, or Windows
- PostgreSQL: Version 17 or higher
- Go: Version 1.21 or higher
- Memory: Minimum 2GB RAM per node
- Disk: Minimum 10GB free space per node
- Network: Reliable network connectivity between nodes
Software Dependencies¶
# Ubuntu/Debian sudo apt-get update sudo apt-get install postgresql-17 postgresql-server-dev-17 golang-go build-essential # CentOS/RHEL sudo yum install postgresql17 postgresql17-devel golang gcc make # macOS brew install postgresql@17 go Installation¶
Step 1: Download and Build¶
# Clone the repository git clone https://github.com/pgelephant/pgraft.git cd pgraft # Build the extension make clean make sudo make install # Verify installation make installcheck Step 2: Verify Installation¶
# Check if extension files are installed ls -la /usr/local/pgsql.17/lib/pgraft* ls -la /usr/local/pgsql.17/share/extension/pgraft* # Expected output: # pgraft.dylib (or .so on Linux) # pgraft.control # pgraft--1.0.sql Basic Cluster Setup¶
Step 1: Prepare PostgreSQL Instances¶
Create three PostgreSQL instances for our cluster:
# Create data directories mkdir -p /data/node1 /data/node2 /data/node3 # Initialize databases /usr/local/pgsql.17/bin/initdb -D /data/node1 /usr/local/pgsql.17/bin/initdb -D /data/node2 /usr/local/pgsql.17/bin/initdb -D /data/node3 Step 2: Configure PostgreSQL¶
Node 1 Configuration (/data/node1/postgresql.conf):
# Network settings listen_addresses = '*' port = 5433 # Load pgraft extension shared_preload_libraries = 'pgraft' # pgraft configuration pgraft.node_id = 1 pgraft.address = '127.0.0.1' pgraft.port = 5433 pgraft.cluster_name = 'tutorial_cluster' # Logging for debugging log_min_messages = info log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h ' log_checkpoints = on log_connections = on log_disconnections = on log_lock_waits = on Node 2 Configuration (/data/node2/postgresql.conf):
# Network settings listen_addresses = '*' port = 5434 # Load pgraft extension shared_preload_libraries = 'pgraft' # pgraft configuration pgraft.node_id = 2 pgraft.address = '127.0.0.1' pgraft.port = 5434 pgraft.cluster_name = 'tutorial_cluster' # Logging for debugging log_min_messages = info log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h ' log_checkpoints = on log_connections = on log_disconnections = on log_lock_waits = on Node 3 Configuration (/data/node3/postgresql.conf):
# Network settings listen_addresses = '*' port = 5435 # Load pgraft extension shared_preload_libraries = 'pgraft' # pgraft configuration pgraft.node_id = 3 pgraft.address = '127.0.0.1' pgraft.port = 5435 pgraft.cluster_name = 'tutorial_cluster' # Logging for debugging log_min_messages = info log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h ' log_checkpoints = on log_connections = on log_disconnections = on log_lock_waits = on Step 3: Start PostgreSQL Instances¶
# Start all three nodes /usr/local/pgsql.17/bin/pg_ctl -D /data/node1 -l /data/node1/logfile start /usr/local/pgsql.17/bin/pg_ctl -D /data/node2 -l /data/node2/logfile start /usr/local/pgsql.17/bin/pg_ctl -D /data/node3 -l /data/node3/logfile start # Verify they're running ps aux | grep postgres Step 4: Initialize the Cluster¶
Connect to each node and initialize pgraft:
# Connect to Node 1 psql -h 127.0.0.1 -p 5433 -U postgres # Create the extension CREATE EXTENSION IF NOT EXISTS pgraft; # Initialize the first node SELECT pgraft_init(); # Check the status SELECT pgraft_get_worker_state(); SELECT * FROM pgraft_get_cluster_status(); # Exit \q # Connect to Node 2 psql -h 127.0.0.1 -p 5434 -U postgres # Create the extension CREATE EXTENSION IF NOT EXISTS pgraft; # Initialize the node SELECT pgraft_init(); # Exit \q # Connect to Node 3 psql -h 127.0.0.1 -p 5435 -U postgres # Create the extension CREATE EXTENSION IF NOT EXISTS pgraft; # Initialize the node SELECT pgraft_init(); # Exit \q Step 5: Form the Cluster¶
Connect to the first node and add the other nodes:
# Connect to Node 1 (should be the initial leader) psql -h 127.0.0.1 -p 5433 -U postgres # Add Node 2 to the cluster SELECT pgraft_add_node(2, '127.0.0.1', 5434); # Add Node 3 to the cluster SELECT pgraft_add_node(3, '127.0.0.1', 5435); # Verify cluster formation SELECT * FROM pgraft_get_nodes(); SELECT * FROM pgraft_get_cluster_status(); SELECT pgraft_is_leader(); # Exit \q Step 6: Verify Cluster Health¶
Check each node to ensure they're properly connected:
# Check Node 1 psql -h 127.0.0.1 -p 5433 -U postgres -c "SELECT pgraft_is_leader(), pgraft_get_term(), pgraft_get_leader();" # Check Node 2 psql -h 127.0.0.1 -p 5434 -U postgres -c "SELECT pgraft_is_leader(), pgraft_get_term(), pgraft_get_leader();" # Check Node 3 psql -h 127.0.0.1 -p 5435 -U postgres -c "SELECT pgraft_is_leader(), pgraft_get_term(), pgraft_get_leader();" Expected output should show: - One node as leader (pgraft_is_leader() returns true) - Same term number on all nodes - Same leader ID on all nodes
Advanced Configuration¶
Performance Tuning¶
Optimize for High Throughput:
# In postgresql.conf pgraft.heartbeat_interval = 500 # Faster heartbeats pgraft.election_timeout = 3000 # Faster elections pgraft.worker_interval = 100 # More frequent processing # PostgreSQL settings shared_buffers = 256MB effective_cache_size = 1GB work_mem = 4MB maintenance_work_mem = 64MB Optimize for Low Latency:
# In postgresql.conf pgraft.heartbeat_interval = 1000 # Standard heartbeats pgraft.election_timeout = 5000 # Standard elections pgraft.worker_interval = 50 # Very frequent processing # PostgreSQL settings synchronous_commit = on fsync = on wal_sync_method = fdatasync Security Configuration¶
Enable SSL/TLS:
# In postgresql.conf ssl = on ssl_cert_file = 'server.crt' ssl_key_file = 'server.key' ssl_ca_file = 'ca.crt' # pgraft will automatically use SSL for inter-node communication Network Security:
# Configure firewall (example for iptables) sudo iptables -A INPUT -p tcp --dport 5433 -s 127.0.0.1 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 5434 -s 127.0.0.1 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 5435 -s 127.0.0.1 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 5433 -j DROP sudo iptables -A INPUT -p tcp --dport 5434 -j DROP sudo iptables -A INPUT -p tcp --dport 5435 -j DROP Cluster Operations¶
Adding a New Node¶
-
Prepare the new node:
-
Start the new node:
-
Add to cluster:
Removing a Node¶
-- Connect to any node psql -h 127.0.0.1 -p 5433 -U postgres -- Remove the node SELECT pgraft_remove_node(4); -- Verify SELECT * FROM pgraft_get_nodes(); Leader Election Testing¶
Test automatic leader election by stopping the current leader:
# Find the current leader psql -h 127.0.0.1 -p 5433 -U postgres -c "SELECT pgraft_is_leader(), pgraft_get_leader();" # Stop the leader (replace with actual port) /usr/local/pgsql.17/bin/pg_ctl -D /data/node1 stop # Wait a few seconds, then check remaining nodes psql -h 127.0.0.1 -p 5434 -U postgres -c "SELECT pgraft_is_leader(), pgraft_get_term();" psql -h 127.0.0.1 -p 5435 -U postgres -c "SELECT pgraft_is_leader(), pgraft_get_term();" # One should now be the leader with a higher term # Restart the stopped node /usr/local/pgsql.17/bin/pg_ctl -D /data/node1 -l /data/node1/logfile start # It will automatically rejoin as a follower Log Replication Testing¶
Test log replication by performing operations:
-- Connect to the leader psql -h 127.0.0.1 -p 5433 -U postgres -- Create a test table CREATE TABLE test_data (id SERIAL PRIMARY KEY, data TEXT, created_at TIMESTAMP DEFAULT NOW()); -- Insert some data INSERT INTO test_data (data) VALUES ('Test entry 1'), ('Test entry 2'), ('Test entry 3'); -- Check that data is replicated to followers -- (Connect to followers and verify the table exists) Monitoring and Maintenance¶
Health Monitoring Script¶
Create a monitoring script:
#!/bin/bash # monitor_cluster.sh NODES=(5433 5434 5435) CLUSTER_NAME="tutorial_cluster" echo "=== pgraft Cluster Health Check ===" echo "Cluster: $CLUSTER_NAME" echo "Timestamp: $(date)" echo "" for port in "${NODES[@]}"; do echo "--- Node on port $port ---" # Check if PostgreSQL is running if pg_isready -h 127.0.0.1 -p $port > /dev/null 2>&1; then echo "PostgreSQL: ✓ Running" # Check pgraft status STATUS=$(psql -h 127.0.0.1 -p $port -U postgres -t -c " SELECT CASE WHEN pgraft_is_leader() THEN 'LEADER' ELSE 'FOLLOWER' END, pgraft_get_term(), pgraft_get_leader() " 2>/dev/null) if [ $? -eq 0 ]; then echo "pgraft: ✓ $STATUS" else echo "pgraft: ✗ Not responding" fi else echo "PostgreSQL: ✗ Not running" fi echo "" done # Check cluster consistency echo "--- Cluster Consistency ---" LEADERS=$(for port in "${NODES[@]}"; do if pg_isready -h 127.0.0.1 -p $port > /dev/null 2>&1; then psql -h 127.0.0.1 -p $port -U postgres -t -c "SELECT pgraft_is_leader()::text" 2>/dev/null fi done | grep -c true) if [ "$LEADERS" -eq 1 ]; then echo "Leadership: ✓ Single leader detected" elif [ "$LEADERS" -gt 1 ]; then echo "Leadership: ✗ Multiple leaders detected (split-brain)" else echo "Leadership: ✗ No leader detected" fi Make it executable and run:
Automated Backup with pgraft¶
Create a backup script that coordinates with the cluster:
#!/bin/bash # backup_cluster.sh BACKUP_DIR="/backups/pgraft" DATE=$(date +%Y%m%d_%H%M%S) CLUSTER_NAME="tutorial_cluster" # Create backup directory mkdir -p $BACKUP_DIR # Find the current leader LEADER_PORT=$(for port in 5433 5434 5435; do if psql -h 127.0.0.1 -p $port -U postgres -t -c "SELECT pgraft_is_leader()" 2>/dev/null | grep -q true; then echo $port break fi done) if [ -z "$LEADER_PORT" ]; then echo "Error: No leader found" exit 1 fi echo "Backing up from leader on port $LEADER_PORT" # Perform backup pg_dump -h 127.0.0.1 -p $LEADER_PORT -U postgres \ --format=custom \ --compress=9 \ --file="$BACKUP_DIR/backup_${CLUSTER_NAME}_${DATE}.dump" \ --verbose # Verify backup if [ $? -eq 0 ]; then echo "Backup completed successfully: backup_${CLUSTER_NAME}_${DATE}.dump" # Clean up old backups (keep last 7 days) find $BACKUP_DIR -name "backup_${CLUSTER_NAME}_*.dump" -mtime +7 -delete else echo "Backup failed" exit 1 fi Performance Monitoring¶
Create a performance monitoring script:
#!/bin/bash # perf_monitor.sh echo "=== pgraft Performance Metrics ===" echo "Timestamp: $(date)" echo "" for port in 5433 5434 5435; do if pg_isready -h 127.0.0.1 -p $port > /dev/null 2>&1; then echo "--- Node on port $port ---" # Get cluster status psql -h 127.0.0.1 -p $port -U postgres -c " SELECT node_id, current_term, leader_id, state, num_nodes, messages_processed, heartbeats_sent, elections_triggered FROM pgraft_get_cluster_status(); " 2>/dev/null # Get log statistics psql -h 127.0.0.1 -p $port -U postgres -c " SELECT log_size, last_index, commit_index, last_applied, replicated, committed, applied, errors FROM pgraft_log_get_stats(); " 2>/dev/null echo "" fi done Troubleshooting¶
Common Issues and Solutions¶
1. Extension Not Loading¶
Symptoms:
Solutions:
# Check if extension is installed ls -la /usr/local/pgsql.17/lib/pgraft* # Rebuild and reinstall cd /path/to/pgraft make clean make sudo make install # Check shared_preload_libraries psql -c "SHOW shared_preload_libraries;" 2. Worker Not Starting¶
Symptoms:
Solutions:
# Check PostgreSQL logs tail -f /data/node1/logfile # Restart PostgreSQL /usr/local/pgsql.17/bin/pg_ctl -D /data/node1 restart # Check if pgraft is in shared_preload_libraries grep shared_preload_libraries /data/node1/postgresql.conf 3. Network Connectivity Issues¶
Symptoms:
Solutions:
# Test network connectivity telnet 127.0.0.1 5434 # Check firewall sudo iptables -L # Verify port configuration netstat -tlnp | grep 543 4. Split-Brain Scenario¶
Symptoms:
-- Multiple nodes think they're leader SELECT pgraft_is_leader() FROM (SELECT 5433 as port UNION SELECT 5434 UNION SELECT 5435) ports; -- Returns multiple true values Solutions:
# Stop all nodes /usr/local/pgsql.17/bin/pg_ctl -D /data/node1 stop /usr/local/pgsql.17/bin/pg_ctl -D /data/node2 stop /usr/local/pgsql.17/bin/pg_ctl -D /data/node3 stop # Wait 30 seconds # Start nodes one by one with delays /usr/local/pgsql.17/bin/pg_ctl -D /data/node1 -l /data/node1/logfile start sleep 10 /usr/local/pgsql.17/bin/pg_ctl -D /data/node2 -l /data/node2/logfile start sleep 10 /usr/local/pgsql.17/bin/pg_ctl -D /data/node3 -l /data/node3/logfile start Debug Mode¶
Enable debug mode for troubleshooting:
-- Enable debug logging SELECT pgraft_set_debug(true); -- Perform operations and check logs SELECT pgraft_get_worker_state(); SELECT * FROM pgraft_get_queue_status(); -- Disable debug logging SELECT pgraft_set_debug(false); Log Analysis¶
Key log patterns to look for:
# Successful operations grep "pgraft: INFO" /data/node*/logfile # Warnings grep "pgraft: WARNING" /data/node*/logfile # Errors grep "pgraft: ERROR" /data/node*/logfile # Leader elections grep "election\|leader" /data/node*/logfile Best Practices¶
1. Cluster Design¶
- Odd Number of Nodes: Use 3, 5, or 7 nodes for optimal fault tolerance
- Geographic Distribution: Place nodes in different availability zones
- Network Latency: Keep inter-node latency under 100ms
- Resource Allocation: Ensure consistent resources across nodes
2. Configuration Management¶
- Consistent Configuration: Use identical settings across all nodes
- Version Control: Track configuration changes
- Documentation: Document all custom settings
- Testing: Test configuration changes in staging first
3. Monitoring and Alerting¶
- Health Checks: Implement automated health monitoring
- Performance Metrics: Track key performance indicators
- Alert Thresholds: Set appropriate alert levels
- Response Procedures: Define incident response procedures
4. Backup and Recovery¶
- Regular Backups: Schedule automated backups
- Backup Testing: Regularly test backup restoration
- Point-in-Time Recovery: Implement PITR capabilities
- Disaster Recovery: Plan for complete cluster failure
5. Security¶
- Network Security: Use firewalls and VPNs
- Authentication: Implement strong authentication
- Encryption: Encrypt data in transit and at rest
- Access Control: Implement principle of least privilege
6. Performance Optimization¶
- Hardware Selection: Choose appropriate hardware
- Configuration Tuning: Optimize for your workload
- Monitoring: Continuously monitor performance
- Capacity Planning: Plan for growth
This tutorial provides a comprehensive guide to setting up and managing a pgraft cluster. For additional information, refer to the main documentation and architecture guides.