Redis and Valkey Replication

Replication keeps copies of a Valkey or Redis dataset on separate nodes. A single node, the master (also called the primary), accepts all writes, and every change is streamed to its replicas. Replication is what read scaling is built on, and it is the foundation underneath every high-availability topology in Valkey and Redis, including Sentinel and Cluster.

This page covers how replication works on the server, what its asynchronous default actually costs you, and how to configure read/write splitting, failover behaviour and lock safety from Java using Redisson.

Master-slave, primary-replica: a note on terminology

You will see two vocabularies for the same thing, and the difference is historical rather than technical.

  • "Master-slave" is the original terminology. It described a well-known computing pattern in which one node coordinates several subordinate nodes.
  • "Primary-replica" is the current terminology. Redis 5.0 introduced REPLICAOF as the preferred spelling of the older SLAVEOF command and began replacing "slave" with "replica" throughout its documentation and configuration. Valkey uses "replica" consistently.

Both still appear in practice. SLAVEOF remains as an alias, INFO replication still reports fields such as slave0, and Redisson retains MasterSlaveServersConfig, useMasterSlaveServers() and addSlaveAddress() for backward compatibility. Treat the two sets of terms as interchangeable.

What replication gives you, and what it does not

Replication solves three problems well:

  • Read scaling. Read-heavy workloads can be spread across replicas instead of concentrating on a single node.
  • Redundancy. If the master fails, a replica already holds a near-current copy of the data and can be promoted.
  • Offloading background work. Backups, exports and analytical scans can run against a replica without adding latency to the master.

It is just as important to know what replication does not do:

  • It is not sharding. Every replica holds the full dataset, so replication scales reads but never write throughput or memory capacity. Splitting data across nodes requires Redis Cluster.
  • It does not provide automatic failover. Plain replication has no mechanism to detect a dead master or promote a replica. That requires Redis Sentinel, Redis Cluster, or a managed service that supplies its own failover.
  • It is not a backup. Replication faithfully copies destructive operations too. A FLUSHALL or an accidental mass deletion reaches the replicas within milliseconds.

How replication works

A replica is attached to a master with a single command:

REPLICAOF 192.168.1.10 6379

From there the process runs in two modes.

Full synchronization happens on a first connection, or whenever a partial resync is not possible. The master produces an RDB snapshot of the dataset, either by forking a child process that writes to disk or, with diskless replication, by streaming the snapshot directly to the replica's socket. While the snapshot is being transferred, the master buffers every incoming write and replays it to the replica once loading is complete.

Partial resynchronization handles the far more common case of a brief network interruption. The master maintains a replication ID together with a running byte offset and a fixed-size backlog buffer of recent commands. When a replica reconnects it reports the offset it last processed. If that offset is still inside the backlog, the master sends only the missing commands rather than repeating a full transfer. If the replica has fallen too far behind, the backlog no longer covers the gap and a full synchronization is triggered instead.

Two further behaviours are worth knowing:

  • Replicas are read-only by default (the replica-read-only setting). Writing directly to a replica is possible but the data is local, not propagated, and is discarded at the next resynchronization.
  • Replication is largely non-blocking on the master. The master continues serving traffic throughout. A replica keeps answering queries with its older copy of the data while it synchronizes, except during the brief window in which a new dataset is being loaded into memory.

Replicas can themselves have replicas, forming a chain. This reduces the fan-out load on the master in deployments with many replicas, at the cost of additional propagation delay down the chain.

Replication is asynchronous by default

This is the single most consequential fact about Valkey and Redis replication, and the one most often missed.

The master acknowledges a write to the client before propagating it to any replica. Throughput and latency benefit enormously, but a failure window exists: if the master crashes in the interval between acknowledging a write and propagating it, and a replica is then promoted, that write is gone. The client was told the write succeeded.

Several tools narrow the window without closing it:

  • WAIT numreplicas timeout blocks until the given number of replicas have acknowledged all writes issued by the current connection, returning how many actually did. It confirms receipt by replicas, not that the data was persisted to disk, and it never rolls anything back. Treat it as a synchronization point, not as a transaction.
  • WAITAOF, added in Redis 7.0, is the stronger variant. It waits for a specified number of local and replica AOF fsyncs, which is an acknowledgement of durability rather than of delivery.
  • min-replicas-to-write and min-replicas-max-lag configure the master to refuse writes when fewer than N replicas are connected and current. This trades availability for a stronger guarantee that accepted writes will survive.

