AOF Persistence in Detail: fsync Strategies Compared
AI generated
SET
TTL
Redis · Persistence · AOF · fsync
AOF Persistence in Detail
fsync Strategies Compared

AOF persistence logs every write operation as a command in an append-only file, giving Redis a much tighter durability guarantee than plain RDB snapshots. Choosing the appendfsync strategy among always, everysec, and no directly decides how many milliseconds of latency get traded for how many seconds of potential data loss.

15 min read appendonly · appendfsync · AOF rewrite · durability Redis 6.x · 7.x

1. What Sets AOF Persistence Apart From RDB

AOF persistence, short for append-only file, takes a fundamentally different approach than RDB snapshots: instead of periodically saving the entire dataset, AOF logs every single write operation as a command in a continuously growing file. A SET key value is appended to the end of the AOF file exactly as that command, and so is an LPUSH. On restart, Redis replays these commands in the same order and reconstructs the exact final state.

The central advantage of AOF persistence lies in the granularity of the durability guarantee: while RDB snapshots can leave a window of minutes open, AOF can shrink the loss window to one second or even zero, depending on the chosen fsync strategy. The price is a larger file size compared to a compact RDB snapshot and a slower restart with very long command histories, unless a recent rewrite has already happened.

In practice, AOF persistence is mostly used where Redis serves not just as a cache but as a primary data source, for example for queues, counters, session stores with strict requirements, or rate-limiting state, where losing seconds of write operations would matter for the business. Combining both mechanisms, AOF and RDB together, is covered head-to-head in the next article in this series.

2. Enabling AOF: appendonly and the Basic Configuration

AOF persistence is enabled via the appendonly yes directive in redis.conf, disabled by default. Once enabled, Redis writes all write commands in addition to the existing RDB mechanisms into the AOF directory, configured via appenddirname, usually a subfolder called appendonlydir relative to the main dir. Since Redis 7, this directory consists of multiple files rather than a single monolithic AOF file, covered in more detail in the file format section.

It is important that enabling AOF at runtime via CONFIG SET appendonly yes immediately triggers an initial AOF rewrite that writes the current dataset as a base file before new commands get appended. This activation should never happen under full load without prior capacity planning, because the initial rewrite uses the same fork-based mechanism as BGSAVE and correspondingly needs copy-on-write memory.


# redis.conf - Basic AOF configuration

# Enable append-only file persistence
appendonly yes

# Directory for AOF files (relative to "dir")
appenddirname "appendonlydir"

# Base filename prefix for AOF manifest and files
appendfilename "appendonly.aof"

# fsync strategy (see next section)
appendfsync everysec

3. appendfsync in Detail: always, everysec, no

The appendfsync directive is the most important lever in AOF persistence, because it defines exactly when Redis forces the operating system buffer of the AOF file physically onto storage via fsync(). A write() system call alone does not guarantee persistence yet: the data first lands in the kernel page cache and could be lost in a power outage before the kernel writes it to disk on its own. fsync() forces exactly that physical write.

With appendfsync always, Redis calls fsync() after every single write command. That delivers the strongest durability guarantee, practically no data loss on a crash, but costs massive latency because every write operation waits on the slowest part of the system: the physical storage device. On spinning disks that can limit throughput to a few hundred operations per second, and even on fast NVMe SSDs a noticeable latency overhead in the low millisecond range remains per write.

With appendfsync everysec, the recommended default, a separate background thread performs fsync() at most once per second. That bounds potential data loss on a crash to one second of write operations, while latency for the client remains practically unaffected, because write() itself is fast and the expensive fsync() call runs asynchronously in the background. With appendfsync no, Redis leaves the timing of the physical write entirely to the operating system, which delivers the best performance but also the largest loss risk, typically 30 seconds or more of data, depending on kernel dirty-page settings.


# redis.conf - appendfsync strategies compared

# Strongest durability: fsync after every write command
# Slowest option, use only when zero data loss is mandatory
appendfsync always

# Recommended default: fsync at most once per second
# Bounded loss window of ~1 second, minimal latency impact
appendfsync everysec

# No explicit fsync by Redis, kernel decides when to flush
# Fastest, largest loss window (often 30s+), rarely recommended
appendfsync no

4. The AOF File Format: Manifest, Base, and Incremental Files

Since Redis 7 the AOF file format was fundamentally reworked and no longer consists of a single growing file, but of several components inside the appendonlydir directory. A manifest file, usually appendonly.aof.manifest, lists all associated files in the correct order: a base file with a .base.rdb or .base.aof suffix that holds the state at the time of the last rewrite in RDB or AOF format, plus one or more incremental files with a .incr.aof suffix that hold all commands executed since then.

This multi-part format solves a practical problem of the old single-file architecture: a rewrite used to have to rewrite the entire file while simultaneously buffering new commands, which caused memory pressure on very large datasets. With the new format, a rewrite simply writes a new base file and starts a new, empty incremental file, while the old incremental file is only deleted after successful completion. That substantially reduces the risk of inconsistent state on a crash during a rewrite.


