Updated on 2026-08-27 GMT+08:00

Connecting to Redis on Lettuce (Java)

This section describes how to access a DCS Redis instance on Lettuce. For more information about how to use other Redis clients, visit the Redis official website.

In Spring Boot projects, Spring Data Redis has been already integrated with Jedis and Lettuce. Spring Boot 1.x is integrated with Jedis, and Spring Boot 2.x is integrated with Lettuce by default. Therefore, you do not need to manually import the Lettuce dependency in Spring Boot 2.x or later.

Notes and Constraints

Spring Boot must be 2.3.12.RELEASE or later, Lettuce must be 6.3.0.RELEASE or later, and Netty must be 4.1.100.Final or later.

Prerequisites

Pom Configuration

<!-- Import the spring-data-redis component. By default, the Lettuce SDK has been integrated. -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
   <groupId>io.lettuce</groupId>
   <artifactId>lettuce-core</artifactId>
   <version>6.3.0.RELEASE</version>
</dependency>

<dependency>
   <groupId>io.netty</groupId>
   <artifactId>netty-transport-native-epoll</artifactId>
   <version>4.1.100.Final</version>
   <classifier>linux-x86_64</classifier>
</dependency>

Configuration Based on the application.properties File

The configuration varies depending on the Spring Boot version. The following are the configurations for Spring Boot 2.x and Spring Boot 3.x.

  • Configuration for single-node, master/standby, read/write splitting, and Proxy Cluster instances
    # Redis host
    spring.redis.host=<host>
    # Redis port
    spring.redis.port=<port>
    # Redis database index
    spring.redis.database=0
    # Redis password
    spring.redis.password=<password>
    # Redis read/write timeout
    spring.redis.timeout=2000
  • Configuration for Cluster instances
    # Redis Cluster node information
    spring.redis.cluster.nodes=<ip:port>,<ip:port>,<ip:port>
    # Maximum number of Redis Cluster redirections
    spring.redis.cluster.max-redirects=3
    # Password of the Redis Cluster node
    spring.redis.password=<password>
    # Redis Cluster timeout
    spring.redis.timeout=2000
    # Whether to enable adaptive topology refresh
    spring.redis.lettuce.cluster.refresh.adaptive=true
    # Interval for adaptive topology refresh
    spring.redis.lettuce.cluster.refresh.period=10S
  • Configuration for single-node, master/standby, read/write splitting, and Proxy Cluster instances
    # Redis host
    spring.data.redis.host=<host>
    # Redis port
    spring.data.redis.port=<port>
    # Redis database index
    spring.data.redis.database=0
    # Redis password
    spring.data.redis.password=<password>
    # Redis read/write timeout
    spring.data.redis.timeout=2000
  • Configuration for Cluster instances
    # Redis Cluster node information
    spring.data.redis.cluster.nodes=<ip:port>,<ip:port>,<ip:port>
    # Maximum number of Redis Cluster redirections
    spring.data.redis.cluster.max-redirects=3
    # Password of the Redis Cluster node
    spring.data.redis.password=<password>
    # Redis Cluster timeout
    spring.data.redis.timeout=2000
    # Whether to enable adaptive topology refresh
    spring.data.redis.lettuce.cluster.refresh.adaptive=true
    # Interval for adaptive topology refresh
    spring.data.redis.lettuce.cluster.refresh.period=10S

