RDB Snapshots Explained and Configured Correctly
AI generated
SET
TTL
Redis · Persistence · RDB · BGSAVE
RDB Snapshots Explained
and Configured Correctly

RDB snapshots store the entire dataset of a Redis server as a compact binary file at fixed points in time. Anyone who understands save points, the BGSAVE fork mechanism, and copy-on-write can configure snapshot intervals so that data loss and latency spikes both stay under control, instead of relying on default values.

14 min read save · BGSAVE · fork · copy-on-write · RDB format Redis 6.x · 7.x

1. What RDB Snapshots Are and What They Are For

An RDB snapshot is a point-in-time capture of the entire Redis dataset, stored as a single, compact binary file. Unlike a log that records every single write operation, RDB only captures the final state of all keys at a given moment. That makes RDB files small, fast to load, and ideal for backups, because a single file represents the complete dataset without needing to replay any operations.

The core advantage of RDB snapshots lies in restart speed: Redis reads an RDB file linearly and reconstructs memory, which is significantly faster for large datasets than replaying an append-only log. The core drawback is equally obvious: any data written between two snapshots is lost in a crash. Anyone relying on RDB snapshots as the sole persistence strategy implicitly accepts a window of possible data loss, controlled through the save configuration.

In practice, RDB snapshots are an excellent fit for caching layers with occasional persistence needs, for read replicas that bootstrap from a snapshot anyway, and for backup scenarios where a consistent full state matters more than second-level loss-freeness. For use cases with strict durability requirements, RDB is usually combined with AOF, which is covered in a separate article in this series.

2. Configuring Save Points: the save Directive in Detail

The save directive in redis.conf defines under which conditions Redis automatically triggers an RDB snapshot. Each save line follows the pattern save <seconds> <changes> and means: if at least the given number of seconds has passed since the last snapshot AND at least the given number of write operations has occurred, a new snapshot is triggered. Multiple save lines are combined with OR logic: as soon as one condition is met, the snapshot starts.

The default configuration of many Redis distributions defines three save points: save 900 1, save 300 10, and save 60 10000. In words: a snapshot after 900 seconds if at least one change occurred, a snapshot after 300 seconds with at least 10 changes, and a snapshot after 60 seconds with at least 10,000 changes. This staggering ensures more frequent saves under heavy write load, while not triggering unnecessary forks under light load.

Anyone who wants to disable RDB snapshots entirely, for example because only AOF is used, sets save "" as an empty string. That removes all configured save points without disabling manual snapshots: BGSAVE via redis-cli still works, only the automatic trigger goes away. For production setups it is recommended to tune save points to actual write volume instead of blindly keeping the defaults.


# redis.conf - RDB save points configuration

# Save after 900 sec (15 min) if at least 1 key changed
save 900 1
# Save after 300 sec (5 min) if at least 10 keys changed
save 300 10
# Save after 60 sec if at least 10000 keys changed
save 60 10000

# Disable RDB entirely (AOF-only setups)
# save ""

# Filename and directory for the RDB file
dbfilename dump.rdb
dir /var/lib/redis

# Stop accepting writes if the last BGSAVE failed
# (protects against silent data loss, disable with caution)
stop-writes-on-bgsave-error yes

3. BGSAVE: Fork and Copy-on-Write in Detail

The mechanism behind automatic RDB snapshots is called BGSAVE and is based on the POSIX system call fork(). When a snapshot is triggered, Redis duplicates the running process: the parent process keeps serving client requests, while the child process writes the entire in-memory content to a temporary RDB file and then atomically moves it into place with rename(). From a client's point of view, an RDB snapshot is therefore practically non-blocking, because the parent process keeps processing requests without interruption.

The decisive efficiency gain comes from copy-on-write, or COW, an operating system feature the Linux kernel provides for forked processes. During a fork, the parent process memory pages are not physically copied. Instead, both processes initially share the same pages in virtual memory. Only when the parent process modifies a page, for example through a new SET command, does the kernel copy exactly that one memory page, typically 4 KB in size, before the write access happens. The child process therefore continues to see the unchanged state at the moment of the fork, exactly the consistency guarantee a snapshot needs.