# Inspect the AOF directory structure (Redis 7+ multi-part format)
ls -la /var/lib/redis/appendonlydir/
# appendonly.aof.1.base.rdb     <- base snapshot from last rewrite
# appendonly.aof.1.incr.aof     <- incremental commands since rewrite
# appendonly.aof.manifest       <- ordered list of active files

cat /var/lib/redis/appendonlydir/appendonly.aof.manifest
# file appendonly.aof.1.base.rdb seq 1 type b
# file appendonly.aof.1.incr.aof seq 1 type i

5. The AOF Rewrite Process in Detail

Without a rewrite, an AOF file would grow indefinitely, even if the same key gets overwritten hundreds of times, because every single command is logged. The BGREWRITEAOF process solves this problem by, analogous to BGSAVE, forking a child process via fork() that writes the current, compact dataset as a new base file instead of preserving the entire command history. A hash overwritten ten times appears in the new base file only with its final value, not as ten separate commands.

While the child process writes the new base file, the parent process keeps buffering incoming write commands into a new incremental file. After the child process finishes the rewrite, Redis atomically adopts the new base file together with the incremental file collected during the rewrite and updates the manifest file accordingly. The old base and incremental files are only deleted afterward, which ensures that a consistent, loadable state always exists even on a crash during the rewrite.

As with BGSAVE, the same applies to BGREWRITEAOF: the fork itself briefly costs CPU time for duplicating the page table, and copy-on-write increases memory demand proportionally to write load during the rewrite. A manual call via redis-cli BGREWRITEAOF is possible at any time, for example after a known phase of intense write load, to proactively reduce AOF size instead of waiting for the automatic trigger.

appendfsync Max. data loss Latency overhead Recommendation
always ~0 (practically none) High, every write waits on disk Only for mandatory zero-loss requirements
everysec Up to 1 second Minimal, fsync in background Recommended default for most setups
no 30s+ (kernel dependent) Very low Only when performance clearly outweighs durability

6. Configuring and Controlling Rewrite Triggers

Redis triggers an automatic AOF rewrite based on two configurable thresholds: auto-aof-rewrite-percentage defines by how many percent the AOF size must have grown since the last rewrite, 100 percent by default, meaning a doubling. auto-aof-rewrite-min-size prevents unnecessarily frequent rewrites on very small AOF files, 64 megabytes as the lower bound by default. Both conditions must be true before Redis automatically calls BGREWRITEAOF.

These thresholds are a direct tradeoff between file size and rewrite frequency: a low percentage keeps the AOF file compact but causes more frequent fork operations with corresponding CPU and memory overhead. A high percentage reduces rewrite frequency but lets the file grow more in the meantime, which increases both disk space usage and load time on restart, unless a recent rewrite happened right before.


# redis.conf - AOF rewrite trigger thresholds

# Trigger a rewrite once the AOF has grown 100% since the last rewrite
auto-aof-rewrite-percentage 100

# But never rewrite below this absolute size (avoids rewrite storms
# on small, freshly started instances)
auto-aof-rewrite-min-size 64mb

# Prevent BGSAVE and BGREWRITEAOF from running simultaneously
# (both fork; running together doubles COW pressure)
no-appendfsync-on-rewrite no

7. Performance Impact of fsync Strategies

The choice of fsync strategy affects not just the latency of individual write operations, but also overall throughput under load. With appendfsync always, every single write command is effectively serialized through a physical disk write, which on classic hard disks means a few hundred operations per second, and even on fast NVMe drives noticeably reduces throughput compared to everysec, because every write must wait for the previous fsync() to complete.

An often overlooked parameter is no-appendfsync-on-rewrite. Set to no by default, Redis continues to perform fsync calls normally even during a running AOF rewrite. On systems with slow I/O this can cause increased latency during a rewrite, because the rewrite child process and the regular fsync calls compete for the same I/O bandwidth. Setting this parameter to yes pauses fsync calls completely during the rewrite, which in the worst case raises the loss risk to the duration of the entire rewrite, but in exchange avoids latency spikes during the rewrite.

In practice, most production Redis setups achieve an optimal balance between durability and throughput with everysec, while always is justified only for very specific compliance or financial use cases with an explicit zero-loss requirement, where the latency cost is knowingly accepted.

8. Checking and Repairing AOF Files

Redis ships redis-check-aof, a dedicated tool for checking AOF files for consistency, especially after a hard crash where the last write operation may have been written incompletely to disk. A truncated last command at the end of the file is a known and tolerable scenario with AOF: Redis detects such a truncation issue on startup and, as long as aof-load-truncated yes is set, can fix it automatically by discarding the incomplete last line.