Bean-based Configuration

  • Configuration for single-node, master/standby, read/write splitting, and Proxy Cluster instances
    import java.time.Duration;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
    import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
    import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
    
    import io.lettuce.core.ClientOptions;
    import io.lettuce.core.SocketOptions;
    
    /**
    * Lettuce non-pooling configuration (use either this or the application.properties configuration)
    */
    @Configuration
    public class RedisConfiguration {
    
        @Value("${redis.host}")
        private String redisHost;
    
        @Value("${redis.port:6379}")
        private Integer redisPort = 6379;
    
        @Value("${redis.database:0}")
        private Integer redisDatabase = 0;
    
        @Value("${redis.password:}")
        private String redisPassword;
    
        @Value("${redis.connect.timeout:2000}")
        private Integer redisConnectTimeout = 2000;
    
        @Value("${redis.read.timeout:2000}")
        private Integer redisReadTimeout = 2000;
        /**
         *  TCP_KEEPALIVE configuration parameters:
         *  Interval between two Keepalive probes = TCP_KEEPALIVE_TIME = 30
         *  Time when a connection must be idle before TCP Keepalive probes are sent = TCP_KEEPALIVE_TIME/3 = 10
         *  Number of Keepalive probes before a connection is dropped = TCP_KEEPALIVE_COUNT = 3
         */
        private static final int TCP_KEEPALIVE_TIME = 30;
    
        /**
         * TCP_USER_TIMEOUT Connection idle timeout, to resolve prolonged Lettuce client timeouts
         * refer: https://github.com/lettuce-io/lettuce-core/issues/2082
         */
        private static final int TCP_USER_TIMEOUT = 30;
    
        @Bean
        public RedisConnectionFactory redisConnectionFactory(LettuceClientConfiguration clientConfiguration) {
    
            RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration();
            standaloneConfiguration.setHostName(redisHost);
            standaloneConfiguration.setPort(redisPort);
            standaloneConfiguration.setDatabase(redisDatabase);
            standaloneConfiguration.setPassword(redisPassword);
    
            LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(standaloneConfiguration, clientConfiguration);
            connectionFactory.setDatabase(redisDatabase);
            return connectionFactory;
        }
    
        @Bean
        public LettuceClientConfiguration clientConfiguration() {
    
    
            SocketOptions socketOptions = SocketOptions.builder()
                .keepAlive(SocketOptions.KeepAliveOptions.builder()
                    // Interval between two Keepalive probes
                    .idle(Duration.ofSeconds(TCP_KEEPALIVE_TIME))
                    // Time when a connection must be idle before TCP Keepalive probes are sent
                    .interval(Duration.ofSeconds(TCP_KEEPALIVE_TIME/3))
                    // Number of Keepalive probes before a connection is dropped
                    .count(3)
                    // Whether to enable Keepalive
                    .enable()
                    .build())
                .tcpUserTimeout(SocketOptions.TcpUserTimeoutOptions.builder()
                    // Resolve the prolonged timeouts caused by server RST.
                    .tcpUserTimeout(Duration.ofSeconds(TCP_USER_TIMEOUT))
                    .enable()
                    .build())
                // Set the TCP connection timeout.
                .connectTimeout(Duration.ofMillis(redisConnectTimeout))
                .build();
    
            ClientOptions clientOptions = ClientOptions.builder()
                    .autoReconnect(true)
                    .pingBeforeActivateConnection(true)
                    .cancelCommandsOnReconnectFailure(false)
                    .disconnectedBehavior(ClientOptions.DisconnectedBehavior.ACCEPT_COMMANDS)
                    .socketOptions(socketOptions)
                    .build();
    
    
            LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
                    .commandTimeout(Duration.ofMillis(redisReadTimeout))
                    // You do not need to set readFrom for Proxy Cluster instances.
                    .readFrom(ReadFrom.MASTER)
                    .clientOptions(clientOptions)
                    .build();
    
            return clientConfiguration;
        }
    }
  • Pooling configuration for single-node, master/standby, read/write splitting, and Proxy Cluster instances
    Importing pooling components
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.11.1</version>
    </dependency>

    Code configuration

    import java.time.Duration;
    
    import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
    import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
    import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
    import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
    
    import io.lettuce.core.ClientOptions;
    import io.lettuce.core.SocketOptions;
    
    /**
    * Lettuce pooling configuration
    */
    @Configuration
    public class RedisPoolConfiguration {
        @Value("${redis.host}")
        private String redisHost;
    
        @Value("${redis.port:6379}")
        private Integer redisPort = 6379;
    
        @Value("${redis.database:0}")
        private Integer redisDatabase = 0;
    
        @Value("${redis.password:}")
        private String redisPassword;
    
        @Value("${redis.connect.timeout:2000}")
        private Integer redisConnectTimeout = 2000;
    
        @Value("${redis.read.timeout:2000}")
        private Integer redisReadTimeout = 2000;
    
        @Value("${redis.pool.minSize:50}")
        private Integer redisPoolMinSize = 50;
    
        @Value("${redis.pool.maxSize:200}")
        private Integer redisPoolMaxSize = 200;
    
        @Value("${redis.pool.maxWaitMillis:2000}")
        private Integer redisPoolMaxWaitMillis = 2000;
    
        @Value("${redis.pool.softMinEvictableIdleTimeMillis:1800000}")
        private Integer redisPoolSoftMinEvictableIdleTimeMillis = 30 * 60 * 1000;
    
        @Value("${redis.pool.timeBetweenEvictionRunsMillis:60000}")
        private Integer redisPoolBetweenEvictionRunsMillis = 60 * 1000;
        /**
         *  TCP_KEEPALIVE configuration parameters:
         *  Interval between two Keepalive probes = TCP_KEEPALIVE_TIME = 30
         *  Time when a connection must be idle before TCP Keepalive probes are sent = TCP_KEEPALIVE_TIME/3 = 10
         *  Number of Keepalive probes before a connection is dropped = TCP_KEEPALIVE_COUNT = 3
         */
        private static final int TCP_KEEPALIVE_TIME = 30;
    
        /**
         * TCP_USER_TIMEOUT Connection idle timeout, to resolve prolonged Lettuce client timeouts
         * refer: https://github.com/lettuce-io/lettuce-core/issues/2082
         */
        private static final int TCP_USER_TIMEOUT = 30;
    
        @Bean
        public RedisConnectionFactory redisConnectionFactory(LettuceClientConfiguration clientConfiguration) {
    
            RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration();
            standaloneConfiguration.setHostName(redisHost);
            standaloneConfiguration.setPort(redisPort);
            standaloneConfiguration.setDatabase(redisDatabase);
            standaloneConfiguration.setPassword(redisPassword);
    
            LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(standaloneConfiguration, clientConfiguration);
            connectionFactory.setDatabase(redisDatabase);
            // Disable connection sharing to allow connection pooling to take effect.
            connectionFactory.setShareNativeConnection(false);
            return connectionFactory;
        }
    
        @Bean
        public LettuceClientConfiguration clientConfiguration() {
    
    
            SocketOptions socketOptions = SocketOptions.builder()
                .keepAlive(SocketOptions.KeepAliveOptions.builder()
                    // Interval between two Keepalive probes
                    .idle(Duration.ofSeconds(TCP_KEEPALIVE_TIME))
                    // Time when a connection must be idle before TCP Keepalive probes are sent
                    .interval(Duration.ofSeconds(TCP_KEEPALIVE_TIME/3))
                    // Number of Keepalive probes before a connection is dropped
                    .count(3)
                    // Whether to enable Keepalive
                    .enable()
                    .build())
                .tcpUserTimeout(SocketOptions.TcpUserTimeoutOptions.builder()
                    // Resolve the prolonged timeouts caused by server RST.
                    .tcpUserTimeout(Duration.ofSeconds(TCP_USER_TIMEOUT))
                    .enable()
                    .build())
                // Set the TCP connection timeout.
                .connectTimeout(Duration.ofMillis(redisConnectTimeout))
                .build();
    
            ClientOptions clientOptions = ClientOptions.builder()
                    .autoReconnect(true)
                    .pingBeforeActivateConnection(true)
                    .cancelCommandsOnReconnectFailure(false)
                    .disconnectedBehavior(ClientOptions.DisconnectedBehavior.ACCEPT_COMMANDS)
                    .socketOptions(socketOptions)
                    .build();
    
    
            LettucePoolingClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder()
                    .poolConfig(poolConfig())
                    .commandTimeout(Duration.ofMillis(redisReadTimeout))
                    .clientOptions(clientOptions)
                    // You do not need to set readFrom for Proxy Cluster instances.
                    .readFrom(ReadFrom.MASTER)
                    .build();
            return clientConfiguration;
        }
    
        private GenericObjectPoolConfig redisPoolConfig() {
            GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
            // Minimum number of connections in the connection pool
            poolConfig.setMinIdle(redisPoolMinSize);
            // Maximum number of idle connections in the connection pool
            poolConfig.setMaxIdle(redisPoolMaxSize);
            // Maximum number of connections in the connection pool
            poolConfig.setMaxTotal(redisPoolMaxSize);
            // Whether to wait for an available connection when the connection pool is exhausted. The default value true indicates to wait. setMaxWait takes effect only when the value is true.
            poolConfig.setBlockWhenExhausted(true);
            // Maximum wait time for obtaining a connection from the pool when the pool is exhausted. The default value -1 indicates to wait indefinitely for a connection to become available.
            poolConfig.setMaxWait(Duration.ofMillis(redisPoolMaxWaitMillis));
            // Whether to validate a new connection using a ping command after it is created. The default value is false.
            poolConfig.setTestOnCreate(false);
            // Whether to validate a connection using a ping command every time a connection is borrowed from the pool. The default value is false. When the service traffic is heavy, you are advised to set this parameter to false to reduce overhead.
            poolConfig.setTestOnBorrow(true);
            // Whether to validate a connection using a ping command every time a connection is returned to the pool. The default value is false. When the service traffic is heavy, you are advised to set this parameter to false to reduce overhead.
            poolConfig.setTestOnReturn(false);
            // Whether to check for idle connections. If the value is false, idle connections are not evicted.
            poolConfig.setTestWhileIdle(true);
            // Duration after which an idle connection is evicted. If the actual idle duration of a connection is greater than this value and the number of idle connections is greater than the minimum number of idle connections, the connection is directly evicted.
            poolConfig.setSoftMinEvictableIdleTime(Duration.ofMillis(redisPoolSoftMinEvictableIdleTimeMillis));
            // Disable eviction of idle connections based on MinEvictableIdleTimeMillis.
            poolConfig.setMinEvictableIdleTime(Duration.ofMillis(-1));
            // Interval for checking and evicting idle connections. The default value is 60s.
            poolConfig.setTimeBetweenEvictionRuns(Duration.ofMillis(redisPoolBetweenEvictionRunsMillis));
            return poolConfig;
        }
    }
  • Configuration for Cluster instances
    import java.time.Duration;
    import java.util.ArrayList;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisClusterConfiguration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.connection.RedisNode;
    import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
    import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
    
    import io.lettuce.core.ClientOptions;
    import io.lettuce.core.SocketOptions;
    import io.lettuce.core.cluster.ClusterClientOptions;
    import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
    
    /**
    * Lettuce Cluster non-pooling configuration (use either this or the application.properties configuration)
    */
    @Configuration
    public class RedisConfiguration {
    
        @Value("${redis.cluster.nodes}")
        private String redisClusterNodes;
    
        @Value("${redis.cluster.maxDirects:3}")
        private Integer redisClusterMaxDirects;
    
        @Value("${redis.password:}")
        private String redisPassword;
    
        @Value("${redis.connect.timeout:2000}")
        private Integer redisConnectTimeout = 2000;
    
        @Value("${redis.read.timeout:2000}")
        private Integer redisReadTimeout = 2000;
    
        @Value("${redis.cluster.topology.refresh.period.millis:10000}")
        private Integer redisClusterTopologyRefreshPeriodMillis = 10000;
        /**
         *  TCP_KEEPALIVE configuration parameters:
         *  Interval between two Keepalive probes = TCP_KEEPALIVE_TIME = 30
         *  Time when a connection must be idle before TCP Keepalive probes are sent = TCP_KEEPALIVE_TIME/3 = 10
         *  Number of Keepalive probes before a connection is dropped = TCP_KEEPALIVE_COUNT = 3
         */
        private static final int TCP_KEEPALIVE_TIME = 30;
    
        /**
         * TCP_USER_TIMEOUT Connection idle timeout, to resolve prolonged Lettuce client timeouts
         * refer: https://github.com/lettuce-io/lettuce-core/issues/2082
         */
        private static final int TCP_USER_TIMEOUT = 30;
    
        @Bean
        public RedisConnectionFactory redisConnectionFactory(LettuceClientConfiguration clientConfiguration) {
    
            RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();
    
            List<RedisNode> clusterNodes = new ArrayList<>();
            for (String clusterNodeStr : redisClusterNodes.split(",")) {
                String[] nodeInfo = clusterNodeStr.split(":");
                clusterNodes.add(new RedisNode(nodeInfo[0], Integer.valueOf(nodeInfo[1])));
            }
            clusterConfiguration.setClusterNodes(clusterNodes);
    
            clusterConfiguration.setPassword(redisPassword);
            clusterConfiguration.setMaxRedirects(redisClusterMaxDirects);
    
            LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfiguration, clientConfiguration);
            return connectionFactory;
        }
    
        @Bean
        public LettuceClientConfiguration clientConfiguration() {
            SocketOptions socketOptions = SocketOptions.builder()
                .keepAlive(SocketOptions.KeepAliveOptions.builder()
                    // Interval between two Keepalive probes
                    .idle(Duration.ofSeconds(TCP_KEEPALIVE_TIME))
                    // Time when a connection must be idle before TCP Keepalive probes are sent
                    .interval(Duration.ofSeconds(TCP_KEEPALIVE_TIME/3))
                    // Number of Keepalive probes before a connection is dropped
                    .count(3)
                    // Whether to enable Keepalive
                    .enable()
                    .build())
                .tcpUserTimeout(SocketOptions.TcpUserTimeoutOptions.builder()
                    // Resolve the prolonged timeouts caused by server RST.
                    .tcpUserTimeout(Duration.ofSeconds(TCP_USER_TIMEOUT))
                    .enable()
                    .build())
                // Set the TCP connection timeout.
                .connectTimeout(Duration.ofMillis(redisConnectTimeout))
                .build();
    
            ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
                    .enableAllAdaptiveRefreshTriggers()
                    .enablePeriodicRefresh(Duration.ofMillis(redisClusterTopologyRefreshPeriodMillis))
                    .build();
    
            ClusterClientOptions clientOptions = ClusterClientOptions.builder()
                    .autoReconnect(true)
                    .pingBeforeActivateConnection(true)
                    .cancelCommandsOnReconnectFailure(false)
                    .disconnectedBehavior(ClientOptions.DisconnectedBehavior.ACCEPT_COMMANDS)
                    .socketOptions(socketOptions)
                    .topologyRefreshOptions(topologyRefreshOptions)
                    .build();
    
    
            LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
                    .commandTimeout(Duration.ofMillis(redisReadTimeout))
                    .readFrom(ReadFrom.MASTER)
                    .clientOptions(clientOptions)
                    .build();
            return clientConfiguration;
        }
    }
  • Cluster instance pooling configuration
    Importing pooling components
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.11.1</version>
    </dependency>

    Code configuration

    import java.time.Duration;
    import java.util.ArrayList;
    import java.util.List;
    
    import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisClusterConfiguration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.connection.RedisNode;
    import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
    import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
    import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
    
    import io.lettuce.core.ClientOptions;
    import io.lettuce.core.SocketOptions;
    import io.lettuce.core.cluster.ClusterClientOptions;
    import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
    
    /**
    * Lettuce pooling configuration
    */
    @Configuration
    public class RedisPoolConfiguration {
    
        @Value("${redis.cluster.nodes}")
        private String redisClusterNodes;
    
        @Value("${redis.cluster.maxDirects:3}")
        private Integer redisClusterMaxDirects;
    
        @Value("${redis.password:}")
        private String redisPassword;
    
        @Value("${redis.connect.timeout:2000}")
        private Integer redisConnectTimeout = 2000;
    
        @Value("${redis.read.timeout:2000}")
        private Integer redisReadTimeout = 2000;
    
        @Value("${redis.cluster.topology.refresh.period.millis:10000}")
        private Integer redisClusterTopologyRefreshPeriodMillis = 10000;
    
        @Value("${redis.pool.minSize:50}")
        private Integer redisPoolMinSize = 50;
    
        @Value("${redis.pool.maxSize:200}")
        private Integer redisPoolMaxSize = 200;
    
        @Value("${redis.pool.maxWaitMillis:2000}")
        private Integer redisPoolMaxWaitMillis = 2000;
    
        @Value("${redis.pool.softMinEvictableIdleTimeMillis:1800000}")
        private Integer redisPoolSoftMinEvictableIdleTimeMillis = 30 * 60 * 1000;
    
        @Value("${redis.pool.timeBetweenEvictionRunsMillis:60000}")
        private Integer redisPoolBetweenEvictionRunsMillis = 60 * 1000;
        /**
         *  TCP_KEEPALIVE configuration parameters:
         *  Interval between two Keepalive probes = TCP_KEEPALIVE_TIME = 30
         *  Time when a connection must be idle before TCP Keepalive probes are sent = TCP_KEEPALIVE_TIME/3 = 10
         *  Number of Keepalive probes before a connection is dropped = TCP_KEEPALIVE_COUNT = 3
         */
        private static final int TCP_KEEPALIVE_TIME = 30;
    
        /**
         * TCP_USER_TIMEOUT Connection idle timeout, to resolve prolonged Lettuce client timeouts
         * refer: https://github.com/lettuce-io/lettuce-core/issues/2082
         */
        private static final int TCP_USER_TIMEOUT = 30;
    
        @Bean
        public RedisConnectionFactory redisConnectionFactory(LettuceClientConfiguration clientConfiguration) {
    
            RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();
    
            List<RedisNode> clusterNodes = new ArrayList<>();
            for (String clusterNodeStr : redisClusterNodes.split(",")) {
                String[] nodeInfo = clusterNodeStr.split(":");
                clusterNodes.add(new RedisNode(nodeInfo[0], Integer.valueOf(nodeInfo[1])));
            }
            clusterConfiguration.setClusterNodes(clusterNodes);
    
            clusterConfiguration.setPassword(redisPassword);
            clusterConfiguration.setMaxRedirects(redisClusterMaxDirects);
    
            LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfiguration, clientConfiguration);
            // Disable connection sharing to allow connection pooling to take effect.
            connectionFactory.setShareNativeConnection(false);
            return connectionFactory;
        }
    
        @Bean
        public LettuceClientConfiguration clientConfiguration() {
            SocketOptions socketOptions = SocketOptions.builder()
                .keepAlive(SocketOptions.KeepAliveOptions.builder()
                    // Interval between two Keepalive probes
                    .idle(Duration.ofSeconds(TCP_KEEPALIVE_TIME))
                    // Time when a connection must be idle before TCP Keepalive probes are sent
                    .interval(Duration.ofSeconds(TCP_KEEPALIVE_TIME/3))
                    // Number of Keepalive probes before a connection is dropped
                    .count(3)
                    // Whether to enable Keepalive
                    .enable()
                    .build())
                .tcpUserTimeout(SocketOptions.TcpUserTimeoutOptions.builder()
                    // Resolve the prolonged timeouts caused by server RST.
                    .tcpUserTimeout(Duration.ofSeconds(TCP_USER_TIMEOUT))
                    .enable()
                    .build())
                // Set the TCP connection timeout.
                .connectTimeout(Duration.ofMillis(redisConnectTimeout))
                .build();
    
            ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
                    .enableAllAdaptiveRefreshTriggers()
                    .enablePeriodicRefresh(Duration.ofMillis(redisClusterTopologyRefreshPeriodMillis))
                    .build();
    
            ClusterClientOptions clientOptions = ClusterClientOptions.builder()
                    .autoReconnect(true)
                    .pingBeforeActivateConnection(true)
                    .cancelCommandsOnReconnectFailure(false)
                    .disconnectedBehavior(ClientOptions.DisconnectedBehavior.ACCEPT_COMMANDS)
                    .socketOptions(socketOptions)
                    .topologyRefreshOptions(topologyRefreshOptions)
                    .build();
    
    
            LettucePoolingClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder()
                    .poolConfig(poolConfig())
                    .commandTimeout(Duration.ofMillis(redisReadTimeout))
                    .clientOptions(clientOptions)
                    .readFrom(ReadFrom.MASTER)
                    .build();
            return clientConfiguration;
        }
    
        private GenericObjectPoolConfig poolConfig() {
            GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
            // Minimum number of connections in the connection pool
            poolConfig.setMinIdle(redisPoolMinSize);
            // Maximum number of idle connections in the connection pool
            poolConfig.setMaxIdle(redisPoolMaxSize);
            // Maximum number of connections in the connection pool
            poolConfig.setMaxTotal(redisPoolMaxSize);
            // Whether to wait for an available connection when the connection pool is exhausted. The default value true indicates to wait. setMaxWait takes effect only when the value is true.
            poolConfig.setBlockWhenExhausted(true);
            // Maximum wait time for obtaining a connection from the pool when the pool is exhausted. The default value -1 indicates to wait indefinitely for a connection to become available.
            poolConfig.setMaxWait(Duration.ofMillis(redisPoolMaxWaitMillis));
            // Whether to validate a new connection using a ping command after it is created. The default value is false.
            poolConfig.setTestOnCreate(false);
            // Whether to validate a connection using a ping command every time a connection is borrowed from the pool. The default value is false. When the service traffic is heavy, you are advised to set this parameter to false to reduce overhead.
            poolConfig.setTestOnBorrow(true);
            // Whether to validate a connection using a ping command every time a connection is returned to the pool. The default value is false. When the service traffic is heavy, you are advised to set this parameter to false to reduce overhead.
            poolConfig.setTestOnReturn(false);
            // Whether to check for idle connections. If the value is false, idle connections are not evicted.
            poolConfig.setTestWhileIdle(true);
            // Validate connections while they are idle in the pool.
            poolConfig.setMinEvictableIdleTime(Duration.ofMillis(-1));
            // Duration after which an idle connection is evicted. If the actual idle duration of a connection is greater than this value and the number of idle connections is greater than the minimum number of idle connections, the connection is directly evicted without following the default eviction policy MinEvictableIdleTimeMillis.
            poolConfig.setSoftMinEvictableIdleTime(Duration.ofMillis(redisPoolSoftMinEvictableIdleTimeMillis));
            // Interval for checking and evicting idle connections. The default value is 60s.
            poolConfig.setTimeBetweenEvictionRuns(Duration.ofMillis(redisPoolBetweenEvictionRunsMillis));
    
            return poolConfig;
        }
    
    }