Replication lag is measured through INFO replication. Compare the master's master_repl_offset against the offset reported for each connected replica. On a replica, master_link_status shows whether the link is currently up. Any monitoring setup that includes replicas should alert on a growing offset gap, because a replica that drifts beyond the backlog will force a costly full resynchronization.

Replication, Sentinel and Cluster compared

Topology Copies data Automatic failover Splits data across nodes
Replication Yes No No
Sentinel Yes Yes No
Cluster Yes, per shard Yes Yes

Sentinel and Cluster do not replace replication; they add monitoring and promotion logic on top of it. For a fuller comparison of the two, see Redis Sentinel vs Redis Cluster and Redis Architecture.

Configuring replication in Java with Redisson

Redisson connects to a master with a fixed set of replicas through master/slave mode:

Config config = new Config();
config.useMasterSlaveServers()
    // use "redis://" for Redis connection
    // use "valkey://" for Valkey connection
    // use "rediss://" for Redis SSL connection
    // use "valkeys://" for Valkey SSL connection
    .setMasterAddress("redis://127.0.0.1:6379")
    .addSlaveAddress("redis://127.0.0.1:6389", "redis://127.0.0.1:6332", "redis://127.0.0.1:6419")
    .addSlaveAddress("redis://127.0.0.1:6399");

RedissonClient redisson = Redisson.create(config);

The mode is activated by a single call, which returns the configuration object:

MasterSlaveServersConfig masterSlaveConfig = config.useMasterSlaveServers();

The settings that matter most for replication behaviour are these:

  • readMode — which node type serves read operations. SLAVE (the default) reads from replicas and falls back to the master when no replica is available; MASTER reads only from the master; MASTER_SLAVE reads from both.
  • subscriptionMode — which node type serves publish/subscribe subscriptions. Defaults to MASTER. Setting it to SLAVE moves subscription connections onto replicas, which relieves the master of pub/sub fan-out but ties your subscribers to replica availability.
  • loadBalancer — how reads are distributed across replicas. Available implementations are RoundRobinLoadBalancer (the default), WeightedRoundRobinBalancer, RandomLoadBalancer and CommandsLoadBalancer. Weighted balancing is the right choice when replicas run on unequal hardware.
  • masterConnectionPoolSize / slaveConnectionPoolSize — maximum pool sizes, both 64 by default. The replica pool size applies per replica node, so the total connection count grows with the number of replicas.
  • fallbackLoadingToMaster — whether a read is retried on the master when a replica returns a LOADING error. A replica returns this while it is loading a dataset into memory, typically just after startup or a failover. Enabled by default, which avoids surfacing transient errors to application code.
  • failedSlaveNodeDetector — the strategy used to decide that a replica has failed. FailedConnectionDetector (the default) reacts to ongoing connection errors; FailedCommandsDetector and FailedCommandsTimeoutDetector react to a threshold of command errors or command timeouts within a check interval.
  • failedSlaveReconnectionInterval — how often, in milliseconds, Redisson attempts to reconnect a replica that was removed from the available list. Defaults to 3000.
  • dnsMonitoringInterval — how often node hostnames are re-resolved, in milliseconds. Defaults to 5000; -1 disables it. This matters in Kubernetes and other environments where node addresses change.

The same configuration can be supplied declaratively in YAML:

---
masterSlaveServersConfig:
  idleConnectionTimeout: 10000
  connectTimeout: 10000
  timeout: 3000
  retryAttempts: 4
  retryDelay: !<org.redisson.config.EqualJitterDelay> {baseDelay: PT1S, maxDelay: PT2S}
  reconnectionDelay: !<org.redisson.config.EqualJitterDelay> {baseDelay: PT0.1S, maxDelay: PT10S}
  failedSlaveReconnectionInterval: 3000
  failedSlaveNodeDetector: !<org.redisson.client.FailedConnectionDetector> {}
  subscriptionsPerConnection: 5
  clientName: null
  loadBalancer: !<org.redisson.connection.balancer.RoundRobinLoadBalancer> {}
  subscriptionConnectionMinimumIdleSize: 1
  subscriptionConnectionPoolSize: 50
  slaveConnectionMinimumIdleSize: 24
  slaveConnectionPoolSize: 64
  masterConnectionMinimumIdleSize: 24
  masterConnectionPoolSize: 64
  readMode: "SLAVE"
  subscriptionMode: "SLAVE"
  slaveAddresses:
  - "redis://127.0.0.1:6381"
  - "redis://127.0.0.1:6380"
  masterAddress: "redis://127.0.0.1:6379"
  database: 0
