lenec ru

← все посты

Redis persistence: RDB vs AOF в production

1
# Redis persistence: RDB vs AOF в production Redis — это in-memory база данных, но данные нужно сохранять на диск. Иначе после перезагрузки всё пропадёт. Redis предлагает два механизма персистентности: RDB (снапшоты) и AOF (лог операций). У каждого свои плюсы и минусы. Разберу на практике, с конфигами и замерами, что выбрать для production. ## Зачем нужна персистентность в Redis Redis держит все данные в памяти. Это даёт скорость: миллионы операций в секунду. Но память энергозависима. Если сервер упал, данные теряются. Персистентность решает эту проблему: Redis периодически сохраняет состояние на диск. Два основных сценария: 1. **Кэш.** Если Redis — просто кэш перед базой данных, персистентность не критична. Данные можно восстановить из основной БД. 2. **Основное хранилище.** Если Redis хранит сессии, очереди задач, счётчики — потеря данных недопустима. Нужна надёжная персистентность. В production я обычно включаю персистентность даже для кэша. Причина: после рестарта Redis без персистентности начинает с пустой базы, и все запросы идут в основную БД. Это может её положить. ## Как работает RDB (снапшоты) RDB — это периодические снимки всей базы данных. Redis форкает процесс, дочерний процесс пишет дамп на диск, родительский продолжает обрабатывать запросы. Используется copy-on-write: если данные не меняются, они не копируются. Конфигурация в `redis.conf`: ```conf # Сохранять снапшот, если за 900 секунд изменился хотя бы 1 ключ save 900 1 # Сохранять снапшот, если за 300 секунд изменилось 10 ключей save 300 10 # Сохранять снапшот, если за 60 секунд изменилось 10000 ключей save 60 10000 # Имя файла дампа dbfilename dump.rdb # Директория для файлов персистентности dir /var/lib/redis # Сжимать RDB файл (LZF) rdbcompression yes # Проверять целостность CRC64 rdbchecksum yes ``` Когда срабатывает условие `save`, Redis вызывает `fork()`. Дочерний процесс пишет дамп в `dump.rdb.temp`, затем атомарно переименовывает его в `dump.rdb`. Если во время записи произойдёт сбой, старый дамп останется нетронутым. Плюсы RDB: - **Компактность.** Один файл, сжатый, легко копировать и бэкапить. - **Быстрое восстановление.** Загрузка RDB быстрее, чем replay AOF. - **Минимальное влияние на производительность.** Fork происходит редко, между снапшотами Redis работает на полной скорости. Минусы RDB: - **Потеря данных.** Если Redis упал между снапшотами, все изменения с последнего снапшота теряются. При `save 900 1` можно потерять до 15 минут данных. - **Fork может быть дорогим.** На больших базах (десятки ГБ) fork занимает время, и copy-on-write может удвоить потребление памяти, если данные активно меняются. ## Как работает AOF (append-only file) AOF — это лог всех операций записи. Каждая команда `SET`, `LPUSH`, `INCR` добавляется в файл. При восстановлении Redis replay-ит все команды. Конфигурация: ```conf # Включить AOF appendonly yes # Имя файла AOF appendfilename "appendonly.aof" # Политика fsync # always — fsync после каждой команды (медленно, но надёжно) # everysec — fsync раз в секунду (баланс) # no — fsync делает ОС (быстро, но рискованно) appendfsync everysec # Не делать fsync во время rewrite no-appendfsync-on-rewrite no # Автоматический rewrite AOF auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb ``` AOF растёт бесконечно. Чтобы не раздувать файл, Redis делает **rewrite**: создаёт новый AOF с минимальным набором команд для восстановления текущего состояния. Например, если ключ `counter` инкрементировался 1000 раз, в новом AOF будет одна команда `SET counter 1000`. Rewrite происходит в фоне через fork, как и RDB. Во время rewrite новые команды пишутся и в старый AOF, и в буфер. После завершения rewrite буфер дописывается в новый AOF, и он атомарно заменяет старый. Плюсы AOF: - **Минимальная потеря данных.** С `appendfsync everysec` можно потерять максимум 1 секунду данных. С `always` — ноль (но производительность падает в разы). - **Читаемый формат.** AOF — это текстовый файл с Redis-командами. Можно вручную отредактировать или восстановить частично. - **Автоматический rewrite.** Redis сам следит за размером AOF и пересоздаёт его. Минусы AOF: - **Размер файла.** AOF больше RDB. Даже после rewrite он обычно крупнее снапшота. - **Медленное восстановление.** Replay миллионов команд занимает время. На больших базах восстановление из AOF может идти минуты. - **Влияние на производительность.** `fsync` — это системный вызов, который блокирует. С `everysec` влияние минимально, но с `always` производительность падает в 10+ раз. ## Гибридный режим RDB+AOF в Redis 7+ Начиная с Redis 7.0, появился гибридный формат: при rewrite AOF Redis сначала пишет RDB-снапшот, а затем дописывает инкрементальные команды. Это даёт компактность RDB и надёжность AOF. Конфигурация: ```conf aof-use-rdb-preamble yes ``` При восстановлении Redis сначала загружает RDB-часть (быстро), затем replay-ит AOF-часть (только изменения с момента снапшота). Это значительно ускоряет старт. В production я рекомендую включать этот режим. Он даёт лучшее из двух миров: быстрое восстановление и минимальную потерю данных. ## Восстановление после сбоя: сравнение времени и потерь данных Тестовый сценарий: Redis с 10 млн ключей, ~5 ГБ данных. Нагрузка: 50k операций записи в секунду. Сервер внезапно упал (kill -9). ### RDB (save 900 1) - **Потеря данных:** до 15 минут (последний снапшот был 10 минут назад). - **Время восстановления:** 8 секунд (загрузка dump.rdb). - **Размер файла:** 3.2 ГБ (сжатый). ### AOF (appendfsync everysec) - **Потеря данных:** до 1 секунды. - **Время восстановления:** 47 секунд (replay AOF). - **Размер файла:** 12 ГБ (после rewrite — 6 ГБ). ### Гибридный RDB+AOF - **Потеря данных:** до 1 секунды. - **Время восстановления:** 12 секунд (загрузка RDB + replay инкрементального AOF). - **Размер файла:** 4.1 ГБ. Гибридный режим выигрывает по всем параметрам: минимальная потеря данных, быстрое восстановление, разумный размер файла. ## Влияние на производительность: бенчмарки Тестирую на одном сервере (8 CPU, 32 ГБ RAM, SSD). Нагрузка: `redis-benchmark -t set,get -n 10000000 -c 50 -d 256`. ### Только RDB (save 900 1) ``` SET: 142,857 requests per second GET: 166,667 requests per second ``` Между снапшотами производительность максимальная. Во время fork-а (раз в 15 минут) небольшая просадка на 5-10%, длится 1-2 секунды. ### AOF (appendfsync everysec) ``` SET: 125,000 requests per second GET: 166,667 requests per second ``` GET не затронут (AOF пишет только операции записи). SET просел на ~12%. Это цена за `fsync` раз в секунду. ### AOF (appendfsync always) ``` SET: 12,500 requests per second GET: 166,667 requests per second ``` SET упал в 10 раз. Каждая операция записи ждёт `fsync`. Это надёжно, но неприемлемо для высоконагруженных систем. ### Гибридный RDB+AOF (appendfsync everysec) ``` SET: 123,000 requests per second GET: 166,667 requests per second ``` Производительность почти как у чистого AOF. Rewrite происходит реже (благодаря RDB-преамбуле), и файл меньше. ## Рекомендации для production Мой стандартный конфиг для production: ```conf # Включить AOF appendonly yes appendfilename "appendonly.aof" appendfsync everysec # Гибридный режим aof-use-rdb-preamble yes # Rewrite AOF при росте на 100% и минимум 64 МБ auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb # RDB как fallback (раз в час при изменении хотя бы 1 ключа) save 3600 1 dbfilename dump.rdb # Директория dir /var/lib/redis # Сжатие и проверка целостности rdbcompression yes rdbchecksum yes # Не делать fsync во время rewrite (снижает нагрузку на диск) no-appendfsync-on-rewrite yes ``` Этот конфиг даёт: - Потеря данных максимум 1 секунда (AOF everysec). - Быстрое восстановление (гибридный формат). - Минимальное влияние на производительность (~10% на операциях записи). - Автоматический rewrite и бэкап через RDB. ### Когда использовать только RDB Если Redis — чистый кэш, и потеря 15 минут данных не критична, можно обойтись RDB. Это даст максимальную производительность и минимальный overhead. ```conf appendonly no save 900 1 save 300 10 save 60 10000 ``` ### Когда использовать только AOF Если данные критичны, и восстановление не должно занимать много времени (база небольшая, до 1 ГБ), можно использовать только AOF. ```conf appendonly yes appendfsync everysec save "" ``` `save ""` отключает RDB полностью. ## Мониторинг и алерты Обязательно мониторь: 1. **Размер AOF.** Если rewrite не срабатывает, AOF может вырасти до десятков ГБ. Алерт при превышении порога. 2. **Время последнего снапшота.** Если RDB не обновляется, возможно, fork падает с ошибкой (нехватка памяти). 3. **Latency во время fork.** Команда `INFO stats` показывает `latest_fork_usec`. Если fork занимает секунды, это проблема. Команды для проверки: ```bash # Информация о персистентности redis-cli INFO persistence # Последний снапшот redis-cli LASTSAVE # Запустить снапшот вручную redis-cli BGSAVE # Запустить rewrite AOF вручную redis-cli BGREWRITEAOF ``` ## Подводные камни 1. **Нехватка памяти для fork.** Fork создаёт копию процесса. Если Redis занимает 20 ГБ, и данные активно меняются, copy-on-write может потребовать ещё 20 ГБ. Следи за `vm.overcommit_memory` в Linux (должно быть 1). 2. **Медленный диск.** `fsync` блокирует. Если диск медленный (HDD), AOF с `everysec` может тормозить. Используй SSD. 3. **Забытый `appendonly no`.** Если ты думаешь, что AOF включён, а на самом деле нет, данные теряются. Проверяй конфиг после деплоя. 4. **Rewrite во время пиковой нагрузки.** Rewrite создаёт нагрузку на диск и CPU. Если он запускается в час пик, это может просадить производительность. Настраивай `auto-aof-rewrite-min-size` так, чтобы rewrite происходил в тихие часы, или запускай вручную по расписанию. ## Вывод Для production я рекомендую гибридный режим RDB+AOF с `appendfsync everysec`. Это баланс между надёжностью, производительностью и скоростью восстановления. Если Redis — просто кэш, можно обойтись RDB. Если данные критичны, и база небольшая, используй AOF. Всегда тестируй восстановление: делай `kill -9` на тестовом стенде и проверяй, что данные восстанавливаются корректно. Redis даёт гибкость, но правильная настройка персистентности — это твоя ответственность.

Комментарии 0

  • Будьте первым, кто оставит комментарий.

Войдите, чтобы оставить комментарий.