redis报错远程主机强迫关闭了一个现有的连接以及超时问题

原创 2019-10-11 16:37 阅读(15566)次

问题说明:

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设计与实现,前者偏实战讲解,后者偏原理。