New features implemented: 1. Backup Catalog (internal/catalog/) - SQLite-based backup tracking - Gap detection and RPO monitoring - Search and statistics - Filesystem sync 2. DR Drill Testing (internal/drill/) - Automated restore testing in Docker containers - Database validation with custom queries - Catalog integration for drill-tested status 3. Smart Notifications (internal/notify/) - Event batching with configurable intervals - Time-based escalation policies - HTML/text/Slack templates 4. Compliance Reports (internal/report/) - SOC2, GDPR, HIPAA, PCI-DSS, ISO27001 frameworks - Evidence collection from catalog - JSON, Markdown, HTML output formats 5. RTO/RPO Calculator (internal/rto/) - Recovery objective analysis - RTO breakdown by phase - Recommendations for improvement 6. Replica-Aware Backup (internal/replica/) - Topology detection for PostgreSQL/MySQL - Automatic replica selection - Configurable selection strategies 7. Parallel Table Backup (internal/parallel/) - Concurrent table dumps - Worker pool with progress tracking - Large table optimization 8. MySQL/MariaDB PITR (internal/pitr/) - Binary log parsing and replay - Point-in-time recovery support - Transaction filtering CLI commands added: catalog, drill, report, rto All changes support the goal: reliable 3 AM database recovery.
10 KiB
MySQL/MariaDB Point-in-Time Recovery (PITR)
This guide explains how to use dbbackup for Point-in-Time Recovery with MySQL and MariaDB databases.
Overview
Point-in-Time Recovery (PITR) allows you to restore your database to any specific moment in time, not just to when a backup was taken. This is essential for:
- Recovering from accidental data deletion or corruption
- Restoring to a state just before a problematic change
- Meeting regulatory compliance requirements for data recovery
How MySQL PITR Works
MySQL PITR uses binary logs (binlogs) which record all changes to the database:
- Base Backup: A full database backup with the binlog position recorded
- Binary Log Archiving: Continuous archiving of binlog files
- Recovery: Restore base backup, then replay binlogs up to the target time
┌─────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Base Backup │ --> │ binlog.00001 │ --> │ binlog.00002 │ --> │ binlog.00003 │
│ (pos: 1234) │ │ │ │ │ │ (current) │
└─────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
│ │ │ │
▼ ▼ ▼ ▼
10:00 AM 10:30 AM 11:00 AM 11:30 AM
↑
Target: 11:15 AM
Prerequisites
MySQL Configuration
Binary logging must be enabled in MySQL. Add to my.cnf:
[mysqld]
# Enable binary logging
log_bin = mysql-bin
server_id = 1
# Recommended: Use ROW format for PITR
binlog_format = ROW
# Optional but recommended: Enable GTID for easier replication and recovery
gtid_mode = ON
enforce_gtid_consistency = ON
# Keep binlogs for at least 7 days (adjust as needed)
expire_logs_days = 7
# Or for MySQL 8.0+:
# binlog_expire_logs_seconds = 604800
After changing configuration, restart MySQL:
sudo systemctl restart mysql
MariaDB Configuration
MariaDB configuration is similar:
[mysqld]
log_bin = mariadb-bin
server_id = 1
binlog_format = ROW
# MariaDB uses different GTID implementation (auto-enabled with log_slave_updates)
log_slave_updates = ON
Quick Start
1. Check PITR Status
# Check if MySQL is properly configured for PITR
dbbackup pitr mysql-status
Example output:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
MySQL/MariaDB PITR Status (mysql)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PITR Status: ❌ NOT CONFIGURED
Binary Logging: ✅ ENABLED
Binlog Format: ROW
GTID Mode: ON
Current Position: mysql-bin.000042:1234
PITR Requirements:
✅ Binary logging enabled
✅ Row-based logging (recommended)
2. Enable PITR
# Enable PITR and configure archive directory
dbbackup pitr mysql-enable --archive-dir /backups/binlog_archive
3. Create a Base Backup
# Create a PITR-capable backup
dbbackup backup single mydb --pitr
4. Start Binlog Archiving
# Run binlog archiver in the background
dbbackup binlog watch --binlog-dir /var/lib/mysql --archive-dir /backups/binlog_archive --interval 30s
Or set up a cron job for periodic archiving:
# Archive new binlogs every 5 minutes
*/5 * * * * dbbackup binlog archive --binlog-dir /var/lib/mysql --archive-dir /backups/binlog_archive
5. Restore to Point in Time
# Restore to a specific time
dbbackup restore pitr mydb_backup.sql.gz --target-time '2024-01-15 14:30:00'
Commands Reference
PITR Commands
pitr mysql-status
Show MySQL/MariaDB PITR configuration and status.
dbbackup pitr mysql-status
pitr mysql-enable
Enable PITR for MySQL/MariaDB.
dbbackup pitr mysql-enable \
--archive-dir /backups/binlog_archive \
--retention-days 7 \
--require-row-format \
--require-gtid
Options:
--archive-dir: Directory to store archived binlogs (required)--retention-days: Days to keep archived binlogs (default: 7)--require-row-format: Require ROW binlog format (default: true)--require-gtid: Require GTID mode enabled (default: false)
Binlog Commands
binlog list
List available binary log files.
# List binlogs from MySQL data directory
dbbackup binlog list --binlog-dir /var/lib/mysql
# List archived binlogs
dbbackup binlog list --archive-dir /backups/binlog_archive
binlog archive
Archive binary log files.
dbbackup binlog archive \
--binlog-dir /var/lib/mysql \
--archive-dir /backups/binlog_archive \
--compress
Options:
--binlog-dir: MySQL binary log directory--archive-dir: Destination for archived binlogs (required)--compress: Compress archived binlogs with gzip--encrypt: Encrypt archived binlogs--encryption-key-file: Path to encryption key file
binlog watch
Continuously monitor and archive new binlog files.
dbbackup binlog watch \
--binlog-dir /var/lib/mysql \
--archive-dir /backups/binlog_archive \
--interval 30s \
--compress
Options:
--interval: How often to check for new binlogs (default: 30s)
binlog validate
Validate binlog chain integrity.
dbbackup binlog validate --binlog-dir /var/lib/mysql
Output shows:
- Whether the chain is complete (no missing files)
- Any gaps in the sequence
- Server ID changes (indicating possible failover)
- Total size and file count
binlog position
Show current binary log position.
dbbackup binlog position
Output:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Current Binary Log Position
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
File: mysql-bin.000042
Position: 123456
GTID Set: 3E11FA47-71CA-11E1-9E33-C80AA9429562:1-1000
Position String: mysql-bin.000042:123456
Restore Scenarios
Restore to Specific Time
# Restore to January 15, 2024 at 2:30 PM
dbbackup restore pitr mydb_backup.sql.gz \
--target-time '2024-01-15 14:30:00'
Restore to Specific Position
# Restore to a specific binlog position
dbbackup restore pitr mydb_backup.sql.gz \
--target-position 'mysql-bin.000042:12345'
Dry Run (Preview)
# See what SQL would be replayed without applying
dbbackup restore pitr mydb_backup.sql.gz \
--target-time '2024-01-15 14:30:00' \
--dry-run
Restore to Backup Point Only
# Restore just the base backup without replaying binlogs
dbbackup restore pitr mydb_backup.sql.gz --immediate
Best Practices
1. Archiving Strategy
- Archive binlogs frequently (every 5-30 minutes)
- Use compression to save disk space
- Store archives on separate storage from the database
2. Retention Policy
- Keep archives for at least as long as your oldest valid base backup
- Consider regulatory requirements for data retention
- Use the cleanup command to purge old archives:
dbbackup binlog cleanup --archive-dir /backups/binlog_archive --retention-days 30
3. Validation
- Regularly validate your binlog chain:
dbbackup binlog validate --binlog-dir /var/lib/mysql
- Test restoration periodically on a test environment
4. Monitoring
- Monitor the
dbbackup binlog watchprocess - Set up alerts for:
- Binlog archiver failures
- Gaps in binlog chain
- Low disk space on archive directory
5. GTID Mode
Enable GTID for:
- Easier tracking of replication position
- Automatic failover in replication setups
- Simpler point-in-time recovery
Troubleshooting
Binary Logging Not Enabled
Error: "Binary logging appears to be disabled"
Solution: Add to my.cnf and restart MySQL:
[mysqld]
log_bin = mysql-bin
server_id = 1
Missing Binlog Files
Error: "Gaps detected in binlog chain"
Causes:
RESET MASTERwas executedexpire_logs_daysis too short- Binlogs were manually deleted
Solution:
- Take a new base backup immediately
- Adjust retention settings to prevent future gaps
Permission Denied
Error: "Failed to read binlog directory"
Solution:
# Add dbbackup user to mysql group
sudo usermod -aG mysql dbbackup_user
# Or set appropriate permissions
sudo chmod g+r /var/lib/mysql/mysql-bin.*
Wrong Binlog Format
Warning: "binlog_format = STATEMENT (ROW recommended)"
Impact: STATEMENT format may not capture all changes accurately
Solution: Change to ROW format (requires restart):
[mysqld]
binlog_format = ROW
Server ID Changes
Warning: "server_id changed from X to Y (possible master failover)"
This warning indicates the binlog chain contains events from different servers, which may happen during:
- Failover in a replication setup
- Restoring from a different server's backup
This is usually informational but review your topology if unexpected.
MariaDB-Specific Notes
GTID Format
MariaDB uses a different GTID format than MySQL:
- MySQL:
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5 - MariaDB:
0-1-100(domain-server_id-sequence)
Tool Detection
dbbackup automatically detects MariaDB and uses:
mariadb-binlogif available (MariaDB 10.4+)- Falls back to
mysqlbinlogfor older versions
Encrypted Binlogs
MariaDB supports binlog encryption. If enabled, ensure the key is available during archive and restore operations.