English translation is not available yet. Showing Russian content.

Настроить Redis с persistent storage (AOF + RDB)

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить Redis с persistent storage (AOF + RDB)

1. Цель задачи

Научиться конфигурировать Redis для надёжного хранения данных на диске с использованием комбинации механизмов RDB (snapshot) и AOF (append-only file). Освоить настройку параметров персистентности, провести тестирование восстановления после симулированного краша и добиться потери данных не более 1 секунды. В результате будет создана конфигурация Redis, готовая к промышленной эксплуатации с гарантированной долговечностью данных.

Ключевой результат Рабочий Redis-инстанс с включёнными AOF (everysec) и RDB (каждые 5 минут, если есть хотя бы 1 изменение), настроенный и протестированный на восстановление после убийства процесса (kill -9). Максимальная потеря данных — менее 1 секунды.

2. Исходные данные

Что нужноОткуда взять
Redis (6.x или новее)Установить через пакетный менеджер (apt, brew, choco) или официальный образ Docker redis:7
Клиент для Redisredis-cli (идёт в комплекте) или библиотека redis-py
Тестовые данныеСгенерировать скриптом: redis-benchmark или собственный Python-скрипт, вставляющий 100 000+ ключей
Тестовый скрипт для крашаBash-скрипт, который пишет данные, убивает процесс redis-server, затем перезапускает и проверяет количество потерянных ключей
Логи Redis/var/log/redis/redis-server.log (зависит от ОС)
Инструмент мониторинга (опционально)redis-cli INFO, redis-cli --stat

Если нет реального инстанса — симулируем локально:

  1. Установите Docker Desktop или Podman.
  2. Запустите контейнер: docker run --name redis-persist -d redis:7 redis-server --save "" --appendonly yes
  3. Выполняйте все операции внутри контейнера (используя docker exec -it redis-persist redis-cli).
  4. Для убийства процесса: docker kill redis-persist (или docker stop --time=0 для резкого останова).
  5. После перезапуска проверьте данные через новый контейнер, смонтировав volume для данных.

3. Технологический стек

КомпонентИнструментыНазначение
Сервер кэшированияRedis (7+)Хранение данных в памяти с персистентностью
ПерсистентностьRDB (dump.rdb), AOF (appendonly.aof)Сохранение данных на диск
Клиентredis-cli, Python redis-pyВзаимодействие с Redis, генерация нагрузки
ТестированиеBash-скрипты, redis-benchmark, kill -9Проверка восстановления после краша
Конфигурацияredis.confОпределение параметров AOF/RDB
Мониторингredis-cli INFO persistenceСостояние персистентности, размер AOF, время последнего RDB
Логирование/var/log/redis/redis.logАнализ загрузки AOF и RDB при старте

4. Этапы выполнения

Этап 1: Подготовка окружения и запуск Redis с базовой конфигурацией (30 минут)

Действия

  1. Установите Redis (локально или Docker):
    docker run --name redis-persist -p 6379:6379 -d redis:7 redis-server
  2. Подключитесь к инстансу через redis-cli и выполните PING — убедитесь, что работает.
  3. Создайте директорию для конфигурации: mkdir -p ~/redis-persist
  4. Скопируйте дефолтный конфиг из контейнера (или скачайте с GitHub): docker cp redis-persist:/usr/local/etc/redis/redis.conf ~/redis-persist/redis.conf
  5. Временно отключите персистентность: в redis.conf закомментируйте все строки save и установите appendonly no.
  6. Перезапустите контейнер с монтированием конфига и отдельного volume для данных:
    docker run --name redis-persist -v ~/redis-persist/redis.conf:/usr/local/etc/redis/redis.conf -v ~/redis-persist/data:/data -p 6379:6379 -d redis:7 redis-server /usr/local/etc/redis/redis.conf
    
  7. Убедитесь, что Redis работает без персистентности: redis-cli INFO persistence — все поля должны быть нулевыми.

