Someone registers for your event. The application increments a counter in Redis, receives a successful reply, and confirms the registration. One second later, the machine loses power. Will that increment still be there when Redis starts again?

The answer depends on what Redis wrote to disk, when it wrote it, and which files it loads during recovery. Those three questions make RDB and AOF much easier to understand than memorizing “snapshot” and “log” as definitions.

This article uses Redis Open Source 7.x; the labs use Redis 7.4 with Docker. Redis 7 matters here because its AOF is split across multiple files. If keys and TTLs are new to you, start with the Redis fundamentals article. The production pitfalls article continues with cache consistency and failover.

1. First, Define What “Durable” Means for Your App

Not all failures have the same effect:

Failure What can happen Why it matters
Redis process exits but the machine stays up Redis RAM is gone; the OS may still have buffered writes Data already handed to the OS may eventually reach disk.
The machine loses power RAM and OS page cache may be lost write() and fsync() are different steps.
A disk or volume is lost Local persistence files are gone A file on the same disk is not an off-machine backup.
An operator runs DEL or FLUSHALL by mistake Valid delete commands can be persisted and replicated A replica is not a historical backup.

Two goals help turn “we need durability” into a decision:

  • RPO, Recovery Point Objective: how much acknowledged data can we afford to lose?
  • RTO, Recovery Time Objective: how long can the service take to recover?

A cache may tolerate losing everything, yet still need a fast recovery so the database is not overwhelmed by a cold start. A payment ledger may not tolerate losing even one confirmed transaction. The two workloads need different designs even if both currently use Redis.

An OK response is not a disk receipt

When SET returns OK, Redis has processed the command under its current configuration. With RDB, the latest snapshot may predate that command. With AOF using appendfsync everysec, the change may not yet have been synchronized to the storage device. Do not read OK as “this survives an immediate power failure.” Redis persistence documentation.

flowchart LR
    C[Client: SET k v] --> M[Redis changes data in RAM]
    M -->|RDB| S[Snapshot at a point in time]
    M -->|AOF| B[AOF buffer]
    B --> W[write to OS page cache]
    W --> F[fsync to storage device]

The diagram simplifies some implementation details, but the timing is the important part: a command can be processed before its bytes have reached durable storage. The appendfsync setting changes how wide that gap can be.

2. RDB: A Photograph of the Dataset

When Redis makes a snapshot

RDB is a binary snapshot of the Redis dataset at a point in time. You can request one with BGSAVE, or configure a rule such as save 60 1000. That rule allows a snapshot after at least 60 seconds and at least 1,000 changes. It is a trigger threshold, not a promise that a new file appears every 60 seconds.

Redis also has SAVE, but it blocks command processing while writing the snapshot. For a running application, BGSAVE is generally the appropriate command to discuss. Redis persistence, BGSAVE.

1
2
3
4
5
6
save 60 1000

# In redis-cli:
BGSAVE
INFO persistence
LASTSAVE

One easy mistake is treating a BGSAVE reply as proof that the file is complete. The reply says Redis accepted the request. BGSAVE SCHEDULE can even defer the work when an AOF rewrite is in progress. Check rdb_bgsave_in_progress, rdb_last_bgsave_status, and whether LASTSAVE changed before relying on the new snapshot. BGSAVE, INFO, LASTSAVE.

How fork and copy-on-write keep the picture stable

When BGSAVE starts, Redis creates a child process using fork(). The child sees the dataset as it existed at that instant and writes the RDB file. The parent continues serving the application.

Initially the two processes share physical memory pages. When the parent changes a page, the operating system copies that page so the child can keep seeing the old contents. This is copy-on-write, or COW: a page is copied when a write makes a copy necessary. The child writes a temporary RDB file and replaces the old snapshot after the new file is complete. Redis persistence, Redis FAQ on fork and COW.

sequenceDiagram
    participant P as Redis parent
    participant C as BGSAVE child
    participant D as Disk
    P->>C: fork at 10:00
    C->>D: write the 10:00 dataset
    P->>P: accept a new SET at 10:00:30
    Note over P,C: Changed memory pages are copied on write
    C->>D: finish temporary file and replace old snapshot

