介紹使(shi)用同(tong)一(yi)VPC內彈性(xing)云主機ECS上的(de)Lettuce連(lian)接Redis實(shi)例的(de)方法(fa)(fa)。更多的(de)客戶端的(de)使(shi)用方法(fa)(fa)請參考。
在(zai)springboot類型(xing)的項(xiang)目中,spring-data-redis中已提供了(le)對(dui)、的集成適配。另外,在(zai)springboot1.x中默(mo)認集成的是jedis,springboot2.x中改為了(le)lettuce,因此在(zai)springboot2.x及更高版本中想集成使(shi)用jedis,無需手(shou)動(dong)引入lettuce依賴(lai)包(bao)。
前提條件
- 已成功申請Redis實例,且狀態為“運行中”。
- 查看并獲取待連接Redis實例的IP地址和端口。
具體步驟請參見查看實例信息。
- 已創建彈性云主機,創建彈性云主機的方法,請參見《彈性云主機用戶指南》。
- 如果彈性云主機為Linux系統,該彈性云主機必須已經安裝java編譯環境。
Pom配置
<!-- 引入spring-data-redis組件,默認已集成lettuce依賴SDK -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
基于application.properties配置
單機、主備(bei)、讀寫分離(li)、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集群實例配置
# 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
- 單機、主備、讀寫分離、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 poolingClientConfiguration = LettucePoolingClientConfiguration.builder()
.poolConfig(redisPoolConfig())
.commandTimeout(Duration.ofMillis(redisReadTimeout))
.clientOptions(clientOptions)
.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.setMinEvictableIdleTime(Duration.ofMillis(-1));
//連接空閑多久后逐出,當空閑時間>該值,并且空閑連接>最大空閑數時直接逐出
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)) .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)
.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;
}
}
參數明細
LettuceConnectionFactory參數
| 參數 | 類型 | 默認值 | 說明 |
|---|---|---|---|
| configuration | RedisConfiguration | - | redis連接配置,常用兩個子類: RedisStandaloneConfiguration RedisClusterConfiguration |
| clientConfiguration | LettuceClientConfiguration | - | 客戶端配置參數,常用子類:LettucePoolingClientConfiguration(用于池化) |
| shareNativeConnection | boolean | true | 是否采用共享連接,默認true,采用連接池時必須設置為false |
RedisStandaloneConfiguration參數
| 參數 | 默認值 | 說明 |
|---|---|---|
| hostName | localhost | 連接Redis實例的IP地址 |
| port | 6379 | 連接端口號 |
| database | 0 | 數據庫下標 |
| password | - | 連接密碼 |
RedisClusterConfiguration參數
| 參數 | 說明 |
|---|---|
| clusterNodes | cluster節點連接信息,需IP、Port |
| maxRedirects | cluster訪問最大重定向次數,建議值:3 |
| password | 連接密碼 |
LettuceClientConfiguration參數(shu)
| 參數 | 類型 | 默認值 | 說明 |
|---|---|---|---|
| timeout | Duration | 60s | 命令超時時間配置,建議值:2s |
| clientOptions | ClientOptions | - | 配置項 |
LettucePoolingClientConfiguration參數
| 參數 | 類型 | 默認值 | 說明 |
|---|---|---|---|
| timeout | Duration | 60s | 命令超時時間配置,建議值:2s |
| clientOptions | ClientOptions | - | 配置項 |
| poolConfig | GenericObjectPoolConfig | - | 連接池配置 |
ClientOptions參數
| 參數 | 類型 | 默認值 | 說明 |
|---|---|---|---|
| autoReconnect | boolean | true | 連接斷開后,是否自動發起重連,建議值:true |
| pingBeforeActivateConnection | boolean | true | 連接創建后,是否通過ping/pong校驗連接可用性,建議值:true |
| cancelCommandsOnReconnectFailure | boolean | true | 連接重連失敗時,是否取消隊列中的命令,建議值:false |
| disconnectedBehavior | DisconnectedBehavior | DisconnectedBehavior.DEFAULT | 連接斷開時的行為,建議值:ACCEPT_COMMANDS DEFAULT:當autoReconnect為true時,允許命令進入隊列等待,當autoReconnect為false時,禁止命令進入隊列等待 ACCPET_COMMANDS:允許命令進入隊列等待 REJECT_COMMANDS:禁止命令進入隊列等待 |
| socketOptions | SocketOptions | - | 網絡配置項 |
SocketOptions參數
| 參數 | 默認值 | 說明 |
|---|---|---|
| connectTimeout | 10s | 連接超時時間配置,建議值:2s |
GenericObjectPoolConfig參數
| 參數 | 默認值 | 說明 |
|---|---|---|
| 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底層采用基于(yu)netty的(de)(de)NIO模(mo)(mo)式(shi),和(he)redis server進行通(tong)信(xin),不(bu)同(tong)于(yu)jedis的(de)(de)BIO模(mo)(mo)式(shi)。底層采用長連(lian)(lian)接(jie) + 隊列的(de)(de)組合模(mo)(mo)式(shi),借助(zhu)TCP順序發(fa)、順序收的(de)(de)特性(xing),來實現同(tong)時處理多請求發(fa)送和(he)多響應接(jie)收,單條連(lian)(lian)接(jie)可(ke)支撐的(de)(de)QPS在(zai)3K~5K不(bu)等(deng),線上(shang)系統建議(yi)不(bu)要(yao)超過3K。lettuce本身不(bu)支持池化,且在(zai)springboot中默認不(bu)開(kai)啟(qi)池化,如需開(kai)啟(qi)池化,需通(tong)過手動引入commons-pool2組件,并關(guan)閉LettuceConnectionFactory.shareNativeConnection(共享連(lian)(lian)接(jie))來實現池化。
因每條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();
- 爆炸半徑
因lettuce底層采用的是單長連接 + 請求隊列的組合模式,一旦遇到網絡抖動/請求,或連接失活,將影響所有請求,尤其是在連接失活場景中,將嘗試tcp重傳,直至重傳超時關閉連接,待連接重建后才能恢復。在重傳期間請求隊列會不斷堆積請求,上層業務非常容易出現批量超時,甚至在部分操作系統內核中的重傳超時配置過長,致使業務系統長時間處于不可用狀態。因此, 不推薦使用lettuce組件,建議用jedis組件替換 。