Ожидаемый результат этапа Запущен Redis без персистентности, готовый к настройке RDB и AOF. Данные не сохраняются на диск.

Этап 2: Настройка RDB (snapshot) (45 минут)

Действия

  1. В файле redis.conf раскомментируйте строки сохранения:
    save 900 1
    save 300 10
    save 60 10000
    
    • save 900 1 — если изменился хотя бы 1 ключ за 15 минут, делаем snapshot.
    • save 300 10 — 10 изменений за 5 минут.
    • save 60 10000 — 10000 изменений за 1 минуту.
  2. Установите параметры RDB:
    dbfilename dump.rdb
    dir /data
    rdbcompression yes
    rdbchecksum yes
    
  3. Включите AOF параллельно? (Нет, пока оставляем appendonly no).
  4. Перезапустите контейнер (или выполните CONFIG REWRITE и CONFIG SET):
    docker restart redis-persist
    
  5. Проверьте, что RDB создаётся:
    • Запишите 10000 ключей: for i in $(seq 1 10000); do redis-cli SET "key:$i" "value:$i"; done
    • Подождите 60 секунд (условие save 60 10000).
    • Проверьте файл: docker exec redis-persist ls -la /data/dump.rdb.
    • Убедитесь через INFO persistence: rdb_last_save_time должен обновиться.
  6. Симулируйте мягкий краш: docker stop redis-persist (нормальное завершение — Redis вызовет SAVE перед выходом, если включена опция stop-writes-on-bgsave-error no). Затем запустите снова и проверьте, что данные восстановлены:
    docker start redis-persist
    redis-cli GET "key:1"  # должен вернуть "value:1"
    redis-cli DBSIZE       # близко к 10000
    

Ожидаемый результат этапа Redis работает с включённым RDB. После штатного останова данные восстанавливаются. Потеря данных при нештатном краше (kill -9) потенциально может достигать 15 минут (максимальное время между snapshot).

Этап 3: Включение AOF и настройка appendfsync everysec (45 минут)

Действия

  1. Отредактируйте redis.conf — включите AOF:
    appendonly yes
    appendfsync everysec
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 64mb
    
  2. Параметр appendfsync everysec обеспечивает синхронизацию AOF каждую секунду в фоновом потоке. Это даёт гарантию потери не более 1 секунды данных (или 0 при наличии always, но с большим снижением производительности).
  3. Оставьте RDB включённым (рекомендуется гибридный режим). Redis 7+ при aof-use-rdb-preamble yes (по умолчанию) будет начинать AOF с RDB-снапшота.
  4. Перезапустите Redis: docker restart redis-persist.
  5. Проверьте статус AOF:
    redis-cli INFO persistence
    # aof_enabled:1
    # aof_current_size: (должен расти после записи)
    
  6. Тест на потерю данных < 1 секунды:
    • Напишите уникальные ключи с высокой частотой в течение 5 минут (например, Python-скрипт, который каждые 10 мс вставляет новый ключ).
    • Зафиксируйте точное количество записанных ключей.
    • Выполните жёсткое убийство процесса: docker kill --signal=KILL redis-persist (эквивалент kill -9).
    • Перезапустите контейнер: docker start redis-persist.
    • Проверьте количество ключей: redis-cli DBSIZE. Разница между записанными и восстановленными — это потеря.
    • Потеря должна быть не более 1 секунды (т.е. количество записей, сделанных за 1 секунду на максимальной скорости). В реальности может быть 0 или 1-2 секунды из-за задержки записи на диск.

Ожидаемый результат этапа AOF работает в режиме everysec. После жёсткого краша потеря данных не превышает 1 секунды. RDB также используется для быстрого восстановления с помощью гибридного AOF.

Этап 4: Тестирование сценариев отказа и восстановления (60 минут)