Suppose the snapshot starts at 10:00 and finishes at 10:01. A registration at 10:00:30 is not in that snapshot: the child sees the 10:00 state. If Redis fails before another snapshot and there is no AOF, that registration can be lost.

Background work still has a cost

BGSAVE runs in the background, but fork() itself can pause Redis, sometimes noticeably with a large dataset. The child reads memory and writes disk. If the parent changes many pages during the snapshot, COW can substantially increase RAM use. Near the machine’s memory limit, fork may fail or latency may rise. Redis persistence, latency guidance.

Around snapshot time, watch free RAM, rdb_last_cow_size, current_cow_size, save duration, disk throughput, and p99 latency. A dump.rdb file on disk might be old if recent snapshot attempts failed; the important question is when the last successful snapshot completed. Redis INFO.

3. AOF: Record the Changes, Then Mind the fsync Gap

AOF stands for Append Only File. It records operations that change data, using the Redis protocol. On startup, Redis can replay those operations to rebuild the dataset. If a counter is incremented a million times, the log can grow even though the current state is only one number. An AOF rewrite represents the current state more compactly. Redis persistence.

1
2
appendonly yes
appendfsync everysec

The three appendfsync choices

Setting When Redis requests fsync Practical tradeoff
always With newly appended writes, before acknowledging the corresponding batch Stronger protection against an OS or power failure, with more I/O and latency.
everysec Approximately once per second Often a useful balance; roughly a second of changes may be at risk in a catastrophic failure.
no Redis does not actively call fsync; the OS decides Less Redis-directed synchronization, but the loss window depends on the OS.

Redis documentation recommends everysec for many workloads. “About a second” describes the tradeoff; it is not a hard guarantee for every failure. Even always does not protect against a destroyed disk, an operational mistake, or a failover to a replica that has not received a write. Redis persistence.

What is the difference between write() and fsync()? After write(), bytes are commonly in the operating system’s page cache. If only the Redis process dies, the OS may still write them to disk. If the whole machine loses power, that page cache can disappear. fsync() asks the OS to synchronize the data to the storage device. The final durability still depends on the filesystem and hardware. This is also why an AOF benchmark should report p99 latency, not just commands per second.

A TTL does not pause while Redis is down

Redis stores expiration against real time. If a session has five seconds left, Redis is down for ten seconds, and then it restarts, the session has already expired. When testing recovery, first use a key without a TTL to see whether the data was restored. Test an expiring key separately so its expected expiration does not look like data loss. Key expiration.

4. Why Redis 7 Uses Multiple AOF Files

Rewrite is more than deleting repeated lines

Imagine incrementing a counter a million times. Retaining every increment takes space, even though Redis currently holds only a single number. BGREWRITEAOF creates a shorter representation of the current dataset. It is not simply a text editor removing duplicate lines from the old log. Redis keeps accepting writes while the rewrite runs. Redis persistence, BGREWRITEAOF.

Be careful with pre-7 explanations

Older articles often describe a secondary buffer that holds new writes while a child process creates a replacement AOF. That describes the approach before Redis 7. Since Redis 7, AOF consists of multiple files. This is an important version distinction when reading the article by Chanh Le: its secondary-buffer explanation is useful historical context, while a Redis 7.4 backup must follow the newer file layout. Redis multi-part AOF documentation.

flowchart TD
    M[Active manifest] --> B[Base AOF: dataset at rewrite]
    M --> I1[Incremental AOF: later writes]
    I1 --> R[BGREWRITEAOF starts]
    R --> C[Child creates a new base]
    R --> I2[Parent opens a new incremental file and keeps writing]
    C --> N[New manifest points to new base and incremental files]
    I2 --> N
    N --> S[New manifest becomes active]

The manifest is the list of files Redis needs to reconstruct the dataset. A base file contains the starting state and may use RDB or AOF format. Incremental files contain subsequent changes. During rewrite, the child creates a new base while the parent keeps recording new writes. When the rewrite completes, Redis switches the manifest to the new set. If the rewrite fails, the still-valid files and current incremental writes remain the recovery path. Redis persistence, Redis 7+.