(Optional) SSL Connection Configuration

If SSL is enabled for the instance, use the following content to replace the LettuceClientConfiguration constructor clientConfiguration() in Bean-based Configuration for connecting to the instance via SSL. For details about whether your Redis instances support SSL, see Transmitting DCS Redis Data with SSL Encryption.

  • Configuration for single-node, master/standby, read/write splitting, and Proxy Cluster instances
    @Bean
    public LettuceClientConfiguration clientConfiguration() {
        SocketOptions socketOptions = SocketOptions.builder()
                .keepAlive(SocketOptions.KeepAliveOptions.builder()
                    // Interval between two Keepalive probes
                    .idle(Duration.ofSeconds(TCP_KEEPALIVE_TIME))
                    // Time when a connection must be idle before TCP Keepalive probes are sent
                    .interval(Duration.ofSeconds(TCP_KEEPALIVE_TIME/3))
                    // Number of Keepalive probes before a connection is dropped
                    .count(3)
                    // Whether to enable Keepalive
                    .enable()
                    .build())
                .tcpUserTimeout(SocketOptions.TcpUserTimeoutOptions.builder()
                    // Resolve the prolonged timeouts caused by server RST.
                    .tcpUserTimeout(Duration.ofSeconds(TCP_USER_TIMEOUT))
                    .enable()
                    .build())
                // Set the TCP connection timeout.
                .connectTimeout(Duration.ofMillis(redisConnectTimeout))
                .build();
    
        SslOptions sslOptions = SslOptions.builder()
            .trustManager(new File(certificationPath))
            .build();
    
        ClientOptions clientOptions = ClientOptions.builder()
            .sslOptions(sslOptions)
            .autoReconnect(true)
            .pingBeforeActivateConnection(true)
            .cancelCommandsOnReconnectFailure(false)
            .disconnectedBehavior(ClientOptions.DisconnectedBehavior.ACCEPT_COMMANDS)
            .socketOptions(socketOptions)
            .build();
        LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
            .commandTimeout(Duration.ofMillis(redisReadTimeout))
            // You do not need to set readFrom for Proxy Cluster instances.
            .readFrom(ReadFrom.MASTER)
            .clientOptions(clientOptions)
            .useSsl()
            .build();
    
        return clientConfiguration;
    }
  • Configuration for Cluster instances
    @Bean
    public LettuceClientConfiguration clientConfiguration() {
        SocketOptions socketOptions = SocketOptions.builder()
                .keepAlive(SocketOptions.KeepAliveOptions.builder()
                    // Interval between two Keepalive probes
                    .idle(Duration.ofSeconds(TCP_KEEPALIVE_TIME))
                    // Time when a connection must be idle before TCP Keepalive probes are sent
                    .interval(Duration.ofSeconds(TCP_KEEPALIVE_TIME/3))
                    // Number of Keepalive probes before a connection is dropped
                    .count(3)
                    // Whether to enable Keepalive
                    .enable()
                    .build())
                .tcpUserTimeout(SocketOptions.TcpUserTimeoutOptions.builder()
                    // Resolve the prolonged timeouts caused by server RST.
                    .tcpUserTimeout(Duration.ofSeconds(TCP_USER_TIMEOUT))
                    .enable()
                    .build())
                // Set the TCP connection timeout.
                .connectTimeout(Duration.ofMillis(redisConnectTimeout))
                .build();
    
        SslOptions sslOptions = SslOptions.builder()
            .trustManager(new File(certificationPath))
            .build();
    
        ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
            .enableAllAdaptiveRefreshTriggers()
            .enablePeriodicRefresh(Duration.ofMillis(redisClusterTopologyRefreshPeriodMillis))
            .build();
    
        ClusterClientOptions clientOptions = ClusterClientOptions.builder()
            .sslOptions(sslOptions)
            .autoReconnect(true)
            .pingBeforeActivateConnection(true)
            .cancelCommandsOnReconnectFailure(false)
            .disconnectedBehavior(ClientOptions.DisconnectedBehavior.ACCEPT_COMMANDS)
            .socketOptions(socketOptions)
            .topologyRefreshOptions(topologyRefreshOptions)
            .build();
    
    
        LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
            .commandTimeout(Duration.ofMillis(redisReadTimeout))
            .readFrom(ReadFrom.MASTER)
            .clientOptions(clientOptions)
            .useSsl()
            .build();
    
        return clientConfiguration;
    }

