





























One of the most fundamental design decisions in Redis replication is that it’s push-based rather than pull-based. This means the master (or primary) actively sends data to replicas, rather than replicas polling the master for updates.
But why did Redis make this choice? What are the trade-offs? And how does this affect your production systems? Let’s dive deep into the engineering reasoning behind this decision.
Before we explore Redis specifically, let’s establish what we mean by push and pull replication models.
Pull-based replication: Replicas periodically ask the master, “What’s new?” The replica is responsible for fetching updates. Think of it like checking your mailbox; you decide when to check, and you pull out whatever’s there.
Redis uses the push model. When a write command is executed on the master, Redis propagates that command to all connected replicas immediately (or as immediately as the network allows).
To understand why push makes sense, we need to understand how Redis replication actually works.
When a replica connects to a master, here’s what happens:
PSYNC command to the masterThis is where the push nature becomes evident. The master doesn’t wait for replicas to ask for updates; it actively streams commands as they happen.
The replication backlog is a circular buffer that the master maintains. It stores a recent history of write commands (default 1MB, but tunable). This buffer serves two critical purposes:
The backlog itself is a push-oriented data structure. The master continuously appends to it and pushes offsets to replicas, rather than replicas pulling from specific offsets.
Now let’s get to the heart of the matter: why did Redis choose push-based replication?
The primary driver is latency. Redis is designed for microsecond-level operations. In a pull-based model, you’d have unavoidable replication lag due to:
With push-based replication, commands propagate to replicas immediately after execution on the master. The only delay is network transmission time. For most use cases, this means replication lag measured in single-digit milliseconds rather than seconds.
Imagine you’re using Redis for session storage in a web application with read replicas. A user logs in (writes to the master), then immediately makes another request that hits a replica. With pull-based replication on a 1-second polling interval, there’s a 50% chance (on average) that the replica doesn’t have the session yet. With push-based replication, the session is likely already there.
Push-based replication creates a clearer consistency model for developers. When you write to Redis, you know:
This is easier to reason about than: “The write is on the master, and replicas will eventually discover it whenever they next poll.”
The push model naturally implements sequential consistency at the replica level. Each replica sees writes in the same order they were executed on the master, which is crucial for maintaining data integrity.
Counterintuitively, push can be more network-efficient than pull in many scenarios.
In pull-based systems:
In push-based systems:
Consider a Redis instance with 1000 writes per second and 10 replicas. In a push model, you send 1000 commands to each replica (10,000 messages). In a pull model with 1-second polling, you’d have 10 polls per second (minimum) plus the 10,000 data messages, and that’s just to match the push latency.
Redis’s core design is single-threaded (for command execution). This actually makes push-based replication more natural to implement.
Here’s why: When Redis executes a write command on the master, it’s already holding the execution context. At that exact moment, it can:
This happens atomically within the same event loop iteration. There’s no need for background threads, complex synchronization, or state management.
In a pull model, Redis would need to:
This would introduce significantly more complexity in a single-threaded architecture.
Push-based replication gives the master better control over flow management. The master can:
repl-timeout and client-output-buffer-limit)This protects the master from resource exhaustion. If a replica is slow or has network issues, the master can make intelligent decisions about whether to wait or disconnect.
In a pull model, the burden would be on replicas to manage their own rate of consumption, but they wouldn’t have visibility into the master’s state or other replicas’ performance.
When things go wrong (and they will), push-based replication offers cleaner failure modes:
Replica disconnection: The master immediately knows via the TCP connection. It can stop trying to push to that replica, freeing resources.
Master failure: Replicas are already in sync up to the last received command. Promotion to master is straightforward, just elect the most up-to-date replica.
Network partition: The master can use min-replicas-to-write and min-replicas-max-lag to refuse writes if too many replicas are unreachable, preventing split-brain scenarios.
These mechanisms are natural in a push model because the master has real-time awareness of the replica state.
No design is perfect. Push-based replication has limitations:
The master must maintain:
For a master with many replicas (say, 100+), this can consume significant memory. The client-output-buffer-limit helps here, but it’s a resource consideration nonetheless.
Replicas can’t control their replication rate. They receive data as fast as the master sends it. This is usually fine, but in extreme cases:
Redis handles this by disconnecting lagging replicas, which is pragmatic but can be disruptive.
Every write on the master triggers replication logic:
In a pull model, this cost would be amortized across poll intervals.
repl-backlog-size: The default 1MB might be too small for high-throughput systems. If replicas frequently disconnect and require full resyncs, increase this.
A good heuristic
(writes_per_second * avg_command_size * expected_disconnect_time * safety_factor)
min-replicas-to-write and min-replicas-max-lag are used to ensure consistency. For example:
min-replicas-to-write 1
min-replicas-max-lag 10
This means the master refuses writes if it doesn’t have at least 1 replica with less than 10 seconds of lag. This prevents data loss if the master fails right after a write.
We use INFO replication on both master and replicas. Key metrics:
master_repl_offset (on master): How many bytes have been sentslave_repl_offset (on replica): How many bytes have been processedCombine with repl_backlog_first_byte_offset to ensure replicas are within the backlog window.
WAIT command when you need stronger consistency: WAIT 1 1000 blocks until at least 1 replica acknowledges a write (with 1-second timeout)Remember, even with push-based replication, Redis replication is asynchronous. There’s no distributed consensus. Reads from replicas may return stale data. For critical reads, go to the master or use WAIT.
Redis (2.8.18+) introduced diskless replication, which is an optimization enabled by push-based architecture.
Normally, during a full resync:
With diskless replication (repl-diskless-sync yes):
Redis replication is push-based because it aligns perfectly with Redis’s design philosophy and constraints.
The push model places more burden on the master and reduces replica autonomy, but for Redis’s primary use cases (caching, session stores, real-time analytics), these trade-offs are absolutely worth it.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。