通过Lettuce连接GeminiDB Redis实例
本章节主要介绍使用Lettuce客户端连接GeminiDB Redis实例。
在Spring Boot项目中,Spring-Data-Redis已提供了对Jedis、Lettuce的集成适配。此外,Spring Boot 1.x默认集成Jedis,而从Spring Boot 2.x开始,默认切换为Lettuce。 因此,若您使用的是Spring Boot 2.x或更高版本,想要使用Lettuce,无需手动添加其依赖包,系统已为您默认集成。
使用须知
- 请确保Spring Boot版本不低于2.3.12.RELEASE,Lettuce版本不低于6.3.0.RELEASE,Netty版本不低于4.1.100.Final。
- Lettuce 可用于连接 GeminiDB Redis,但线上生产应用不建议优先选择 Lettuce。若业务无强依赖,建议优先使用 Jedis 或 Redisson;若必须使用 Lettuce,请按本文配置建议设置连接池、超时、拓扑刷新和读模式,并在上线前完成故障切换和高并发压测验证。
前提条件
配置建议
- 连接地址配置
针对主备版、Proxy集群版或Cluster集群版,请统一填写实例的“负载均衡地址”以确保连接时的高可用, 您可以单击实例名称,进入“基本信息”页面,在网络信息区域获取“负载均衡地址”。