Parameters

Table 1 LettuceConnectionFactory parameters

Parameter

Type

Default Value

Description

configuration

RedisConfiguration

-

Redis connection configuration. The following two subclasses are commonly used:

  • RedisStandaloneConfiguration
  • RedisClusterConfiguration

clientConfiguration

LettuceClientConfiguration

-

Client configuration. The following subclass is commonly used:

LettucePoolingClientConfiguration (used for pooling)

shareNativeConnection

boolean

true

Whether to use shared connections. The default value is true. If a connection pool is used, set this parameter to false.

Table 2 RedisStandaloneConfiguration parameters

Parameter

Default Value

Description

hostName

localhost

IP address/domain name for connecting to a DCS Redis instance.

port

6379

Port number for setting up the connection.

database

0

Database index.

password

-

Password for connecting to a DCS Redis instance. If password-free access is enabled for the instance, you do not need to enter the password. If you forget the password or need to reset it, see Resetting an Instance Password.

  • If you use the password set during DCS Redis instance creation (the password of the default account of the instance), change it to the actual password.
  • If you use an ACL account to connect to the instance, set the instance password in the format of {username:password}. For details about how to create or view an ACL account, see Configuring ACL Accounts for DCS Redis Instances.
Table 3 RedisClusterConfiguration parameters