password: null
username: null
threads: 16
nettyThreads: 32
codec: !<org.redisson.codec.Kryo5Codec> {}
transportMode: "NIO"

The full list of settings is available in the Redisson configuration reference.

Read/write splitting and stale reads

Because readMode defaults to SLAVE, a Redisson client sends reads to replicas out of the box. This is usually what you want, but it introduces a consequence that has to be handled in application code: a value written to the master may not yet be visible on the replica that serves the next read.

The pattern that exposes this most often is read-after-write. A request writes an object and immediately reads it back, or writes on one request and reads on the next, and receives either stale data or nothing at all. The replication delay is usually sub-millisecond on a healthy local network, which is precisely why the bug appears intermittently and is difficult to reproduce.

There are three workable approaches:

  • Set readMode to MASTER when correctness matters more than read throughput. Sessions, counters, idempotency keys and anything read immediately after being written belong in this category.
  • Use two Redisson clients against the same deployment, one configured with readMode MASTER for consistency-sensitive paths and one with SLAVE for bulk reads that tolerate staleness. This keeps the scaling benefit where it is safe to have it.
  • Accept staleness explicitly for genuinely tolerant workloads: catalogue reads, cached lookups, dashboards, recommendations.

The mistake to avoid is leaving the default in place and assuming replication is instantaneous.

Replication and distributed locks

Replication interacts with distributed locks in a way that catches many teams out. A lock acquired on the master and not yet replicated will vanish if that master fails and a replica is promoted. A second client can then acquire the same lock, and two processes hold what they both believe is an exclusive lock.

Redisson addresses this directly with two settings:

  • checkLockSyncedSlaves — whether to verify, after a lock is acquired, that the number of synchronized replicas matches the actual number of replicas. Enabled by default.
  • slavesSyncTimeout — the replica synchronization timeout in milliseconds, applied to each RLock, RSemaphore and RPermitExpirableSemaphore operation. Defaults to 1000.

With these enabled, lock acquisition is confirmed against replica state rather than trusting the master alone. Where stronger guarantees are needed, see the Redlock algorithm and Java FencedLock, which adds fencing tokens for protection against stale lock holders.

Managed and multi-datacenter replication

Master/slave mode assumes a fixed, known set of nodes. Managed services and multi-region deployments need different handling, and Redisson provides a connection mode for each:

  • Replicated mode polls the role of each node to detect when a failover has produced a new master. This is the correct mode for non-clustered AWS ElastiCache, Azure Redis Cache and Google Cloud Memorystore, where the provider manages promotion and the client must follow it.
  • Multi Cluster mode connects several Cluster deployments in an active-passive relationship, with replicationMode controlling whether writes wait for cross-deployment replication and datastoreMode controlling which deployments serve reads. It is compatible with AWS ElastiCache Global Datastore.
  • Multi Sentinel mode provides the same active-passive arrangement across multiple Sentinel deployments.
  • Proxy mode supports active-active replication, including Redis Enterprise Active-Active databases and Azure active geo-replication.

Multi Cluster, Multi Sentinel and Proxy modes are available in Redisson PRO. For a practical walkthrough of a cross-region setup, see Redis Cross-Data Center Replication and Creating Regional Replicas With Multiple Redis Clusters on Java.

Frequently asked questions

Is Redis replication synchronous or asynchronous?
Asynchronous by default. The master acknowledges the write to the client before propagating it. The WAIT command can block until a given number of replicas have acknowledged, and WAITAOF can wait for fsync, but neither makes replication synchronous in the transactional sense.

How many replicas should a master have?
Two is the common baseline, because it allows one replica to be lost or taken out for maintenance while redundancy is retained. Each additional replica adds propagation load on the master; chained replication can relieve this in larger deployments.

Can you write to a replica?
Only if replica-read-only is disabled, and it is rarely a good idea. Data written locally to a replica is not propagated anywhere and is discarded at the next full resynchronization.

What is the difference between replication and persistence?
Replication copies data to other nodes; persistence (RDB or AOF) writes it to disk. They protect against different failures. Losing every node in a replication group loses the dataset unless persistence is also configured.

Does Valkey replication differ from Redis replication?
Not in its fundamentals. Valkey was forked from Redis 7.2.4 and retains the same replication design, commands and configuration directives. Redisson connects to either using the same configuration, with the valkey:// and valkeys:// URI schemes available alongside redis:// and rediss://.

Similar terms