The cost of this mechanism depends directly on the write rate during BGSAVE: the more keys change while the child process is still writing, the more memory pages get duplicated, and the more extra RAM is briefly allocated. For a dataset with high write load and a large working set, the additional memory demand during a BGSAVE can reach 20 to 50 percent of the original dataset size. That is the main reason Redis instances should never be configured right up to the physical memory limit.


# Trigger a manual RDB snapshot
redis-cli BGSAVE
# Background saving started

# Check whether a BGSAVE is currently running
redis-cli INFO persistence | grep rdb_bgsave_in_progress
# rdb_bgsave_in_progress:1   -> snapshot running
# rdb_bgsave_in_progress:0   -> idle

# Check outcome and timing of the last BGSAVE
redis-cli INFO persistence | grep -E "rdb_last_bgsave_status|rdb_last_bgsave_time_sec|rdb_last_cow_size"
# rdb_last_bgsave_status:ok
# rdb_last_bgsave_time_sec:3
# rdb_last_cow_size:41943040   -> ~40 MB copy-on-write overhead

4. SAVE vs. BGSAVE: the Decisive Difference

Besides BGSAVE, Redis also has the synchronous command SAVE, which produces the RDB snapshot directly in the main process without forking. While SAVE runs, Redis blocks completely: no client command is processed until the snapshot finishes. For small datasets that might be in the millisecond range, but with several gigabytes of data, SAVE can take seconds to minutes, during which the entire instance appears unreachable to clients.

In production environments, SAVE should practically never be called manually. The only legitimate use case is a controlled shutdown, where Redis is not going to serve any more requests anyway and maximum consistency without fork overhead is desired. The SHUTDOWN command internally calls SAVE by default, as long as save points are configured, before the process terminates, so that no data state is lost.

Criterion SAVE BGSAVE
Execution Synchronous in the main process Asynchronous via fork()
Blocks clients Yes, completely No, only the brief fork moment
Memory overhead No extra COW memory Up to 20-50% via copy-on-write
Typical use Controlled shutdown Automatic save points, manual backups
Trigger Manual or SHUTDOWN save directive, manual, before replication

5. The RDB File Format: Structure and Versioning

An RDB file is binary, but its structure is well documented and follows a clear layout. It starts with a magic string REDIS, followed by a four-digit version number of the RDB format, for example 0011 for version 11. This version number is independent of the Redis server version and only increases when the binary format itself changes, for example with new data types. After that come any number of opcodes encoding metadata such as the selected database number, expire times, and finally the actual key-value pairs.

Every key is stored together with a type byte indicating whether it is a string, a list, a set, a sorted set, or a hash structure, followed by a type-specific serialization of the value. Redis uses compact encodings such as ziplist or listpack for small collections to save space, only switching to the full data structure once configurable thresholds are exceeded. At the end of the file sits an end-of-file opcode, followed by an 8-byte CRC64 checksum over the entire preceding content.

This checksum is the central integrity protection of RDB files: when loading, Redis checks whether the computed checksum matches the stored one, and refuses to start on a mismatch, as long as rdbchecksum is enabled. Compatibility between RDB versions is fundamentally forward-directed: a newer Redis server can read older RDB file formats, but an older server cannot load an RDB file written with newer data types or opcodes. This is a commonly overlooked pitfall when downgrading a Redis version.


# Inspect the raw header bytes of an RDB file
xxd dump.rdb | head -3
# 00000000: 5245 4449 5330 3031 31fa 0972 6564 6973  REDIS0011..redis
# 00000010: 2d76 6572 0736 2e32 2e37 fa0a 7265 6469  -ver.6.2.7..redi
# 00000020: 732d 6269 7473 c040 fa05 6374 696d 65c2  s-bits.@..ctime.

# Byte breakdown:
#   "REDIS"      magic string (5 bytes)
#   "0011"       RDB format version (4 bytes, ASCII)
#   0xFA         opcode: auxiliary field (metadata) follows
#   "redis-ver"  metadata key
#   "6.2.7"      metadata value (server version at write time)

# Verify the trailing CRC64 checksum manually (Redis does this on load)
tail -c 8 dump.rdb | xxd

6. Compression, Checksums, and Other RDB Parameters

Redis compresses string values inside an RDB file by default using the LZF algorithm, controlled by the rdbcompression yes directive. LZF is deliberately optimized for low CPU cost rather than maximum compression ratio, because the BGSAVE process is already under load from copy-on-write, and extra CPU load would extend the fork duration. For datasets with many short strings, such as session IDs or counters, compression rarely pays off, because the per-value overhead can exceed the savings, which is why Redis automatically skips compression for very short values.