Parameter

Description

clusterNodes

Cluster node connection information, including the node IP address and port number.

maxRedirects

Maximum number of Cluster redirections. The recommended value is 3.

password

Password for connecting to a DCS Redis instance. If password-free access is enabled for the instance, you do not need to enter the password. If you forget the password or need to reset it, see Resetting an Instance Password.

  • If you use the password set during DCS Redis instance creation (the password of the default account of the instance), change it to the actual password.
  • If you use an ACL account to connect to the instance, set the instance password in the format of {username:password}. For details about how to create or view an ACL account, see Configuring ACL Accounts for DCS Redis Instances.
Table 4 LettuceClientConfiguration parameters

Parameter

Type

Default Value

Description

timeout

Duration

60s

Command timeout: The recommended value is 2s.

clientOptions

ClientOptions

-

Configuration options.

readFrom

readFrom

MASTER

Read mode. The recommended value is MASTER. Other configurations may cause access failures in failover scenarios.

Table 5 LettucePoolingClientConfiguration parameters

Parameter

Type

Default Value

Description

timeout

Duration

60s

Command timeout: The recommended value is 2s.

clientOptions

ClientOptions

-

Configuration options.

poolConfig

GenericObjectPoolConfig

-

Connection pool configurations.

readFrom

readFrom

