问题描述
为什么Redis不推荐使用Lettuce
回答
问题原因
- 在Lettuce 连接到 Redis 主机并正常读写时。
- 此时如果主机出现故障(硬件问题直接导致关机,此时没有给客户端的RST回复)。
- 客户端会继续超时,直到tcp重传结束,才能恢复。此时在 Linux 中大约需要 925.6 s(参考 tcp_retries2 )。
为什么keepalive 没有起到保活的效果:
因为重传包的优先级高于keepalive,所以在到达keepalive阶段之前,会继续重传,直到重新连接。
问题出现的场景
- 在大多数情况下,当操作系统关闭和进程退出时,RST可以返回给客户端,但当电源被切断或某些机器硬件发生故障时,RST将不会返回。
- 在云环境中,通常使用SLB。当后端主机故障时,如果SLB不支持连接耗尽,就会出现问题
问题重现步骤
- Start a Redis on a certain port, let's say 6379, and use the following code to connect to Redis.
RedisClientclient=RedisClient.create(RedisURI.Builder.redis(host, port).withPassword(args[1]) .withTimeout(Duration.ofSeconds(timeout)).build()); client.setOptions(ClientOptions.builder() .socketOptions(socketOptions) .autoReconnect(autoReconnect) .disconnectedBehavior(disconnectedBehavior) .build()); RedisCommands<String, String>sync=client.connect().sync(); for (inti=0; i<times; i++) { Thread.sleep(1000); try { LOGGER.info("{}:{}", i, sync.set(""+i, ""+i)); } catch (Exceptione) { LOGGER.error("Set Exception: {}", e.getMessage()); } }
- Use iptables to disable port 6379 packets on the Redis machine.
iptables -A INPUT -p tcp --dport 6379 -j DROP
iptables -A OUTPUT -p tcp --sport 6379 -j DROP
- Observe that the client starts timing out and cannot recover until after 925.6 s (related to tcp_retries2)
- After the test, clear the iptables rules
iptables -F INPUT
iptables -F OUTPUT
参考issues 记录:https://github.com/lettuce-io/lettuce-core/issues/2082
解决方案
建议使用Jedis 客户端连接。