The rdbchecksum yes directive enables the CRC64 checksum at the end of the file. When disabled, Redis saves a small amount of CPU time on write and read, but loses any ability to detect silent corruption of the file, for example from a faulty storage device or an interrupted copy. For production systems, rdbchecksum should practically always stay enabled, the performance difference is barely measurable in normal operation.

Other relevant parameters include sanitize-dump-payload, which performs additional validation against manipulated or corrupt payloads when loading RDB files or RESTORE commands, and rdb-key-save-delay, a parameter mainly intended for testing that artificially inserts a delay between writing individual keys to simulate COW behavior under load. In production, this parameter stays at 0.


# redis.conf - RDB compression, checksums, and validation

# LZF compression for string values inside the RDB file
rdbcompression yes

# CRC64 checksum at the end of the RDB file (integrity check)
rdbchecksum yes

# Extra validation when loading RDB payloads (RESTORE, replication)
sanitize-dump-payload yes

# Keep the previous RDB file if BGSAVE fails (Redis 7+)
rdb-del-sync-files no

7. Performance Impact: Fork Time and Latency Spikes

The duration of the fork() call itself, not the subsequent write work done by the child process, is the most critical latency factor in RDB snapshots. The fork is theoretically cheap thanks to copy-on-write, since no memory pages are physically copied, but the kernel still has to duplicate the entire page table of the process. For instances with a very large heap, say 50 GB or more, this step alone can take several hundred milliseconds, during which the parent process is fully blocked, because fork() itself is a synchronous system call.

This fork latency shows up in the INFO output as latest_fork_usec and should be monitored regularly. Values in the low single-digit millisecond range are normal for small instances, while values above 100 milliseconds on large instances indicate that BGSAVE calls cause noticeable latency spikes in application traffic. The operating system's overcommit setting also plays a role here: with vm.overcommit_memory=1 in the kernel, Linux does not reserve extra memory upfront on fork, which prevents fork failures under tight memory and is commonly recommended.

On spinning disks or overloaded network storage, the actual write phase of the child process can additionally become a bottleneck, because parallel I/O load from application logs or other processes extends the snapshot duration and therefore also enlarges the window for copy-on-write overhead. On SSD or NVMe-backed systems this effect is usually negligible. For latency-critical setups, it is advisable to schedule BGSAVE deliberately during periods of low write load, rather than relying solely on automatic save points.

8. RDB Files in Operation: Location, Naming, Signals

The dir and dbfilename parameters in redis.conf determine where an RDB file is stored, defaulting to dump.rdb in the process working directory. In production setups, dir should always point explicitly to a dedicated, monitored storage volume, never to a temporary or ephemeral filesystem, otherwise snapshots are lost on a container restart. Redis first writes to a temporary file in the same directory and only atomically renames it into the target file after successful completion, which makes an incomplete RDB file after a crash during writing practically impossible.

Redis also does not respond to the SIGHUP signal with an RDB snapshot, but a regular SHUTDOWN command triggers a final SAVE by default, as long as at least one save point is configured. With SHUTDOWN NOSAVE this step is deliberately skipped, for example when a restart follows anyway and the last automatic snapshot is considered sufficient. For systemd-managed Redis instances, it is important to set TimeoutStopSec generously enough that a final snapshot on a large dataset is not interrupted by a hard SIGKILL.


#!/usr/bin/env bash
# check_rdb_health.sh - Monitor RDB snapshot status and age
set -euo pipefail

STATUS=$(redis-cli INFO persistence | grep rdb_last_bgsave_status | cut -d: -f2 | tr -d '\r')
LAST_SAVE_EPOCH=$(redis-cli LASTSAVE)
NOW_EPOCH=$(date +%s)
AGE_MIN=$(( (NOW_EPOCH - LAST_SAVE_EPOCH) / 60 ))

if [[ "$STATUS" != "ok" ]]; then
  echo "[ALERT] Last BGSAVE failed: $STATUS" >&2
  exit 1
fi

if (( AGE_MIN > 30 )); then
  echo "[WARN] Last RDB snapshot is $AGE_MIN minutes old" >&2
  exit 1
fi

echo "[OK] RDB snapshot healthy, age: ${AGE_MIN} min"