MASTER

Read mode. The recommended value is MASTER. Other configurations may cause access failures in failover scenarios.

Table 6 ClientOptions parameters

Parameter

Type

Default Value

Description

autoReconnect

boolean

true

Whether to automatically initiate a reconnection after a disconnection. The recommended value is true.

pingBeforeActivateConnection

boolean

true

Whether to use the PING/PONG mechanism to test connectivity after a connection is created. The recommended value is true.

cancelCommandsOnReconnectFailure

boolean

true

Whether to cancel the commands in the queue when the reconnection fails. The recommended value is false.

disconnectedBehavior

DisconnectedBehavior

DisconnectedBehavior.DEFAULT

Action to be taken when the connection is dropped. The recommended value is ACCEPT_COMMANDS.

  • DEFAULT: When autoReconnect is set to true, commands are allowed to wait in queue. When autoReconnect is set to false, commands are not allowed to wait in queue.
  • ACCEPT_COMMANDS: Commands are allowed to wait in queue.
  • REJECT_COMMANDS: Commands are not allowed to wait in queue.

socketOptions

SocketOptions

-

Network configurations.

Table 7 SocketOptions parameters

Parameter

Default Value

Description

connectTimeout

10s

Connection timeout: The recommended value is 2s.

Table 8 GenericObjectPoolConfig parameters