Действия

  1. Сценарий A: kill -9 во время записи AOF

    • Выполните массовую запись (скриптом redis-benchmark).
    • Через 2 секунды после старта выполните kill -9Docker: docker kill --signal=KILL redis-persist).
    • Перезапустите и проверьте целостность AOF: Redis автоматически выполнит AOF rewrite при загрузке, если файл корректен. Проверьте лог на предмет Reading the remaining AOF.
    • Если AOF повреждён — Redis может использовать redis-check-aof для восстановления (входит в образ).
  2. Сценарий B: kill -9 во время RDB snapshot

    • Установите RDB условие save 5 1 (snapshot каждые 5 секунд, если есть изменения).
    • Запишите один ключ, подождите 3 секунды (до снятия snapshot), затем убейте процесс.
    • При старте Redis загрузит последний валидный RDB (возможно, с потерей данных, но AOF должен перекрыть).
    • Проверьте, что AOF был использован для восстановления.
  3. Сценарий C: Сбои при записи AOF (диск полный)

    • Имитируйте заполнение диска (можно создать файл-заглушку).
    • Наблюдайте поведение Redis: при ошибке записи AOF Redis по умолчанию переключается в режим abort (отключает запись). Проверьте логи.
    • Настройте no-appendfsync-on-rewrite no (по умолчанию) — во время перезаписи AOF fsync не выполняется, что безопасно.
  4. Сценарий D: Гибридный режим (AOF preamble)

    • Убедитесь, что aof-use-rdb-preamble yes включён.
    • Сгенерируйте большой объём данных (1 млн ключей).
    • Дождитесь автоматической перезаписи AOF (по достижении 64 MB или 100% роста).
    • Проверьте, что новый AOF начинается с RDB-заголовка: docker exec redis-persist head -c 100 /data/appendonly.aof | xxd.
    • Первые байты будут REDIS... (RDB).

Ожидаемый результат этапа Полное понимание поведения Redis при различных типах отказов. Конфигурация оптимизирована для минимальной потери данных.

Этап 5: Финальная настройка и документирование (30 минут)

Действия

  1. Установите финальные параметры в redis.conf:
    save 300 1
    save 60 100
    stop-writes-on-bgsave-error no
    rdbcompression yes
    rdbchecksum yes
    appendonly yes
    appendfsync everysec
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 64mb
    aof-load-truncated yes
    aof-use-rdb-preamble yes
    
  2. Настройте мониторинг персистентности:
    • В redis-cli INFO persistence регулярно смотрите aof_last_bgrewrite_status, rdb_last_bgsave_status.
    • Добавьте алерт в Prometheus/Grafana (если есть) на метрику redis_rdb_last_save_time (если snapshot не создавался > 1 часа — предупреждение).
  3. Напишите небольшой документ (README) с описанием конфигурации и процедурой восстановления (что делать при обнаружении повреждённого AOF).
  4. Зафиксируйте результаты тестов потери данных:
    • Средняя потеря при kill -9: X миллисекунд.
    • Максимальная зафиксированная: Y миллисекунд (должно быть < 1000 мс).
  5. Выгрузите последний исправный redis.conf и AOF-файл как артефакт.

Ожидаемый результат этапа Готовая конфигурация Redis с персистентностью и документация по эксплуатации.

5. Критерии приемки (Definition of Done)

  • Redis работает с включёнными AOF (appendfsync everysec) и RDB (snapshot каждые 5 минут при >= 1 изменении).
  • После kill -9 (жесткий краш) потеря данных не превышает 1 секунды (проверено минимум 3 раза).
  • После мягкого останова (SIGTERM) все данные восстанавливаются без потерь.
  • Повреждённый AOF автоматически восстанавливается (redis-check-aof) или Redis успешно его загружает, используя aof-load-truncated yes.
  • Гибридный AOF (с RDB преамбулой) включён и проверено, что файл начинается с магической строки "REDIS".
  • Настроен мониторинг (INFO persistence) и написана инструкция по восстановлению.
  • Все тестовые скрипты (kill, check) сохранены в репозитории.
  • Конфигурация redis.conf закоммичена в Git с комментариями.

6. Ожидаемый результат

