前言

在前几天的一个springboot 项目中,使用到了redis 作为缓存,理所当然地使用了连接池,因为频繁的创建和销毁连接实在是太耗费资源了,可是在测试环境下使用是没有问题的,将项目放到了线上后就时不时出现连接的异常,具体异常信息如下:

ERROR --- [nio-8080-exec-2] c.l.a.exception.GlobalExceptionHandler   : error: 
org.springframework.data.redis.RedisConnectionFailureException: Unexpected end of stream.; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Unexpected end of stream.

然后过一会儿又没有问题了,实在是让人头疼。

原因

咨询了redis的相关同学后,发现问题的根源应该是 redis 集群存在自动关闭策略,并且客户端这边没有配置连接检测导致的,也就是说 redis 服务端已经将连接关闭了,而客户端还在使用这个失效的连接去操纵 redis ,那么自然就会出现这个错误了。

解决方案

解决方案其实很简单,在 application.yml 中配置一下连接检测的参数就行了。
这里把相关的配置参数说明贴出来,希望能让大家避免一些坑吧。

  1. minIdle
    资源池确保最少空闲的连接数,默认值:0
  2. maxIdle
    资源池允许最大空闲的连接数,默认值:8
  3. maxTotal
    资源池中最大连接数,默认值:8
  4. maxWaitMillis
    当资源池连接用尽后,调用者的最大等待时间,单位是毫秒,默认值:-1(表示永不超时),建议根据业务修改为合理的值
  5. testOnBorrow
    向资源池借用连接时,是否做连接有效性检测,无效连接会被移除,默认值:false ,业务量很大时建议为false,减少一次ping的开销
  6. testOnCreate
    创建新的资源连接后,是否做连接有效性检测,无效连接会被移除,默认值:false ,业务量很大时建议为false,减少一次ping的开销
  7. testOnReturn
    向资源池归还连接时,是否做连接有效性检测,无效连接会被移除,默认值:false,业务量很大时建议为false,减少一次ping的开销
  8. testWhileIdle
    是否在空闲资源监测时通过ping命令监测连接有效性,无效连接将被销毁
  9. blockWhenExhausted
    当资源池用尽后,调用者是否要等待。默认值:true,当为true时,maxWaitMillis参数才会生效,建议使用默认值
  10. lifo
    资源池里放池对象的方式,LIFO
    Last In First Out 后进先出,true(默认值),表示放在空闲队列最前面,false:放在空闲队列最后面
  11. timeBetweenEvictionRunsMillis
    空闲资源的检测周期,单位为毫秒,默认值:-1,表示不检测,建议设置一个合理的值,周期性运行监测任务
  12. minEvictableIdleTimeMillis
    资源池中资源最小空闲时间,单位为毫秒,默认值:30分钟,当达到该值后空闲资源将被移除,建议根据业务来调整
  13. numTestsPerEvictionRun
    做空闲资源检测时,每次的检测的连接个数,默认值:3,如果设置为 -1,表示对所有连接做空闲监测,建议根据业务来进行调整