Parameter

Default Value

Description

minIdle

-

Minimum number of connections in the connection pool.

maxIdle

-

Maximum number of idle connections in the connection pool.

maxTotal

-

Maximum number of connections in the connection pool.

blockWhenExhausted

true

Whether to wait for an available connection when the connection pool is exhausted. The default value true indicates to wait. maxWaitMillis takes effect only when this parameter is set to true.

maxWaitMillis

-1

Maximum wait time for obtaining a connection from the pool when the pool is exhausted. The default value -1 indicates to wait indefinitely for a connection to become available.

testOnCreate

false

Whether to validate a new connection using a ping command after it is created. The default value is false.

testOnBorrow

false

Whether to validate a connection using a ping command every time a connection is borrowed from the pool. The default value is false. When the service traffic is heavy, you are advised to set this parameter to false to reduce overhead.

testOnReturn

false

Whether to validate a connection using a ping command every time a connection is returned to the pool. The default value is false. When the service traffic is heavy, you are advised to set this parameter to false to reduce overhead.

testWhileIdle

false

Whether to check for idle connections. If the value is false, idle connections are not evicted. The recommended value is true.

softMinEvictableIdleTimeMillis

-1

Duration after which an idle connection is evicted, in milliseconds. If the actual idle duration of a connection is greater than this value and the number of idle connections is greater than the minimum number of idle connections, the connection is directly evicted. The recommended value is 1800000.

