This is the multi-page printable view of this section. .
Administration
- 1: Parameter Tuning
- 2: Maintenance
- 3: Failure SOP
- 4: Data Loss Recovery
How to maintain an existing PostgreSQL cluster with Pigsty?
Here are some SOP for common pgsql admin tasks
- Case 1: Create Cluster
- Case 2: Create User
- Case 3: Create Database
- Case 4: Reload Service
- Case 5: Reload HBARule
- Case 6: Config Cluster
- Case 7: Append Replica
- Case 8: Remove Replica
- Case 9: Remove Cluster
- Case 10: Switchover
- Case 11: Backup Cluster
- Case 12: Restore Cluster
- Case 13: Adding Packages
- Case 14: Install Extension
- Case 15: Minor Upgrade
- Case 16: Major Upgrade
Cheatsheet
PGSQL playbooks and shortcuts:
Patroni admin command and shortcuts:
pgBackRest backup & restore command and shortcuts:
Systemd components quick reference
Create Cluster
To create a new Postgres cluster, define it in the inventory first, then init with:
Beware, perform
bin/node-addfirst, thenbin/pgsql-add, PGSQL works on managed nodes only.
Create User
To create a new business user on the existing Postgres cluster, add user definition to all.children.<cls>.pg_users, then create the user as follows:
Create Database
To create a new database user on the existing Postgres cluster, add database definition to all.children.<cls>.pg_databases, then create the database as follows:
Note: If the database has specified an owner, the user should already exist, or you’ll have to Create User first.
Reload Service
Services are exposed access point served by HAProxy.
This task is used when cluster membership has changed, e.g., append/remove replicas, switchover/failover / exposing new service or updating existing service’s config (e.g., LB Weight)
To create new services or reload existing services on entire proxy cluster or specific instances:
Reload HBARule
This task is used when your Postgres/Pgbouncer HBA rules have changed, you may have to reload hba to apply changes.
If you have any role-specific HBA rules, you may have to reload hba after a switchover/failover, too.
To reload postgres & pgbouncer HBA rules on entire cluster or specific instances:
Config Cluster
To change the config of a existing Postgres cluster, you have to initiate control command on admin node with admin user:
Change patroni parameters & postgresql.parameters, save & apply changes with the wizard.
Append Replica
To add a new replica to the existing Postgres cluster, you have to add its definition to the inventory: all.children.<cls>.hosts, then:
It will add node <ip> to pigsty and init it as a replica of the cluster <cls>.
Cluster services will be reloaded to adopt the new member
Remove Replica
To remove a replica from the existing PostgreSQL cluster:
It will remove instance <ip> from cluster <cls>. Cluster services will be reloaded to kick the removed instance from load balancer.
Remove Cluster
To remove the entire Postgres cluster, just run:
Switchover
You can perform a PostgreSQL cluster switchover with patroni cmd.
Backup Cluster
To create a backup with pgBackRest, run as local dbsu:
Check Backup & PITR for details.
Restore Cluster
To restore a cluster to a previous time point (PITR), run as local dbsu:
Check Backup & Restore docs for more details.
Adding Packages
To add the newer version of RPM/DEB packages, you have to add them to repo_packages and repo_url_packages
Then rebuild repo on infra nodes with ./infra.yml -t repo_build subtask, Then you can install these packages with ansible module package:
Install Extension
If you want to install extension on pg clusters, Add them to pg_extensions and make sure them installed with:
Some extension needs to be loaded in shared_preload_libraries, You can add them to pg_libs, or Config an existing cluster.
Finally, CREATE EXTENSION <extname>; on the cluster primary instance to install it.
Check PGSQL Extensions: Install for details.
Minor Upgrade
To perform a minor server version upgrade/downgrade, you have to add packages to yum/apt repo first.
Then perform a rolling upgrade/downgrade from all replicas, then switchover the cluster to upgrade the leader.
Major Upgrade
The simplest way to achieve a major version upgrade is to create a new cluster with the new version, then migration with logical replication & green/blue deployment.
You can also perform an in-place major upgrade, which is not recommended, especially when certain extensions are installed. But it is possible.
Assume you want to upgrade PostgreSQL 14 to 15, you have to add packages to yum/apt repo, and guarantee the extensions have the exact same version too.
1 - Parameter Tuning
Pigsty provides four scenario-specific parameter templates by default, which can be specified and used via the pg_conf parameter.
tiny.yml: Optimized for small nodes, virtual machines, and small demos (1-8 cores, 1-16GB)oltp.yml: Optimized for OLTP workloads and latency-sensitive applications (4C8GB+) (default template)olap.yml: Optimized for OLAP workloads and throughput (4C8G+)crit.yml: Optimized for data consistency and critical applications (4C8G+)
Pigsty adopts different parameter optimization strategies for these four default scenarios, as shown below:
Memory Parameters
Pigsty automatically detects system memory size and uses it as the basis for setting maximum connections and memory-related parameters.
pg_max_conn: PostgreSQL maximum connections,autowill use recommended values for different scenariospg_shared_buffer_ratio: Shared buffer memory ratio, defaults to 0.25
By default, Pigsty uses 25% of memory as PostgreSQL shared buffers, leaving the remaining 75% for the operating system cache.
By default, if users don’t set a pg_max_conn maximum connection count, Pigsty will use default values according to these rules:
- oltp: 500 (pgbouncer) / 1000 (postgres)
- crit: 500 (pgbouncer) / 1000 (postgres)
- tiny: 300
- olap: 300
For OLTP and CRIT templates, if services point directly to the PostgreSQL database instead of the pgbouncer connection pool, maximum connections double to 1000.
After determining maximum connections, work_mem is calculated based on shared memory amount / maximum connections, constrained within a 64MB ~ 1GB range.
CPU Parameters
In PostgreSQL, there are 4 important parameters related to parallel queries. Pigsty automatically optimizes these parameters based on the current system’s CPU core count. Across all strategies, the total parallel process count (total budget) is typically set to CPU cores + 8, with a minimum of 16, thus reserving sufficient background worker capacity for logical replication and extensions. OLAP and TINY templates vary slightly based on scenario.
| OLTP | Configuration Logic | Range Constraints |
|---|---|---|
max_worker_processes |
max(100% CPU + 8, 16) | Cores + 4, minimum 12 |
max_parallel_workers |
max(ceil(50% CPU), 2) | 1/2 CPU rounded up, minimum 2 |
max_parallel_maintenance_workers |
max(ceil(33% CPU), 2) | 1/3 CPU rounded up, minimum 2 |
max_parallel_workers_per_gather |
min(max(ceil(20% CPU), 2),8) | 1/5 CPU rounded down, minimum 2, maximum 8 |
| OLAP | Configuration Logic | Range Constraints |
|---|---|---|
max_worker_processes |
max(100% CPU + 12, 20) | Cores + 12, minimum 20 |
max_parallel_workers |
max(ceil(80% CPU, 2)) | 4/5 CPU rounded up, minimum 2 |
max_parallel_maintenance_workers |
max(ceil(33% CPU), 2) | 1/3 CPU rounded up, minimum 2 |
max_parallel_workers_per_gather |
max(floor(50% CPU), 2) | 1/2 CPU rounded up, minimum 2 |
| CRIT | Configuration Logic | Range Constraints |
|---|---|---|
max_worker_processes |
max(100% CPU + 8, 16) | Cores + 8, minimum 16 |
max_parallel_workers |
max(ceil(50% CPU), 2) | 1/2 CPU rounded up, minimum 2 |
max_parallel_maintenance_workers |
max(ceil(33% CPU), 2) | 1/3 CPU rounded up, minimum 2 |
max_parallel_workers_per_gather |
0, enable as needed |
| TINY | Configuration Logic | Range Constraints |
|---|---|---|
max_worker_processes |
max(100% CPU + 4, 12) | Cores + 4, minimum 12 |
max_parallel_workers |
max(ceil(50% CPU) 1) | 50% CPU rounded down, minimum 1 |
max_parallel_maintenance_workers |
max(ceil(33% CPU), 1) | 33% CPU rounded down, minimum 1 |
max_parallel_workers_per_gather |
0, enable as needed |
Note that CRIT and TINY templates disable parallel queries directly by setting max_parallel_workers_per_gather = 0.
Users can set this parameter as needed to enable parallel queries.
Both OLTP and CRIT templates set the following additional parameters, doubling parallel query costs to reduce the tendency to use parallel queries:
Note that max_worker_processes parameter adjustments only take effect after a restart. Additionally, when a replica’s configuration value for this parameter exceeds the primary’s, the replica cannot start.
This parameter must be adjusted through Patroni configuration management. The parameter is managed by Patroni to ensure consistent primary-replica configuration and prevent new replicas from failing to start during failover.
Storage Parameters
Pigsty automatically detects the total disk space where the /data/postgres main data directory resides and uses it as the basis for specifying the following parameters:
temp_file_limitdefaults to 5% of disk space, capped at 200GB maximum.min_wal_sizedefaults to 5% of disk space, capped at 200GB maximum.max_wal_sizedefaults to 20% of disk space, capped at 2TB maximum.max_slot_wal_keep_sizedefaults to 30% of disk space, capped at 3TB maximum.
As a special case, the OLAP template allows 20% for temp_file_limit, capped at 2TB maximum.
2 - Maintenance
Ensuring healthy and stable operation of Pigsty and PostgreSQL clusters requires routine maintenance work.
Regular Monitoring Review
Pigsty provides an out-of-the-box monitoring platform. We recommend reviewing monitoring dashboards daily to track system status. At minimum, we suggest weekly monitoring reviews, focusing on alert events to proactively avoid most failures and issues.
Here’s a list of predefined alert rules in Pigsty.
Failover Follow-up
Pigsty’s high availability architecture allows PostgreSQL clusters to automatically perform primary-replica switching, meaning operations and DBAs don’t require immediate intervention. However, users still need to perform follow-up tasks at appropriate times (e.g., next business day), including:
- Investigate and confirm failure root cause to prevent recurrence
- Optionally restore original primary-replica topology or update configuration manifest to match new state
- Refresh load balancer configuration via
bin/pgsql-svcto update service routing state - Refresh cluster HBA rules via
bin/pgsql-hbato prevent primary-replica specific rule drift - If necessary, remove failed servers with
bin/pgsql-rmand expand with new replicas usingbin/pgsql-add
Bloat Control
Long-running PostgreSQL instances develop “table bloat” / “index bloat”, degrading system performance.
Regular online rebuilding of tables and indexes using pg_repack helps maintain optimal PostgreSQL performance.
Pigsty installs and enables this extension by default in all databases, ready for immediate use.
You can check table and index bloat through Pigsty’s PGCAT Database - Table Bloat panel.
Select tables and indexes with high bloat rates (larger tables with >50% bloat) for online reorganization using pg_repack:
Normal reads/writes continue during reorganization, but the switch moment at completion requires an AccessExclusive lock, blocking all access. For high-throughput operations, schedule during low-traffic periods or maintenance windows. For more details, see: Managing Relation Bloat
VACUUM FREEZE
Freezing expired transaction IDs (VACUUM FREEZE) is a critical PostgreSQL maintenance task preventing transaction ID (XID) exhaustion outages. While PostgreSQL provides AutoVacuum mechanisms, for high-standard production environments, we recommend combining automatic and manual approaches, regularly executing database-wide VACUUM FREEZE to ensure XID safety.
3 - Failure SOP
This document outlines potential failures in PostgreSQL and Pigsty, along with SOPs for diagnosing, handling, and analyzing issues.
Disk Space Exhaustion
Disk space exhaustion is the most common type of failure.
Symptoms
When the disk hosting the database runs out of space, PostgreSQL cannot function properly. You may observe: database logs repeatedly reporting “no space left on device”, inability to write new data, or PostgreSQL triggering a PANIC and forcing shutdown.
Pigsty includes a NodeFsSpaceFull alert rule that triggers when filesystem available space drops below 10%. Use the monitoring system’s NODE Instance panel to review FS metric panels for diagnosis.
Diagnosis
You can also log into the database node and use df -h to check usage rates for each mount point, determining which partition is full.
For database nodes, focus on these directories and their sizes to determine which file category is consuming space:
- Data directory (
/pg/data/base): Stores table and index data files, watch for heavy writes and temporary files - WAL directory (e.g.,
pg/data/pg_wal): Stores PG WAL, WAL accumulation/replication slot retention are common causes of disk exhaustion - Database log directory (e.g.,
pg/log): If PG logs aren’t rotated timely and massive errors are written, this can consume significant space - Local backup directory (e.g.,
data/backups): When using pgBackRest to save backups locally, this can also fill the disk
For Pigsty admin nodes or monitoring nodes, also consider:
- Monitoring data: Both Prometheus time-series metrics storage and Loki log storage consume disk space, check retention policies
- Object storage data: Pigsty’s integrated MinIO object storage may be used for PG backup storage
After identifying directories consuming the most space, use du -sh <directory> to drill down for specific large files or subdirectories.
Resolution
Disk exhaustion is an emergency requiring immediate action to free space and maintain database operation:
Emergency scenario: When data and system disks aren’t separated, disk exhaustion can prevent shell commands from executing. In this case, delete the /pg/dummy placeholder file to free emergency space for shell command recovery.
After freeing space with above measures, PostgreSQL should resume normal operation. If the database crashed due to pg_wal exhaustion, restart the database service after clearing space and carefully verify data integrity.
Transaction ID Wraparound
PostgreSQL uses 32-bit transaction IDs (XIDs) cyclically. When XIDs are exhausted, “transaction ID wraparound” failure occurs.
Symptoms
Initial symptoms include PGSQL Persist - Age Usage panel age saturation entering the warning zone.
Database logs begin showing: WARNING: database "postgres" must be vacuumed within xxxxxxxx transactions.
If the problem worsens, PostgreSQL enters protection mode: when remaining transaction IDs drop below ~1 million, the database switches to read-only mode; at the limit of ~2.1 billion (2^31), it refuses new transactions and forces server shutdown to prevent data corruption.
Diagnosis
PostgreSQL and Pigsty enable AutoVacuum by default, so this failure usually indicates deeper root causes. Common causes include: super-aged transactions (SAGE), misconfigured Autovacuum, blocked replication slots, insufficient resources, storage engine/extension bugs, disk corruption.
First identify the database with the oldest age, then use the Pigsty PGCAT Database - Tables panel to check table age distribution. Review database error logs for clues to identify root causes.
Resolution
- Immediate transaction freezing: If the database hasn’t entered read-only protection, immediately execute manual VACUUM FREEZE on affected databases. Start with the most aged tables rather than the entire database to expedite results. As superuser, run
VACUUM FREEZE tablename;on tables with highestrelfrozenxid, prioritizing tables with oldest XID age. This quickly reclaims significant transaction ID space. - Single-user mode rescue: If the database refuses writes or has crashed for protection, start the database in single-user mode for freeze operations. In single-user mode, run
VACUUM FREEZE database_name;to freeze-clean the entire database. Then restart in multi-user mode. This releases wraparound locks and restores write capability. Exercise extreme caution in single-user mode and ensure sufficient transaction ID headroom for freezing. - Standby takeover: In complex scenarios (e.g., hardware issues preventing vacuum completion), consider promoting a read-only standby to primary for a cleaner environment. For example, if the primary has bad blocks preventing vacuum, manually failover to promote the standby as new primary, then perform emergency vacuum freeze. After ensuring the new primary has frozen old transactions, switch load back.
Connection Exhaustion
PostgreSQL has a maximum connection limit (max_connections). When client connections exceed this limit, new connection requests are rejected. Typical symptoms include applications unable to connect with errors like
FATAL: remaining connection slots are reserved for non-replication superuser connections or too many clients already.
This indicates regular connection slots are exhausted, leaving only slots reserved for superusers or replication.
Diagnosis
Connection exhaustion typically results from massive concurrent client requests. You can review current active sessions through PGCAT Instance / PGCAT Database / PGCAT Locks to determine what queries are filling the system for further action. Pay special attention to numerous Idle in Transaction connections and long-running transactions (and slow queries).
Resolution
Kill queries: For exhaustion blocking business operations, immediately use pg_terminate_backend(pid) for emergency relief.
For connection pool users, adjust pool size parameters and reload to reduce database-level connections.
You can also use pg edit-config to increase max_connections, but this parameter requires database restart to take effect.
etcd Quota Exhaustion
etcd quota exhaustion causes PG high availability control plane failure, preventing configuration changes. Versions between Pigsty v2.0.0 - v2.5.1 are affected by default.
Diagnosis
Pigsty uses etcd as distributed configuration storage (DCS) for high availability. etcd has a storage quota (default ~2GB). When etcd storage reaches the quota limit, etcd refuses write operations with error “etcdserver: mvcc: database space exceeded”. In this state, Patroni cannot write heartbeats or update configurations to etcd, causing cluster management failure.
Resolution
Pigsty v2.6.0 adds auto-compaction configuration for deployed etcd. If you only use it for PG high availability leases, regular use cases won’t encounter this issue.
Defective Storage Engines
Currently, TimescaleDB’s experimental Hypercore storage engine has proven defects, with documented cases of VACUUM failing to reclaim XIDs causing wraparound failures. Users of this feature should migrate promptly to PostgreSQL native tables or TimescaleDB’s default engine.
Details: PG New Storage Engine Failure Case
4 - Data Loss Recovery
Accidental Data Deletion
For small-batch DELETE operations performed in error, consider using the pg_surgery extension for in-place surgical recovery.
If the deleted data has already been reclaimed by VACUUM, follow the general data loss recovery workflow.
Accidental Object Deletion
When DROP/DELETE operations are performed in error, follow this workflow to determine the recovery approach:
- Verify if the data can be recovered through business systems or other data sources. If possible, recover directly from the business side.
- Check for delayed replica availability. If available, advance the delayed replica to the point before deletion and query the data for recovery.
- If data is confirmed deleted, verify backup coverage for the deletion timepoint. If covered, initiate PITR.
- Determine whether to perform in-place PITR rollback on the entire cluster, replay on a new server, or use a replica for replay, then execute the recovery strategy.
Accidental Cluster Deletion
In cases where an entire database cluster is accidentally deleted, such as mistakenly executing the pgsql-rm.yml playbook:
Unless you explicitly specified pg_rm_backup: false beforehand, backups will typically be deleted along with the database cluster.