For deeper repairs, run redis-check-aof --fix on the affected incremental file. The tool reads the file sequentially, validates each command against the RESP protocol format, and truncates the file at the last fully valid command. Important: always make a copy of the original file before any --fix call, because the repair is destructive and in the worst case discards more data than was actually damaged.


#!/usr/bin/env bash
# check_aof_integrity.sh - Validate AOF files before a risky restart
set -euo pipefail

AOF_DIR="/var/lib/redis/appendonlydir"
BACKUP_DIR="/var/backups/redis/aof-precheck-$(date +%Y%m%d-%H%M%S)"

mkdir -p "$BACKUP_DIR"
cp -a "$AOF_DIR"/. "$BACKUP_DIR/"

for incr_file in "$AOF_DIR"/*.incr.aof; do
  echo "Checking: $incr_file"
  if ! redis-check-aof "$incr_file"; then
    echo "[WARN] Issues found in $incr_file, backup preserved at $BACKUP_DIR" >&2
  fi
done

echo "[OK] AOF integrity check complete, backup at $BACKUP_DIR"

9. Common Mistakes With AOF Persistence

A common mistake is using appendfsync always in environments with slow storage without measuring the throughput loss beforehand. On network storage with high fsync latency, this setting can reduce effective write throughput by an order of magnitude, which frequently goes unnoticed in load tests, because those usually test smaller data volumes and lower concurrency than production.

A second mistake is letting BGSAVE and BGREWRITEAOF run at the same time without accounting for no-appendfsync-on-rewrite. Both operations fork the process and create copy-on-write pressure, so the combined memory overhead when they run concurrently is noticeably higher than when each runs separately. Redis tries by default to avoid overlapping rewrites, but manually triggered backups via BGSAVE running alongside an automatic AOF rewrite can still overlap.

A third, subtler mistake is assuming that AOF persistence automatically protects against data corruption from application bugs. AOF logs exactly the commands the application sends, including faulty delete or overwrite operations. An accidental FLUSHALL is persisted just as reliably and replayed on the next restart like any other command. AOF therefore does not replace a separate backup strategy with point-in-time recovery.

Mironsoft

Redis operations, persistence strategy, and backup infrastructure

The right fsync strategy for your Redis setup?

We analyze your write load, measure the actual latency impact of appendfsync options, and configure AOF rewrite triggers that match your data volume and availability requirements.

Durability Analysis

Weigh appendfsync strategies against your actual loss tolerance

Rewrite Tuning

Tune auto-aof-rewrite-percentage and min-size to your data volume

Incident Readiness

Establish redis-check-aof processes and recovery runbooks

10. Summary

AOF persistence logs every write operation as a command and therefore allows a much tighter loss window than plain RDB snapshots. Choosing the appendfsync strategy is the central decision: always for maximum durability with noticeable latency overhead, everysec as the recommended compromise with one second of potential loss, no for maximum performance with greater risk. The AOF rewrite process keeps file size under control via BGREWRITEAOF, controlled by auto-aof-rewrite-percentage and auto-aof-rewrite-min-size.

The multi-part file format since Redis 7, with manifest, base, and incremental files, makes rewrites more robust against crashes than the old single-file format. redis-check-aof remains the central tool for diagnosis and repair after a hard crash. It stays important that AOF persistence protects against technical data loss, not against logical application errors like an accidental FLUSHALL, for which a separate backup strategy is still needed.

AOF Persistence in Detail: the Essentials at a Glance

fsync Strategies

always for zero loss, everysec as the default, no only with a clear performance priority.

AOF Rewrite

BGREWRITEAOF compacts the command history, controlled by percentage and min-size triggers.

File Format

Manifest, base file, and incremental file since Redis 7, more robust against crashes during rewrite.

Repair

redis-check-aof --fix after a hard crash, always make a copy of the original file first.

11. FAQ: AOF Persistence in Detail

1AOF vs. RDB: what is the difference?
AOF logs every command with a small loss window. RDB periodically saves the entire dataset with a larger loss window.
2Which appendfsync setting should I use?
everysec is the best compromise between loss window and latency for most setups.
3Why is appendfsync always so slow?
Every write waits on a physical fsync() to disk before it is confirmed.
4What does BGREWRITEAOF do?
Compacts the AOF history via fork() into a new, minimal base file.
5When does Redis trigger a rewrite automatically?
When auto-aof-rewrite-percentage AND auto-aof-rewrite-min-size are both exceeded.
6What is the AOF manifest?
Lists base and incremental files in correct load order, since Redis 7.
7How do I repair a corrupted AOF file?
With redis-check-aof --fix, always after copying the original file first.
8What does aof-load-truncated do?
Automatically discards a truncated last command on startup instead of refusing to start.
9Does AOF protect against FLUSHALL?
No, FLUSHALL is persisted reliably and replayed. Separate backups are needed for that.
10Can BGSAVE and BGREWRITEAOF run at the same time?
Technically yes, but both fork and increase COW memory pressure together.