# Стратегии резервного копирования и восстановления SFERA ## 🎯 Обзор Комплексная система резервного копирования и аварийного восстановления для платформы SFERA, обеспечивающая защиту данных, минимизацию простоев и быстрое восстановление после сбоев. ## 📊 Архитектура резервного копирования ### Стратегия 3-2-1 - **3** копии данных (оригинал + 2 резервные копии) - **2** различных носителя (локальный + облачный) - **1** копия хранится удаленно (географически отдельно) ```mermaid graph TB A[Основная БД PostgreSQL] --> B[Локальное резервное копирование] A --> C[Репликация на Slave] A --> D[Облачное резервное копирование] B --> E[Ежедневные бэкапы] B --> F[Инкрементальные бэкапы] C --> G[Read Replica] C --> H[Standby Server] D --> I[AWS S3/Yandex Cloud] D --> J[Географически удаленный сервер] ``` ## 🗄️ База данных ### 1. PostgreSQL Backup Strategy #### Автоматические ежедневные бэкапы ```bash #!/bin/bash # scripts/backup/daily-backup.sh # Конфигурация DB_HOST="localhost" DB_PORT="5432" DB_NAME="sfera_prod" DB_USER="sfera_backup" BACKUP_DIR="/var/backups/sfera" RETENTION_DAYS=30 DATE=$(date +%Y%m%d_%H%M%S) # Создание директории для бэкапов mkdir -p "$BACKUP_DIR/daily" mkdir -p "$BACKUP_DIR/logs" # Логирование LOG_FILE="$BACKUP_DIR/logs/backup_$DATE.log" exec 1> >(tee -a "$LOG_FILE") exec 2>&1 echo "=== Starting backup at $(date) ===" # Проверка свободного места (минимум 10GB) FREE_SPACE=$(df "$BACKUP_DIR" | awk 'NR==2 {print $4}') if [ "$FREE_SPACE" -lt 10485760 ]; then echo "ERROR: Insufficient disk space. Free space: ${FREE_SPACE}KB" exit 1 fi # Создание дампа базы данных BACKUP_FILE="$BACKUP_DIR/daily/sfera_backup_$DATE.sql" echo "Creating database dump..." pg_dump \ --host="$DB_HOST" \ --port="$DB_PORT" \ --username="$DB_USER" \ --dbname="$DB_NAME" \ --verbose \ --clean \ --if-exists \ --create \ --format=custom \ --compress=9 \ --file="$BACKUP_FILE" if [ $? -eq 0 ]; then echo "Database backup completed successfully" # Проверка целостности бэкапа echo "Verifying backup integrity..." pg_restore --list "$BACKUP_FILE" > /dev/null if [ $? -eq 0 ]; then echo "Backup integrity verification passed" # Сжатие бэкапа echo "Compressing backup..." gzip "$BACKUP_FILE" BACKUP_FILE="${BACKUP_FILE}.gz" # Вычисление контрольной суммы echo "Calculating checksum..." md5sum "$BACKUP_FILE" > "${BACKUP_FILE}.md5" # Размер бэкапа BACKUP_SIZE=$(du -h "$BACKUP_FILE" | cut -f1) echo "Backup size: $BACKUP_SIZE" # Отправка в облако (если настроено) if [ -n "$CLOUD_STORAGE_ENABLED" ]; then echo "Uploading to cloud storage..." upload_to_cloud "$BACKUP_FILE" fi else echo "ERROR: Backup integrity verification failed" rm -f "$BACKUP_FILE" exit 1 fi else echo "ERROR: Database backup failed" exit 1 fi # Очистка старых бэкапов echo "Cleaning up old backups..." find "$BACKUP_DIR/daily" -name "sfera_backup_*.sql.gz" -mtime +$RETENTION_DAYS -delete find "$BACKUP_DIR/daily" -name "sfera_backup_*.md5" -mtime +$RETENTION_DAYS -delete echo "=== Backup completed at $(date) ===" # Отправка уведомления о результате send_notification "SUCCESS" "Database backup completed successfully. Size: $BACKUP_SIZE" ``` #### Инкрементальные бэкапы с WAL-E ```bash #!/bin/bash # scripts/backup/wal-backup.sh # Конфигурация WAL-E для непрерывного архивирования export WALE_S3_PREFIX="s3://sfera-backups/wal" export AWS_ACCESS_KEY_ID="your-access-key" export AWS_SECRET_ACCESS_KEY="your-secret-key" # Настройка PostgreSQL для WAL архивирования # В postgresql.conf: # wal_level = replica # archive_mode = on # archive_command = 'wal-e wal-push %p' # max_wal_senders = 3 # wal_keep_segments = 32 # Создание базового бэкапа create_base_backup() { echo "Creating base backup with WAL-E..." wal-e backup-push /var/lib/postgresql/data if [ $? -eq 0 ]; then echo "Base backup created successfully" # Сохранение метаданных бэкапа cat > "/var/backups/sfera/base_backup_$(date +%Y%m%d_%H%M%S).meta" << EOF { "timestamp": "$(date -Iseconds)", "backup_type": "base", "wal_file": "$(pg_current_wal_file)", "database_size": "$(du -sh /var/lib/postgresql/data | cut -f1)" } EOF else echo "ERROR: Base backup failed" return 1 fi } # Проверка статуса архивирования check_wal_status() { echo "Checking WAL archiving status..." # Получение текущего WAL файла CURRENT_WAL=$(psql -t -c "SELECT pg_current_wal_file()" -d sfera_prod) # Проверка последнего архивированного WAL LAST_ARCHIVED=$(wal-e wal-list | tail -1) echo "Current WAL: $CURRENT_WAL" echo "Last archived WAL: $LAST_ARCHIVED" # Проверка отставания архивирования if [ -n "$CURRENT_WAL" ] && [ -n "$LAST_ARCHIVED" ]; then echo "WAL archiving is operational" else echo "WARNING: WAL archiving may have issues" fi } # Основная логика case "$1" in "base") create_base_backup ;; "status") check_wal_status ;; *) echo "Usage: $0 {base|status}" exit 1 ;; esac ``` ### 2. Point-in-Time Recovery (PITR) ```bash #!/bin/bash # scripts/recovery/pitr-restore.sh # Функция восстановления на определенную точку времени perform_pitr() { local TARGET_TIME="$1" local RESTORE_DIR="$2" echo "=== Starting Point-in-Time Recovery ===" echo "Target time: $TARGET_TIME" echo "Restore directory: $RESTORE_DIR" # Остановка PostgreSQL echo "Stopping PostgreSQL..." systemctl stop postgresql # Создание резервной копии текущих данных if [ -d "/var/lib/postgresql/data" ]; then echo "Backing up current data directory..." mv /var/lib/postgresql/data "/var/lib/postgresql/data.backup.$(date +%s)" fi # Создание нового каталога данных mkdir -p "$RESTORE_DIR" chown postgres:postgres "$RESTORE_DIR" # Восстановление базового бэкапа echo "Restoring base backup..." wal-e backup-fetch "$RESTORE_DIR" LATEST if [ $? -ne 0 ]; then echo "ERROR: Failed to restore base backup" return 1 fi # Создание recovery.conf cat > "$RESTORE_DIR/recovery.conf" << EOF restore_command = 'wal-e wal-fetch %f %p' recovery_target_time = '$TARGET_TIME' recovery_target_action = 'promote' EOF # Установка правильных прав chown postgres:postgres "$RESTORE_DIR/recovery.conf" chmod 600 "$RESTORE_DIR/recovery.conf" # Обновление конфигурации PostgreSQL if [ -f "$RESTORE_DIR/postgresql.conf" ]; then sed -i "s|^data_directory.*|data_directory = '$RESTORE_DIR'|" "$RESTORE_DIR/postgresql.conf" fi # Запуск PostgreSQL в режиме восстановления echo "Starting PostgreSQL in recovery mode..." sudo -u postgres pg_ctl start -D "$RESTORE_DIR" # Ожидание завершения восстановления echo "Waiting for recovery to complete..." while [ -f "$RESTORE_DIR/recovery.conf" ]; do sleep 5 echo -n "." done echo echo "Point-in-Time Recovery completed successfully" # Проверка восстановления echo "Verifying database integrity..." sudo -u postgres psql -d sfera_prod -c "SELECT COUNT(*) FROM users;" > /dev/null if [ $? -eq 0 ]; then echo "Database verification passed" return 0 else echo "ERROR: Database verification failed" return 1 fi } # Проверка параметров if [ $# -ne 2 ]; then echo "Usage: $0 " echo "Example: $0 '2024-01-15 14:30:00' '/var/lib/postgresql/data_restored'" exit 1 fi perform_pitr "$1" "$2" ``` ## 📁 Файловая система ### 1. Backup файлов приложения ```bash #!/bin/bash # scripts/backup/files-backup.sh # Конфигурация APP_DIR="/var/www/sfera" BACKUP_DIR="/var/backups/sfera/files" UPLOADS_DIR="$APP_DIR/uploads" LOGS_DIR="$APP_DIR/logs" DATE=$(date +%Y%m%d_%H%M%S) # Создание архива с исключениями create_files_backup() { echo "Creating files backup..." # Список исключений cat > /tmp/backup_exclude.txt << EOF node_modules/ .next/ .git/ *.log *.tmp .cache/ coverage/ dist/ build/ EOF # Создание tar архива tar -czf "$BACKUP_DIR/files_backup_$DATE.tar.gz" \ --exclude-from=/tmp/backup_exclude.txt \ -C "$(dirname "$APP_DIR")" \ "$(basename "$APP_DIR")" if [ $? -eq 0 ]; then echo "Files backup completed" # Контрольная сумма md5sum "$BACKUP_DIR/files_backup_$DATE.tar.gz" > "$BACKUP_DIR/files_backup_$DATE.tar.gz.md5" # Размер архива BACKUP_SIZE=$(du -h "$BACKUP_DIR/files_backup_$DATE.tar.gz" | cut -f1) echo "Backup size: $BACKUP_SIZE" else echo "ERROR: Files backup failed" return 1 fi # Очистка временного файла rm -f /tmp/backup_exclude.txt } # Backup загруженных файлов отдельно backup_uploads() { if [ -d "$UPLOADS_DIR" ]; then echo "Backing up uploaded files..." rsync -av --delete \ "$UPLOADS_DIR/" \ "$BACKUP_DIR/uploads_$DATE/" # Создание архива загруженных файлов tar -czf "$BACKUP_DIR/uploads_$DATE.tar.gz" \ -C "$BACKUP_DIR" \ "uploads_$DATE" # Удаление временной директории rm -rf "$BACKUP_DIR/uploads_$DATE" echo "Uploads backup completed" fi } # Backup логов backup_logs() { if [ -d "$LOGS_DIR" ]; then echo "Backing up logs..." # Архивирование логов старше 1 дня find "$LOGS_DIR" -name "*.log" -mtime +1 -exec \ tar -czf "$BACKUP_DIR/logs_$DATE.tar.gz" {} + echo "Logs backup completed" fi } # Основная логика mkdir -p "$BACKUP_DIR" create_files_backup backup_uploads backup_logs echo "Files backup process completed" ``` ### 2. Синхронизация с облачным хранилищем ```bash #!/bin/bash # scripts/backup/cloud-sync.sh # Конфигурация облачного хранилища CLOUD_PROVIDER="yandex" # или "aws" BUCKET_NAME="sfera-backups" LOCAL_BACKUP_DIR="/var/backups/sfera" # Функция загрузки в Yandex Cloud upload_to_yandex() { local file_path="$1" local remote_path="$2" s3cmd put "$file_path" "s3://$BUCKET_NAME/$remote_path" \ --config=/etc/s3cmd/yandex.conf \ --storage-class=COLD } # Функция загрузки в AWS S3 upload_to_aws() { local file_path="$1" local remote_path="$2" aws s3 cp "$file_path" "s3://$BUCKET_NAME/$remote_path" \ --storage-class GLACIER } # Синхронизация бэкапов с облаком sync_backups() { echo "Starting cloud synchronization..." # Поиск новых бэкапов find "$LOCAL_BACKUP_DIR" -name "*.gz" -mtime -1 | while read backup_file; do # Определение типа бэкапа if [[ "$backup_file" == *"sfera_backup_"* ]]; then remote_path="database/$(basename "$backup_file")" elif [[ "$backup_file" == *"files_backup_"* ]]; then remote_path="files/$(basename "$backup_file")" elif [[ "$backup_file" == *"uploads_"* ]]; then remote_path="uploads/$(basename "$backup_file")" else remote_path="misc/$(basename "$backup_file")" fi echo "Uploading $backup_file to cloud storage..." case "$CLOUD_PROVIDER" in "yandex") upload_to_yandex "$backup_file" "$remote_path" ;; "aws") upload_to_aws "$backup_file" "$remote_path" ;; *) echo "Unknown cloud provider: $CLOUD_PROVIDER" ;; esac if [ $? -eq 0 ]; then echo "Successfully uploaded $(basename "$backup_file")" # Создание метаданных о загруженном файле cat > "${backup_file}.cloud_meta" << EOF { "uploaded_at": "$(date -Iseconds)", "cloud_provider": "$CLOUD_PROVIDER", "remote_path": "$remote_path", "file_size": "$(stat -c%s "$backup_file")", "checksum": "$(md5sum "$backup_file" | cut -d' ' -f1)" } EOF else echo "ERROR: Failed to upload $(basename "$backup_file")" fi done } # Проверка доступности облачного хранилища check_cloud_connectivity() { echo "Checking cloud connectivity..." case "$CLOUD_PROVIDER" in "yandex") s3cmd ls "s3://$BUCKET_NAME/" --config=/etc/s3cmd/yandex.conf > /dev/null ;; "aws") aws s3 ls "s3://$BUCKET_NAME/" > /dev/null ;; esac if [ $? -eq 0 ]; then echo "Cloud connectivity: OK" return 0 else echo "ERROR: Cannot connect to cloud storage" return 1 fi } # Основная логика if check_cloud_connectivity; then sync_backups else echo "Skipping cloud sync due to connectivity issues" exit 1 fi ``` ## 🔄 Репликация и высокая доступность ### 1. PostgreSQL Streaming Replication ```bash #!/bin/bash # scripts/replication/setup-streaming.sh # Настройка мастер-сервера setup_master() { echo "Configuring master server..." # Создание пользователя для репликации sudo -u postgres psql << EOF CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'repl_password'; EOF # Конфигурация postgresql.conf cat >> /etc/postgresql/14/main/postgresql.conf << EOF # Replication settings wal_level = replica max_wal_senders = 3 wal_keep_segments = 64 synchronous_commit = on synchronous_standby_names = 'standby1' EOF # Конфигурация pg_hba.conf cat >> /etc/postgresql/14/main/pg_hba.conf << EOF # Replication connections host replication replicator 0.0.0.0/0 md5 EOF # Перезапуск PostgreSQL systemctl restart postgresql echo "Master server configured" } # Настройка slave-сервера setup_slave() { local master_host="$1" echo "Configuring slave server..." # Остановка PostgreSQL systemctl stop postgresql # Очистка каталога данных rm -rf /var/lib/postgresql/14/main/* # Создание базового бэкапа с мастера sudo -u postgres pg_basebackup \ -h "$master_host" \ -D /var/lib/postgresql/14/main \ -U replicator \ -v -P -W # Создание recovery.conf cat > /var/lib/postgresql/14/main/recovery.conf << EOF standby_mode = 'on' primary_conninfo = 'host=$master_host port=5432 user=replicator password=repl_password application_name=standby1' recovery_target_timeline = 'latest' EOF chown postgres:postgres /var/lib/postgresql/14/main/recovery.conf # Запуск PostgreSQL systemctl start postgresql echo "Slave server configured" } # Проверка статуса репликации check_replication_status() { echo "=== Replication Status ===" # На мастере sudo -u postgres psql -c "SELECT * FROM pg_stat_replication;" # На slave sudo -u postgres psql -c "SELECT * FROM pg_stat_wal_receiver;" # Проверка отставания sudo -u postgres psql -c "SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()));" } # Основная логика case "$1" in "master") setup_master ;; "slave") if [ -z "$2" ]; then echo "Usage: $0 slave " exit 1 fi setup_slave "$2" ;; "status") check_replication_status ;; *) echo "Usage: $0 {master|slave |status}" exit 1 ;; esac ``` ### 2. Failover и Failback процедуры ```bash #!/bin/bash # scripts/failover/failover.sh # Конфигурация MASTER_HOST="10.0.1.10" SLAVE_HOST="10.0.1.11" APP_HOST="10.0.1.20" VIP="10.0.1.100" # Virtual IP # Автоматический failover perform_failover() { echo "=== STARTING EMERGENCY FAILOVER ===" # Проверка доступности мастера if ! pg_isready -h "$MASTER_HOST" -p 5432; then echo "Master server is not responding. Proceeding with failover..." # Промоут slave в master echo "Promoting slave to master..." ssh postgres@"$SLAVE_HOST" "pg_ctl promote -D /var/lib/postgresql/14/main" # Ожидание завершения промоута sleep 10 # Переключение Virtual IP echo "Switching virtual IP to new master..." switch_vip "$SLAVE_HOST" # Обновление конфигурации приложения echo "Updating application database configuration..." update_app_config "$SLAVE_HOST" # Перезапуск приложения echo "Restarting application..." ssh root@"$APP_HOST" "systemctl restart sfera" # Уведомление администраторов send_alert "FAILOVER" "Database failover completed. New master: $SLAVE_HOST" echo "=== FAILOVER COMPLETED ===" else echo "Master server is responding. No failover needed." fi } # Планируемое переключение (для обслуживания) planned_switchover() { echo "=== STARTING PLANNED SWITCHOVER ===" # Синхронизация данных echo "Waiting for replica synchronization..." wait_for_sync # Остановка приложения echo "Stopping application..." ssh root@"$APP_HOST" "systemctl stop sfera" # Остановка мастера echo "Stopping master database..." ssh postgres@"$MASTER_HOST" "pg_ctl stop -D /var/lib/postgresql/14/main -m fast" # Промоут slave echo "Promoting slave to master..." ssh postgres@"$SLAVE_HOST" "pg_ctl promote -D /var/lib/postgresql/14/main" # Переключение IP switch_vip "$SLAVE_HOST" # Обновление конфигурации update_app_config "$SLAVE_HOST" # Запуск приложения echo "Starting application..." ssh root@"$APP_HOST" "systemctl start sfera" echo "=== SWITCHOVER COMPLETED ===" } # Процедура failback perform_failback() { local old_master="$1" echo "=== STARTING FAILBACK ===" # Настройка старого мастера как slave echo "Configuring old master as slave..." ssh postgres@"$old_master" " rm -f /var/lib/postgresql/14/main/recovery.conf cat > /var/lib/postgresql/14/main/recovery.conf << EOF standby_mode = 'on' primary_conninfo = 'host=$SLAVE_HOST port=5432 user=replicator' recovery_target_timeline = 'latest' EOF " # Запуск старого мастера как slave ssh postgres@"$old_master" "pg_ctl start -D /var/lib/postgresql/14/main" # Ожидание синхронизации wait_for_sync # Теперь можно выполнить switchover обратно planned_switchover echo "=== FAILBACK COMPLETED ===" } # Вспомогательные функции wait_for_sync() { echo "Waiting for synchronization..." while true; do LAG=$(ssh postgres@"$SLAVE_HOST" "psql -t -c \"SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()));\"") if (( $(echo "$LAG < 1" | bc -l) )); then echo "Synchronization complete (lag: ${LAG}s)" break fi echo "Current lag: ${LAG}s" sleep 2 done } switch_vip() { local new_host="$1" # Здесь реализация переключения Virtual IP # (зависит от используемого решения: keepalived, pacemaker, etc.) echo "Virtual IP switched to $new_host" } update_app_config() { local new_db_host="$1" ssh root@"$APP_HOST" " sed -i 's/DATABASE_URL=.*/DATABASE_URL=\"postgresql:\/\/user:pass@$new_db_host:5432\/sfera_prod\"/' /var/www/sfera/.env " } send_alert() { local type="$1" local message="$2" # Отправка в Slack/email/etc. curl -X POST -H 'Content-type: application/json' \ --data "{\"text\":\"[$type] $message\"}" \ "$SLACK_WEBHOOK_URL" } # Основная логика case "$1" in "failover") perform_failover ;; "switchover") planned_switchover ;; "failback") if [ -z "$2" ]; then echo "Usage: $0 failback " exit 1 fi perform_failback "$2" ;; *) echo "Usage: $0 {failover|switchover|failback }" exit 1 ;; esac ``` ## 📋 Процедуры восстановления ### 1. Полное восстановление системы ```bash #!/bin/bash # scripts/recovery/full-restore.sh # Процедура полного восстановления full_system_restore() { local backup_date="$1" local restore_path="$2" echo "=== STARTING FULL SYSTEM RESTORE ===" echo "Backup date: $backup_date" echo "Restore path: $restore_path" # Создание директории восстановления mkdir -p "$restore_path" cd "$restore_path" # 1. Восстановление базы данных echo "Restoring database..." restore_database "$backup_date" # 2. Восстановление файлов приложения echo "Restoring application files..." restore_application_files "$backup_date" # 3. Восстановление загруженных файлов echo "Restoring uploaded files..." restore_uploads "$backup_date" # 4. Настройка конфигурации echo "Configuring restored system..." configure_restored_system # 5. Проверка целостности echo "Verifying system integrity..." verify_system_integrity echo "=== FULL SYSTEM RESTORE COMPLETED ===" } # Восстановление базы данных restore_database() { local backup_date="$1" local backup_file="sfera_backup_${backup_date}.sql.gz" # Поиск файла бэкапа if [ -f "/var/backups/sfera/daily/$backup_file" ]; then echo "Found local backup: $backup_file" BACKUP_PATH="/var/backups/sfera/daily/$backup_file" else echo "Local backup not found. Downloading from cloud..." download_from_cloud "database/$backup_file" "/tmp/$backup_file" BACKUP_PATH="/tmp/$backup_file" fi # Проверка контрольной суммы if [ -f "${BACKUP_PATH}.md5" ]; then echo "Verifying backup integrity..." if ! md5sum -c "${BACKUP_PATH}.md5"; then echo "ERROR: Backup integrity check failed" return 1 fi fi # Создание новой базы данных echo "Creating restored database..." sudo -u postgres createdb sfera_restored # Восстановление данных echo "Restoring database data..." gunzip -c "$BACKUP_PATH" | sudo -u postgres pg_restore -d sfera_restored -v if [ $? -eq 0 ]; then echo "Database restore completed successfully" else echo "ERROR: Database restore failed" return 1 fi } # Восстановление файлов приложения restore_application_files() { local backup_date="$1" local backup_file="files_backup_${backup_date}.tar.gz" # Поиск и восстановление файлов if [ -f "/var/backups/sfera/files/$backup_file" ]; then echo "Restoring application files from $backup_file" tar -xzf "/var/backups/sfera/files/$backup_file" -C "$restore_path" else echo "Downloading application files from cloud..." download_from_cloud "files/$backup_file" "/tmp/$backup_file" tar -xzf "/tmp/$backup_file" -C "$restore_path" fi } # Восстановление загруженных файлов restore_uploads() { local backup_date="$1" local backup_file="uploads_${backup_date}.tar.gz" if [ -f "/var/backups/sfera/files/$backup_file" ]; then echo "Restoring uploaded files from $backup_file" tar -xzf "/var/backups/sfera/files/$backup_file" -C "$restore_path" fi } # Скачивание из облачного хранилища download_from_cloud() { local remote_path="$1" local local_path="$2" case "$CLOUD_PROVIDER" in "yandex") s3cmd get "s3://$BUCKET_NAME/$remote_path" "$local_path" \ --config=/etc/s3cmd/yandex.conf ;; "aws") aws s3 cp "s3://$BUCKET_NAME/$remote_path" "$local_path" ;; esac } # Настройка восстановленной системы configure_restored_system() { echo "Configuring restored system..." # Обновление конфигурации базы данных sed -i 's/sfera_prod/sfera_restored/g' "$restore_path/sfera/.env" # Установка правильных прав доступа chown -R www-data:www-data "$restore_path/sfera" chmod -R 755 "$restore_path/sfera" # Создание символических ссылок ln -sf "$restore_path/sfera" "/var/www/sfera_restored" } # Проверка целостности восстановленной системы verify_system_integrity() { echo "Verifying system integrity..." # Проверка подключения к базе данных if sudo -u postgres psql -d sfera_restored -c "SELECT COUNT(*) FROM users;" > /dev/null; then echo "✓ Database connectivity: OK" else echo "✗ Database connectivity: FAILED" return 1 fi # Проверка файлов приложения if [ -f "$restore_path/sfera/package.json" ]; then echo "✓ Application files: OK" else echo "✗ Application files: MISSING" return 1 fi # Проверка конфигурации if [ -f "$restore_path/sfera/.env" ]; then echo "✓ Configuration files: OK" else echo "✗ Configuration files: MISSING" return 1 fi echo "System integrity verification completed" } # Проверка параметров if [ $# -ne 2 ]; then echo "Usage: $0 " echo "Example: $0 20240115_143000 /var/restore" exit 1 fi full_system_restore "$1" "$2" ``` ## 📊 Monitoring и алерты ### 1. Мониторинг состояния бэкапов ```bash #!/bin/bash # scripts/monitoring/backup-monitor.sh # Проверка состояния резервных копий check_backup_health() { local status="OK" local alerts=() echo "=== Backup Health Check ===" # Проверка последнего бэкапа базы данных LAST_DB_BACKUP=$(find /var/backups/sfera/daily -name "sfera_backup_*.sql.gz" -mtime -1 | wc -l) if [ "$LAST_DB_BACKUP" -eq 0 ]; then alerts+=("No database backup in last 24 hours") status="ERROR" else echo "✓ Database backup: Recent backup found" fi # Проверка размера бэкапов BACKUP_SIZE=$(du -sh /var/backups/sfera | cut -f1) echo "✓ Total backup size: $BACKUP_SIZE" # Проверка свободного места FREE_SPACE=$(df /var/backups/sfera | awk 'NR==2 {print $4}') if [ "$FREE_SPACE" -lt 1048576 ]; then # Меньше 1GB alerts+=("Low disk space for backups: ${FREE_SPACE}KB") status="WARNING" else echo "✓ Disk space: Sufficient (${FREE_SPACE}KB available)" fi # Проверка облачной синхронизации CLOUD_SYNC_LOG="/var/backups/sfera/logs/cloud-sync.log" if [ -f "$CLOUD_SYNC_LOG" ]; then LAST_SYNC=$(grep "Successfully uploaded" "$CLOUD_SYNC_LOG" | tail -1 | grep -o '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}') if [ -n "$LAST_SYNC" ]; then echo "✓ Cloud sync: Last successful sync on $LAST_SYNC" else alerts+=("No successful cloud sync found") status="WARNING" fi fi # Проверка репликации if pg_isready -h localhost -p 5432; then REPL_LAG=$(sudo -u postgres psql -t -c "SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()));" 2>/dev/null) if [ -n "$REPL_LAG" ] && (( $(echo "$REPL_LAG < 300" | bc -l) )); then echo "✓ Replication: Lag ${REPL_LAG}s (acceptable)" elif [ -n "$REPL_LAG" ]; then alerts+=("High replication lag: ${REPL_LAG}s") status="WARNING" fi fi # Отправка алертов при необходимости if [ ${#alerts[@]} -gt 0 ]; then echo "⚠ Alerts detected:" for alert in "${alerts[@]}"; do echo " - $alert" done # Отправка уведомления send_backup_alert "$status" "${alerts[*]}" fi echo "Overall backup status: $status" return $([ "$status" = "OK" ] && echo 0 || echo 1) } # Отправка алертов send_backup_alert() { local status="$1" local message="$2" # Slack уведомление if [ -n "$SLACK_WEBHOOK_URL" ]; then curl -X POST -H 'Content-type: application/json' \ --data "{\"text\":\"🔴 Backup Alert [$status]: $message\"}" \ "$SLACK_WEBHOOK_URL" fi # Email уведомление if command -v mail >/dev/null; then echo "Backup system alert: $message" | \ mail -s "SFERA Backup Alert [$status]" admin@company.com fi # Лог echo "$(date): ALERT [$status] $message" >> /var/log/sfera-backup-alerts.log } # Генерация отчета о бэкапах generate_backup_report() { local report_file="/var/backups/sfera/reports/backup_report_$(date +%Y%m%d).html" mkdir -p "$(dirname "$report_file")" cat > "$report_file" << EOF SFERA Backup Report - $(date +%Y-%m-%d)