minEvictableIdleTimeMillis

1800000

Minimum time a connection may remain idle in the pool before it is eligible for eviction. The recommended value is -1, indicating that this policy is disabled, and the softMinEvictableIdleTimeMillis policy is used.

timeBetweenEvictionRunsMillis

-1

Interval for checking and evicting idle connections, in milliseconds. The recommended value is 60000.

Recommended DCS Instance Configurations

  • Connection pooling

    Unlike Jedis relying on the Blocking I/O (BIO) model, Lettuce communicates with the Redis server via an underlying Netty-based Non-blocking I/O (NIO) framework. By leveraging long-lived connections and command queues, Lettuce utilizes TCP's ordered delivery to enable request pipelining. While a single connection can sustain 3000 to 5000 QPS, it is recommended to keep the production traffic no more than 3000 QPS. Lettuce does not support pooling, and pooling is disabled by default in Spring Boot. To enable pooling, you need to manually import the commons-pool2 component and disable LettuceConnectionFactory.shareNativeConnection (connection sharing).

    By default, each Lettuce connection requires an I/O thread pool and a computation thread pool to support I/O event reads and asynchronous event processing. If you configure Lettuce with a connection pool, every connection spins up two thread pools, leading to excessive memory overhead. Due to Lettuce's underlying model implementation and its efficient processing for single connections, you are not advised to use Lettuce with a connection pool.

  • Topology refresh

    When connecting to a Redis Cluster instance, Lettuce randomly selects a node from the seed list and executes CLUSTER NODES during initialization to obtain the cluster's slot topology. Subsequent operations such as cluster scaling and master/standby switchover will cause topology changes. By default, Lettuce is unaware of these changes. You need to manually enable adaptive topology refresh.

    • Configuration based on the application.properties file
      # Enable adaptive topology refresh.
      spring.redis.lettuce.cluster.refresh.adaptive=true
      # Allow the topology to be refreshed every 10 seconds.
      spring.redis.lettuce.cluster.refresh.period=10S
    • Configuration by calling APIs
      ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
          .enableAllAdaptiveRefreshTriggers()
          .enablePeriodicRefresh(Duration.ofMillis(redisClusterTopologyRefreshPeriodMillis))
          .build();
      
      ClusterClientOptions clientOptions = ClusterClientOptions.builder()
              ...
              ...
              .topologyRefreshOptions(topologyRefreshOptions)
              .build();
  • Blast radius

    Lettuce couples single long-lived connections with command queues in its underlying design. Any network jitter, intermittent disconnection, or connection deadness will adversely affect all requests. In particular, if a connection becomes inactive, TCP retransmission is triggered until the retransmission times out and the connection is torn down. Requests cannot be restored until the connection is reestablished. During the retransmission, requests continuously back up within the queue, making it highly likely for upper-layer services to experience cascading timeouts. Additionally, if the retransmission timeout is excessively long due to default OS kernel configurations, the service system may remain unavailable for an extended period. Therefore, you are advised to use Jedis instead of Lettuce.

Related Document

When accessing Redis fails, see Troubleshooting Redis Connection Failures.