9. Common Mistakes and Pitfalls With RDB Snapshots

The most common mistake with RDB snapshots is relying on them alone and underestimating the window between two save points. With save 900 1 as the only save point, up to 15 minutes of write operations can be lost in the worst case of a hard crash. That may be tolerable for session storage or caches, but it is careless for order data or financial transactions without additional AOF protection or application-side persistence.

A second common mistake is setting stop-writes-on-bgsave-error to no without thinking it through, in an attempt to boost availability. By default, Redis blocks write operations when the last BGSAVE has failed, for example because the disk was full, so the operator notices the problem before data silently accumulates without any persistence guarantee. Anyone who disables this safeguard loses exactly this early-warning system and risks silent, unnoticed data loss over a long period.

A third mistake concerns memory overcommit: if vm.overcommit_memory is not set to 1, the fork() system call can fail under tight free memory, even though copy-on-write practically requires almost no additional memory immediately. The result is a failed BGSAVE at exactly the moment a backup is needed most, usually under heavy load. The Redis log explicitly warns about this misconfiguration at startup, and that warning should never be ignored.

Mironsoft

Redis operations, persistence strategy, and backup infrastructure

RDB snapshots that actually help when it counts?

We review existing Redis instances for save configuration, fork latency, and backup coverage, and set up snapshot strategies that match your actual write volume.

Configuration Review

Tune save points, rdbcompression, and stop-writes-on-bgsave-error to your write volume

Latency Analysis

Measure fork time and copy-on-write overhead and optimize snapshot windows

Backup Automation

Automate, verify, and keep RDB snapshots off-site

10. Summary

RDB snapshots are the most efficient tool in Redis for capturing an entire dataset as a compact, fast-to-load binary file. The save directive controls how aggressively automatic snapshots happen, while BGSAVE, through fork() and copy-on-write, ensures that a snapshot practically does not block ongoing operations. The RDB file format, with its magic string, opcodes, and CRC64 checksum, is stably documented, compact, and forward-compatible, though not guaranteed to be backward-compatible across Redis versions.

Anyone running RDB snapshots in production should tune save points to real write volume, keep rdbchecksum and stop-writes-on-bgsave-error enabled, and monitor fork latency via latest_fork_usec regularly. For use cases with strict loss requirements, RDB alone is rarely enough, and combining it with AOF persistence, covered in the next article in this series, provides the missing safety net between two snapshots.

RDB Snapshots Explained and Configured: the Essentials at a Glance

Save Points

save 900 1, save 300 10, save 60 10000, combined with OR logic, tune to real write volume.

BGSAVE Mechanics

fork() plus copy-on-write produces a consistent snapshot without noticeably blocking clients.

File Format

Magic string, versioned opcodes, CRC64 checksum at the end, compact and forward-compatible.

Monitoring

Check rdb_last_bgsave_status, rdb_last_cow_size, and latest_fork_usec regularly.

11. FAQ: RDB Snapshots Explained and Configured

1What exactly does an RDB snapshot store?
The complete dataset of all databases at a fixed point in time as a binary file, including expire times. Only the final state, no intermediate steps.
2How often should I configure save points?
Depends on write volume. The defaults are a good starting point but should be tuned to real write rates.
3Does BGSAVE block my application?
Only for the brief fork() duration itself. The actual write process runs in parallel in the child process.
4What happens with many changes during BGSAVE?
Copy-on-write duplicates changed memory pages. Under heavy load that can raise temporary memory demand by 20 to 50 percent.
5Can I disable RDB snapshots?
Yes, with save "" in redis.conf. Manual BGSAVE still works, only the automatic trigger goes away.
6Why does BGSAVE fail despite free memory?
Usually because vm.overcommit_memory is not set to 1. The kernel then refuses the fork() as a precaution.
7Is an RDB file compatible across versions?
Newer versions read older formats fine. Downgrades can fail with newer opcodes or data types.
8What does stop-writes-on-bgsave-error do?
Blocks write operations after a failed BGSAVE, so data loss cannot silently accumulate.
9How do I check the last snapshot status?
With redis-cli INFO persistence and rdb_last_bgsave_status, plus LASTSAVE for the timestamp.
10Is RDB alone enough for production systems?
For caches, usually yes. For indispensable data, AOF persistence provides the missing safety net between two snapshots.