Lettuce客户端连接Redis(Java)
本章节介绍使用Lettuce客户端连接Redis实例的方法。更多的客户端的使用方法请参考Redis客户端。
在springboot类型的项目中,spring-data-redis中已提供了对jedis、lettuce的集成适配。另外,在springboot1.x中默认集成的是jedis,springboot2.x中改为了lettuce,因此在springboot2.x及更高版本中想集成使用lettuce,无需手动引入lettuce依赖包。
Springboot版本不得低于2.3.12.RELEASE,Lettuce版本不得低于6.3.0.RELEASE。
前提条件
- 已成功创建Redis实例,且状态为“运行中”。创建Redis实例的操作请参考购买Redis实例。
- 查看并获取待连接Redis实例的IP地址/域名和端口。具体步骤请参见查看和修改DCS实例基本信息。
- 连接实例前确保客户端与Redis实例之间网络互通,具体请参考连接Redis网络要求。
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>${lettuce.version}</version> </dependency>
基于application.properties配置
- 单机、主备、读写分离、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=2000
- Cluster集群实例配置
# redis cluster节点信息 spring.redis.cluster.nodes=<ip:port>,<ip:port>,<ip:port> # redis cluster 最大重定向次数 spring.redis.cluster.max-redirects=3 # redis cluster 节点密码 spring.redis.password=<password> # redis cluster 超时配置 spring.redis.timeout=2000 # 开启自适应拓扑刷新 spring.redis.lettuce.cluster.refresh.adaptive=true # 开启每10S定时刷新拓扑结构 spring.redis.lettuce.cluster.refresh.period=10S
基于Bean方式配置
- 单机、主备、读写分离、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:2000}") private Integer redisReadTimeout = 2000; @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().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)) .readFrom(ReadFrom.MASTER) .clientOptions(clientOptions) .build(); return clientConfiguration; } }
- 单机、主备、读写分离、Proxy集群实例池化配置
引入池化组件
<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: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; @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().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) .readFrom(ReadFrom.MASTER) .build(); return poolingClientConfiguration; } 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:2000}") private Integer redisReadTimeout = 2000; @Value("${redis.cluster.topology.refresh.period.millis:10000}") private Integer redisClusterTopologyRefreshPeriodMillis = 10000; @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().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实例池化配置
引入池化组件
<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: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; @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().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; } }
SSL连接配置(可选配置)
当实例开启了SSL,通过SSL连接实例时,请使用以下内容替换基于Bean方式配置中的LettuceClientConfiguration构造方法clientConfiguration()。Redis实例支持SSL的情况请参考配置Redis SSL数据加密传输。
- 单机、主备、读写分离、Proxy集群实例配置
@Bean public LettuceClientConfiguration clientConfiguration() { SocketOptions socketOptions = SocketOptions.builder().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)) .readFrom(ReadFrom.MASTER) .clientOptions(clientOptions) .useSsl() .build(); return clientConfiguration; }
- Cluster集群实例配置
@Bean public LettuceClientConfiguration clientConfiguration() { SocketOptions socketOptions = SocketOptions.builder().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; }
参数明细
参数 |
类型 |
默认值 |
说明 |
---|---|---|---|
configuration |
RedisConfiguration |
- |
redis连接配置,常用两个子类:
|
clientConfiguration |
LettuceClientConfiguration |
- |
客户端配置参数,常用子类: LettucePoolingClientConfiguration(用于池化) |
shareNativeConnection |
boolean |
true |
是否采用共享连接,默认true,采用连接池时必须设置为false |
参数 |
默认值 |
说明 |
---|---|---|
hostName |
localhost |
连接Redis实例的IP地址/域名 |
port |
6379 |
连接端口号 |
database |
0 |
数据库下标 |
password |
- |
连接密码 |
参数 |
说明 |
---|---|
clusterNodes |
cluster节点连接信息,需节点IP、Port |
maxRedirects |
cluster访问最大重定向次数,建议值:3 |
password |
连接密码 |
参数 |
类型 |
默认值 |
说明 |
---|---|---|---|
timeout |
Duration |
60s |
命令超时时间配置,建议值:2s |
clientOptions |
ClientOptions |
- |
配置项 |
readFrom |
readFrom |
MASTER |
读取模式,建议值:MASTER,其余配置在发生故障切换场景下,均存在访问失败风险 |
参数 |
类型 |
默认值 |
说明 |
---|---|---|---|
timeout |
Duration |
60s |
命令超时时间配置,建议值:2s |
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 |
1800000 |
连接空闲多久后逐出,(空闲时间>该值 && 空闲连接>最大空闲数)时直接逐出 |
minEvictableIdleTimeMillis |
60000 |
根据minEvictableIdleTimeMillis判断逐出,建议值:-1,关闭该策略,改用softMinEvictableIdleTimeMillis策略 |
timeBetweenEvictionRunsMillis |
60000 |
空闲连接逐出的检测周期,单位:毫秒 |
DCS实例配置建议
- 连接池化
因lettuce底层采用基于netty的NIO模式,和redis server进行通信,不同于jedis的BIO模式。底层采用长连接 + 队列的组合模式,借助TCP顺序发、顺序收的特性,来实现同时处理多请求发送和多响应接收,单条连接可支撑的QPS在3K~5K不等,线上系统建议不要超过3K。lettuce本身不支持池化,且在springboot中默认不开启池化,如需开启池化,需通过手动引入commons-pool2组件,并关闭LettuceConnectionFactory.shareNativeConnection(共享连接)来实现池化。
因每条lettuce连接默认需要配置两个线程池-I/O thread pools、computation thread pool,用于支撑IO事件读取和异步event处理,如配置成连接池形式使用,每个连接都将会创建两个线程池,对内存资源的占用偏高。鉴于lettuce的底层模型实现,及单连接突出的处理能力,不建议通过池化的方式使用lettuce。
- 拓扑刷新
在连接cluster类型实例中,lettuce会在初始化时,向配置的节点列表随机发送cluster nodes来获取集群slot的分布信息。如后续cluster扩/缩容、主备切换等,会导致集群拓扑结构发生变化,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配置
- 爆炸半径
因lettuce底层采用的是单长连接 + 请求队列的组合模式,一旦遇到网络抖动/闪断,或连接失活,将影响所有请求,尤其是在连接失活场景中,将尝试tcp重传,直至重传超时关闭连接,待连接重建后才能恢复。在重传期间请求队列会不断堆积请求,上层业务非常容易出现批量超时,甚至在部分操作系统内核中的重传超时配置过长,致使业务系统长时间处于不可用状态。因此,不推荐使用lettuce组件,建议用jedis组件替换。