AOF — журнал команд
Предпосылки: RDB, файловые системы и fsync.
← RDB | Внутренние кодировки →
Запись каждой команды
RDB сохраняет снимки с интервалом в минуты — всё, что произошло между снимками, при падении теряется. AOF (Append Only File) сужает это окно: он записывает каждую команду записи в конец лог-файла. При перезапуске Redis «проигрывает» лог от начала до конца, восстанавливая состояние.
Подход напоминает журнал упреждающей записи (WAL в PostgreSQL), но с важным отличием: Redis пишет в AOF после выполнения команды, а не до. Если Redis упал между выполнением команды и записью в лог — команда выполнена в памяти, но в AOF не попала. При перезапуске эта команда будет потеряна. Именно поэтому даже appendfsync always не даёт абсолютной гарантии — окно в одну команду остаётся.
Три режима fsync
write() помещает данные в page cache, а fsync() сбрасывает их на диск (fsync). Redis предоставляет три режима, определяющих, как часто вызывается fsync.
appendfsync always вызывает fsync после каждой записи. Наименьшее окно потери среди трёх режимов: при падении теряется максимум одна команда (та, что выполнилась в памяти, но не успела попасть в лог — см. выше). Минимальная производительность: каждая команда ждёт завершения дискового I/O.
appendfsync everysec (по умолчанию) вызывает fsync раз в секунду. При падении теряется не более секунды данных. Фоновый поток выполняет fsync, основной поток не блокируется — для большинства приложений это оптимальный компромисс.
appendfsync no означает, что Redis не вызывает fsync явно, полагаясь на ОС (Linux по умолчанию сбрасывает dirty pages каждые ~30 секунд). Максимальная производительность, но при сбое можно потерять данные за десятки секунд.
Рост файла и AOF rewrite
Режим fsync определяет, как часто данные попадают на диск. Но каждая команда записи добавляет строку в файл, и он растёт неограниченно. AOF растёт с каждой командой. Тысяча INCR counter превращается в тысячу строк, хотя текущее состояние — одно число. AOF rewrite создаёт новый файл, содержащий минимальный набор команд для восстановления текущего состояния. Вместо тысячи INCR — один SET counter 1000.
Rewrite запускается автоматически, когда файл вырос в auto-aof-rewrite-percentage раз от базового размера (по умолчанию 100%), или вручную командой BGREWRITEAOF. Как и BGSAVE, rewrite выполняется дочерним процессом через fork() с copy-on-write.
Пока дочерний процесс пишет новый файл, родительский продолжает принимать команды. Новые команды дописываются и в старый AOF (чтобы не потерять данные при сбое), и в специальный буфер. После завершения rewrite буфер дописывается в новый файл, и новый файл атомарно заменяет старый.
Начиная с Redis 7.0 AOF хранится как набор файлов (multi-part AOF): базовый файл + инкрементальные файлы. Это упрощает rewrite и уменьшает риск потери данных при сбое во время перезаписи.
Гибрид: RDB + AOF (Redis 4.0+)
AOF rewrite сжимает лог, но загрузка через «проигрывание» команд всё равно медленнее, чем десериализация бинарного RDB. Гибридный формат объединяет оба подхода: при rewrite Redis записывает RDB-снимок в начало нового AOF-файла, а после него — только команды, поступившие во время rewrite. При загрузке Redis быстро десериализует RDB-часть и затем «проигрывает» хвост из команд. Быстрая загрузка от RDB, минимальное окно потери от AOF. Включается директивой aof-use-rdb-preamble yes (по умолчанию включено).
Конфигурация на практике
Для большинства сценариев, где потеря данных нежелательна:
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes
save 900 1 -- RDB как дополнительный бэкапПри загрузке Redis использует AOF (точнее). RDB остаётся для бэкапов и клонирования.
Для чистого кеша, где потеря данных допустима, можно отключить оба механизма (appendonly no, save ""). Redis работает быстрее без дискового I/O.
Если AOF-файл повреждён (например, из-за сбоя файловой системы), утилита redis-check-aof --fix обрезает файл до последней корректной записи. Параметр aof-load-truncated yes (по умолчанию) позволяет Redis при загрузке игнорировать обрезанный хвост AOF вместо отказа стартовать.
Персистентность — на весь инстанс
Все описанные настройки (AOF, RDB, гибридный формат) применяются ко всем ключам в базе. Redis не позволяет настроить персистентность для отдельных ключей. Если одни данные требуют AOF, а другие нет — запускают несколько инстансов Redis с разными настройками.
Sources
- Redis Documentation: Persistence — AOF. https://redis.io/docs/management/persistence/
- Redis source:
src/aof.c
← RDB | Внутренние кодировки →