This matters for backups. Copying one *.base.rdb file is not a complete AOF backup. Keep the manifest and every file it references together. Copying the directory mid-rewrite without a consistency procedure can leave you with files from different moments. The Redis documentation describes pausing rewrite, checking aof_rewrite_in_progress, copying the directory, and re-enabling rewrite. Managed services may have their own backup procedure. Redis backup guidance.

What “hybrid AOF” means

With aof-use-rdb-preamble yes, the rewritten AOF base can be in binary RDB format while the incremental files continue recording later changes. This can make loading the base faster than replaying a long command history. “Hybrid” describes the format inside the AOF set; it does not automatically create a separate, independent RDB backup. Redis persistence.

5. What Redis Loads After a Restart

If both RDB and AOF are enabled, Redis prefers AOF at startup because it usually includes newer changes. Seeing a valid dump.rdb on disk does not prove that Redis will load it. Check CONFIG GET appendonly, AOF status, and the startup log to see which files Redis actually read. Redis persistence.

flowchart TD
    START[Redis starts] --> A{AOF enabled?}
    A -->|Yes| AOF[Read manifest and AOF files]
    A -->|No| RDB[Read RDB snapshot, if present]
    AOF --> RAM[Rebuild dataset in RAM]
    RDB --> RAM

A cut-off tail is different from corruption in the middle

After an abrupt stop, the final AOF command may be only partly written. Depending on configuration, Redis can discard the incomplete tail and continue loading; inspect the log to confirm what it did. Damage in the middle of a file is more serious. Truncating from that point could discard many later changes. Make a copy of the original file and use redis-check-aof to inspect it before considering --fix. A successful startup after repair is not proof that all business data survived. Redis AOF corruption guidance.

PING can succeed while persistence is broken

Redis can reply PONG even when saving has failed. Full disks, incorrect permissions, a failed fork, and rewrite errors all need alerts. Watch rdb_last_bgsave_status, aof_last_write_status, aof_last_bgrewrite_status, aof_delayed_fsync, free disk space, and logs. Depending on configuration, Redis can refuse writes after an RDB save failure. A health check that only sends PING cannot tell you whether data is being persisted. Redis INFO, persistence.

6. Choose Persistence by Data, Not by Slogan

Setup Suitable when What to verify or accept
No disk persistence Cache is rebuildable and the database can handle a cold start Restart means an empty cache; many requests may hit the database together.
RDB only Losing changes since the last snapshot is acceptable Loss depends on the last successful snapshot.
AOF only You want a smaller potential loss window Manage multi-part AOF, disk space, rewrite, and load time.
RDB + AOF You want newer AOF data and an independent snapshot for backup Extra I/O and disk use; Redis prefers AOF at startup.

Does a replica replace a backup? No. Replication is usually asynchronous, so recent writes can be missing when a replica is promoted. A mistaken delete can also be replicated. A backup is a separate copy that you can inspect and restore after the current files or an entire cluster are lost. Redis persistence, WAIT and its limits.

For a cache or session, start with: “What will users see if all of this state disappears?” For a confirmed financial operation, agree on RPO and RTO with the product owners and practice both failover and restore. A single appendfsync always setting cannot replace that exercise.

A GitHub case study: moving durable data elsewhere

In “Moving persistent data out of Redis”, GitHub’s engineers separated data they could rebuild from data that existed only in Redis. They moved the latter to MySQL, which they already knew how to operate, and disabled persistence for the Redis data that remained. This reduced operational complexity and disk I/O in their environment. It was a decision for GitHub’s workload at that time, not a rule that Redis persistence is always wrong.

The interesting part is how they approached the move. They measured writes and found that activity feeds produced much of the load. Instead of copying each event into every user’s feed, they changed the data model to store activity by organization and filter at read time. They migrated feed types in stages, used a period of dual writes, and watched capacity and replication delay. Sometimes the better persistence decision starts with where the authoritative data lives and how it is modeled, not with changing appendfsync. GitHub Engineering.

7. Two Docker Labs You Can Inspect

The following PowerShell commands use Docker on your own machine and create named volumes dedicated to this exercise. Run each command after the previous one finishes.

Lab A: make and reload an RDB snapshot

