Stage 3 · Build
Databases in Kubernetes
Capstone: Database Reliability Review
Audit a production PostgreSQL deployment and write a reliability improvement plan.
Reliability Review Framework
A database reliability review examines every aspect of your database deployment: configuration, backups, replication, monitoring, security, and operational procedures. The goal is to identify risks before they become incidents and create an actionable improvement plan.
review_areas:
configuration:
- Memory settings (shared_buffers, work_mem)
- Connection limits (max_connections)
- Autovacuum tuning
- WAL and checkpoint settings
high_availability:
- Replication setup (synchronous vs asynchronous)
- Failover procedures (manual vs automated)
- Replica health and lag
backups:
- Backup strategy (pg_dump, pg_basebackup, WAL archiving)
- Recovery point objective (RPO) and recovery time objective (RTO)
- Backup verification and restore testing
monitoring:
- Metrics collection (pg_stat_statements, pg_exporter)
- Alerting rules (lag, connections, disk, locks)
- Dashboard coverage
security:
- Authentication (SCRAM, mTLS)
- Authorization (RBAC, row-level security)
- Encryption (at rest and in transit)
- Audit logging
operations:
- Migration procedures
- Incident runbooks
- On-call procedures
- Capacity planningThis framework covers the six pillars of database reliability. Each area has specific questions to answer and evidence to collect. The review produces a gap analysis and prioritized improvement plan.
Audit Checklist
-- 1. Configuration audit
SELECT name, setting, unit, context
FROM pg_settings
WHERE name IN (
'shared_buffers', 'work_mem', 'effective_cache_size',
'max_connections', 'autovacuum', 'wal_level',
'checkpoint_timeout', 'max_wal_size'
);
-- 2. Connection health
SELECT
count(*) AS total_connections,
current_setting('max_connections')::int AS max_connections,
ROUND(count(*)::numeric / current_setting('max_connections')::int * 100, 1) AS pct_used
FROM pg_stat_activity;
-- 3. Cache hit ratio (should be > 99%)
SELECT
ROUND(100.0 * sum(blks_hit) / GREATEST(sum(blks_hit) + sum(blks_read), 1), 2) AS cache_hit_pct
FROM pg_stat_database
WHERE datname = current_database();
-- 4. Dead tuple accumulation
SELECT
relname,
n_live_tup,
n_dead_tup,
ROUND(n_dead_tup::numeric / GREATEST(n_live_tup, 1) * 100, 1) AS dead_pct
FROM pg_stat_user_tables
WHERE n_dead_tup > 10000
ORDER BY n_dead_tup DESC;
-- 5. Replication status
SELECT
client_addr,
state,
replay_lag,
pg_wal_lsn_diff(sent_lsn, replay_lsn) AS lag_bytes
FROM pg_stat_replication;
-- 6. Unused indexes (candidates for removal)
SELECT indexrelname, idx_scan
FROM pg_stat_user_indexes
WHERE idx_scan = 0 AND indexrelname LIKE 'idx_%';
-- 7. Long-running queries
SELECT pid, now() - query_start AS duration, LEFT(query, 80)
FROM pg_stat_activity
WHERE state = 'active' AND query_start < now() - INTERVAL '5 minutes';Run these queries during the audit and document the results. Each query reveals a specific reliability dimension: configuration, connections, cache efficiency, bloat, replication, index health, and query performance.
PostgreSQL Configuration Audit
| Setting | Current | Recommended | Risk if Wrong |
|---|---|---|---|
| shared_buffers | Check value | 25% of RAM (max 8GB) | Low cache hit ratio |
| work_mem | Check value | Conservative based on connections | OOM or disk spills |
| max_connections | Check value | Match connection pool, not app count | Connection exhaustion |
| autovacuum | Check if on | Always on, tuned scale factors | Table bloat, TXID wraparound |
| wal_level | Check value | replica (for PITR) | No point-in-time recovery |
| checkpoint_completion_target | Check value | 0.9 | I/O spikes during checkpoints |
Backup and Recovery Audit
- What is the backup strategy? (pg_dump, pg_basebackup, WAL archiving, pgBackRest)
- What is the RPO? (maximum data loss in minutes)
- What is the RTO? (maximum time to restore)
- When was the last restore test?
- Are backups verified automatically?
- Is there offsite backup (different region/cloud)?
- Are backup encryption and access controls in place?
- Is there a documented restore procedure?
-- Check backup status (if using pgBackRest)
-- pgbackrest info
-- Check WAL archiving status
SELECT
archived_count,
failed_count,
last_archived_wal,
last_archived_time,
last_failed_wal,
last_failed_time
FROM pg_stat_archiver;
-- Calculate potential data loss window
-- Time since last successful backup
SELECT
now() - pg_postmaster_start_time() AS uptime,
(SELECT last_archived_time FROM pg_stat_archiver) AS last_wal_archive;If last_wal_archive is more than a few hours old, WAL archiving is broken. If archived_count is 0, archiving is not configured. Both indicate that point-in-time recovery is not available.
Monitoring and Alerting Audit
- Is pg_stat_statements enabled and collecting query statistics?
- Are metrics exported to Prometheus/Grafana?
- Are dashboards covering: connections, cache hit ratio, replication lag, dead tuples?
- Are alerts configured for: disk > 80%, connections > 80%, replication lag > 30s?
- Is slow query logging enabled (auto-explain)?
- Are lock contention alerts configured?
- Is on-call rotation set up for database alerts?
Writing the Improvement Plan
improvement_plan:
title: "PostgreSQL Reliability Improvement Plan"
date: "2024-06-15"
reviewer: "SRE Team"
findings:
- area: "Configuration"
finding: "shared_buffers set to 128MB on 32GB server"
risk: "High"
recommendation: "Increase to 8GB"
effort: "Low (config change + restart)"
timeline: "This sprint"
- area: "Backups"
finding: "No WAL archiving configured"
risk: "Critical"
recommendation: "Enable WAL archiving to S3"
effort: "Medium (setup + testing)"
timeline: "Next sprint"
- area: "Monitoring"
finding: "No replication lag alerts"
risk: "High"
recommendation: "Add Prometheus alert for lag > 30s"
effort: "Low (alerting rule)"
timeline: "This sprint"
- area: "Security"
finding: "Application using superuser account"
risk: "High"
recommendation: "Create dedicated read-write user with minimal permissions"
effort: "Medium (code + config change)"
timeline: "Next sprint"
timeline:
immediate: # This week
- "Fix shared_buffers"
- "Add replication lag alert"
short_term: # This month
- "Enable WAL archiving"
- "Create restricted database user"
- "Enable auto-explain"
medium_term: # This quarter
- "Implement connection pooling with PgBouncer"
- "Set up pg_basebackup CronJob"
- "Create database incident runbooks"
long_term: # This year
- "Evaluate database operator for HA"
- "Implement automated backup verification"
- "Conduct disaster recovery drill"The improvement plan prioritizes findings by risk and effort. Critical findings get fixed immediately. High-risk findings are addressed this quarter. The plan includes specific owners and timelines for accountability.
A reliability review is not a one-time event. Schedule quarterly reviews to track progress, identify new risks, and adjust priorities. The goal is continuous improvement, not perfection.
The output of this review should be: 1) A findings document with risk ratings. 2) An improvement plan with priorities and timelines. 3) Updated runbooks for identified gaps. 4) A follow-up review date to verify progress.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.