参考地址:
Springboot 项目中Redis用lettuce连接池经常断连的问题解决_idlestatehandler redis-优快云博客
https://www.cnblogs.com/hushaojun/p/16285486.html
业务场景:已经启动的springboot应用 使用了redis,但页面一段时间不操作后redis连接就会断开并且出现异常:java.io.IOException: 远程主机强迫关闭了一个现有的连接
总结原因:
1.jedis和lettuce
Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接
Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,应为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。
解决方法(单应用环境换一个连接方式):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!--默认的客户端链接方式是lettuce,如果要使用jedis作为客户端连接工具,增加下面的exclusions-->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 添加jedis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
或者
@Configuration
public class ClientConfig {
@Bean
public ClientResources clientResources(){
NettyCustomizer nettyCustomizer = new NettyCustomizer() {
@Override
public void afterChannelInitialized(Channel channel) {
channel.pipeline().addLast(
//此处事件必须小于超时时间
new IdleStateHandler(40, 0, 0));
channel.pipeline().addLast(new ChannelDuplexHandler() {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
ctx.disconnect();
}
}
});
}
@Override
public void afterBootstrapInitialized(Bootstrap bootstrap) {
}
};
return ClientResources.builder().nettyCustomizer(nettyCustomizer ).build();
}
}
2.网络原因(待测试):换个网络试试,这可能是NAT(网络地址转换协议)的会话过期导致的
这个协议的作用是在本地多个设备使用同一个公网IP的情况下,通过一些配置路由到对应的子网设备。