- 连接池化
Lettuce底层采用基于Netty的NIO模式与Redis Server通信,与Jedis使用的BIO模式不同。其底层利用长连接与队列相结合的方式,借助TCP的有序发送与接收特性,实现多请求的并发发送与多响应的并发接收。单条连接在正常情况下可以支撑3K~5K的QPS(每秒请求数),在生产系统中建议不要超过3K。
需要注意的是,Lettuce本身不支持连接池化,并且在Spring Boot中默认没有启用连接池化。如需启用池化功能,需要手动引入commons-pool2组件,并关闭 LettuceConnectionFactory.shareNativeConnection(共享连接),从而实现池化支持。
然而,由于每条Lettuce连接默认需要配置两个线程池(-I/O thread pools、computation thread pool),用于支持I/O事件的读取和异步事件的处理。如果配置为连接池方式进行使用,每个连接都将会创建两个线程池,对内存资源的占用偏高。结合Lettuce的底层模型实现方式以及单连接的高处理能力,我们不建议通过池化的方式来使用Lettuce。
- 拓扑刷新
在连接Cluster集群版的GeminiDB Redis实例时,Lettuce在初始化阶段会随机向配置的节点列表发送CLUSTER NODES命令,以获取集群中slot的分布信息。然而,后续集群发生扩缩容、主备切换等操作,会导致拓扑结构发生变化,Lettuce默认是不会自动感知这些变化的。为了使Lettuce主动感知并更新集群拓扑信息,需要手动开启相关配置,如下所示:
- 基于application.properties配置
# 开启自适应拓扑刷新 spring.redis.lettuce.cluster.refresh.adaptive=true # 开启每10s定时刷新拓扑结构 spring.redis.lettuce.cluster.refresh.period=10S
- 基于API配置
ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder() .enableAllAdaptiveRefreshTriggers() .enablePeriodicRefresh(Duration.ofMillis(redisClusterTopologyRefreshPeriodMillis)) .build(); ClusterClientOptions clientOptions = ClusterClientOptions.builder() ... ... .topologyRefreshOptions(topologyRefreshOptions) .build();
- 基于application.properties配置
操作步骤
步骤一:Pom配置
<!-- 引入spring-data-redis组件,默认已集成Lettuce依赖SDK -->
<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> 步骤二:application.properties文件或者Bean方式配置。
可以选择使用application.properties文件进行配置,也可以通过定义Bean的方式来实现配置。
主备版、Proxy集群版实例配置
#redis host spring.redis.host=<host> #redis 端口号 spring.redis.port=<port> #redis 数据库下标 spring.redis.database=0 #redis 密码 spring.redis.password=<password> #redis 读写超时 spring.redis.timeout=5000
Cluster集群版实例配置
# redis cluster节点信息 spring.redis.cluster.nodes=<ip:port>,<ip:port>,<ip:port> # redis cluster 最大重定向次数 spring.redis.cluster.max-redirects=10 # redis cluster 节点密码 spring.redis.password=<password> # redis cluster 超时配置 spring.redis.timeout=5000 # 开启自适应拓扑刷新 spring.redis.lettuce.cluster.refresh.adaptive=true # 开启每10S定时刷新拓扑结构 spring.redis.lettuce.cluster.refresh.period=10S
主备版、Proxy集群版
- 实例配置
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 非池化配置,与 application.properties 配置方式二选一 */ @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:5000}") private Integer redisReadTimeout = 5000; /** * TCP_KEEPALIVE 配置参数: * 两次 keepalive 间的时间间隔 = TCP_KEEPALIVE_TIME = 30 * 连接空闲多久开始 keepalive = TCP_KEEPALIVE_TIME/3 = 10 * keepalive 几次之后断开连接 = TCP_KEEPALIVE_COUNT = 3 */ private static final int TCP_KEEPALIVE_TIME = 30; /** * TCP_USER_TIMEOUT 连接空闲限制时间,解决Lettuce长时间超时问题。 * 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() // 两次 keepalive 间的时间间隔 .idle(Duration.ofSeconds(TCP_KEEPALIVE_TIME)) // 连接空闲多久开始 keepalive .interval(Duration.ofSeconds(TCP_KEEPALIVE_TIME/3)) // keepalive 几次之后断开连接 .count(3) // 是否开启保活连接 .enable() .build()) .tcpUserTimeout(SocketOptions.TcpUserTimeoutOptions.builder() // 解决服务端rst导致的长时间超时问题 .tcpUserTimeout(Duration.ofSeconds(TCP_USER_TIMEOUT)) .enable() .build()) // tcp 连接超时设置 .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)) // Proxy集群实例无需设置readFrom .readFrom(ReadFrom.MASTER) .clientOptions(clientOptions) .build(); return clientConfiguration; } } - 池化配置
- 引入池化组件
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.11.1</version> </dependency> - 代码配置
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 池化配置 */ @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:5000}") private Integer redisReadTimeout = 5000; @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 配置参数: * 两次 keepalive 间的时间间隔 = TCP_KEEPALIVE_TIME = 30 * 连接空闲多久开始 keepalive = TCP_KEEPALIVE_TIME/3 = 10 * keepalive 几次之后断开连接 = TCP_KEEPALIVE_COUNT = 3 */ private static final int TCP_KEEPALIVE_TIME = 30; /** * TCP_USER_TIMEOUT 连接空闲限制时间,解决Lettuce长时间超时问题。 * 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); //关闭共享链接,才能池化生效 connectionFactory.setShareNativeConnection(false); return connectionFactory; } @Bean public LettuceClientConfiguration clientConfiguration() { SocketOptions socketOptions = SocketOptions.builder() .keepAlive(SocketOptions.KeepAliveOptions.builder() // 两次 keepalive 间的时间间隔 .idle(Duration.ofSeconds(TCP_KEEPALIVE_TIME)) // 连接空闲多久开始 keepalive .interval(Duration.ofSeconds(TCP_KEEPALIVE_TIME/3)) // keepalive 几次之后断开连接 .count(3) // 是否开启保活连接 .enable() .build()) .tcpUserTimeout(SocketOptions.TcpUserTimeoutOptions.builder() // 解决服务端rst导致的长时间超时问题 .tcpUserTimeout(Duration.ofSeconds(TCP_USER_TIMEOUT)) .enable() .build()) // tcp 连接超时设置 .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) // Proxy集群实例无需设置readFrom .readFrom(ReadFrom.MASTER) .build(); return clientConfiguration; } private GenericObjectPoolConfig redisPoolConfig() { GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); //连接池的最小连接数 poolConfig.setMinIdle(redisPoolMinSize); //连接池的最大空闲连接数 poolConfig.setMaxIdle(redisPoolMaxSize); //连接池的最大连接数 poolConfig.setMaxTotal(redisPoolMaxSize); //连接池耗尽后是否需要等待,默认true表示等待。当值为true时,setMaxWait才会生效 poolConfig.setBlockWhenExhausted(true); //连接池耗尽后获取连接的最大等待时间,默认-1表示一直等待 poolConfig.setMaxWait(Duration.ofMillis(redisPoolMaxWaitMillis)); //创建连接时校验有效性(ping),默认false poolConfig.setTestOnCreate(false); //获取连接时校验有效性(ping),默认false,业务量大时建议设置为false减少开销 poolConfig.setTestOnBorrow(true); //归还连接时校验有效性(ping),默认false,业务量大时建议设置为false减少开销 poolConfig.setTestOnReturn(false); //是否开启空闲连接检测,如为false,则不剔除空闲连接 poolConfig.setTestWhileIdle(true); //连接空闲多久后逐出,当空闲时间>该值,并且空闲连接数>最小空闲连接数时直接逐出 poolConfig.setSoftMinEvictableIdleTime(Duration.ofMillis(redisPoolSoftMinEvictableIdleTimeMillis)); //关闭根据MinEvictableIdleTimeMillis判断逐出 poolConfig.setMinEvictableIdleTime(Duration.ofMillis(-1)); //空闲连接逐出的检测周期,默认为60s poolConfig.setTimeBetweenEvictionRuns(Duration.ofMillis(redisPoolBetweenEvictionRunsMillis)); return poolConfig; } }
- 引入池化组件
Cluster集群版
- 实例配置
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 非池化配置,与 application.properties 配置方式二选一 */ @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:5000}") private Integer redisReadTimeout = 5000; @Value("${redis.cluster.topology.refresh.period.millis:10000}") private Integer redisClusterTopologyRefreshPeriodMillis = 10000; /** * TCP_KEEPALIVE 配置参数: * 两次 keepalive 间的时间间隔 = TCP_KEEPALIVE_TIME = 30 * 连接空闲多久开始 keepalive = TCP_KEEPALIVE_TIME/3 = 10 * keepalive 几次之后断开连接 = TCP_KEEPALIVE_COUNT = 3 */ private static final int TCP_KEEPALIVE_TIME = 30; /** * TCP_USER_TIMEOUT 连接空闲限制时间,解决Lettuce长时间超时问题。 * 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() // 两次 keepalive 间的时间间隔 .idle(Duration.ofSeconds(TCP_KEEPALIVE_TIME)) // 连接空闲多久开始 keepalive .interval(Duration.ofSeconds(TCP_KEEPALIVE_TIME/3)) // keepalive 几次之后断开连接 .count(3) // 是否开启保活连接 .enable() .build()) .tcpUserTimeout(SocketOptions.TcpUserTimeoutOptions.builder() // 解决服务端rst导致的长时间超时问题 .tcpUserTimeout(Duration.ofSeconds(TCP_USER_TIMEOUT)) .enable() .build()) // tcp 连接超时设置 .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; } } - 池化配置
- 引入池化组件
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.11.1</version> </dependency> - 代码配置
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 池化配置 */ @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:5000}") private Integer redisReadTimeout = 5000; @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 配置参数: * 两次 keepalive 间的时间间隔 = TCP_KEEPALIVE_TIME = 30 * 连接空闲多久开始 keepalive = TCP_KEEPALIVE_TIME/3 = 10 * keepalive 几次之后断开连接 = TCP_KEEPALIVE_COUNT = 3 */ private static final int TCP_KEEPALIVE_TIME = 30; /** * TCP_USER_TIMEOUT 连接空闲限制时间,解决Lettuce长时间超时问题。 * 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); //一定要关闭共享连接,否则连接池将不会生效 connectionFactory.setShareNativeConnection(false); return connectionFactory; } @Bean public LettuceClientConfiguration clientConfiguration() { SocketOptions socketOptions = SocketOptions.builder() .keepAlive(SocketOptions.KeepAliveOptions.builder() // 两次 keepalive 间的时间间隔 .idle(Duration.ofSeconds(TCP_KEEPALIVE_TIME)) // 连接空闲多久开始 keepalive .interval(Duration.ofSeconds(TCP_KEEPALIVE_TIME/3)) // keepalive 几次之后断开连接 .count(3) // 是否开启保活连接 .enable() .build()) .tcpUserTimeout(SocketOptions.TcpUserTimeoutOptions.builder() // 解决服务端rst导致的长时间超时问题 .tcpUserTimeout(Duration.ofSeconds(TCP_USER_TIMEOUT)) .enable() .build()) // tcp 连接超时设置 .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(); //连接池的最小连接数 poolConfig.setMinIdle(redisPoolMinSize); //连接池的最大空闲连接数 poolConfig.setMaxIdle(redisPoolMaxSize); //连接池的最大连接数 poolConfig.setMaxTotal(redisPoolMaxSize); //连接池耗尽后是否需要等待, 默认true表示等待. 当值为true时, setMaxWait才会生效 poolConfig.setBlockWhenExhausted(true); //连接池耗尽后获取连接的最大等待时间, 默认-1表示一直等待 poolConfig.setMaxWait(Duration.ofMillis(redisPoolMaxWaitMillis)); //创建连接时校验有效性(ping),默认false poolConfig.setTestOnCreate(false); //获取连接时校验有效性(ping), 默认false, 业务量大时建议设置为false减少开销 poolConfig.setTestOnBorrow(true); //归还连接时校验有效性(ping),默认false, 业务量大时建议设置为false减少开销 poolConfig.setTestOnReturn(false); //是否开启空闲连接检测,如为false,则不剔除空闲连接 poolConfig.setTestWhileIdle(true); //禁止最小空闲时间关闭连接 poolConfig.setMinEvictableIdleTime(Duration.ofMillis(-1)); //连接空闲多久后逐出,当空闲时间>该值,并且空闲连接数>最小空闲连接数时直接逐出,不再根据MinEvictableIdleTimeMillis判断(默认逐出策略) poolConfig.setSoftMinEvictableIdleTime(Duration.ofMillis(redisPoolSoftMinEvictableIdleTimeMillis)); //空闲连接逐出的检测周期,默认为60s poolConfig.setTimeBetweenEvictionRuns(Duration.ofMillis(redisPoolBetweenEvictionRunsMillis)); return poolConfig; } }
- 引入池化组件
参数解释
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| configuration | RedisConfiguration | - | redis连接配置,常用两个子类:
|
| clientConfiguration | LettuceClientConfiguration | - | 客户端配置参数,常用子类: LettucePoolingClientConfiguration(用于池化) |
| shareNativeConnection | boolean | true | 是否采用共享连接,默认true,采用连接池时必须设置为false。 |
| 参数 | 默认值 | 说明 |
|---|---|---|
| hostName | localhost | 连接Redis实例的IP地址/域名, 请填写实例的负载均衡地址,以确保可用性。 |
| port | 6379 | 连接端口号。 |
| database | 0 | 数据库下标。 |
| password | - | 连接Redis实例的密码。如果实例已开启免密访问,无需输入实例的访问密码。 |
| 参数 | 说明 |
|---|---|
| clusterNodes | cluster节点连接信息,需节点IP、Port。 |
| maxRedirects | cluster访问最大重定向次数,建议值:10 |
| password | 连接Redis实例的密码。如果实例已开启免密访问,无需输入实例的访问密码。 |
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| timeout | Duration | 60s | 命令超时时间配置,建议值:5s。 |
| clientOptions | ClientOptions | - | 配置项。 |
| readFrom | readFrom | MASTER | 读取模式,建议值:MASTER,其余配置在发生故障切换场景下,均存在访问失败风险。 |
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| timeout | Duration | 60s | 命令超时时间配置,建议值:5s。 |
| clientOptions | ClientOptions | - | 配置项。 |
| poolConfig | GenericObjectPoolConfig | - | 连接池配置。 |
| readFrom | readFrom | MASTER | 读取模式,建议值:MASTER,其余配置在发生故障切换场景下,均存在访问失败风险。 |
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| autoReconnect | boolean | true | 连接断开后,是否自动发起重连,建议值:true。 |
| pingBeforeActivateConnection | boolean | true | 连接创建后,是否通过ping/pong校验连接可用性,建议值:true。 |
| cancelCommandsOnReconnectFailure | boolean | true | 连接重连失败时,是否取消队列中的命令,建议值:false。 |
| disconnectedBehavior | DisconnectedBehavior | DisconnectedBehavior.DEFAULT | 连接断开时的行为,建议值:ACCEPT_COMMANDS
|
| socketOptions | SocketOptions | - | 网络配置项。 |
| 参数 | 默认值 | 说明 |
|---|---|---|
| connectTimeout | 10s | 连接超时时间配置,建议值:2s。 |
| 参数 | 默认值 | 说明 |
|---|---|---|
| minIdle | - | 连接池的最小连接数。 |
| maxIdle | - | 连接池的最大空闲连接数。 |
| maxTotal | - | 连接池的最大连接数。 |
| blockWhenExhausted | true | 连接池耗尽后是否需要等待,默认true表示等待。当值为true时,设置maxWaitMillis才会生效。 |
| maxWaitMillis | -1 | 连接池耗尽后获取连接的最大等待时间,默认-1表示一直等待。 |
| testOnCreate | false | 创建连接时校验有效性(ping),默认false。 |
| testOnBorrow | false | 获取连接时校验有效性(ping),默认false,业务量大时建议设置为false减少开销。 |
| testOnReturn | false | 归还连接时校验有效性(ping),默认false,业务量大时建议设置为false减少开销。 |
| testWhileIdle | false | 是否开启空闲连接检测,如为false,则不剔除空闲连接,建议值:true。 |
| softMinEvictableIdleTimeMillis | -1 | 连接空闲多久后逐出,(空闲时间>该值 && 空闲连接数>最小空闲连接数)时直接逐出,建议值:1800000,单位:毫秒。 |
| minEvictableIdleTimeMillis | 1800000 | 根据minEvictableIdleTimeMillis判断逐出,建议值:-1,关闭该策略,改用softMinEvictableIdleTimeMillis策略。 |
| timeBetweenEvictionRunsMillis | -1 | 空闲连接逐出的检测周期,建议值:60000,单位:毫秒。 |