Redis operates as an in-memory data store, leveraging RAM to achieve high-speed data access. While the primary design goal is performance, relying solely on memory introduces a risk of data loss during power outages or process failures. To mitigate this, Redis provides robust persistence mechanisms to save the in-memory state to disk, allowing the dataset to be reconstructed after a restart.
RDB Snapshots
The most straightforward approach to persistence is creating point-in-time snapshots of the dataset. This is the foundation of the Redis Database (RDB) persistence mechanism. RDB generates a binary file containing a compact representation of the database state at a specific moment.
Manual and Background Saves
Redis offers two primary commands for triggering RDB snapshots: SAVE and BGSAVE.
When SAVE is executed, the main Redis process performs a synchronous dump of all data to the disk. During this operation, the server blocks all incoming client requests, which is generally unacceptable for production environments due to the resulting pause.
To avoid blocking, BGSAVE (Background Save) forks a child process. The child process handles the I/O operations of writing the RDB file to disk, while the parent process continues to process client commands. This approach ensures availability, although the fork operation itself can cause a brief spike in memory usage if the dataset is large.
Automatic Persistence Configuration
Rather than relying on manual intervention, Redis can be configured to save snapshots automatically based on time and the number of write operations. The configuration syntax follows this pattern:
save <seconds> <changes>
For example, the configuration below defines three saving conditions:
save 900 1
save 300 10
save 60 10000
This directive tells Redis to perform a BGSAVE if at least one key is modified within 900 seconds, or if 10 keys are modified within 300 seconds, or if 10,000 keys are modified within 60 seconds. These conditions are cumulative; if any are met, the save operation is triggered.
Internal Persistence Logic
Internally, the Redis server maintains state variables to manage these rules. The server structure tracks the number of modifications (dirty) and the timestamp of the last successful save (lastsave). A periodic cron function (serverCron) runs every 100 milliseconds to iterate through the configured save rules. If a rule condition is met—specifically, if the current time minus lastsave is greater than the configured seconds, and the dirty counter exceeds the configured changes count—the BGSAVE operation is triggered. Upon completion, the dirty counter is reset and lastsave is updated.
RDB File Structure
The RDB file is a compressed binary file organized into specific sections:
- Magic Number: The string "REDIS" identifies the file type.
- Version: Indicates the RDB file format version.
- Databases: Contains the key-value pairs for the selected databases, including auxiliary fields like expiry times.
- EOF: Marks the end of the file content.
- Check Sum: A checksum value to verify file integrity during loading.
AOF Persistence
While RDB provides snapshots, it risks losing data written between the last save and a system crash. The Append Only File (AOF) mechanism addresses this by logging every write operation received by the server. These commands are appended to a file in a format identical to the Redis protocol. Upon restart, Redis replays these commands to reconstruct the original dataset.
The AOF Process
AOF persistence is enabled by setting appendonly yes. When a write command modifies the dataset, the command is appended to the AOF buffer in memory. The actual disk persistence behavior is controlled by the appendfsync configuration, which determines how often data is flushed from the kernel buffer to the physical disk.
The appendfsync setting accepts three values:
- always: Forces a synchronous
fsyncafter every write. This provides maximum durability (data is lost only if the disk itself fails) but significantly impacts latency. - everysec: Performs an
fsyncexactly once per second, usually in a separate thread. This offers a good balance between performance and safety, losing at most one second of data. - no: Delegates the flushing decision to the operating system. This offers the best performance but leaves data vulnerable for up to 30 seconds depending on the OS's flush policy.
Data Loading
If both RDB and AOF files exist at startup, Redis prioritizes the AOF file for data reconstruction because it is typically more complete and recent. The server reads the AOF file, parses the Redis protocol commands sequentially, and executes them to restore the state.
AOF Rewriting
As the server runs, the AOF file size grows indefinitely. Furthermore, multiple updates to the same key result in redundant commands in the log. To combat this, Redis implements AOF rewriting. This process does not analyze the existing log; instead, it reads the current value of keys in memory and writes a minimal set of commands required to recreate the current state.
Background Rewrite (BGREWRITEAOF)
Similar to RDB, performing a rewrite in the main thread would block the server. Therefore, Redis forks a child process to perform the rewrite. The child process writes the new optimized AOF file to a temporary file.
A challenge arises during this process: the parent process continues to accept write commands while the child is rewriting. To ensure data consistency, Redis introduces an AOF rewrite buffer. When the child process is created, the server starts buffering new write commands not only in the standard AOF buffer but also in this rewrite buffer.
When the child process finishes writing the temporary file, it signals the parent. The parent then performs the following atomic operations:
- Write all accumulated commands from the AOF rewrite buffer to the temporary file.
- Rename the temporary file over the existing AOF file atomically.
This ensures that the new AOF file contains the snapshot generated by the child plus all增量 writes executed during the rewrite process.