SFERA Backup Report

Generated: $(date)

Database Backups

EOF # Добавление информации о бэкапах find /var/backups/sfera/daily -name "sfera_backup_*.sql.gz" -mtime -7 | sort -r | while read backup; do BACKUP_DATE=$(basename "$backup" | sed 's/sfera_backup_\(.*\)\.sql\.gz/\1/') BACKUP_SIZE=$(du -h "$backup" | cut -f1) STATUS="OK" if [ -f "${backup}.md5" ]; then if md5sum -c "${backup}.md5" >/dev/null 2>&1; then STATUS="OK" else STATUS="ERROR" fi else STATUS="WARNING" fi echo " " >> "$report_file" done cat >> "$report_file" << EOF
DateSizeStatus
$BACKUP_DATE$BACKUP_SIZE$STATUS

System Status

  • Total backup size: $(du -sh /var/backups/sfera | cut -f1)
  • Available disk space: $(df -h /var/backups/sfera | awk 'NR==2 {print $4}')
  • Database status: $(pg_isready -h localhost -p 5432 && echo "Running" || echo "Down")
EOF echo "Backup report generated: $report_file" } # Основная логика case "$1" in "check") check_backup_health ;; "report") generate_backup_report ;; *) echo "Usage: $0 {check|report}" exit 1 ;; esac ``` ## ⚙️ Автоматизация ### 1. Cron Jobs ```bash # /etc/cron.d/sfera-backup # Ежедневные бэкапы базы данных в 2:00 0 2 * * * root /opt/sfera/scripts/backup/daily-backup.sh # Синхронизация с облаком в 3:00 0 3 * * * root /opt/sfera/scripts/backup/cloud-sync.sh # Еженедельные бэкапы файлов в воскресенье в 1:00 0 1 * * 0 root /opt/sfera/scripts/backup/files-backup.sh # Проверка состояния бэкапов каждые 6 часов 0 */6 * * * root /opt/sfera/scripts/monitoring/backup-monitor.sh check # Ежемесячный отчет в первый день месяца 0 8 1 * * root /opt/sfera/scripts/monitoring/backup-monitor.sh report # Проверка статуса репликации каждые 5 минут */5 * * * * root /opt/sfera/scripts/replication/setup-streaming.sh status > /dev/null # Очистка старых логов еженедельно 0 4 * * 1 root find /var/backups/sfera/logs -name "*.log" -mtime +30 -delete ``` ## 🎯 Recovery Time Objective (RTO) и Recovery Point Objective (RPO) ### Целевые показатели - **RPO (Recovery Point Objective)**: 1 час - Максимальная потеря данных при сбое - Обеспечивается частыми WAL архивами - **RTO (Recovery Time Objective)**: 4 часа - Максимальное время восстановления - Включает время на диагностику и восстановление ### Сценарии восстановления | Сценарий | RPO | RTO | Процедура | | ------------------- | ------- | -------- | ------------------------------- | | Сбой диска БД | 5 минут | 30 минут | Failover на реплику | | Повреждение БД | 1 час | 2 часа | PITR восстановление | | Полный сбой сервера | 1 час | 4 часа | Восстановление на новом сервере | | Логическая ошибка | 1 час | 1 час | PITR до точки до ошибки | | Сбой ЦОД | 1 час | 6 часов | Восстановление в резервном ЦОД | ## 🎯 Заключение Система резервного копирования и восстановления SFERA обеспечивает: 1. **Надежность**: Множественные копии данных в разных местах 2. **Быстрое восстановление**: Автоматизированные процедуры 3. **Мониторинг**: Постоянный контроль состояния бэкапов 4. **Соответствие SLA**: Достижение целевых RPO и RTO 5. **Автоматизация**: Минимальное участие человека в рутинных операциях Регулярно тестируйте процедуры восстановления и обновляйте документацию для обеспечения готовности к любым сценариям сбоев.