Skip to content

Storage for Databases: PostgreSQL + Ceph

This guide explains how to configure PostgreSQL with Ceph as storage backend, optimizing performance and high availability for critical databases.

🏗️ Architecture

Main Components

graph TD
    A[PostgreSQL] --> B[RBD Block Device]
    B --> C[Ceph Cluster]
    C --> D[OSD Nodes]
    C --> E[Monitor Nodes]
    C --> F[Manager Nodes]

    G[Client] --> A

Benefits of this combination: - ✅ Scalability: Virtually unlimited storage - ✅ HA: Automatic data replication - ✅ Performance: RBD optimized for databases - ✅ Backup: Consistent snapshots - ✅ Recovery: Minimal RTO/RPO

📋 Prerequisites

Ceph Cluster

# Check cluster status
ceph status
ceph health

# Check available pools
ceph osd pool ls

PostgreSQL Node

# Install Ceph tools
sudo apt update
sudo apt install ceph-common

# Copy Ceph configuration
sudo scp ceph-admin:/etc/ceph/ceph.conf /etc/ceph/
sudo scp ceph-admin:/etc/ceph/ceph.client.admin.keyring /etc/ceph/

🚀 Step-by-step Configuration

1. Create RBD-optimized pool

# Pool for PostgreSQL data
ceph osd pool create pg_data 128 128
ceph osd pool set pg_data size 3
ceph osd pool set pg_data min_size 2

# Pool for WAL (Write-Ahead Log)
ceph osd pool create pg_wal 64 64
ceph osd pool set pg_wal size 3
ceph osd pool set pg_wal min_size 2

# Pool for backups
ceph osd pool create pg_backup 128 128

2. Create RBD images

# Image for main data (100GB)
rbd create pg_data/postgres_data --size 100G --pool pg_data

# Image for WAL (20GB)
rbd create pg_wal/postgres_wal --size 20G --pool pg_wal

# Image for backups (200GB)
rbd create pg_backup/postgres_backup --size 200G --pool pg_backup

# Verify creation
rbd ls pg_data
rbd info pg_data/postgres_data

3. Map and format RBD

# Map devices
sudo rbd map pg_data/postgres_data
sudo rbd map pg_wal/postgres_wal

# Verify mapping
rbd showmapped

# Format with XFS (recommended for PostgreSQL)
sudo mkfs.xfs /dev/rbd/pg_data/postgres_data
sudo mkfs.xfs /dev/rbd/pg_wal/postgres_wal

# Create mount points
sudo mkdir -p /var/lib/postgresql/data
sudo mkdir -p /var/lib/postgresql/wal

# Mount
sudo mount /dev/rbd/pg_data/postgres_data /var/lib/postgresql/data
sudo mount /dev/rbd/pg_wal/postgres_wal /var/lib/postgresql/wal

4. Install and configure PostgreSQL

# Install PostgreSQL
sudo apt install postgresql postgresql-contrib

# Stop service
sudo systemctl stop postgresql

# Configure permissions
sudo chown postgres:postgres /var/lib/postgresql/data
sudo chown postgres:postgres /var/lib/postgresql/wal

5. PostgreSQL Configuration for Ceph

# File: /etc/postgresql/14/main/postgresql.conf
sudo tee /etc/postgresql/14/main/postgresql.conf > /dev/null <<EOF
# Configuration optimized for Ceph RBD
data_directory = '/var/lib/postgresql/data'
hba_file = '/etc/postgresql/14/main/pg_hba.conf'
ident_file = '/etc/postgresql/14/main/pg_ident.conf'

# Memory
shared_buffers = 256MB
effective_cache_size = 1GB
work_mem = 4MB
maintenance_work_mem = 64MB

# WAL
wal_level = replica
wal_buffers = 16MB
wal_writer_delay = 200ms
wal_writer_flush_after = 1MB

# Checkpointing
checkpoint_completion_target = 0.9
checkpoint_timeout = 15min
max_wal_size = 2GB
min_wal_size = 80MB

# Logging
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_statement = 'ddl'
log_duration = on
log_lock_waits = on

# Replication (if applicable)
max_replication_slots = 10
max_wal_senders = 10

# Connections
listen_addresses = '*'
max_connections = 100
EOF

6. pg_hba.conf Configuration

# File: /etc/postgresql/14/main/pg_hba.conf
sudo tee /etc/postgresql/14/main/pg_hba.conf > /dev/null <<EOF
# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   all             postgres                                peer
local   all             all                                     peer
host    all             all             127.0.0.1/32            md5
host    all             all             ::1/128                 md5
host    all             all             10.0.0.0/8              md5
host    all             all             192.168.0.0/16          md5
EOF

🔧 Performance Optimizations

RBD Configuration

