# Стратегии резервного копирования и восстановления 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 <target_time> <restore_directory>"
    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 <master_host>"
            exit 1
        fi
        setup_slave "$2"
        ;;
    "status")
        check_replication_status
        ;;
    *)
        echo "Usage: $0 {master|slave <master_host>|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 <old_master_host>"
            exit 1
        fi
        perform_failback "$2"
        ;;
    *)
        echo "Usage: $0 {failover|switchover|failback <old_master_host>}"
        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 <backup_date> <restore_path>"
    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
<!DOCTYPE html>
<html>
<head>
    <title>SFERA Backup Report - $(date +%Y-%m-%d)</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        .status-ok { color: green; }
        .status-warning { color: orange; }
        .status-error { color: red; }
        table { border-collapse: collapse; width: 100%; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #f2f2f2; }
    </style>
</head>
<body>
    <h1>SFERA Backup Report</h1>
    <p>Generated: $(date)</p>

    <h2>Database Backups</h2>
    <table>
        <tr><th>Date</th><th>Size</th><th>Status</th></tr>
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 "        <tr><td>$BACKUP_DATE</td><td>$BACKUP_SIZE</td><td class=\"status-$(echo $STATUS | tr '[:upper:]' '[:lower:]')\">$STATUS</td></tr>" >> "$report_file"
    done

    cat >> "$report_file" << EOF
    </table>

    <h2>System Status</h2>
    <ul>
        <li>Total backup size: $(du -sh /var/backups/sfera | cut -f1)</li>
        <li>Available disk space: $(df -h /var/backups/sfera | awk 'NR==2 {print $4}')</li>
        <li>Database status: $(pg_isready -h localhost -p 5432 && echo "Running" || echo "Down")</li>
    </ul>
</body>
</html>
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. **Автоматизация**: Минимальное участие человека в рутинных операциях

Регулярно тестируйте процедуры восстановления и обновляйте документацию для обеспечения готовности к любым сценариям сбоев.