Файлы/артефакты

  • redis.conf — финальная конфигурация с персистентностью.
  • test_persistence.sh — bash-скрипт для автоматизации краш-тестов (записывает данные, убивает процесс, перезапускает, сравнивает DBSIZE).
  • load_generator.py — Python-скрипт для высокочастотной записи (каждые 10 мс).
  • incident_report.md — отчёт о тестах: дата, количество записанных ключей, потеря, время восстановления.
  • docs/recovery_procedure.md — описание действий на production при сбое персистентности.

Содержание отчёта

  • Результаты каждого сценария (A-D) с графиками (опционально)
  • Измеренная потеря данных: avg = 0.2 сек, max = 0.7 сек
  • Конфигурационные параметры и rationale

Опционально

  • Docker Compose файл для быстрого развёртывания тестового окружения.
  • Правила оповещения для Prometheus (redis_up == 0, redis_rdb_last_save_time > 3600).

7. Возможные сложности и их решение

СложностьРешение
kill -9 может повредить AOF, Redis не стартуетИспользуйте aof-load-truncated yes для автоматического усечения последней неправильной записи. Если не помогает — запустите redis-check-aof --fix appendonly.aof перед стартом.
Потеря данных больше 1 секунды из-за задержки fsyncПроверьте настройки appendfsync: everysec гарантирует fsync раз в секунду, но если диск сильно занят, возможна задержка. Используйте always (но резкое падение производительности). В production ставьте no только если допустима потеря.
RDB snapshot блокирует запись во время bgsaveПараметр stop-writes-on-bgsave-error no предотвращает блокировку при ошибках. Убедитесь, что диск не переполнен.
Гибридный AOF не включается (старая версия Redis)Обновитесь до 6.2+ или используйте aof-use-rdb-preamble yes. Для Redis 5 гибридный режим недоступен, тогда только AOF.
Размер AOF растёт бесконтрольноВключите автоматическую перезапись: auto-aof-rewrite-percentage 100 и auto-aof-rewrite-min-size 64mb.
В Docker данные не сохраняются между перезапускамиВсегда монтируйте volume для /data и используйте docker stop/start, а не docker rm.

8. Бюджет времени (оценка)

ЭтапВремя
1. Подготовка окружения30 мин
2. Настройка RDB45 мин
3. Включение AOF и тест потери45 мин
4. Сценарии отказа и восстановления60 мин
5. Финальная настройка и документирование30 мин
Итого~3,5 часа

Примечание: При первом выполнении задачи может потребоваться до 5 часов, если возникают неожиданные проблемы с Docker или версией Redis. Рекомендуется работать в изолированном контейнере, чтобы не влиять на другие проекты.

9. Связанные вопросы из базы знаний

ВопросТема
12Что такое RDB и AOF в Redis? В чём отличия?
18Как работает appendfsync? Режимы always, everysec, no.
24Как восстановить повреждённый AOF? Команда redis-check-aof.
31Настройка гибридного персистентного режима (RDB + AOF).
45Мониторинг состояния персистентности Redis через INFO persistence.
52Параметры save для планирования RDB snapshot.
68Влияние AOF на производительность Redis.
73Стратегии бэкапа Redis для минимизации потери данных.
89Настройка Redis в Docker с постоянным хранением.
104Использование BGSAVE и BGREWRITEAOF вручную.

10. Чек-лист самопроверки

  • Я умею включать RDB и AOF через redis.conf и через команды CONFIG SET.
  • Я могу симулировать краш (kill -9) и перезапустить Redis с сохранением данных.
  • Я проверил, что после appendfsync everysec потеря данных не превышает 1 секунды.
  • Я настроил автоматическую перезапись AOF и убедился, что работает гибридный режим.
  • Я написал тестовый скрипт для измерения потери данных и задокументировал результаты.
  • Я понимаю разницу между мягким и жёстким крашем и знаю, как восстановить данные в каждом случае.
  • Я могу объяснить коллеге, почему выбран именно такой набор параметров персистентности.