# Increase queue depth for better IOPS
rbd config global set rbd rbd_default_queue_depth 256

# Configure QoS per pool
ceph osd pool set pg_data qos_iops_limit 10000
ceph osd pool set pg_wal qos_iops_limit 5000

# Enable RBD caching
rbd config image set pg_data/postgres_data rbd_cache true
rbd config image set pg_data/postgres_data rbd_cache_max_dirty 100

PostgreSQL Optimizations

-- Database configuration
ALTER SYSTEM SET shared_preload_libraries = 'pg_stat_statements';
ALTER SYSTEM SET track_io_timing = on;
ALTER SYSTEM SET track_functions = all;

-- Create user for monitoring
CREATE USER ceph_monitor WITH PASSWORD 'secure_password';
GRANT pg_monitor TO ceph_monitor;

-- Configure tablespaces if necessary
CREATE TABLESPACE ceph_data OWNER postgres LOCATION '/var/lib/postgresql/data';
CREATE TABLESPACE ceph_wal OWNER postgres LOCATION '/var/lib/postgresql/wal';

Performance Monitoring

# RBD IOPS
rbd perf image iostat pg_data/postgres_data

# Ceph latency
ceph tell osd.* perf dump | jq '.osd.osd_op_lat'

# PostgreSQL statistics
psql -c "SELECT * FROM pg_stat_bgwriter;"
psql -c "SELECT * FROM pg_stat_database;"

🛡️ High Availability

Replica Configuration

# Create snapshot for backup
rbd snap create pg_data/postgres_data@snapshot_$(date +%Y%m%d_%H%M%S)

# Clone for replica
rbd snap protect pg_data/postgres_data@snapshot_20231201_120000
rbd clone pg_data/postgres_data@snapshot_20231201_120000 pg_data/postgres_data_replica

# Configure PostgreSQL streaming replication
# In slave postgresql.conf:
# hot_standby = on
# primary_conninfo = 'host=master_ip port=5432 user=replicator'

Backup Strategy

#!/bin/bash
# backup_postgres_ceph.sh

DATE=$(date +%Y%m%d_%H%M%S)
SNAP_NAME="backup_$DATE"

# Create consistent snapshot
psql -c "SELECT pg_start_backup('$SNAP_NAME');"
rbd snap create pg_data/postgres_data@$SNAP_NAME
psql -c "SELECT pg_stop_backup();"

# Export snapshot
rbd export pg_data/postgres_data@$SNAP_NAME /backup/postgres_$DATE.img

# Clean old snapshots (keep 7 days)
rbd snap ls pg_data/postgres_data | grep backup | head -n -7 | awk '{print $2}' | xargs -I {} rbd snap rm pg_data/postgres_data@{}

📊 Monitoring and Troubleshooting

Key Metrics

# Storage usage
ceph df
rbd du pg_data/postgres_data

# PostgreSQL performance
psql -c "SELECT * FROM pg_stat_bgwriter;"
psql -c "SELECT * FROM pg_stat_database WHERE datname = 'postgres';"

# Error logs
tail -f /var/log/postgresql/postgresql-14-main.log

Common Issues

Slow Performance

# Check RBD latency
rbd perf image iostat pg_data/postgres_data --period 10

# Adjust PostgreSQL parameters
# Increase shared_buffers if memory available
# Adjust work_mem based on complex queries

Ceph Connectivity

# Check connectivity
ceph ping mon.a
ceph ping osd.0

# Check RBD logs
dmesg | grep rbd
journalctl -u ceph-rbd-mirror

Disaster Recovery

# Simulate failure
sudo umount /var/lib/postgresql/data
sudo rbd unmap /dev/rbd/pg_data/postgres_data

# Recover
sudo rbd map pg_data/postgres_data
sudo mount /dev/rbd/pg_data/postgres_data /var/lib/postgresql/data
sudo systemctl start postgresql

🔄 Migration from Traditional Storage

Migration Strategy

# 1. Create full backup
pg_dumpall > full_backup.sql

# 2. Stop application
sudo systemctl stop myapp

# 3. Migrate data
rsync -av /var/lib/postgresql/data/ /tmp/postgres_backup/
cp -r /tmp/postgres_backup/* /var/lib/postgresql/data/

# 4. Verify integrity
psql -c "SELECT count(*) FROM pg_database;"

# 5. Restart services
sudo systemctl start postgresql
sudo systemctl start myapp

📈 Scaling and Growth

Adding More OSDs

# Add new OSD
ceph-deploy osd create node-03:sdb

# Rebalance data
ceph balancer on
ceph balancer mode upmap

Expanding Pools

# Add more PGs if necessary
ceph osd pool set pg_data pg_num 256
ceph osd pool set pg_data pgp_num 256

# Monitor rebalancing
ceph status
watch ceph -s

📚 Additional Resources