Backend Development 9 min read

Enable Adaptive Cluster Topology Refresh in Spring Boot 2.3 for Seamless Redis Failover

This article demonstrates how to set up a Redis cluster, connect it with Spring Boot 2.3 using Lettuce, simulate a node failure, and configure Spring Boot's adaptive topology refresh to achieve automatic failover without application downtime.

Java Architecture Diary
Java Architecture Diary
Java Architecture Diary
Enable Adaptive Cluster Topology Refresh in Spring Boot 2.3 for Seamless Redis Failover

Background

In production we usually deploy Redis using a high‑availability cluster architecture, which provides data sharding and automatic node failover. The typical deployment topology is shown below:

Creating a Test Cluster

Use the pig4cloud/redis-cluster:4.0 image to spin up a six‑node Redis cluster test environment.

<code>docker run --name redis-cluster -d -e CLUSTER_ANNOUNCE_IP=HOST_IP \
-p 7000-7005:7000-7005 -p 17000-17005:17000-17005 pig4cloud/redis-cluster:4.0</code>

Viewing Cluster Nodes

<code>./redis-cli -h 172.17.0.111 -p 7000 -c
172.17.0.111:7000> cluster nodes
3d882206d40935beef84ff564b538d57369e4fd9 172.17.0.111:7003@17003 slave b8d24150df4a221c1045cd9a0696bd1972912d52 0 1591344590000 4 connected
b8d24150df4a221c1045cd9a0696bd1972912d52 172.17.0.111:7001@17001 master - 0 1591344590513 2 connected 5461-10922
c21167a6da7f8af31d2dd612d449cdf92ad2e7e9 172.17.0.111:7005@17005 slave 810baa140db6e008a137708f09d4335f5207ede3 0 1591344591000 6 connected
810baa140db6e008a137708f09d4335f5207ede3 172.17.0.111:7000@17000 myself,master - 0 1591344590000 1 connected 0-5460
05d2f9884d350a50ac9e38f575b57f19e864e74c 172.17.0.111:7004@17004 slave b3cf24a918d96a1949f49a1d7b3a965ff9dc858c 0 1591344590011 5 connected
b3cf24a918d96a1949f49a1d7b3a965ff9dc858c 172.17.0.111:7002@17002 master - 0 1591344591617 3 connected 10923-16383</code>

Application Layer Integration

Spring Boot 2.2 (default) uses Lettuce as the Redis client.

<code>spring:
  redis:
    cluster:
      nodes:
        - 172.17.0.111:7000
        - 172.17.0.111:7001
        - 172.17.0.111:7002
        - 172.17.0.111:7003
        - 172.17.0.111:7004
        - 172.17.0.111:7005
</code>

Simple

RedisTemplate

usage to set a key.

<code>@RestController
public class DemoController {
    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("/add")
    public String redis() {
        redisTemplate.opsForValue().set("k1", "v1");
        return "ok";
    }
}
</code>

Calling the endpoint:

<code>curl http://localhost:8080/add
ok</code>

The write operation is performed on node 7000.

<code>[channel=0x5ff7aa8f, /172.17.0.156:50783 -> /172.17.0.111:7000, epid=0x8] write() writeAndFlush command ClusterCommand [command=AsyncCommand [type=SET, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command], redirections=0, maxRedirections=5]
[channel=0x5ff7aa8f, /172.17.0.156:50783 -> /172.17.0.111:7000, epid=0x8] write() done
</code>

Simulating a Single‑Node Failure

Shut down node 7000.

<code>./redis-cli -h 172.17.0.111 -p 7000 -c
172.17.0.111:7000> SHUTDOWN
</code>

Watch the cluster logs (e.g.,

docker logs -f redis-cluster

) to see the failover election.

<code>23:S 05 Jun 08:24:49.387 # Starting a failover election for epoch 7.
29:M 05 Jun 08:24:49.388 # Failover auth granted to c21167a6da7f8af31d2dd612d449cdf92ad2e7e9 for epoch 7
... (additional log lines) ...
23:M 05 Jun 08:24:49.390 # Cluster state changed: ok
</code>

After the election, node 7005 becomes the new master (shown in the screenshot).

Application Layer Logs After Failure

Connection attempts to node 7000 are refused.

<code>io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /172.17.0.111:7000
Caused by: java.net.ConnectException: Connection refused
</code>

Further

redisTemplate

calls block because Lettuce does not automatically refresh the cluster view.

<code>curl http://localhost:8080/add
</code>

The client keeps trying to connect to the dead node based on the original slot mapping.

Dynamic Cluster Topology Detection

The client can automatically adapt to changes in the Redis cluster topology, enabling seamless failover.

In Spring Boot 2.3.0 you only need to enable this feature.

<code>spring:
  redis:
    lettuce:
      cluster:
        refresh:
          adaptive: true
</code>

Lettuce has supported this for a while, but Spring Data Redis only exposed it starting with Spring Boot 2.3.

Compatibility with Older Versions

To achieve the same effect in earlier releases, configure a

LettuceConnectionFactory

with a topology‑refresh option.

<code>@Bean
public LettuceConnectionFactory redisConnectionFactory(RedisProperties redisProperties) {
    RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
    // https://github.com/lettuce-io/lettuce-core/wiki/Redis-Cluster#user-content-refreshing-the-cluster-topology-view
    ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
        .enablePeriodicRefresh()
        .enableAllAdaptiveRefreshTriggers()
        .refreshPeriod(Duration.ofSeconds(5))
        .build();
    ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
        .topologyRefreshOptions(clusterTopologyRefreshOptions).build();
    // https://github.com/lettuce-io/lettuce-core/wiki/ReadFrom-Settings
    LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
        .readFrom(ReadFrom.REPLICA_PREFERRED)
        .clientOptions(clusterClientOptions).build();
    return new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);
}
</code>

References

[1] Spring Boot 2.3 新特性优雅停机详解 – https://juejin.im/post/5ec1d89de51d454ddf2367ab

[2] Spring Boot 2.3 新特性分层 JAR – https://juejin.im/post/5ecb1d41f265da76ec0079b2

[3] Lettuce Cluster Topology Refresh – https://github.com/lettuce-io/lettuce-core/wiki/Redis-Cluster#user-content-refreshing-the-cluster-topology-view

backend developmentSpring BootLettuceFailoverRedis ClusterAdaptive Refresh
Java Architecture Diary
Written by

Java Architecture Diary

Committed to sharing original, high‑quality technical articles; no fluff or promotional content.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.