1
2
3
4
5
docker volume create redis-rdb-lab-vol
docker run -d --name redis-rdb-lab -v redis-rdb-lab-vol:/data redis:7.4 redis-server --save 60 1 --appendonly no
docker exec redis-rdb-lab redis-cli SET lab:rdb hello
docker exec redis-rdb-lab redis-cli BGSAVE
docker exec redis-rdb-lab redis-cli INFO persistence

In the INFO persistence output, wait for rdb_bgsave_in_progress:0 and check rdb_last_bgsave_status:ok. Now stop and remove the container, then recreate it with the same volume:

1
2
3
4
docker stop redis-rdb-lab
docker rm redis-rdb-lab
docker run -d --name redis-rdb-lab -v redis-rdb-lab-vol:/data redis:7.4 redis-server --save 60 1 --appendonly no
docker exec redis-rdb-lab redis-cli GET lab:rdb

GET should return hello. This demonstrates loading a completed snapshot after a normal stop. It does not simulate a power failure or measure RDB’s RPO; we deliberately waited for BGSAVE before stopping Redis.

Lab B: inspect the AOF file set

1
2
3
4
5
6
7
docker volume create redis-aof-lab-vol
docker run -d --name redis-aof-lab -v redis-aof-lab-vol:/data redis:7.4 redis-server --appendonly yes --appendfsync everysec
docker exec redis-aof-lab redis-cli SET lab:aof hello
docker exec redis-aof-lab redis-cli INCR lab:aof:counter
docker exec redis-aof-lab redis-cli BGREWRITEAOF
docker exec redis-aof-lab redis-cli INFO persistence
docker exec redis-aof-lab ls -l /data/appendonlydir

Wait for aof_rewrite_in_progress:0 and check aof_last_bgrewrite_status:ok. You will typically find base, incremental, and manifest files in the directory. Names and counts can vary with rewrite timing; the manifest tells you which set is active. The image may also retain default RDB save rules. This lab observes AOF while it is enabled, and Redis will prefer AOF at startup.

1
2
3
4
docker stop redis-aof-lab
docker rm redis-aof-lab
docker run -d --name redis-aof-lab -v redis-aof-lab-vol:/data redis:7.4 redis-server --appendonly yes --appendfsync everysec
docker exec redis-aof-lab redis-cli GET lab:aof

GET should again return hello. If you later want to experiment with AOF repair, copy the volume first; editing the only recovery copy tells you little about safe recovery.

What should be on a dashboard?

Area Example signals Question to answer
RDB rdb_last_bgsave_status, rdb_last_save_time, rdb_last_cow_size Did the latest snapshot finish, and how much RAM did COW use?
AOF aof_last_write_status, aof_rewrite_in_progress, aof_delayed_fsync, aof_current_size Are writes and rewrites healthy?
Machine Free disk, available RAM, p99 latency, restart/load time Could this machine recover within our target?
Backup Last successful copy, checksum, last restore exercise Can we actually use the backup?

INFO fields can differ between Redis versions. Check the fields on the version you run rather than assuming every field exists everywhere. Redis INFO.

8. Six Easy Misreadings of Persistence

  1. “AOF means zero data loss.” everysec has a synchronization gap. Disk failure and mistaken deletes need separate recovery plans.
  2. "BGSAVE returned, so the new snapshot is ready." Wait for completion and check its status.
  3. “Redis 7 has one appendonly.aof file.” Look for base, incremental files, and the manifest.
  4. “We have a replica, so we have a backup.” A replica can copy a mistaken delete. Keep a separate copy and test restoring it.
  5. “Background save uses no extra memory.” Fork can pause Redis, and writes during a snapshot can grow COW memory.
  6. “Redis will load dump.rdb because it exists.” When AOF is enabled, Redis prefers AOF.

9. Closing Thought

RDB captures the dataset at a moment. AOF records changes needed to rebuild the dataset. RDB’s snapshot can miss later writes; AOF’s durability depends on when those changes reach disk. Since Redis 7, the AOF files work as a set managed by a manifest. When deciding what to enable, name the failure you are preparing for, the amount of data you can lose, and the file or backup from which you will recover.

Further reading