生产环境使用
让您的 Lettuce 应用做好生产准备
以下部分解释了如何处理生产环境中可能发生的情况。
超时
Lettuce 为许多操作提供了超时设置,例如命令执行、SSL 握手和 Sentinel 发现。默认情况下,Lettuce 对这些操作使用全局超时值 60 秒,但您可以为每个操作使用单独的超时值来覆盖全局超时值。
先决条件
要设置 TCP 级别超时,您需要确保已安装 Netty 原生传输 之一。最常见的是 netty-transport-native-epoll
,用于 Linux 系统。您可以通过在 pom.xml
文件中包含以下依赖项将其添加到您的项目
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-epoll</artifactId>
<version>${netty.version}</version> <!-- e.g., 4.1.118.Final -->
<classifier>linux-x86_64</classifier>
</dependency>
安装原生传输依赖项后,您可以使用以下代码进行验证
logger.info("Lettuce epool is available: {}", EpollProvider.isAvailable());
如果上面的代码片段返回 false
,您需要为 io.lettuce.core
和 io.netty
启用调试日志,以查看为何原生传输不可用。
有关使用 Netty 原生传输的更多信息,请参阅 Lettuce 参考指南。
设置超时
下面是设置套接字级别超时的一个示例。TCP_USER_TIMEOUT
设置对于服务器停止响应而未确认最后一个请求的场景很有用,而 KEEPALIVE
设置适合检测客户端和服务器之间没有流量的死连接。
RedisURI redisURI = RedisURI.Builder
.redis("localhost")
// set the global default from the default 60 seconds to 30 seconds
.withTimeout(Duration.ofSeconds(30))
.build();
try (RedisClient client = RedisClient.create(redisURI)) {
// or set specific timeouts for things such as the TCP_USER_TIMEOUT and TCP_KEEPALIVE
// A good general rule of thumb is to follow the rule
// TCP_USER_TIMEOUT = TCP_KEEP_IDLE+TCP_KEEPINTVL * TCP_KEEPCNT
// in this case, 20 = 5 + 5 * 3
SocketOptions.TcpUserTimeoutOptions tcpUserTimeout = SocketOptions.TcpUserTimeoutOptions.builder()
.tcpUserTimeout(Duration.ofSeconds(20))
.enable().build();
SocketOptions.KeepAliveOptions keepAliveOptions = SocketOptions.KeepAliveOptions.builder()
.interval(Duration.ofSeconds(5))
.idle(Duration.ofSeconds(5))
.count(3).enable().build();
SocketOptions socketOptions = SocketOptions.builder()
.tcpUserTimeout(tcpUserTimeout)
.keepAlive(keepAliveOptions)
.build();
client.setOptions(ClientOptions.builder()
.socketOptions(socketOptions)
.build());
StatefulRedisConnection<String, String> connection = client.connect();
System.out.println(connection.sync().ping());
}
集群拓扑刷新
Redis 集群配置是动态的,可以在运行时更改。可以添加新节点,特定槽位的主节点也可以转移。Lettuce 自动处理 MOVED 和 ASK 重定向,但为了增强应用程序的弹性,您应启用自适应拓扑刷新
RedisURI redisURI = RedisURI.Builder
.redis("localhost")
// set the global default from the default 60 seconds to 30 seconds
.withTimeout(Duration.ofSeconds(30))
.build();
// Create a RedisClusterClient with adaptive topology refresh
try (RedisClusterClient clusterClient = RedisClusterClient.create(redisURI)) {
// Enable TCP keep-alive and TCP user timeout just like in the standalone example
SocketOptions.TcpUserTimeoutOptions tcpUserTimeout = SocketOptions.TcpUserTimeoutOptions.builder()
.tcpUserTimeout(Duration.ofSeconds(20))
.enable()
.build();
SocketOptions.KeepAliveOptions keepAliveOptions = SocketOptions.KeepAliveOptions.builder()
.interval(Duration.ofSeconds(5))
.idle(Duration.ofSeconds(5))
.count(3)
.enable()
.build();
SocketOptions socketOptions = SocketOptions.builder()
.tcpUserTimeout(tcpUserTimeout)
.keepAlive(keepAliveOptions)
.build();
// Enable adaptive topology refresh
// Configure adaptive topology refresh options
ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
.enableAllAdaptiveRefreshTriggers()
.adaptiveRefreshTriggersTimeout(Duration.ofSeconds(30))
.build();
ClusterClientOptions options = ClusterClientOptions.builder()
.topologyRefreshOptions(topologyRefreshOptions)
.socketOptions(socketOptions).build();
clusterClient.setOptions(options);
StatefulRedisClusterConnection<String, String> connection = clusterClient.connect();
System.out.println(connection.sync().ping());
connection.close();
}
在 参考指南 中了解有关拓扑刷新配置设置的更多信息。
DNS 缓存与 Redis
当您连接到具有多个端点的 Redis 服务器时,例如 Redis Enterprise Active-Active,您**必须**禁用 JVM 的 DNS 缓存。如果服务器节点或代理失败,受故障影响的任何数据库的 IP 地址将发生变化。此时,如果启用了 DNS 缓存,您的应用程序将继续尝试使用过时的 IP 地址。
使用以下代码禁用 DNS 缓存
java.security.Security.setProperty("networkaddress.cache.ttl","0");
java.security.Security.setProperty("networkaddress.cache.negative.ttl", "0");