استراتيجيات النسخ الاحتياطي لقاعدة بيانات الإنتاج التي تعمل بالفعل: MySQL وPostgreSQL
استراتيجيات النسخ الاحتياطي والاسترداد المثبتة لـ MySQL وPostgreSQL في الإنتاج
فقدان بيانات الإنتاج هو نوع من الحوادث التي تنهي الوظائف، وتغلق الشركات، وتتصدر الصفحة الأولى من Hacker News لجميع الأسباب الخاطئة. ومع ذلك، تتعامل معظم الفرق مع النسخ الاحتياطية لقاعدة البيانات كفكرة لاحقة - وهي مهمة cron أنشأها شخص ما قبل عامين ولم يتحقق أحد من صحتها منذ ذلك الحين. توضح هذه المقالة إستراتيجيات النسخ الاحتياطي التي تم اختبارها في المعركة لـ MySQL وPostgreSQL والتي تم إثبات كفاءتها في بيئات الإنتاج التي تتراوح من مجموعات k3s أحادية العقدة إلى عمليات النشر السحابية متعددة المناطق التي تعالج ملايين المعاملات يوميًا.
سنغطي النطاق الكامل: طرق النسخ الاحتياطي المنطقية والمادية، والاسترداد في الوقت المناسب، والجدولة الآلية، وأهداف التخزين السحابي، والتشفير، والتحقق، وأساليب Kubernetes الأصلية، وتخطيط التعافي من الكوارث الذي يربط كل ذلك معًا. تأتي كل توصية مصحوبة بتكوين محدد ورمز يمكنك تكييفه مع بيئتك.
فهم أنواع النسخ الاحتياطي
قبل الغوص في أدوات محددة، تحتاج إلى نموذج ذهني واضح لاستراتيجيات النسخ الاحتياطي الأساسية الأربعة وكيفية تفاعلها مع أهداف الاسترداد. تقوم كل إستراتيجية بمفاضلة مختلفة بين سرعة النسخ الاحتياطي واستهلاك التخزين ووقت الاسترداد.
النسخ الاحتياطي الكامليلتقطقاعدة البيانات بأكملها في وقت واحد. إنه الأسهل في التفكير والأسرع في الاستعادة، ولكنه أيضًا الأكثر تكلفة في التخزين والأبطأ في الإنشاء. النسخ الاحتياطي التزايدييلتقطفقط البيانات التي تغيرت منذ آخر نسخة احتياطية من أي نوع. إنه سريع الإنشاء وصغير الحجم في التخزين، لكن الاستعادة تتطلب إعادة تشغيل السلسلة الكاملة: آخر نسخة احتياطية كاملة بالإضافة إلى كل عملية تزايدية لاحقة. النسخ الاحتياطي التفاضلييلتقطكل ما تغير منذ آخر نسخة احتياطية كاملة. إنها تحتل أرضية متوسطة - أكبر من التزايدية ولكن من الأسهل استعادتها لأنك تحتاج فقط إلى آخر كامل بالإضافة إلى أحدث فرق. أخيرًا، الأرشفة المستمرة لـ(أرشفة WAL في PostgreSQL، وتدفق السجل الثنائي في MySQL) تلتقط كل معاملة فردية فور حدوثها، مما يتيح الاسترداد في أي لحظة بين النسخ الاحتياطية.
الإستراتيجية المثالية لمعظم أنظمة الإنتاج هي الجمع بين: النسخ الاحتياطي الكامل الأسبوعي، والزيادات اليومية أو التفاضلية، والأرشفة المستمرة لـ WAL/binlog. يمنحك هذا استردادًا سريعًا من النسخ الاحتياطية الكاملة الحديثة والقدرة على الاسترداد في أي وقت عندما تحتاج إليه.
MySQL طرق النسخ الاحتياطي
يوفرMySQL العديد من أدوات النسخ الاحتياطي، كل منها يناسب أحجام قواعد البيانات المختلفة ومتطلبات الاسترداد. يعتمد الاختيار الصحيح على حجم بياناتك ونافذة النسخ الاحتياطي المقبولة وأهداف RTO/RPO.
mysqldump — النسخ الاحتياطي المنطقي العالمي
ينتجmysqldumpعبارات SQL التي تعيد إنشاء المخطط والبيانات. إنه يعمل على كل إصدار ومحرك تخزين MySQL، مما يجعله البديل العالمي. ومع ذلك، فإنه يقوم بتأمين الجداول أثناء التفريغ (ما لم يتم استخدام--single-transactionمع InnoDB)، وتنخفض سرعة الاستعادة بشكل كبير لقواعد البيانات التي تتجاوز 50-100 جيجابايت لأنها تعيد تشغيل عبارات INSERT الفردية.
# Full logical backup with consistent snapshot for InnoDB
mysqldump --single-transaction --routines --triggers --events \
--set-gtid-purged=ON --all-databases \
| gzip > /backups/mysql-full-$(date +%Y%m%d-%H%M%S).sql.gz
# Single database backup with compression
mysqldump --single-transaction --routines --triggers \
--databases production_db \
| pigz -p4 > /backups/production_db-$(date +%Y%m%d).sql.gz
# Schema-only backup for migration planning
mysqldump --no-data --routines --triggers --events \
--all-databases > /backups/schema-only-$(date +%Y%m%d).sqlmysqlpump — النسخ الاحتياطي المنطقي الموازي
تم تحسينmysqlpumpعلىmysqldumpمن خلال تفريغ الجدول المتوازي والضغط المدمج. يمكن أن يقلل بشكل كبير من وقت النسخ الاحتياطي لقواعد البيانات التي تحتوي على العديد من الجداول المستقلة.
# Parallel logical backup with 4 threads and zstd compression
mysqlpump --default-parallelism=4 --compress-output=ZSTD \
--include-databases=production_db,analytics_db \
--set-gtid-purged=ON \
> /backups/mysql-pump-$(date +%Y%m%d).sql.zstPercona XtraBackup — النسخ الاحتياطي الفعلي لـ InnoDB
بالنسبة لقواعد البيانات التي يزيد حجمها عن 50 جيجابايت، تصبح عمليات النسخ الاحتياطي المنطقي غير عملية - حيث تنمو نافذة النسخ الاحتياطي ووقت الاستعادة بشكل خطي مع حجم البيانات. يأخذ Percona XtraBackup نسخًا على المستوى الفعلي من ملفات بيانات InnoDB دون قفل قاعدة البيانات، مما يجعله مناسبًا لعمليات النشر متعددة التيرابايت.
# Full physical backup with streaming to compressed archive
xtrabackup --backup --target-dir=/backups/full-$(date +%Y%m%d) \
--user=backup_user --password=secure_pass \
--parallel=4 --compress --compress-threads=4
# Incremental backup based on last full
xtrabackup --backup --target-dir=/backups/incr-$(date +%Y%m%d) \
--incremental-basedir=/backups/full-20260412 \
--user=backup_user --password=secure_pass \
--parallel=4
# Stream full backup directly to S3 via xbstream
xtrabackup --backup --stream=xbstream --compress \
--user=backup_user --password=secure_pass | \
aws s3 cp - s3://db-backups/mysql/full-$(date +%Y%m%d).xbstream
# Prepare for restore (apply redo log)
xtrabackup --prepare --target-dir=/backups/full-20260412
# Prepare incremental on top of full
xtrabackup --prepare --apply-log-only --target-dir=/backups/full-20260412
xtrabackup --prepare --target-dir=/backups/full-20260412 \
--incremental-dir=/backups/incr-20260412
# Restore
systemctl stop mysqld
xtrabackup --copy-back --target-dir=/backups/full-20260412
chown -R mysql:mysql /var/lib/mysql
systemctl start mysqldMySQL السجل الثنائي — استرداد النقطة الزمنية
تسجل السجلات الثنائيةMySQL كل بيان تعديل البيانات أو تغيير الصف. عند دمجها مع نسخة احتياطية كاملة أو فعلية، فإنها تتيح إمكانية الاسترداد في وقت محدد في أي لحظة بعد أخذ النسخة الاحتياطية.
# Enable binary logging in my.cnf
[mysqld]
server-id = 1
log-bin = /var/log/mysql/mysql-bin
binlog_format = ROW
binlog_expire_logs_seconds = 604800 # 7 days
sync_binlog = 1
gtid_mode = ON
enforce_gtid_consistency = ON
# Flush and archive binary logs
mysqladmin flush-logs
mysqlbinlog --read-from-remote-server --host=db-primary \
--raw --stop-never --result-file=/backup/binlogs/ \
mysql-bin.000042
# Point-in-time recovery: replay binlog up to specific timestamp
mysqlbinlog --stop-datetime="2026-04-12 14:30:00" \
/backup/binlogs/mysql-bin.000042 \
/backup/binlogs/mysql-bin.000043 | mysql -u rootPostgreSQL طرق النسخ الاحتياطي
يمكن القول إن النظام البيئي للنسخ الاحتياطي لـPostgreSQL أكثر ثراءً من نظام MySQL، مع أدوات الطرف الأول ومجموعة ناضجة من حلول المجتمع المصممة خصيصًا لبيئات الإنتاج واسعة النطاق.
pg_dump وpg_dumpall — النسخ الاحتياطية المنطقية
مثلmysqldump، يقومpg_dumpبإنشاء نسخ احتياطية منطقية. يعد التنسيق المخصص (-Fc) هو التنسيق الافتراضي الموصى به لأنه يدعم الاستعادة المتوازية واستعادة الجدول الانتقائي والضغط المضمن.
# Custom format with parallel dump (4 worker jobs)
pg_dump -Fc -j4 -f /backups/production-$(date +%Y%m%d).dump production_db
# Directory format for maximum parallelism on large databases
pg_dump -Fd -j8 -f /backups/production-$(date +%Y%m%d)/ production_db
# All databases including globals (roles, tablespaces)
pg_dumpall > /backups/pg-all-$(date +%Y%m%d).sql
# Parallel restore from custom format
pg_restore -j4 -d production_db_restored /backups/production-20260412.dump
# Selective restore: single table
pg_restore -j4 -d production_db -t orders /backups/production-20260412.dumppg_basebackup — مؤسسة النسخ الاحتياطي الفعلي
يأخذpg_basebackupنسخة فعلية من دليل بيانات PostgreSQL بأكمله. إنه الأساس لكل من الاسترداد المستقل وإعداد النسخ المتماثل المتدفق. ومن خلال دمجه مع أرشفة WAL، فإنه يتيح إمكانية الاسترداد في الوقت المناسب.
# Physical backup with WAL files included
pg_basebackup -D /backups/base-$(date +%Y%m%d) \
-Ft -z -Xs -P -c fast \
-U replication_user -h db-primary
# Stream backup directly to a tar archive with checksums
pg_basebackup -D - -Ft -Xs -c fast \
-U replication_user -h db-primary | \
gzip > /backups/pg-base-$(date +%Y%m%d).tar.gzpgBackRest — إدارة النسخ الاحتياطي على مستوى المؤسسات
pgBackRest هو المعيار الذهبي لإدارة النسخ الاحتياطي لـ PostgreSQL. وهو يدعم النسخ الاحتياطي الكامل والتزايدي والتفاضلي، والنسخ الاحتياطي والاستعادة المتوازيين، والتشفير، والأهداف متعددة المستودعات (القرص المحلي، S3، GCS، Azure Blob)، وأرشفة WAL الآلية - كل ذلك من خلال تكوين واحد متماسك.
# /etc/pgbackrest/pgbackrest.conf
[global]
repo1-type=s3
repo1-s3-bucket=pg-backups-production
repo1-s3-endpoint=s3.eu-west-1.amazonaws.com
repo1-s3-region=eu-west-1
repo1-s3-key=AKIAIOSFODNN7EXAMPLE
repo1-s3-key-secret=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
repo1-path=/pgbackrest
repo1-retention-full=4
repo1-retention-diff=14
repo1-cipher-type=aes-256-cbc
repo1-cipher-pass=a_very_secure_encryption_passphrase
# Second repository for geographic redundancy
repo2-type=azure
repo2-azure-container=pg-backups-dr
repo2-azure-account=prodbackupstorage
repo2-azure-key=base64encodedkeyhere
repo2-path=/pgbackrest
repo2-retention-full=2
process-max=4
compress-type=zst
compress-level=6
log-level-console=info
log-level-file=detail
start-fast=y
[production]
pg1-path=/var/lib/postgresql/16/main
pg1-port=5432
# PostgreSQL WAL archive configuration (postgresql.conf)
# archive_mode = on
# archive_command = 'pgbackrest --stanza=production archive-push %p'
# Create the stanza
pgbackrest --stanza=production stanza-create
# Verify the stanza configuration
pgbackrest --stanza=production check
# Full backup
pgbackrest --stanza=production --type=full backup
# Differential backup
pgbackrest --stanza=production --type=diff backup
# Incremental backup
pgbackrest --stanza=production --type=incr backup
# List backups
pgbackrest --stanza=production infoWAL-G - أرشفة WAL خفيفة الوزن للتخزين السحابي
يعدWAL-G بديلاً أبسط لـ pgBackRest الذي يركز على تدفق مقاطع WAL والنسخ الاحتياطية الأساسية لتخزين الكائنات السحابية. إنه شائع في البيئات المعبأة في حاويات حيث تريد ثنائيًا واحدًا بأقل قدر من التكوين.
# Environment variables for WAL-G with S3
export WALG_S3_PREFIX=s3://pg-wal-archive/production
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
export AWS_REGION=eu-west-1
export WALG_COMPRESSION_METHOD=lz4
export PGHOST=/var/run/postgresql
# Configure WAL archiving in postgresql.conf
# archive_mode = on
# archive_command = 'wal-g wal-push %p'
# restore_command = 'wal-g wal-fetch %f %p'
# Take a base backup
wal-g backup-push /var/lib/postgresql/16/main
# List backups
wal-g backup-list
# Restore from latest backup
wal-g backup-fetch /var/lib/postgresql/16/main LATEST
# Delete old backups (retain last 4)
wal-g delete retain FULL 4 --confirmBarman — خادم النسخ الاحتياطي المركزي
تم تصميمBarman (مدير النسخ الاحتياطي والاسترداد) للبيئات التي يقوم فيها خادم نسخ احتياطي مخصص بإدارة النسخ الاحتياطية لمثيلات PostgreSQL المتعددة. وهو يدعم كلاً من بروتوكولات rsync/SSH ونسخ النسخ المتدفق لنقل النسخ الاحتياطي.
# /etc/barman.d/production.conf
[production]
description = "Production PostgreSQL 16"
ssh_command = ssh postgres@db-primary
conninfo = host=db-primary user=barman dbname=postgres
streaming_conninfo = host=db-primary user=streaming_barman
backup_method = postgres
streaming_archiver = on
slot_name = barman
retention_policy = RECOVERY WINDOW OF 14 DAYS
# Create replication slot and start streaming
barman receive-wal --create-slot production
barman switch-wal --force --archive production
# Take a backup
barman backup production
# List backups
barman list-backup production
# Restore to point in time
barman recover --target-time "2026-04-12 14:30:00" \
production 20260412T120000 /var/lib/postgresql/16/mainاستعادة النقاط في الوقت المناسب (PITR)
يعد استردادفي الوقت المناسب أهم قدرة في مجموعة أدوات النسخ الاحتياطي لديك. فهو يسمح لك باستعادة قاعدة البيانات إلى الحالة الدقيقة التي كانت عليها في أي لحظة محددة - ليس فقط عند أخذ النسخ الاحتياطية، ولكن في أي ثانية بين النسخ الاحتياطية. يعد هذا أمرًا بالغ الأهمية للتعافي من الحذف غير المقصود للبيانات، وأخطاء التطبيق التي تفسد البيانات، والحوادث الأمنية التي تحتاج فيها إلى تحديد اللحظة الدقيقة للاختراق.
PITR لـ PostgreSQL
يعملPostgreSQL PITR عن طريق استعادة نسخة احتياطية أساسية وإعادة تشغيل مقاطع WAL حتى الطابع الزمني المستهدف. مع pgBackRest، العملية برمتها عبارة عن أمر واحد.
# Restore to specific point in time with pgBackRest
pgbackrest --stanza=production \
--type=time --target="2026-04-12 16:42:30" \
--target-action=promote \
restore
# Manual PITR using pg_basebackup + WAL archive
# 1. Stop PostgreSQL
systemctl stop postgresql
# 2. Clear the data directory and restore base backup
rm -rf /var/lib/postgresql/16/main/*
tar xzf /backups/pg-base-20260412.tar.gz -C /var/lib/postgresql/16/main/
# 3. Create recovery signal and configure restore
cat > /var/lib/postgresql/16/main/postgresql.auto.conf << 'CONF'
restore_command = 'cp /backup/wal_archive/%f %p'
recovery_target_time = '2026-04-12 16:42:30'
recovery_target_action = 'promote'
CONF
touch /var/lib/postgresql/16/main/recovery.signal
# 4. Start PostgreSQL — it will replay WAL and stop at target
systemctl start postgresqlPITR لـ MySQL
يجمعMySQL PITR بين استعادة XtraBackup الفعلية وإعادة تشغيل السجل الثنائي.
# 1. Restore the XtraBackup
systemctl stop mysqld
rm -rf /var/lib/mysql/*
xtrabackup --prepare --target-dir=/backups/full-20260412
xtrabackup --copy-back --target-dir=/backups/full-20260412
chown -R mysql:mysql /var/lib/mysql
systemctl start mysqld
# 2. Identify the binlog position from XtraBackup metadata
cat /backups/full-20260412/xtrabackup_binlog_info
# Output: mysql-bin.000042 154 3E11FA47-1111-1111-1111-AAAAAAAAAAAA:1-1234
# 3. Replay binlogs up to target time
mysqlbinlog --start-position=154 \
--stop-datetime="2026-04-12 16:42:30" \
/backup/binlogs/mysql-bin.000042 \
/backup/binlogs/mysql-bin.000043 | mysql -u rootبنية النسخ الاحتياطي متعدد السحابة
يجب أن تأخذ استراتيجيات النسخ الاحتياطي للإنتاجفي الاعتبار فشل أي مزود سحابي أو منطقة واحدة. إن تخزين النسخ الاحتياطية بشكل حصري في نفس الحساب السحابي وفي نفس المنطقة مثل قاعدة بيانات الإنتاج الخاصة بك يعني أن اختراق حساب واحد، أو مشكلة الفوترة، أو انقطاع الخدمة الإقليمي يمكن أن يؤدي إلى إزالة بياناتك ونسخك الاحتياطية في وقت واحد. ترسل البنية القوية نسخًا احتياطية إلى هدفين تخزين مستقلين على الأقل مع النسخ المتماثل عبر المناطق.
تكوين التخزين السحابي مع سياسات دورة الحياة
# AWS S3 lifecycle policy (Terraform)
resource "aws_s3_bucket_lifecycle_configuration" "backup_lifecycle" {
bucket = aws_s3_bucket.db_backups.id
rule {
id = "backup-tiering"
status = "Enabled"
transition {
days = 30
storage_class = "STANDARD_IA"
}
transition {
days = 90
storage_class = "GLACIER"
}
transition {
days = 365
storage_class = "DEEP_ARCHIVE"
}
expiration {
days = 2555 # 7 years for compliance
}
}
rule {
id = "wal-segments"
status = "Enabled"
filter {
prefix = "wal-archive/"
}
expiration {
days = 30
}
}
}
# Enable cross-region replication
resource "aws_s3_bucket_replication_configuration" "backup_replication" {
bucket = aws_s3_bucket.db_backups.id
role = aws_iam_role.replication.arn
rule {
id = "cross-region-dr"
status = "Enabled"
destination {
bucket = aws_s3_bucket.db_backups_dr.arn
storage_class = "STANDARD_IA"
encryption_configuration {
replica_kms_key_id = aws_kms_key.dr_key.arn
}
}
source_selection_criteria {
sse_kms_encrypted_objects {
status = "Enabled"
}
}
}
}# Azure Blob immutability policy (Azure CLI)
az storage container immutability-policy create \
--account-name prodbackupstorage \
--container-name pg-backups \
--period 365 \
--allow-protected-append-writes true
# GCS lifecycle with nearline transition
gsutil lifecycle set /dev/stdin gs://pg-backups-production << 'JSON'
{
"rule": [
{"action": {"type": "SetStorageClass", "storageClass": "NEARLINE"}, "condition": {"age": 30}},
{"action": {"type": "SetStorageClass", "storageClass": "COLDLINE"}, "condition": {"age": 90}},
{"action": {"type": "Delete"}, "condition": {"age": 2555}}
]
}
JSONتشفير النسخ الاحتياطي والأمن
تعد النسخ الاحتياطيةهدفًا عالي القيمة للمهاجمين. تمنح النسخة الاحتياطية المسروقة غير المشفرة للمهاجم نسخة كاملة من بيانات الإنتاج الخاصة بك دون الحاجة إلى اختراق أنظمة التشغيل الخاصة بك. يجب تشفير كل نسخة احتياطية، سواء أثناء النقل أو أثناء الراحة.
التشفير أثناء النقليعني استخدام TLS لجميع الاتصالات بين خادم قاعدة البيانات ووجهة النسخ الاحتياطي. يتم بث كل من pgBackRest وXtraBackup عبر القنوات المشفرة عند تكوينهما باستخدام TLS. عند الشحن إلى S3 أو Azure Blob أو GCS، تستخدم مجموعات SDK الخاصة بالعميل HTTPS بشكل افتراضي.
التشفير في حالة الراحة يحتويعلى طبقتين. يقوم التشفير من جانب الخادم (SSE) بتشفير البيانات بعد وصولها إلى هدف التخزين - S3 SSE-KMS، أو Azure Storage Service Encryption، أو التشفير الافتراضي GCS. يقوم التشفير من جانب العميل بتشفير البيانات قبل أن تغادر خادم قاعدة البيانات، مما يضمن عدم رؤية موفر السحابة لبيانات النص العادي مطلقًا. يدعم كل من pgBackRest وWAL-G التشفير من جانب العميل محليًا.
# pgBackRest client-side encryption config
repo1-cipher-type=aes-256-cbc
repo1-cipher-pass=long_random_passphrase_stored_in_vault
# WAL-G client-side encryption
export WALG_LIBSODIUM_KEY=$(cat /etc/wal-g/encryption.key)
# Or GPG-based
export WALG_GPG_KEY_ID=backup@example.com
# MySQL XtraBackup with encryption
xtrabackup --backup --encrypt=AES256 \
--encrypt-key-file=/etc/mysql/backup-encryption.key \
--target-dir=/backups/full-encrypted-$(date +%Y%m%d)قم بتخزين مفاتيح التشفير بشكل منفصل عن النسخ الاحتياطية نفسها. يعد مدير الأسرار مثل HashiCorp Vault أو AWS Secrets Manager أو Azure Key Vault هو الأسلوب الموصى به. إذا قمت بتخزين المفتاح إلى جانب النسخة الاحتياطية، فإن المهاجم الذي يمكنه الوصول إلى مخزن النسخ الاحتياطي الخاص بك سيكون لديه كل ما يحتاج إليه.
جدولة النسخ الاحتياطي الآلي
النسخ الاحتياطية اليدوية ليست نسخًا احتياطية - إنها تطلعات. يجب أن تكون جداول النسخ الاحتياطي آلية ومراقبتها والتنبيه عند الفشل.
نظامCron للمعادن العارية وأجهزة VMs
# /etc/cron.d/database-backups
# PostgreSQL — pgBackRest
# Full backup every Sunday at 01:00
0 1 * * 0 postgres pgbackrest --stanza=production --type=full backup 2>&1 | logger -t pgbackrest-full
# Differential backup every day at 01:00 (except Sunday)
0 1 * * 1-6 postgres pgbackrest --stanza=production --type=diff backup 2>&1 | logger -t pgbackrest-diff
# MySQL — XtraBackup
# Full backup every Sunday at 02:00
0 2 * * 0 root /usr/local/bin/mysql-backup.sh full 2>&1 | logger -t xtrabackup-full
# Incremental backup every day at 02:00 (except Sunday)
0 2 * * 1-6 root /usr/local/bin/mysql-backup.sh incremental 2>&1 | logger -t xtrabackup-incr
# Backup verification — restore test every Wednesday at 04:00
0 4 * * 3 root /usr/local/bin/verify-backup.sh 2>&1 | logger -t backup-verifyKubernetes كرونجوبز
في بيئات Kubernetes، يحل CronJobs محل cron النظام. إنها توفر منطق إعادة المحاولة المدمج والتحكم في التزامن والتكامل مع RBAC الخاص بالمجموعة والإدارة السرية.
apiVersion: batch/v1
kind: CronJob
metadata:
name: pg-backup-full
namespace: database
spec:
schedule: "0 1 * * 0" # Sunday 01:00 UTC
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 4
failedJobsHistoryLimit: 3
jobTemplate:
spec:
backoffLimit: 2
activeDeadlineSeconds: 7200 # 2 hour timeout
template:
spec:
serviceAccountName: db-backup
restartPolicy: OnFailure
containers:
- name: pgbackrest
image: pgbackrest/pgbackrest:2.50
command:
- /bin/bash
- -c
- |
pgbackrest --stanza=production --type=full backup
RESULT=$?
if [ $RESULT -eq 0 ]; then
curl -s -X POST "$SLACK_WEBHOOK" \
-d '{"text":"PostgreSQL full backup completed successfully"}'
else
curl -s -X POST "$SLACK_WEBHOOK" \
-d '{"text":"ALERT: PostgreSQL full backup FAILED"}'
fi
exit $RESULT
envFrom:
- secretRef:
name: pgbackrest-credentials
- secretRef:
name: slack-webhook
resources:
requests:
memory: 512Mi
cpu: 500m
limits:
memory: 2Gi
cpu: "2"
volumeMounts:
- name: pgbackrest-config
mountPath: /etc/pgbackrest
volumes:
- name: pgbackrest-config
configMap:
name: pgbackrest-conf
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: pg-backup-diff
namespace: database
spec:
schedule: "0 1 * * 1-6" # Mon-Sat 01:00 UTC
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 7
failedJobsHistoryLimit: 3
jobTemplate:
spec:
backoffLimit: 2
activeDeadlineSeconds: 3600
template:
spec:
serviceAccountName: db-backup
restartPolicy: OnFailure
containers:
- name: pgbackrest
image: pgbackrest/pgbackrest:2.50
command:
- /bin/bash
- -c
- |
pgbackrest --stanza=production --type=diff backup
envFrom:
- secretRef:
name: pgbackrest-credentials
resources:
requests:
memory: 256Mi
cpu: 250m
limits:
memory: 1Gi
cpu: "1"
volumeMounts:
- name: pgbackrest-config
mountPath: /etc/pgbackrest
volumes:
- name: pgbackrest-config
configMap:
name: pgbackrest-conf
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: mysql-backup-full
namespace: database
spec:
schedule: "0 2 * * 0"
concurrencyPolicy: Forbid
jobTemplate:
spec:
backoffLimit: 2
activeDeadlineSeconds: 7200
template:
spec:
serviceAccountName: db-backup
restartPolicy: OnFailure
containers:
- name: xtrabackup
image: percona/percona-xtrabackup:8.0
command:
- /bin/bash
- -c
- |
xtrabackup --backup --stream=xbstream --compress \
--user=$MYSQL_BACKUP_USER \
--password=$MYSQL_BACKUP_PASS \
--host=mysql-primary.database.svc | \
aws s3 cp - s3://$S3_BUCKET/mysql/full-$(date +%Y%m%d).xbstream
envFrom:
- secretRef:
name: mysql-backup-credentials
- secretRef:
name: aws-credentials
resources:
requests:
memory: 512Mi
cpu: 500m
limits:
memory: 2Gi
cpu: "2"Kubernetes- نهج النسخ الاحتياطي الأصلي
يقدم تشغيل قواعد البيانات في Kubernetes بعدًا جديدًا لاستراتيجية النسخ الاحتياطي. بالإضافة إلى النسخ الاحتياطية لقاعدة البيانات على مستوى التطبيق، يتعين عليك مراعاة النسخ الاحتياطي على مستوى المجموعة (إلخ)، ولقطات الحجم المستمرة، والنسخ الاحتياطية التي يديرها المشغل.
Velero للنسخ الاحتياطي على مستوى المجموعة
يقومVelero بعمل نسخة احتياطية من موارد Kubernetes (عمليات النشر والخدمات وخرائط التكوين والأسرار) ووحدات التخزين المستمرة. وهو ليس بديلاً للنسخ الاحتياطية لقاعدة البيانات على مستوى التطبيق - فهو يلتقط لقطة متسقة من التعطل للوحدات الكهروضوئية، والتي قد لا تكون متسقة من حيث المعاملات لقواعد البيانات. استخدم Velero لاستعادة المجموعة والأدوات على مستوى التطبيق (pgBackRest، XtraBackup) لاستعادة قاعدة البيانات.
# Install Velero with S3 backend
velero install \
--provider aws \
--bucket velero-backups \
--secret-file ./credentials-velero \
--backup-location-config region=eu-west-1 \
--snapshot-location-config region=eu-west-1 \
--use-volume-snapshots=true \
--plugins velero/velero-plugin-for-aws:v1.9.0
# Create a scheduled backup of the database namespace
velero schedule create db-namespace-backup \
--schedule="0 3 * * *" \
--include-namespaces database \
--ttl 720h \
--storage-location default \
--volume-snapshot-locations default
# On-demand backup before maintenance
velero backup create pre-maintenance-$(date +%Y%m%d) \
--include-namespaces database,monitoring \
--wait
# Restore a namespace from backup
velero restore create --from-backup pre-maintenance-20260412 \
--include-namespaces databaseلقطاتLonghorn على k3s
تستخدم عمليات نشرk3s عادةً Longhorn كموفر تخزين CSI الخاص بها. يوفر Longhorn لقطات على مستوى الصوت والقدرة على نسخ اللقطات إلى وحدة تخزين الكائنات المتوافقة مع S3. بالنسبة لقواعد البيانات، قم بدمج لقطات Longhorn مع النسخ الاحتياطية على مستوى التطبيق للدفاع بعمق.
# Longhorn recurring snapshot job via CRD
apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
name: pg-data-snapshot
namespace: longhorn-system
spec:
cron: "0 */4 * * *" # every 4 hours
task: snapshot
retain: 6
concurrency: 1
groups:
- pg-data
labels:
app: postgresql
---
# Longhorn recurring backup to S3
apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
name: pg-data-s3-backup
namespace: longhorn-system
spec:
cron: "0 2 * * *" # daily at 02:00
task: backup
retain: 14
concurrency: 1
groups:
- pg-data
labels:
app: postgresql
---
# VolumeSnapshot using Longhorn CSI
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: pg-data-snap-$(date +%Y%m%d)
namespace: database
spec:
volumeSnapshotClassName: longhorn-snapshot-vsc
source:
persistentVolumeClaimName: pg-data-postgresql-0النسخ الاحتياطية التي يديرها المشغل
يقوم مشغلو قواعد البياناتمثل CloudNativePG (لـ PostgreSQL) وPercona Operator (لـ MySQL) بدمج إدارة النسخ الاحتياطي مباشرة في دورة حياة قاعدة البيانات. يتعامل المشغل مع الجدولة وأرشفة WAL والاحتفاظ تلقائيًا من خلال الموارد المخصصة.
# CloudNativePG cluster with integrated backup
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: production-pg
namespace: database
spec:
instances: 3
storage:
size: 100Gi
storageClass: longhorn
backup:
barmanObjectStore:
destinationPath: s3://pg-backups/cnpg/
endpointURL: https://s3.eu-west-1.amazonaws.com
s3Credentials:
accessKeyId:
name: aws-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: aws-creds
key: SECRET_ACCESS_KEY
wal:
compression: gzip
maxParallel: 4
data:
compression: gzip
retentionPolicy: "30d"
---
apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
name: production-pg-weekly
namespace: database
spec:
schedule: "0 1 * * 0"
backupOwnerReference: self
cluster:
name: production-pgاستراتيجياتالخاصة بموفر الخدمة السحابية
AWS — RDS وأورورا
يوفرAWS RDS لقطات يومية تلقائية مع الاحتفاظ القابل للتكوين (حتى 35 يومًا) والنسخ الاحتياطي المستمر عبر أرشفة سجل المعاملات من أجل الاسترداد في الوقت المناسب. تضيف Aurora خاصية Backtrack، والتي يمكنها إرجاع المجموعة إلى أي نقطة داخل نافذة التراجع دون الحاجة إلى استعادة - فهي ببساطة تعكس الحالة الداخلية لقاعدة البيانات.
# Enable automated backups with maximum retention (Terraform)
resource "aws_db_instance" "production" {
identifier = "production-pg"
engine = "postgres"
engine_version = "16.2"
instance_class = "db.r6g.xlarge"
allocated_storage = 500
backup_retention_period = 35 # maximum
backup_window = "03:00-04:00"
copy_tags_to_snapshot = true
deletion_protection = true
storage_encrypted = true
kms_key_id = aws_kms_key.rds.arn
# Enable PITR
enabled_cloudwatch_logs_exports = ["postgresql", "upgrade"]
}
# Cross-region automated backup replication
resource "aws_db_instance_automated_backups_replication" "dr" {
source_db_instance_arn = aws_db_instance.production.arn
kms_key_id = aws_kms_key.dr_rds.arn
retention_period = 14
}
# Aurora Backtrack (MySQL-compatible Aurora only)
resource "aws_rds_cluster" "aurora_production" {
cluster_identifier = "aurora-production"
engine = "aurora-mysql"
engine_version = "8.0.mysql_aurora.3.05.2"
backtrack_window = 86400 # 24 hours of backtrack
backup_retention_period = 35
preferred_backup_window = "03:00-04:00"
storage_encrypted = true
}
# Manual snapshot with cross-region copy
aws rds create-db-snapshot \
--db-instance-identifier production-pg \
--db-snapshot-identifier pre-migration-$(date +%Y%m%d)
aws rds copy-db-snapshot \
--source-db-snapshot-identifier arn:aws:rds:eu-west-1:123456789:snapshot:pre-migration-20260412 \
--target-db-snapshot-identifier pre-migration-20260412-dr \
--source-region eu-west-1 \
--region us-east-1 \
--kms-key-id arn:aws:kms:us-east-1:123456789:key/dr-key-idAzure — خادم مرن
تشتمل قاعدة بياناتAzure للخادم المرن PostgreSQL وMySQL على نسخ احتياطية تلقائية مع مساحة تخزين زائدة محليًا أو جغرافية زائدة عن الحاجة. يتيح النسخ الاحتياطي الجغرافي المتكرر إمكانية الاستعادة عبر المناطق للتعافي من الكوارث.
# Azure Flexible Server with geo-redundant backup (Terraform)
resource "azurerm_postgresql_flexible_server" "production" {
name = "production-pg"
location = "westeurope"
resource_group_name = azurerm_resource_group.db.name
sku_name = "GP_Standard_D4s_v3"
version = "16"
storage_mb = 524288 # 512 GB
backup_retention_days = 35
geo_redundant_backup_enabled = true
authentication {
active_directory_auth_enabled = true
password_auth_enabled = false
}
}
# Azure Blob immutability for self-managed backups
resource "azurerm_storage_management_policy" "backup_lifecycle" {
storage_account_id = azurerm_storage_account.backups.id
rule {
name = "backup-tiering"
enabled = true
filters {
blob_types = ["blockBlob"]
prefix_match = ["pg-backups/"]
}
actions {
base_blob {
tier_to_cool_after_days_since_modification_greater_than = 30
tier_to_archive_after_days_since_modification_greater_than = 90
delete_after_days_since_modification_greater_than = 2555
}
}
}
}GCP — السحابة SQL
يوفرCloud SQL نسخًا احتياطية آلية واستردادًا فوريًا خارج الصندوق. بالنسبة لقواعد البيانات المُدارة ذاتيًا على GCE أو GKE، توفر GCS مع فئات تخزين الخطوط القريبة والخطوط الباردة تخزينًا احتياطيًا فعالاً من حيث التكلفة على المدى الطويل.
# Cloud SQL with automated backups and PITR (Terraform)
resource "google_sql_database_instance" "production" {
name = "production-pg"
database_version = "POSTGRES_16"
region = "europe-west1"
settings {
tier = "db-custom-4-16384"
backup_configuration {
enabled = true
start_time = "03:00"
point_in_time_recovery_enabled = true
transaction_log_retention_days = 7
backup_retention_settings {
retained_backups = 30
retention_unit = "COUNT"
}
}
ip_configuration {
ssl_mode = "ENCRYPTED_ONLY"
}
}
}
# Export to GCS for long-term retention
gcloud sql export sql production-pg \
gs://pg-backups-longterm/export-$(date +%Y%m%d).sql.gz \
--database=production_db \
--offloadالتحقق من النسخ الاحتياطي واختبار الاستعادة
النسخة الاحتياطية التي لم يتم اختبارها من قبل ليست نسخة احتياطية - إنها أمل. يجب أن يتم تشغيل اختبار الاستعادة التلقائي وفقًا لجدول زمني منتظم، ويفضل أن يكون أسبوعيًا، في بيئة معزولة. يجب أن يتحقق الاختبار ليس فقط من اكتمال عملية الاستعادة دون أخطاء، بل أيضًا من أن البيانات المستعادة متسقة ويمكن للتطبيق الاتصال بها والاستعلام عنها.
#!/bin/bash
# verify-backup.sh — Automated backup verification script
set -euo pipefail
RESTORE_DIR="/tmp/backup-verify-$(date +%Y%m%d-%H%M%S)"
LOG_FILE="/var/log/backup-verify.log"
SLACK_WEBHOOK="${SLACK_WEBHOOK_URL}"
DB_TYPE="${1:-postgresql}" # postgresql or mysql
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; }
alert() {
log "ALERT: $*"
curl -s -X POST "$SLACK_WEBHOOK" \
-H 'Content-Type: application/json' \
-d "{\"text\":\"BACKUP VERIFY FAILED: $*\"}"
}
cleanup() {
log "Cleaning up $RESTORE_DIR"
rm -rf "$RESTORE_DIR"
if [ "$DB_TYPE" = "postgresql" ]; then
pg_ctlcluster 16 verify stop 2>/dev/null || true
else
mysqladmin -S /tmp/mysql-verify.sock shutdown 2>/dev/null || true
fi
}
trap cleanup EXIT
mkdir -p "$RESTORE_DIR"
if [ "$DB_TYPE" = "postgresql" ]; then
log "Starting PostgreSQL backup verification"
# Restore latest pgBackRest backup to temporary directory
pgbackrest --stanza=production \
--pg1-path="$RESTORE_DIR/pgdata" \
--type=immediate \
--target-action=promote \
restore 2>&1 | tee -a "$LOG_FILE"
if [ ${PIPESTATUS[0]} -ne 0 ]; then
alert "pgBackRest restore failed"
exit 1
fi
# Start PostgreSQL on a different port
pg_ctlcluster 16 verify start -- \
-D "$RESTORE_DIR/pgdata" \
-o "-p 5433" \
-o "-c listen_addresses=127.0.0.1"
sleep 5
# Verify data integrity
TABLES=$(psql -p 5433 -d production_db -t -c \
"SELECT count(*) FROM information_schema.tables WHERE table_schema='public';")
log "Verified $TABLES tables exist"
ROW_CHECK=$(psql -p 5433 -d production_db -t -c \
"SELECT count(*) FROM orders WHERE created_at > now() - interval '7 days';")
log "Recent orders count: $ROW_CHECK"
if [ "$ROW_CHECK" -lt 1 ]; then
alert "PostgreSQL restore has no recent data — possible stale backup"
exit 1
fi
# Run pg_amcheck for corruption detection (PostgreSQL 14+)
pg_amcheck -p 5433 -d production_db --heapallindexed 2>&1 | tee -a "$LOG_FILE"
log "PostgreSQL backup verification PASSED"
else
log "Starting MySQL backup verification"
# Prepare and restore latest XtraBackup
LATEST_FULL=$(ls -td /backups/full-* | head -1)
cp -r "$LATEST_FULL" "$RESTORE_DIR/mysql-data"
xtrabackup --prepare --target-dir="$RESTORE_DIR/mysql-data"
# Start MySQL on a different socket and port
mysqld --datadir="$RESTORE_DIR/mysql-data" \
--socket=/tmp/mysql-verify.sock \
--port=3307 \
--skip-networking=0 \
--bind-address=127.0.0.1 &
sleep 10
# Verify data
TABLES=$(mysql -S /tmp/mysql-verify.sock -e \
"SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='production_db';" -sN)
log "Verified $TABLES tables exist"
mysqlcheck -S /tmp/mysql-verify.sock --all-databases --check 2>&1 | tee -a "$LOG_FILE"
log "MySQL backup verification PASSED"
fi
curl -s -X POST "$SLACK_WEBHOOK" \
-H 'Content-Type: application/json' \
-d "{\"text\":\"Backup verification PASSED for $DB_TYPE at $(date)\"}"
log "Verification complete"تخطيط التعافي من الكوارث: RTO وRPO
يجب تصميم كل إستراتيجية نسخ احتياطي حول مقياسين: هدف وقت الاسترداد (RTO)- المدة التي يمكنك تحملها للتوقف - وهدف نقطة الاسترداد (RPO)- مقدار البيانات التي يمكنك تحمل خسارتها. تدفع هذه الأرقام كل قرار بشأن تكرار النسخ الاحتياطي وأسلوبه وبنيته.
| السيناريو | RTO | RPO | استراتيجية |
|---|---|---|---|
| الخروج من التجارة الإلكترونية | < 5 دقائق | 0 (فقدان البيانات صفر) | النسخ المتماثل المتزامن + أرشفة WAL المستمرة + تجاوز الفشل في وضع الاستعداد |
| SaaS | < 30 دقيقة | < دقيقة واحدة من | نسخ البث + الأرشفة المستمرة WAL-G + تجاوز الفشل الآلي |
| الأدوات الداخلية | < 4 ساعات | < ساعة واحدة | تفاضل يومي + تزايدي بالساعة + أرشفة WAL |
| / مستودع البيانات | < 24 ساعة | < 24 ساعة | نسخ احتياطي يومي كامل للتخزين السحابي |
| Dev / التدريج | < 48 ساعة | < أسبوع واحد | نسخ احتياطي أسبوعي كامل |
للحصول على صفر RPO، تحتاج إلى النسخ المتماثل المتزامن في وضع الاستعداد واحد على الأقل. وهذا يضيف زمن الوصول إلى كل معاملة كتابة ولكنه يضمن عدم فقدان أي معاملة ملتزم بها. تقبل معظم أنظمة الإنتاج ما يقارب الصفر من RPO (ثواني الخسارة المحتملة) باستخدام النسخ المتماثل المتدفق غير المتزامن مع أرشفة WAL/binlog المستمرة، مما يتجنب عقوبة زمن استجابة الكتابة.
قالب دليل التشغيل للتعافي من الكوارث
# DR Runbook: Database Recovery
## Severity Levels
- P1: Complete data loss / corruption — all hands, CEO notified
- P2: Partial data loss / single region down — on-call team + escalation
- P3: Replica failure / backup failure — on-call investigation
## Recovery Procedures
### Scenario A: Primary DB failure, replicas healthy
1. Promote replica to primary (automated via Patroni / orchestrator)
2. Verify application connectivity
3. Re-establish replication from new primary
4. Investigate root cause
### Scenario B: Complete cluster failure, backups intact
1. Provision new database infrastructure
2. Restore latest full backup
3. Apply WAL/binlog to reach latest consistent point
4. Verify data integrity with checksums
5. Update DNS / connection strings
6. Resume application traffic
7. Re-establish backup schedule immediately
### Scenario C: Data corruption (bad migration / SQL injection)
1. Identify exact timestamp of corruption
2. Restore to point-in-time just before corruption
3. Export affected tables from restored copy
4. Merge clean data into production
5. OR: full PITR restore if corruption is widespread
## Contacts
- DBA on-call: [PagerDuty rotation]
- Infrastructure: [PagerDuty rotation]
- VP Engineering: [phone number]
## Validation Checklist
- [ ] Application health checks pass
- [ ] Row counts match expected ranges
- [ ] Recent transactions are present
- [ ] Replication re-established
- [ ] Backup schedule resumed
- [ ] Post-incident review scheduledمراقبة النسخ الاحتياطي والتنبيه
أنظمة النسخ الاحتياطيتفشل بصمت. تستمر قاعدة البيانات في العمل، ويستمر التطبيق في تقديم حركة المرور، ولا يلاحظ أحد أن النسخ الاحتياطية توقفت عن العمل منذ ثلاثة أسابيع - حتى يحتاجوا إليها. المراقبة الاستباقية ضرورية.
# Prometheus alerting rules for backup monitoring
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: backup-alerts
namespace: monitoring
spec:
groups:
- name: database-backups
rules:
- alert: BackupTooOld
expr: |
(time() - backup_last_successful_timestamp_seconds) > 90000
for: 10m
labels:
severity: critical
annotations:
summary: "Database backup is older than 25 hours"
description: "Last successful backup for {{ $labels.database }} was {{ $value | humanizeDuration }} ago"
- alert: BackupJobFailed
expr: |
kube_job_status_failed{job_name=~".*backup.*"} > 0
for: 5m
labels:
severity: critical
annotations:
summary: "Backup CronJob failed: {{ $labels.job_name }}"
- alert: WALArchivingLagging
expr: |
pg_stat_archiver_failed_count > 0
for: 5m
labels:
severity: warning
annotations:
summary: "PostgreSQL WAL archiving has failures"
- alert: BackupStorageQuotaNearing
expr: |
(backup_storage_used_bytes / backup_storage_quota_bytes) > 0.85
for: 30m
labels:
severity: warning
annotations:
summary: "Backup storage at {{ $value | humanizePercentage }} capacity"
- alert: BinlogSpaceCritical
expr: |
mysql_binlog_size_bytes > 53687091200
for: 10m
labels:
severity: warning
annotations:
summary: "MySQL binlog space exceeds 50GB — check archiving"# Custom Prometheus exporter for pgBackRest metrics
#!/usr/bin/env python3
"""pgBackRest Prometheus exporter — exposes backup age and size metrics."""
import json
import subprocess
import time
from prometheus_client import start_http_server, Gauge
BACKUP_AGE = Gauge('pgbackrest_last_backup_age_seconds', 'Seconds since last backup', ['stanza', 'type'])
BACKUP_SIZE = Gauge('pgbackrest_last_backup_size_bytes', 'Size of last backup', ['stanza', 'type'])
BACKUP_REPO_SIZE = Gauge('pgbackrest_repo_size_bytes', 'Total repository size', ['stanza'])
def collect():
result = subprocess.run(
['pgbackrest', '--output=json', 'info'],
capture_output=True, text=True
)
info = json.loads(result.stdout)
for stanza_info in info:
stanza = stanza_info['name']
for backup in stanza_info.get('backup', []):
backup_type = backup['type']
stop_time = backup['timestamp']['stop']
age = time.time() - stop_time
BACKUP_AGE.labels(stanza=stanza, type=backup_type).set(age)
size = backup['info']['size']
BACKUP_SIZE.labels(stanza=stanza, type=backup_type).set(size)
if __name__ == '__main__':
start_http_server(9854)
while True:
collect()
time.sleep(300)الأخطاء الشائعة والأنماط المضادة
بعد إدارة النسخ الاحتياطية لقاعدة البيانات عبر العشرات من بيئات الإنتاج، هذه هي الأخطاء التي تسبب أكبر قدر من الضرر.
1. النسخ الاحتياطي على نفس القرص مثل قاعدة البيانات.إذا فشل القرص، فستفقد قاعدة البيانات والنسخة الاحتياطية. قم دائمًا بكتابة النسخ الاحتياطية إلى هدف تخزين منفصل - ومن الأفضل أن تكون خارج المضيف وخارج المنطقة.
2. لا يتم اختبار الاستعادة أبدًا.النسخة الاحتياطية التي لا يمكن استعادتها ليست نسخة احتياطية. قم بجدولة اختبارات الاستعادة التلقائية أسبوعيًا واطلب من المهندسين إجراء تدريبات الاستعادة اليدوية كل ثلاثة أشهر.
3. الاعتماد فقط على النسخ المتماثل كنسخة احتياطية. النسخ المتماثلليس نسخة احتياطية. يتم نسخDROP TABLEالموجود على الجهاز الأساسي على الفور إلى جميع النسخ المتماثلة. النسخ المتماثل يحمي من فشل الأجهزة، وليس الأخطاء المنطقية.
4. عدم مراقبة مهام النسخ الاحتياطي. تفشل وظائفCron بصمت. تم تعليق Kubernetes CronJobs. تنتهي صلاحية بيانات اعتماد S3. يجب أن تقوم كل مهمة نسخ احتياطي بإبلاغ نظام المراقبة بالنجاح أو الفشل، والتنبيه إذا كانت أحدث نسخة احتياطية ناجحة أقدم من RPO الخاص بك.
5. تخزين مفاتيح التشفير بجانب النسخ الاحتياطية.إذا تمكن أحد المهاجمين من الوصول إلى مخزن النسخ الاحتياطي الخاص بك، فلا ينبغي أن يكون لديه أيضًا مفتاح فك التشفير. قم بتخزين المفاتيح في مدير أسرار مخصص.
6. لا توجد سياسة للاحتفاظ.بدون سياسات دورة الحياة، ينمو تخزين النسخ الاحتياطي بلا حدود. تحديد فترات احتفاظ واضحة: 7 أيام لشرائح WAL، و30 يومًا للنسخ الاحتياطي اليومي، و12 شهرًا للنسخ الاحتياطية الشهرية، وحذفها تلقائيًا.
7. تجاهل تأثير أداء النسخ الاحتياطي.يؤدي تشغيل نسخة احتياطية كاملة على قاعدة البيانات الأساسية خلال ساعات الذروة إلى انخفاض أداء التطبيق. قم بجدولة النسخ الاحتياطية أثناء النوافذ ذات حركة المرور المنخفضة، أو قم بالنسخ الاحتياطي من نسخة متماثلة مخصصة.
8. استخدامmysqldumpلقواعد البيانات الكبيرة بدون--single-transaction.بدون هذه العلامة، يقومmysqldumpبتأمين الجداول وحظر الكتابة طوال مدة التفريغ. بالنسبة لقواعد البيانات الكبيرة، قد يعني هذا دقائق أو ساعات من التوقف.
9. نسيان عمل نسخة احتياطية لتكوين قاعدة البيانات.استعادة البيانات ليست سوى نصف المعركة. إذا فقدتpostgresql.confوpg_hba.confوmy.cnfوإعدادات النسخ المتماثل ومنح المستخدم، فلن تتمكن من إعادة قاعدة البيانات إلى حالة قابلة للاستخدام. قم بتضمين ملفات التكوين في عملية النسخ الاحتياطي.
10. عدم توثيق إجراء الاستعادة.أثناء انقطاع الخدمة، قد لا يكون الشخص الذي يقوم باستعادة قاعدة البيانات هو الشخص الذي قام بإعداد النسخ الاحتياطية. يعد كتاب التشغيل المكتوب والمختبر أمرًا بالغ الأهمية.
تحسين تكلفةلتخزين النسخ الاحتياطية
يمكن أن تنمو تكاليف تخزين النسخ الاحتياطيةبسرعة، خاصة مع النسخ الاحتياطية الكاملة المتكررة لقواعد البيانات الكبيرة. تعمل هذه الاستراتيجيات على إبقاء التكاليف تحت السيطرة دون المساس بإمكانية الاسترداد.
استخدم النسخ الاحتياطية التزايدية/التفاضلية.تستخدم الفروق الأسبوعية الكاملة بالإضافة إلى الفروق اليومية جزءًا صغيرًا من مساحة التخزين مقارنة بالنسخ الاحتياطية الكاملة اليومية. تعني إمكانية استعادة دلتا الخاصة بـ pgBackRest أن استعادة النسخ الاحتياطية المتزايدة بنفس سرعة النسخ الاحتياطية الكاملة تقريبًا.
تمكين الضغط.توفر خوارزميات الضغط الحديثة مثل zstd نسب ضغط ممتازة (5:1 إلى 10:1 لبيانات قاعدة البيانات النموذجية) مع الحد الأدنى من حمل CPU. يدعم كل من pgBackRest وXtraBackup zstd محليًا.
تنفيذ طبقات التخزين.انقل النسخ الاحتياطية إلى طبقات تخزين أرخص تدريجيًا مع تقدم العمر. يمكن لسياسات دورة الحياة الموضحة سابقًا (S3 Standard → IA → Glacier، GCS Standard → Nearline → Coldline) تقليل تكاليف التخزين طويل المدى بنسبة 70-90%.
قم بإلغاء التكرارات حيثما أمكن ذلك. يستخدمpgBackRest إلغاء البيانات المكررة على مستوى الكتلة في مستودعه، حيث يقوم بتخزين الكتل التي تم تغييرها فقط عبر النسخ الاحتياطية. يؤدي هذا إلى تقليل مساحة تخزين قواعد البيانات بشكل كبير حيث تكون غالبية البيانات ثابتة.
نوافذ الاحتفاظ بالحجم الصحيح.تتخلف العديد من الفرق عن الاحتفاظ بالنسخ الاحتياطية إلى الأبد بعيدًا عن الحذر. قم بتحليل أنماط الاسترداد الفعلية ومتطلبات الامتثال، ثم قم بتعيين الاحتفاظ المطابق. يمكن لمتطلبات الاحتفاظ لمدة 7 سنوات استخدام تخزين أرشيف عميق بأقل من 1 دولار أمريكي لكل تيرابايت شهريًا لدى معظم موفري الخدمات السحابية.
# Cost comparison: Full vs Incremental backup storage
# Assuming 500 GB database, 5% daily change rate, 30-day retention
# Strategy A: Daily full backups
# 500 GB × 30 days = 15,000 GB = 15 TB
# S3 Standard: 15 TB × $0.023/GB = $345/month
# Strategy B: Weekly full + daily incremental
# 4 full × 500 GB = 2,000 GB
# 26 incremental × 25 GB = 650 GB
# Total: 2,650 GB ≈ 2.6 TB
# S3 Standard: 2.6 TB × $0.023/GB = $59.80/month
# Strategy C: Strategy B + lifecycle tiering
# Current week: 525 GB Standard = $12.08
# Weeks 2-4: 2,125 GB Standard-IA = $26.56
# Total: $38.64/month
# Savings: Strategy C is 89% cheaper than Strategy Aتجميع كل شيء معًا: بنية نسخ احتياطي كاملة
فيما يلي بنية النسخ الاحتياطي الموصى بها لبيئة الإنتاج التي تشغل كلاً من MySQL وPostgreSQL، والتي تم نشرها على Kubernetes مع التعافي من الكوارث على السحابة المتعددة.
لـ PostgreSQL:
- pgBackRest كأداة النسخ الاحتياطي الأساسية مع مستودعين (S3 + Azure Blob)
- أرشفة WAL المستمرة لكلا المستودعين
- النسخ الاحتياطي الكامل الأسبوعي + التفاضلي اليومي (عبر K8s CronJob) لقطات حجم
- Longhorn كل 4 ساعات للرجوع السريع إلى الحالة السابقة
- التحقق من الاستعادة التلقائية كل أربعاء مراقبة
- Prometheus مع تنبيهات بشأن عمر النسخ الاحتياطي والفشل والتخزين
لـ MySQL:
- Percona XtraBackup للنسخ الاحتياطية الفعلية المتدفقة إلى S3
- شحن السجل الثنائي المستمر إلى وحدة تخزين منفصلة
- أسبوعي كامل + يومي تزايدي (عبر K8s CronJob)
mysqldumpاليومي للمخططات الهامة للنسخ الاحتياطي المنطقي المحمول لقطات حجم- Longhorn كل 4 ساعات
- التحقق من الاستعادة التلقائية كل يوم خميس
لمجموعة Kubernetes:
- Velero النسخ الاحتياطي اليومي لمساحات أسماء قاعدة البيانات مع اللقطات الكهروضوئية لقطات
- RKE2/k3s وما إلى ذلك كل 6 ساعات للتخزين خارج المجموعة مستودع
- GitOps كمصدر الحقيقة لجميع بيانات
للتعافي من الكوارث:
- النسخ المتماثل عبر المنطقة
- S3 إلى منطقة DR
- Azure GRS للنسخ الاحتياطية الجغرافية الزائدة تمرين DR الشهري
- : إعادة بناء المجموعة الكاملة من النسخ الاحتياطية في منطقة DR
- دليل التشغيل الموثق مع شجرة القرار لكل سيناريو فشل
خط الدفاع الأخير بين عملك وفقدان البيانات الكارثي. تمثل الاستراتيجيات الموضحة في هذه المقالة - النسخ الاحتياطية المادية والمنطقية، والأرشفة المستمرة لـ WAL وbinlog، والتخزين السحابي المتعدد مع سياسات دورة الحياة، والتشفير في كل طبقة، والجدولة التلقائية عبر Kubernetes CronJobs، والتحقق المنهجي من الاستعادة - الحالة الفنية الحالية لبيئات الإنتاج MySQL وPostgreSQL.
أهم ما يمكن تعلمه هو:استراتيجية النسخ الاحتياطي جيدة مثل اختبار الاستعادة الناجح الأخير. كل أداة ونص برمجي ونمط بنية موجود في هذه المقالة يخدم غرضًا واحدًا - وهو ضمان أنه عندما يحدث الأسوأ، يمكنك استرداد بياناتك، والوفاء بالتزامات RTO وRPO، والحفاظ على استمرارية أعمالك. قم ببناء نظام النسخ الاحتياطي الخاص بك، وقم بتشغيله تلقائيًا، وراقبه، واختبره، ثم اختبره مرة أخرى. سوف تشكرك نفسك في المستقبل.