redis报错远程主机强迫关闭了一个现有的连接以及超时问题
问题说明:
spring boot2.x+redis开发时,总是时不是发生redis超时,时不时报:远程主机强迫关闭了一个现有的连接以及超时问题。这个问题总是偶有出现,烦人。
spring boot2.x版本默认redis连接池为lettuce,以前在非spring boot项目中使用jedis连接redis时,好像没有过这种烦人的问题,搞的现在对redis有阴影。。。我的项目也是使用默认的lettuce连接redis。
我们先看超时问题的报错:
io.lettuce.core.RedisCommandTimeoutException: Command timed out after 5 second(s)
再看看远程主机强迫关闭了一个现有的连接报错:
org.springframework.data.redis.RedisSystemException: Redis exception; nested exception is io.lettuce.core.RedisException: java.io.IOException: 远程主机强迫关闭了一个现有的连接。
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:74)
at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41)
at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44)
真的烦。
这两个问题我暂时的解决办法(有待观察):
将spring boot redis配置设置超时时间比redis.conf中的timeout要小,比如spring boot redis中设置超时30秒,那么服务器中redis timeout设置为40秒;另外将redis.conf中的tcp-keepalive改成10:
# Unix socket.
#
# Specify the path for the Unix socket that will be used to listen for
# incoming connections. There is no default, so Redis will not listen
# on a unix socket when not specified.
#
# unixsocket /tmp/redis.sock
# unixsocketperm 700
# Close the connection after a client is idle for N seconds (0 to disable)
timeout 40
# TCP keepalive.
#
# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence
# of communication. This is useful for two reasons:
#
# 1) Detect dead peers.
# 2) Take the connection alive from the point of view of network
# equipment in the middle.
#
# On Linux, the specified value (in seconds) is the period used to send ACKs.
# Note that to close the connection the double of the time is needed.
# On other kernels the period depends on the kernel configuration.
#
# A reasonable value for this option is 300 seconds, which is the new
# Redis default starting with Redis 3.2.1.
tcp-keepalive 10
这样好像就不会报Command timed out after xxx second(s)了,但是对于“远程主机强迫关闭了一个现有的连接”这个问题貌似只能把lettuce连接池切回jedis了,我今天实在是忍受不了lettuce了。把配置文件改成如下:
spring:
redis:
host: xxxxx
port: 6379
password: xxxxxx
timeout: 30s
# lettuce:
# pool:
# min-idle: 10
# max-idle: 20
# max-active: 200
# max-wait: -1ms
jedis:
pool:
min-idle: 10
max-idle: 20
max-wait: -1ms
max-active: 200
Maven pom.xml:
<!-- redis缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</exclusion>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.2</version>
</dependency>
改完后,我在本地观察了一会,好像不会出现以上两个问题。不过上到生产可能还要观察一段时间。唉,烦
(观察了几天还真没有再发现问题了)
---------------------------------------------------------------------------------------
了解更多redis复杂问题,可以看看这本书《Redis实战》
或者《Redis设计与实现》,前者偏实战讲解,后者偏原理。