记录服务器上,不定时出现io.lettuce.core.RedisCommandTimeoutException: Command timed out after xxx millisecond(s)

4 篇文章 0 订阅

记录服务器上,不定时出现io.lettuce.core.RedisCommandTimeoutException: Command timed out after 12 millisecond(s)

  • 日志

    • org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is org.springframework.data.redis.connection.PoolException: Could not get a resource from the pool; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 192.168.10.143:6350
      	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.translateException(LettuceConnectionFactory.java:1534) ~[spring-data-redis-2.3.5.RELEASE.jar:2.3.5.RELEASE]
      	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.getConnection(LettuceConnectionFactory.java:1442) ~[spring-data-redis-2.3.5.RELEASE.jar:2.3.5.RELEASE]
      	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getNativeConnection(LettuceConnectionFactory.java:1228) ~[spring-data-redis-2.3.5.RELEASE.jar:2.3.5.RELEASE]
      	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getConnection(LettuceConnectionFactory.java:1211) ~[spring-data-redis-2.3.5.RELEASE.jar:2.3.5.RELEASE]
      	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.getSharedReactiveConnection(LettuceConnectionFactory.java:985) ~[spring-data-redis-2.3.5.RELEASE.jar:2.3.5.RELEASE]
      	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.getReactiveConnection(LettuceConnectionFactory.java:446) ~[spring-data-redis-2.3.5.RELEASE.jar:2.3.5.RELEASE]
      	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.getReactiveConnection(LettuceConnectionFactory.java:99) ~[spring-data-redis-2.3.5.RELEASE.jar:2.3.5.RELEASE]
      	at reactor.core.publisher.MonoSupplier.call(MonoSupplier.java:85) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
      	at reactor.core.publisher.FluxSubscribeOnCallable$CallableSubscribeOnSubscription.run(FluxSubscribeOnCallable.java:225) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
      	at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
      	at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28) ~[reactor-core-3.3.11.RELEASE.jar:3.3.11.RELEASE]
      	at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) ~[na:1.8.0_251]
      	at java.util.concurrent.FutureTask.run(FutureTask.java) ~[na:1.8.0_251]
      	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) ~[na:1.8.0_251]
      	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) ~[na:1.8.0_251]
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_251]
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_251]
      	at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_251]
      Caused by: org.springframework.data.redis.connection.PoolException: Could not get a resource from the pool; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 192.168.10.143:6350
      	at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.getConnection(LettucePoolingConnectionProvider.java:109) ~[spring-data-redis-2.3.5.RELEASE.jar:2.3.5.RELEASE]
      	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.getConnection(LettuceConnectionFactory.java:1440) ~[spring-data-redis-2.3.5.RELEASE.jar:2.3.5.RELEASE]
      	... 16 common frames omitted
      Caused by: io.lettuce.core.RedisConnectionException: Unable to connect to 192.168.10.143:6350
      	at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:78) ~[lettuce-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
      	at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:56) ~[lettuce-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
      	at io.lettuce.core.AbstractRedisClient.getConnection(AbstractRedisClient.java:242) ~[lettuce-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
      	at io.lettuce.core.RedisClient.connect(RedisClient.java:206) ~[lettuce-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
      	at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider.lambda$getConnection$1(StandaloneConnectionProvider.java:115) ~[spring-data-redis-2.3.5.RELEASE.jar:2.3.5.RELEASE]
      	at java.util.Optional.orElseGet(Optional.java:267) ~[na:1.8.0_251]
      	at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider.getConnection(StandaloneConnectionProvider.java:115) ~[spring-data-redis-2.3.5.RELEASE.jar:2.3.5.RELEASE]
      	at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.lambda$null$0(LettucePoolingConnectionProvider.java:97) ~[spring-data-redis-2.3.5.RELEASE.jar:2.3.5.RELEASE]
      	at io.lettuce.core.support.ConnectionPoolSupport$RedisPooledObjectFactory.create(ConnectionPoolSupport.java:211) ~[lettuce-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
      	at io.lettuce.core.support.ConnectionPoolSupport$RedisPooledObjectFactory.create(ConnectionPoolSupport.java:201) ~[lettuce-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
      	at org.apache.commons.pool2.BasePooledObjectFactory.makeObject(BasePooledObjectFactory.java:58) ~[commons-pool2-2.8.1.jar:2.8.1]
      	at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:899) ~[commons-pool2-2.8.1.jar:2.8.1]
      	at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:429) ~[commons-pool2-2.8.1.jar:2.8.1]
      	at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:354) ~[commons-pool2-2.8.1.jar:2.8.1]
      	at io.lettuce.core.support.ConnectionPoolSupport$1.borrowObject(ConnectionPoolSupport.java:122) ~[lettuce-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
      	at io.lettuce.core.support.ConnectionPoolSupport$1.borrowObject(ConnectionPoolSupport.java:117) ~[lettuce-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
      	at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.getConnection(LettucePoolingConnectionProvider.java:103) ~[spring-data-redis-2.3.5.RELEASE.jar:2.3.5.RELEASE]
      	... 17 common frames omitted
      Caused by: io.lettuce.core.RedisCommandTimeoutException: Command timed out after 12 millisecond(s)
      	at io.lettuce.core.ExceptionFactory.createTimeoutException(ExceptionFactory.java:51) ~[lettuce-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
      	at io.lettuce.core.protocol.CommandExpiryWriter.lambda$potentiallyExpire$0(CommandExpiryWriter.java:172) ~[lettuce-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
      	at io.netty.util.concurrent.PromiseTask.runTask(PromiseTask.java:98) ~[netty-common-4.1.53.Final.jar:4.1.53.Final]
      	at io.netty.util.concurrent.ScheduledFutureTask.run(ScheduledFutureTask.java:170) ~[netty-common-4.1.53.Final.jar:4.1.53.Final]
      	at io.netty.util.concurrent.DefaultEventExecutor.run(DefaultEventExecutor.java:66) ~[netty-common-4.1.53.Final.jar:4.1.53.Final]
      	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) ~[netty-common-4.1.53.Final.jar:4.1.53.Final]
      	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.53.Final.jar:4.1.53.Final]
      	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.53.Final.jar:4.1.53.Final]
      	... 1 common frames omitted
      
      
      
原因分析
  • 由于lettuce没有心跳检测,直接能判断为查询redis数据超时了。

  • 网上百度了一波,发现有结论说是替换lettuce 为 jedis 就能解决问题**【此方案无效】**

    • 修改pom文件

      •     <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>redis.clients</groupId>
              <artifactId>jedis</artifactId>
            </dependency>
        
  • 替换后,使用jedis链接池运行一段时间,又报出了JedisConnectionException: java.net.SocketTimeoutException: Read timed out异常,接下去继续分析

记录服务器上,不定时出现JedisConnectionException: java.net.SocketTimeoutException: Read timed out的问题

错误日志
  • org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
    	at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:282)
    	at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:476)
    	at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:134)
    	at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:97)
    	at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:84)
    	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:215)
    	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:188)
    	at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:96)
    	at org.springframework.data.redis.core.DefaultSetOperations.size(DefaultSetOperations.java:330)
    	at com.rivtower.rivus.product.service.impl.ProductDefServiceImpl.handlePublishingQty(ProductDefServiceImpl.java:279)
    	at com.rivtower.rivus.product.service.impl.ProductDefServiceImpl$$FastClassBySpringCGLIB$$e459cf51.invoke(<generated>)
    	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:687)
    	at com.rivtower.rivus.product.service.impl.ProductDefServiceImpl$$EnhancerBySpringCGLIB$$85b0914f.handlePublishingQty(<generated>)
    	at com.rivtower.rivus.product.controller.ProductDefController.queryProductDefByRegisterId(ProductDefController.java:85)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
    	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
    	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
    	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
    	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
    	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)
    	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    	at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    	at org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter.doFilterInternal(BearerTokenAuthenticationFilter.java:130)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    	at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)
    	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
    	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
    	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
    	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
    	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
    	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
    	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
    	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
    	at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:747)
    	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
    	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
    	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
    	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    	at java.lang.Thread.run(Thread.java:748)
    Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
    	at redis.clients.jedis.util.RedisInputStream.ensureFill(RedisInputStream.java:205)
    	at redis.clients.jedis.util.RedisInputStream.readByte(RedisInputStream.java:43)
    	at redis.clients.jedis.Protocol.process(Protocol.java:155)
    	at redis.clients.jedis.Protocol.read(Protocol.java:220)
    	at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:278)
    	at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:196)
    	at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:119)
    	at redis.clients.jedis.BinaryJedis.connect(BinaryJedis.java:1904)
    	at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:277)
    	... 103 common frames omitted
    Caused by: java.net.SocketTimeoutException: Read timed out
    	at java.net.SocketInputStream.socketRead0(Native Method)
    	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    	at java.net.SocketInputStream.read(SocketInputStream.java:171)
    	at java.net.SocketInputStream.read(SocketInputStream.java:141)
    	at java.net.SocketInputStream.read(SocketInputStream.java:127)
    	at redis.clients.jedis.util.RedisInputStream.ensureFill(RedisInputStream.java:199)
    	... 111 common frames omitted
    
问题分析
  • 前面将redis的连接池从lettuce换成了jedis,但是依然出现了redis超时异常,由此可见应该从配置问题找起。不过首先先定位下报错位置,从错误日志最底部的方法栈排查java.net.SocketInputStream.socketRead0为本地方法,可以从java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
问题排查
  • 由于排查SocketInputStream这个IO类没有识别性,最终定位错误日志最终在redis.clients.jedis.util.RedisInputStream.ensureFill(RedisInputStream.java:199),

    • Caused by: java.net.SocketTimeoutException: Read timed out
      	at java.net.SocketInputStream.socketRead0(Native Method)
      	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
      	at java.net.SocketInputStream.read(SocketInputStream.java:171)
      	at java.net.SocketInputStream.read(SocketInputStream.java:141)
      	at java.net.SocketInputStream.read(SocketInputStream.java:127)
      	at redis.clients.jedis.util.RedisInputStream.ensureFill(RedisInputStream.java:199)
      	... 111 common frames omitted
      
  • 定位代码报错位置

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SQ0fCrrX-1650870043921)(D:\cita\doc\问题记录pic\2022-04-22\jedisInputStream.png)]
  • 下断点后排查,发现超时时间是SocketInputStream的一个属性,那么就找下这个属性的初始化赋值。

    • 在这里插入图片描述
反向推理
  • 方向查询SocketInputStream的初始化创建过程

    • SocketInputStream <- RedisInputStream(InputStream in, int size) <- redis.clients.jedis.Connection.connect() <- new RedisInputStream(socket.getInputStream()) <- jedisSocketFactory.createSocket() <- 	DefaultJedisSocketFactory.createSocket()
      
  • 查看createSocket()源码,发现超时时间是 通过getSoTimeout()获取,getSoTimeout()方法获取的是DefaultJedisSocketFactory的属性值soTimeout,那么接下去追溯DefaultJedisSocketFactory创建过程

    •   @Override
        public Socket createSocket() throws IOException {
          Socket socket = null;
          try {
            socket = new Socket();
            // ->@wjw_add
            socket.setReuseAddress(true);
            socket.setKeepAlive(true); // Will monitor the TCP connection is
            // valid
            socket.setTcpNoDelay(true); // Socket buffer Whetherclosed, to
            // ensure timely delivery of data
            socket.setSoLinger(true, 0); // Control calls close () method,
            // the underlying socket is closed
            // immediately
            // <-@wjw_add
      
            socket.connect(new InetSocketAddress(getHost(), getPort()), getConnectionTimeout());
            //超时时间
            socket.setSoTimeout(getSoTimeout());
      
            if (ssl) {
              if (null == sslSocketFactory) {
                sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
              }
              socket = sslSocketFactory.createSocket(socket, getHost(), getPort(), true);
              if (null != sslParameters) {
                ((SSLSocket) socket).setSSLParameters(sslParameters);
              }
              if ((null != hostnameVerifier)
                  && (!hostnameVerifier.verify(getHost(), ((SSLSocket) socket).getSession()))) {
                String message = String.format(
                  "The connection to '%s' failed ssl/tls hostname verification.", getHost());
                throw new JedisConnectionException(message);
              }
            }
            return socket;
          } catch (Exception ex) {
            if (socket != null) {
              socket.close();
            }
            throw ex;
          }
        }
      
  • DefaultJedisSocketFactory创建过程

    • DefaultJedisSocketFactory(String host, int port, int connectionTimeout, int soTimeout,
            boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters,
            HostnameVerifier hostnameVerifier) <- setSoTimeout() <-  BinaryJedis(final String host, final int port, final int connectionTimeout,
            final int soTimeout) <- Jedis(final String host, final int port, final int connectionTimeout, final int soTimeout) <-  JedisConnectionFactory.getActiveSentinel()
      
  • 在JedisConnectionFactory.getActiveSentinel方法中找到如下逻辑

    • public class JedisConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory {
          
          private final JedisClientConfiguration clientConfiguration;
          
      	private Jedis getActiveSentinel() {
      
      		Assert.isTrue(RedisConfiguration.isSentinelConfiguration(configuration), "SentinelConfig must not be null!");
      
      		for (RedisNode node : ((SentinelConfiguration) configuration).getSentinels()) {
      			//创建Jedis
      			Jedis jedis = new Jedis(node.getHost(), node.getPort(), getConnectTimeout(), getReadTimeout());
      
      			try {
      				if (jedis.ping().equalsIgnoreCase("pong")) {
      
      					potentiallySetClientName(jedis);
      					return jedis;
      				}
      			} catch (Exception ex) {
      				log.warn(String.format("Ping failed for sentinel host:%s", node.getHost()), ex);
      			}
      		}
      
      		throw new InvalidDataAccessResourceUsageException("No Sentinel found");
      	}
      
      	private int getReadTimeout() {
      		return Math.toIntExact(clientConfiguration.getReadTimeout().toMillis());
      	}
      }
      
    • 可以看到,readTimeOut最终是获取了JedisClientConfiguration clientConfiguration。接下去还是一样,查询JedisClientConfiguration的初始化赋值过程

  • 下断点排查是通过public JedisConnectionFactory(RedisStandaloneConfiguration standaloneConfig, JedisClientConfiguration clientConfig) 构造方法初始化的 JedisConnectionFactory。而在此构造方法中传入了 JedisClientConfiguration clientConfig,这个类的具体实现类是 DefaultJedisClientConfiguration,这里可以发现已经是排查到spring-data-redis模块了,接下去可以提前设想下,这个Configuration类 读取的配置 是读取 yml文件或者config文件的配置。

    • package org.springframework.data.redis.connection.jedis;
      
      class DefaultJedisClientConfiguration implements JedisClientConfiguration {
      	DefaultJedisClientConfiguration(boolean useSsl, @Nullable SSLSocketFactory sslSocketFactory,
      			@Nullable SSLParameters sslParameters, @Nullable HostnameVerifier hostnameVerifier, boolean usePooling,
      			@Nullable GenericObjectPoolConfig poolConfig, @Nullable String clientName, Duration readTimeout,
      			Duration connectTimeout) {
      
      		this.useSsl = useSsl;
      		this.sslSocketFactory = Optional.ofNullable(sslSocketFactory);
      		this.sslParameters = Optional.ofNullable(sslParameters);
      		this.hostnameVerifier = Optional.ofNullable(hostnameVerifier);
      		this.usePooling = usePooling;
      		this.poolConfig = Optional.ofNullable(poolConfig);
      		this.clientName = Optional.ofNullable(clientName);
      		this.readTimeout = readTimeout;
      		this.connectTimeout = connectTimeout;
      	}
      }
      
  • 继续追溯org.springframework.data.redis.connection.jedis.DefaultJedisClientConfiguration 初始化过程

    • public interface JedisClientConfiguration {
          private Duration readTimeout = Duration.ofMillis(Protocol.DEFAULT_TIMEOUT);
          
          @Override
          public JedisClientConfigurationBuilder readTimeout(Duration readTimeout) {
      
              Assert.notNull(readTimeout, "Duration must not be null!");
      
              this.readTimeout = readTimeout;
              return this;
          }
      
          @Override
          public JedisClientConfiguration build() {
      
              return new DefaultJedisClientConfiguration(useSsl, sslSocketFactory, sslParameters, hostnameVerifier, usePooling, poolConfig, clientName, readTimeout, connectTimeout);
          }
      }
      
      
      
  • 最终找到了 spring-data-redis-starter的自动装配的类

    • package org.springframework.boot.autoconfigure.data.redis;
      
      import java.net.UnknownHostException;
      import java.time.Duration;
      
      import org.apache.commons.pool2.impl.GenericObjectPool;
      import redis.clients.jedis.Jedis;
      import redis.clients.jedis.JedisPoolConfig;
      
      import org.springframework.beans.factory.ObjectProvider;
      import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
      import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.data.redis.connection.RedisClusterConfiguration;
      import org.springframework.data.redis.connection.RedisConnectionFactory;
      import org.springframework.data.redis.connection.RedisSentinelConfiguration;
      import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
      import org.springframework.data.redis.connection.jedis.JedisClientConfiguration.JedisClientConfigurationBuilder;
      import org.springframework.data.redis.connection.jedis.JedisConnection;
      import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
      import org.springframework.util.StringUtils;
      
      /**
       * Redis connection configuration using Jedis.
       *
       * @author Mark Paluch
       * @author Stephane Nicoll
       */
      @Configuration(proxyBeanMethods = false)
      @ConditionalOnClass({ GenericObjectPool.class, JedisConnection.class, Jedis.class })
      class JedisConnectionConfiguration extends RedisConnectionConfiguration {
      
      	JedisConnectionConfiguration(RedisProperties properties,
      			ObjectProvider<RedisSentinelConfiguration> sentinelConfiguration,
      			ObjectProvider<RedisClusterConfiguration> clusterConfiguration) {
      		super(properties, sentinelConfiguration, clusterConfiguration);
      	}
      
      	@Bean
      	@ConditionalOnMissingBean(RedisConnectionFactory.class)
      	JedisConnectionFactory redisConnectionFactory(
      			ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) throws UnknownHostException {
      		return createJedisConnectionFactory(builderCustomizers);
      	}
      
      	private JedisConnectionFactory createJedisConnectionFactory(
      			ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {
      		JedisClientConfiguration clientConfiguration = getJedisClientConfiguration(builderCustomizers);
      		if (getSentinelConfig() != null) {
      			return new JedisConnectionFactory(getSentinelConfig(), clientConfiguration);
      		}
      		if (getClusterConfiguration() != null) {
      			return new JedisConnectionFactory(getClusterConfiguration(), clientConfiguration);
      		}
      		return new JedisConnectionFactory(getStandaloneConfig(), clientConfiguration);
      	}
      
      	private JedisClientConfiguration getJedisClientConfiguration(
      			ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {
      		JedisClientConfigurationBuilder builder = applyProperties(JedisClientConfiguration.builder());
      		RedisProperties.Pool pool = getProperties().getJedis().getPool();
      		if (pool != null) {
      			applyPooling(pool, builder);
      		}
      		if (StringUtils.hasText(getProperties().getUrl())) {
      			customizeConfigurationFromUrl(builder);
      		}
      		builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
      		return builder.build();
      	}
      
      	private JedisClientConfigurationBuilder applyProperties(JedisClientConfigurationBuilder builder) {
      		if (getProperties().isSsl()) {
      			builder.useSsl();
      		}
      		if (getProperties().getTimeout() != null) {
      			Duration timeout = getProperties().getTimeout();
      			builder.readTimeout(timeout).connectTimeout(timeout);
      		}
      		if (StringUtils.hasText(getProperties().getClientName())) {
      			builder.clientName(getProperties().getClientName());
      		}
      		return builder;
      	}
      
      	private void applyPooling(RedisProperties.Pool pool,
      			JedisClientConfiguration.JedisClientConfigurationBuilder builder) {
      		builder.usePooling().poolConfig(jedisPoolConfig(pool));
      	}
      
      	private JedisPoolConfig jedisPoolConfig(RedisProperties.Pool pool) {
      		JedisPoolConfig config = new JedisPoolConfig();
      		config.setMaxTotal(pool.getMaxActive());
      		config.setMaxIdle(pool.getMaxIdle());
      		config.setMinIdle(pool.getMinIdle());
      		if (pool.getTimeBetweenEvictionRuns() != null) {
      			config.setTimeBetweenEvictionRunsMillis(pool.getTimeBetweenEvictionRuns().toMillis());
      		}
      		if (pool.getMaxWait() != null) {
      			config.setMaxWaitMillis(pool.getMaxWait().toMillis());
      		}
      		return config;
      	}
      
      	private void customizeConfigurationFromUrl(JedisClientConfiguration.JedisClientConfigurationBuilder builder) {
      		ConnectionInfo connectionInfo = parseUrl(getProperties().getUrl());
      		if (connectionInfo.isUseSsl()) {
      			builder.useSsl();
      		}
      	}
      }
      
    • @ConfigurationProperties(prefix = "spring.redis")
      public class RedisProperties {
      
         /**
          * Database index used by the connection factory.
          */
         private int database = 0;
      
         /**
          * Connection URL. Overrides host, port, and password. User is ignored. Example:
          * redis://user:password@example.com:6379
          */
         private String url;
      
         /**
          * Redis server host.
          */
         private String host = "localhost";
      
         /**
          * Login password of the redis server.
          */
         private String password;
      
         /**
          * Redis server port.
          */
         private int port = 6379;
      
         /**
          * Whether to enable SSL support.
          */
         private boolean ssl;
      
         /**
          * Connection timeout.
          */
         private Duration timeout;
      
         /**
          * Client name to be set on connections with CLIENT SETNAME.
          */
         private String clientName;
      
         private Sentinel sentinel;
      
         private Cluster cluster;
      
         private final Jedis jedis = new Jedis();
      
         private final Lettuce lettuce = new Lettuce();
      
         public int getDatabase() {
            return this.database;
         }
      
         public void setDatabase(int database) {
            this.database = database;
         }
      
         public String getUrl() {
            return this.url;
         }
      
         public void setUrl(String url) {
            this.url = url;
         }
      
         public String getHost() {
            return this.host;
         }
      
         public void setHost(String host) {
            this.host = host;
         }
      
         public String getPassword() {
            return this.password;
         }
      
         public void setPassword(String password) {
            this.password = password;
         }
      
         public int getPort() {
            return this.port;
         }
      
         public void setPort(int port) {
            this.port = port;
         }
      
         public boolean isSsl() {
            return this.ssl;
         }
      
         public void setSsl(boolean ssl) {
            this.ssl = ssl;
         }
      
         public void setTimeout(Duration timeout) {
            this.timeout = timeout;
         }
      
         public Duration getTimeout() {
            return this.timeout;
         }
      
         public String getClientName() {
            return this.clientName;
         }
      
         public void setClientName(String clientName) {
            this.clientName = clientName;
         }
      
         public Sentinel getSentinel() {
            return this.sentinel;
         }
      
         public void setSentinel(Sentinel sentinel) {
            this.sentinel = sentinel;
         }
      
         public Cluster getCluster() {
            return this.cluster;
         }
      
         public void setCluster(Cluster cluster) {
            this.cluster = cluster;
         }
      
         public Jedis getJedis() {
            return this.jedis;
         }
      
         public Lettuce getLettuce() {
            return this.lettuce;
         }
      
         /**
          * Pool properties.
          */
         public static class Pool {
      
            /**
             * Maximum number of "idle" connections in the pool. Use a negative value to
             * indicate an unlimited number of idle connections.
             */
            private int maxIdle = 8;
      
            /**
             * Target for the minimum number of idle connections to maintain in the pool. This
             * setting only has an effect if both it and time between eviction runs are
             * positive.
             */
            private int minIdle = 0;
      
            /**
             * Maximum number of connections that can be allocated by the pool at a given
             * time. Use a negative value for no limit.
             */
            private int maxActive = 8;
      
            /**
             * Maximum amount of time a connection allocation should block before throwing an
             * exception when the pool is exhausted. Use a negative value to block
             * indefinitely.
             */
            private Duration maxWait = Duration.ofMillis(-1);
      
            /**
             * Time between runs of the idle object evictor thread. When positive, the idle
             * object evictor thread starts, otherwise no idle object eviction is performed.
             */
            private Duration timeBetweenEvictionRuns;
      
            public int getMaxIdle() {
               return this.maxIdle;
            }
      
            public void setMaxIdle(int maxIdle) {
               this.maxIdle = maxIdle;
            }
      
            public int getMinIdle() {
               return this.minIdle;
            }
      
            public void setMinIdle(int minIdle) {
               this.minIdle = minIdle;
            }
      
            public int getMaxActive() {
               return this.maxActive;
            }
      
            public void setMaxActive(int maxActive) {
               this.maxActive = maxActive;
            }
      
            public Duration getMaxWait() {
               return this.maxWait;
            }
      
            public void setMaxWait(Duration maxWait) {
               this.maxWait = maxWait;
            }
      
            public Duration getTimeBetweenEvictionRuns() {
               return this.timeBetweenEvictionRuns;
            }
      
            public void setTimeBetweenEvictionRuns(Duration timeBetweenEvictionRuns) {
               this.timeBetweenEvictionRuns = timeBetweenEvictionRuns;
            }
      
         }
      
         /**
          * Cluster properties.
          */
         public static class Cluster {
      
            /**
             * Comma-separated list of "host:port" pairs to bootstrap from. This represents an
             * "initial" list of cluster nodes and is required to have at least one entry.
             */
            private List<String> nodes;
      
            /**
             * Maximum number of redirects to follow when executing commands across the
             * cluster.
             */
            private Integer maxRedirects;
      
            public List<String> getNodes() {
               return this.nodes;
            }
      
            public void setNodes(List<String> nodes) {
               this.nodes = nodes;
            }
      
            public Integer getMaxRedirects() {
               return this.maxRedirects;
            }
      
            public void setMaxRedirects(Integer maxRedirects) {
               this.maxRedirects = maxRedirects;
            }
      
         }
      
         /**
          * Redis sentinel properties.
          */
         public static class Sentinel {
      
            /**
             * Name of the Redis server.
             */
            private String master;
      
            /**
             * Comma-separated list of "host:port" pairs.
             */
            private List<String> nodes;
      
            /**
             * Password for authenticating with sentinel(s).
             */
            private String password;
      
            public String getMaster() {
               return this.master;
            }
      
            public void setMaster(String master) {
               this.master = master;
            }
      
            public List<String> getNodes() {
               return this.nodes;
            }
      
            public void setNodes(List<String> nodes) {
               this.nodes = nodes;
            }
      
            public String getPassword() {
               return this.password;
            }
      
            public void setPassword(String password) {
               this.password = password;
            }
      
         }
      
         /**
          * Jedis client properties.
          */
         public static class Jedis {
      
            /**
             * Jedis pool configuration.
             */
            private Pool pool;
      
            public Pool getPool() {
               return this.pool;
            }
      
            public void setPool(Pool pool) {
               this.pool = pool;
            }
      
         }
      
         /**
          * Lettuce client properties.
          */
         public static class Lettuce {
      
            /**
             * Shutdown timeout.
             */
            private Duration shutdownTimeout = Duration.ofMillis(100);
      
            /**
             * Lettuce pool configuration.
             */
            private Pool pool;
      
            private final Cluster cluster = new Cluster();
      
            public Duration getShutdownTimeout() {
               return this.shutdownTimeout;
            }
      
            public void setShutdownTimeout(Duration shutdownTimeout) {
               this.shutdownTimeout = shutdownTimeout;
            }
      
            public Pool getPool() {
               return this.pool;
            }
      
            public void setPool(Pool pool) {
               this.pool = pool;
            }
      
            public Cluster getCluster() {
               return this.cluster;
            }
      
            public static class Cluster {
      
               private final Refresh refresh = new Refresh();
      
               public Refresh getRefresh() {
                  return this.refresh;
               }
      
               public static class Refresh {
      
                  /**
                   * Cluster topology refresh period.
                   */
                  private Duration period;
      
                  /**
                   * Whether adaptive topology refreshing using all available refresh
                   * triggers should be used.
                   */
                  private boolean adaptive;
      
                  public Duration getPeriod() {
                     return this.period;
                  }
      
                  public void setPeriod(Duration period) {
                     this.period = period;
                  }
      
                  public boolean isAdaptive() {
                     return this.adaptive;
                  }
      
                  public void setAdaptive(boolean adaptive) {
                     this.adaptive = adaptive;
                  }
      
               }
      
            }
      
         }
      
      }
      
  • 总结最后发现RedisInputStream的readTimeout的值,是从RedisProperties 配置类中获取的,获取的配置项是spring.redis.timeout

正向总结-逻辑
  1. 项目类依赖于RedisTemplate

    • //1.存在类存在属性依赖RedisTemplate,这就开始了Redis相关类bean的初始化
      public class Test{
      	@Autowired
      	private RedisTemplate<String,String> redisTemplate;
      }
      
  2. RedisTemplate由项目中配置类创建Bean,此处决定RedisTemplate的初始化创建依赖于RedisConnectionFactory factory

    • @Configuration
      @EnableCaching //开启注解
      public class RedisConfig extends CachingConfigurerSupport {
        @Resource(name = "customObjectMapper")
        private ObjectMapper om;
      
        /**
         * redisTemplate相关配置
         * @param factory
         * @return
         */
        @Bean
        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
      
          RedisTemplate<String, Object> template = new RedisTemplate<>();
          // 配置连接工厂
          template.setConnectionFactory(factory);
      
          //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
          Jackson2JsonRedisSerializer<Object> jacksonSerial = new Jackson2JsonRedisSerializer<>(Object.class);
      
          jacksonSerial.setObjectMapper(om);
      
          // 值采用json序列化
          template.setValueSerializer(jacksonSerial);
          //使用StringRedisSerializer来序列化和反序列化redis的key值
          template.setKeySerializer(new StringRedisSerializer());
      
          // 设置hash key 和value序列化模式
          template.setHashKeySerializer(new StringRedisSerializer());
          template.setHashValueSerializer(jacksonSerial);
          template.afterPropertiesSet();
      
          return template;
        }
      
      
      }
      
  3. RedisConnectionFactory 的创建是由org.springframework.boot.autoconfigure.data.redis.JedisConnectionConfiguration创建的。这里需要记住JedisConnectionConfiguration下的两个属性,因为JedisConnectionConfiguration是继承RedisConnectionConfiguration,在RedisConnectionConfiguration中存在属性 private final RedisProperties properties;后续会用到

    • package org.springframework.boot.autoconfigure.data.redis;
      /**
       * Redis connection configuration using Jedis.
       *
       * @author Mark Paluch
       * @author Stephane Nicoll
       */
      @Configuration(proxyBeanMethods = false)
      @ConditionalOnClass({ GenericObjectPool.class, JedisConnection.class, Jedis.class })
      class JedisConnectionConfiguration extends RedisConnectionConfiguration {
      
      	JedisConnectionConfiguration(RedisProperties properties,
      			ObjectProvider<RedisSentinelConfiguration> sentinelConfiguration,
      			ObjectProvider<RedisClusterConfiguration> clusterConfiguration) {
      		super(properties, sentinelConfiguration, clusterConfiguration);
      	}
      
          //当项目中不存在RedisConnectionFactory,则创建RedisConnectionFactory
      	@Bean
      	@ConditionalOnMissingBean(RedisConnectionFactory.class)
      	JedisConnectionFactory redisConnectionFactory(
      			ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) throws UnknownHostException {
              //调用私有方法createJedisConnectionFactory(ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers)
      		return createJedisConnectionFactory(builderCustomizers);
      	}
      
      	private JedisConnectionFactory createJedisConnectionFactory(
      			ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {
      		JedisClientConfiguration clientConfiguration = getJedisClientConfiguration(builderCustomizers);
      		if (getSentinelConfig() != null) {
      			return new JedisConnectionFactory(getSentinelConfig(), clientConfiguration);
      		}
      		if (getClusterConfiguration() != null) {
      			return new JedisConnectionFactory(getClusterConfiguration(), clientConfiguration);
      		}
      		return new JedisConnectionFactory(getStandaloneConfig(), clientConfiguration);
      	}
      
      	private JedisClientConfiguration getJedisClientConfiguration(
      			ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {
      		JedisClientConfigurationBuilder builder = applyProperties(JedisClientConfiguration.builder());
      		RedisProperties.Pool pool = getProperties().getJedis().getPool();
      		if (pool != null) {
      			applyPooling(pool, builder);
      		}
      		if (StringUtils.hasText(getProperties().getUrl())) {
      			customizeConfigurationFromUrl(builder);
      		}
      		builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
      		return builder.build();
      	}
      
      	private JedisClientConfigurationBuilder applyProperties(JedisClientConfigurationBuilder builder) {
      		if (getProperties().isSsl()) {
      			builder.useSsl();
      		}
      		if (getProperties().getTimeout() != null) {
      			Duration timeout = getProperties().getTimeout();
      			builder.readTimeout(timeout).connectTimeout(timeout);
      		}
      		if (StringUtils.hasText(getProperties().getClientName())) {
      			builder.clientName(getProperties().getClientName());
      		}
      		return builder;
      	}
      
      	private void applyPooling(RedisProperties.Pool pool,
      			JedisClientConfiguration.JedisClientConfigurationBuilder builder) {
      		builder.usePooling().poolConfig(jedisPoolConfig(pool));
      	}
      
      	private JedisPoolConfig jedisPoolConfig(RedisProperties.Pool pool) {
      		JedisPoolConfig config = new JedisPoolConfig();
      		config.setMaxTotal(pool.getMaxActive());
      		config.setMaxIdle(pool.getMaxIdle());
      		config.setMinIdle(pool.getMinIdle());
      		if (pool.getTimeBetweenEvictionRuns() != null) {
      			config.setTimeBetweenEvictionRunsMillis(pool.getTimeBetweenEvictionRuns().toMillis());
      		}
      		if (pool.getMaxWait() != null) {
      			config.setMaxWaitMillis(pool.getMaxWait().toMillis());
      		}
      		return config;
      	}
      
      	private void customizeConfigurationFromUrl(JedisClientConfiguration.JedisClientConfigurationBuilder builder) {
      		ConnectionInfo connectionInfo = parseUrl(getProperties().getUrl());
      		if (connectionInfo.isUseSsl()) {
      			builder.useSsl();
      		}
      	}
      
      }
      
    • abstract class RedisConnectionConfiguration {
      
      	private final RedisProperties properties;
      }
      
  4. 而从JedisConnectionConfiguration(RedisProperties properties,
    ObjectProvider sentinelConfiguration,
    ObjectProvider clusterConfiguration)可以看到,JedisConnectionConfiguration依赖RedisProperties配置类

    • @ConfigurationProperties(prefix = "spring.redis")
      public class RedisProperties {
      
      	/**
      	 * Database index used by the connection factory.
      	 */
      	private int database = 0;
      
      	/**
      	 * Connection URL. Overrides host, port, and password. User is ignored. Example:
      	 * redis://user:password@example.com:6379
      	 */
      	private String url;
      
      	/**
      	 * Redis server host.
      	 */
      	private String host = "localhost";
      
      	/**
      	 * Login password of the redis server.
      	 */
      	private String password;
      
      	/**
      	 * Redis server port.
      	 */
      	private int port = 6379;
      
      	/**
      	 * Whether to enable SSL support.
      	 */
      	private boolean ssl;
      
      	/**
      	 * Connection timeout.
      	 */
      	private Duration timeout;
      
      	/**
      	 * Client name to be set on connections with CLIENT SETNAME.
      	 */
      	private String clientName;
      
      	private Sentinel sentinel;
      
      	private Cluster cluster;
      
      	private final Jedis jedis = new Jedis();
      
      	private final Lettuce lettuce = new Lettuce();
      
      	public int getDatabase() {
      		return this.database;
      	}
      
      	public void setDatabase(int database) {
      		this.database = database;
      	}
      
      	public String getUrl() {
      		return this.url;
      	}
      
      	public void setUrl(String url) {
      		this.url = url;
      	}
      
      	public String getHost() {
      		return this.host;
      	}
      
      	public void setHost(String host) {
      		this.host = host;
      	}
      
      	public String getPassword() {
      		return this.password;
      	}
      
      	public void setPassword(String password) {
      		this.password = password;
      	}
      
      	public int getPort() {
      		return this.port;
      	}
      
      	public void setPort(int port) {
      		this.port = port;
      	}
      
      	public boolean isSsl() {
      		return this.ssl;
      	}
      
      	public void setSsl(boolean ssl) {
      		this.ssl = ssl;
      	}
      
      	public void setTimeout(Duration timeout) {
      		this.timeout = timeout;
      	}
      
      	public Duration getTimeout() {
      		return this.timeout;
      	}
      
      	public String getClientName() {
      		return this.clientName;
      	}
      
      	public void setClientName(String clientName) {
      		this.clientName = clientName;
      	}
      
      	public Sentinel getSentinel() {
      		return this.sentinel;
      	}
      
      	public void setSentinel(Sentinel sentinel) {
      		this.sentinel = sentinel;
      	}
      
      	public Cluster getCluster() {
      		return this.cluster;
      	}
      
      	public void setCluster(Cluster cluster) {
      		this.cluster = cluster;
      	}
      
      	public Jedis getJedis() {
      		return this.jedis;
      	}
      
      	public Lettuce getLettuce() {
      		return this.lettuce;
      	}
      
      	/**
      	 * Pool properties.
      	 */
      	public static class Pool {
      
      		/**
      		 * Maximum number of "idle" connections in the pool. Use a negative value to
      		 * indicate an unlimited number of idle connections.
      		 */
      		private int maxIdle = 8;
      
      		/**
      		 * Target for the minimum number of idle connections to maintain in the pool. This
      		 * setting only has an effect if both it and time between eviction runs are
      		 * positive.
      		 */
      		private int minIdle = 0;
      
      		/**
      		 * Maximum number of connections that can be allocated by the pool at a given
      		 * time. Use a negative value for no limit.
      		 */
      		private int maxActive = 8;
      
      		/**
      		 * Maximum amount of time a connection allocation should block before throwing an
      		 * exception when the pool is exhausted. Use a negative value to block
      		 * indefinitely.
      		 */
      		private Duration maxWait = Duration.ofMillis(-1);
      
      		/**
      		 * Time between runs of the idle object evictor thread. When positive, the idle
      		 * object evictor thread starts, otherwise no idle object eviction is performed.
      		 */
      		private Duration timeBetweenEvictionRuns;
      
      		public int getMaxIdle() {
      			return this.maxIdle;
      		}
      
      		public void setMaxIdle(int maxIdle) {
      			this.maxIdle = maxIdle;
      		}
      
      		public int getMinIdle() {
      			return this.minIdle;
      		}
      
      		public void setMinIdle(int minIdle) {
      			this.minIdle = minIdle;
      		}
      
      		public int getMaxActive() {
      			return this.maxActive;
      		}
      
      		public void setMaxActive(int maxActive) {
      			this.maxActive = maxActive;
      		}
      
      		public Duration getMaxWait() {
      			return this.maxWait;
      		}
      
      		public void setMaxWait(Duration maxWait) {
      			this.maxWait = maxWait;
      		}
      
      		public Duration getTimeBetweenEvictionRuns() {
      			return this.timeBetweenEvictionRuns;
      		}
      
      		public void setTimeBetweenEvictionRuns(Duration timeBetweenEvictionRuns) {
      			this.timeBetweenEvictionRuns = timeBetweenEvictionRuns;
      		}
      
      	}
      
      	/**
      	 * Cluster properties.
      	 */
      	public static class Cluster {
      
      		/**
      		 * Comma-separated list of "host:port" pairs to bootstrap from. This represents an
      		 * "initial" list of cluster nodes and is required to have at least one entry.
      		 */
      		private List<String> nodes;
      
      		/**
      		 * Maximum number of redirects to follow when executing commands across the
      		 * cluster.
      		 */
      		private Integer maxRedirects;
      
      		public List<String> getNodes() {
      			return this.nodes;
      		}
      
      		public void setNodes(List<String> nodes) {
      			this.nodes = nodes;
      		}
      
      		public Integer getMaxRedirects() {
      			return this.maxRedirects;
      		}
      
      		public void setMaxRedirects(Integer maxRedirects) {
      			this.maxRedirects = maxRedirects;
      		}
      
      	}
      
      	/**
      	 * Redis sentinel properties.
      	 */
      	public static class Sentinel {
      
      		/**
      		 * Name of the Redis server.
      		 */
      		private String master;
      
      		/**
      		 * Comma-separated list of "host:port" pairs.
      		 */
      		private List<String> nodes;
      
      		/**
      		 * Password for authenticating with sentinel(s).
      		 */
      		private String password;
      
      		public String getMaster() {
      			return this.master;
      		}
      
      		public void setMaster(String master) {
      			this.master = master;
      		}
      
      		public List<String> getNodes() {
      			return this.nodes;
      		}
      
      		public void setNodes(List<String> nodes) {
      			this.nodes = nodes;
      		}
      
      		public String getPassword() {
      			return this.password;
      		}
      
      		public void setPassword(String password) {
      			this.password = password;
      		}
      
      	}
      
      	/**
      	 * Jedis client properties.
      	 */
      	public static class Jedis {
      
      		/**
      		 * Jedis pool configuration.
      		 */
      		private Pool pool;
      
      		public Pool getPool() {
      			return this.pool;
      		}
      
      		public void setPool(Pool pool) {
      			this.pool = pool;
      		}
      
      	}
      
      	/**
      	 * Lettuce client properties.
      	 */
      	public static class Lettuce {
      
      		/**
      		 * Shutdown timeout.
      		 */
      		private Duration shutdownTimeout = Duration.ofMillis(100);
      
      		/**
      		 * Lettuce pool configuration.
      		 */
      		private Pool pool;
      
      		private final Cluster cluster = new Cluster();
      
      		public Duration getShutdownTimeout() {
      			return this.shutdownTimeout;
      		}
      
      		public void setShutdownTimeout(Duration shutdownTimeout) {
      			this.shutdownTimeout = shutdownTimeout;
      		}
      
      		public Pool getPool() {
      			return this.pool;
      		}
      
      		public void setPool(Pool pool) {
      			this.pool = pool;
      		}
      
      		public Cluster getCluster() {
      			return this.cluster;
      		}
      
      		public static class Cluster {
      
      			private final Refresh refresh = new Refresh();
      
      			public Refresh getRefresh() {
      				return this.refresh;
      			}
      
      			public static class Refresh {
      
      				/**
      				 * Cluster topology refresh period.
      				 */
      				private Duration period;
      
      				/**
      				 * Whether adaptive topology refreshing using all available refresh
      				 * triggers should be used.
      				 */
      				private boolean adaptive;
      
      				public Duration getPeriod() {
      					return this.period;
      				}
      
      				public void setPeriod(Duration period) {
      					this.period = period;
      				}
      
      				public boolean isAdaptive() {
      					return this.adaptive;
      				}
      
      				public void setAdaptive(boolean adaptive) {
      					this.adaptive = adaptive;
      				}
      
      			}
      
      		}
      
      	}
      
      }
      
  5. RedisProperties配置类获取的是从配置类中获取spring.redis 下的相关配置项

    1.  redis:
          database: 4
          host: 192.168.10.143
          port: 6350
          password:
          lettuce:
            pool:
              max-idle: 8
              max-active: 8
              min-idle: 0
              max-wait: -1
          timeout: 12
      
  6. 上一步为初始化JedisConnectionConfiguration及其相关的依赖配置类,接下去的步骤是初始化JedisConnectionFactory类 的bean,通过JedisConnectionConfiguration.createJedisConnectionFactory() 方法

    • 	@Bean
      	@ConditionalOnMissingBean(RedisConnectionFactory.class)
      	JedisConnectionFactory redisConnectionFactory(
      			ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) throws UnknownHostException {
      		return createJedisConnectionFactory(builderCustomizers);
      	}
      
      	//创建JedisConnectionFactory
      	private JedisConnectionFactory createJedisConnectionFactory(
      			ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {
              //获取JedisClientConfigurationBuilder
      		JedisClientConfiguration clientConfiguration = getJedisClientConfiguration(builderCustomizers);
      		if (getSentinelConfig() != null) {
      			return new JedisConnectionFactory(getSentinelConfig(), clientConfiguration);
      		}
      		if (getClusterConfiguration() != null) {
      			return new JedisConnectionFactory(getClusterConfiguration(), clientConfiguration);
      		}
      		return new JedisConnectionFactory(getStandaloneConfig(), clientConfiguration);
      	}
      
          //获取JedisClientConfigurationBuilder
      	private JedisClientConfiguration getJedisClientConfiguration(
      			ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {
              //  org.springframework.data.redis.connection.jedis.JedisClientConfiguration.DefaultJedisClientConfigurationBuilder
              //关键步骤调用applyProperties 将redisProperties的timeout属性值 赋值给builder的readTimeout字段
      		JedisClientConfigurationBuilder builder = applyProperties(JedisClientConfiguration.builder());
      		RedisProperties.Pool pool = getProperties().getJedis().getPool();
      		if (pool != null) {
      			applyPooling(pool, builder);
      		}
      		if (StringUtils.hasText(getProperties().getUrl())) {
      			customizeConfigurationFromUrl(builder);
      		}
      		builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
              //Build the {@link JedisClientConfiguration} with the configuration applied from this builder. 这里要注意的是readTimeout的赋值
      		return builder.build();
      	}
      	
      	private JedisClientConfigurationBuilder applyProperties(JedisClientConfigurationBuilder builder) 	{
      		if (getProperties().isSsl()) {
      			builder.useSsl();
      		}
              //此处设置了redis readTimeout
      		if (getProperties().getTimeout() != null) {
                  //获取的是RedisProperties的Timeout属性
      			Duration timeout = getProperties().getTimeout();
      			builder.readTimeout(timeout).connectTimeout(timeout);
      		}
      		if (StringUtils.hasText(getProperties().getClientName())) {
      			builder.clientName(getProperties().getClientName());
      		}
      		return builder;
      	}
      
      
      
      	class DefaultJedisClientConfigurationBuilder implements JedisClientConfigurationBuilder,
      			JedisPoolingClientConfigurationBuilder, JedisSslClientConfigurationBuilder {
          	
              //初始化默认为Protocol.DEFAULT_TIMEOUT public static final int DEFAULT_TIMEOUT = 2000;
      		private Duration readTimeout = Duration.ofMillis(Protocol.DEFAULT_TIMEOUT);
      		/*
      		 * (non-Javadoc)
      		 * @see org.springframework.data.redis.connection.jedis.JedisClientConfiguration.JedisClientConfigurationBuilder#build()
      		 */
      		@Override
      		public JedisClientConfiguration build() {
      
      			return new DefaultJedisClientConfiguration(useSsl, sslSocketFactory, sslParameters, hostnameVerifier, usePooling,
      					poolConfig, clientName, readTimeout, connectTimeout);
      		}
              
              
      		/*
      		 * (non-Javadoc)
      		 * @see org.springframework.data.redis.connection.jedis.JedisClientConfiguration.JedisClientConfigurationBuilder#readTimeout(java.time.Duration)
      		 */
      		@Override
      		public JedisClientConfigurationBuilder readTimeout(Duration readTimeout) {
      
      			Assert.notNull(readTimeout, "Duration must not be null!");
      
      			this.readTimeout = readTimeout;
      			return this;
      		}
          }
      
  7. 此处可以获得到逻辑

    1. 初始化JedisConnectionFactory类 的bean
    2. 调用getJedisClientConfiguration()方法生成JedisClientConfigurationBuilder对象
    3. 生成JedisClientConfigurationBuilder对象后,调用applyProperties(JedisClientConfigurationBuilder builder)方法,将redisProperties的timeout属性值,赋值给JedisClientConfigurationBuilder 的ReadTimeout属性
    4. 总结:由此框架就定义了redis的readTimeout时间,至此在createJedisConnectionFactory()方法中的getJedisClientConfiguration()逻辑结束了。
  8. 将生成的JedisClientConfiguration赋值给JedisConnectionFactory,最后返回JedisConnectionFactory

    • 	private JedisConnectionFactory createJedisConnectionFactory(
      			ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {
      		JedisClientConfiguration clientConfiguration = getJedisClientConfiguration(builderCustomizers);
      		if (getSentinelConfig() != null) {
      			return new JedisConnectionFactory(getSentinelConfig(), clientConfiguration);
      		}
      		if (getClusterConfiguration() != null) {
      			return new JedisConnectionFactory(getClusterConfiguration(), clientConfiguration);
      		}
      		return new JedisConnectionFactory(getStandaloneConfig(), clientConfiguration);
      	}
      
  9. 创建完JedisConnectionFactory类的Bean对象后,回到redisTemplate类的Bean创建方法中,通过setConnectionFactory() 给redisTemplate赋值redis工厂。最后,完成redisTemplate 类的Bean创建。

    •   @Bean
        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
      
          RedisTemplate<String, Object> template = new RedisTemplate<>();
          // 配置连接工厂
          template.setConnectionFactory(factory);
      
          //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
          Jackson2JsonRedisSerializer<Object> jacksonSerial = new Jackson2JsonRedisSerializer<>(Object.class);
      
          jacksonSerial.setObjectMapper(om);
      
          // 值采用json序列化
          template.setValueSerializer(jacksonSerial);
          //使用StringRedisSerializer来序列化和反序列化redis的key值
          template.setKeySerializer(new StringRedisSerializer());
      
          // 设置hash key 和value序列化模式
          template.setHashKeySerializer(new StringRedisSerializer());
          template.setHashValueSerializer(jacksonSerial);
          template.afterPropertiesSet();
      
          return template;
        }
      
      
  10. 接下去是调用流程

    • redisTemplate.opsForValue().get(key);
      
    • public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
          
          AbstractOperations(RedisTemplate<K, V> template) {
      		this.template = template;
      	}
          
          DefaultValueOperations(RedisTemplate<K, V> template) {
      		super(template);
      	}
          
          private final ValueOperations<K, V> valueOps = new DefaultValueOperations<>(this);
          
      	/*
      	 * (non-Javadoc)
      	 * @see org.springframework.data.redis.core.RedisOperations#opsForValue()
      	 */
      	@Override
      	public ValueOperations<K, V> opsForValue() {
      		return valueOps;
      	}
          
          @Nullable
      	public <T> T execute(RedisCallback<T> action, boolean exposeConnection) {
      		return execute(action, exposeConnection, false);
      	}
          
          @Nullable
      	public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {
      
      		Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
      		Assert.notNull(action, "Callback object must not be null");
      
      		RedisConnectionFactory factory = getRequiredConnectionFactory();
      		RedisConnection conn = null;
      		try {
      
      			if (enableTransactionSupport) {
      				// only bind resources in case of potential transaction synchronization
      				conn = RedisConnectionUtils.bindConnection(factory, enableTransactionSupport);
      			} else {
      				conn = RedisConnectionUtils.getConnection(factory);
      			}
      
      			boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);
      
      			RedisConnection connToUse = preProcessConnection(conn, existingConnection);
      
      			boolean pipelineStatus = connToUse.isPipelined();
      			if (pipeline && !pipelineStatus) {
      				connToUse.openPipeline();
      			}
      
      			RedisConnection connToExpose = (exposeConnection ? connToUse : createRedisConnectionProxy(connToUse));
      			T result = action.doInRedis(connToExpose);
      
      			// close pipeline
      			if (pipeline && !pipelineStatus) {
      				connToUse.closePipeline();
      			}
      
      			// TODO: any other connection processing?
      			return postProcessResult(result, connToUse, existingConnection);
      		} finally {
      			RedisConnectionUtils.releaseConnection(conn, factory, enableTransactionSupport);
      		}
      	}
      }
      
    • class DefaultValueOperations<K, V> extends AbstractOperations<K, V> implements ValueOperations<K, V> {
      
      	DefaultValueOperations(RedisTemplate<K, V> template) {
      		super(template);
      	}
      
          	@Nullable
      	<T> T execute(RedisCallback<T> callback, boolean exposeConnection) {
      		return template.execute(callback, exposeConnection);
      	}
          
      	/*
      	 * redis get 命令
      	 */
      	@Override
      	public V get(Object key) {
      
      		return execute(new ValueDeserializingRedisCallback(key) {
      
      			@Override
      			protected byte[] inRedis(byte[] rawKey, RedisConnection connection) {
      				return connection.get(rawKey);
      			}
      		}, true);
      	}
      }
      
    • public abstract class RedisConnectionUtils {
      	public static RedisConnection getConnection(RedisConnectionFactory factory) {
      		return getConnection(factory, false);
      	}
          
          public static RedisConnection getConnection(RedisConnectionFactory factory, boolean transactionSupport) {
      		return doGetConnection(factory, true, false, transactionSupport);
      	}
          
          public static RedisConnection doGetConnection(RedisConnectionFactory factory, boolean allowCreate, boolean bind,
      			boolean transactionSupport) {
      
      		Assert.notNull(factory, "No RedisConnectionFactory specified");
      
      		RedisConnectionHolder connHolder = (RedisConnectionHolder) TransactionSynchronizationManager.getResource(factory);
      
      		if (connHolder != null) {
      			if (transactionSupport) {
      				potentiallyRegisterTransactionSynchronisation(connHolder, factory);
      			}
      			return connHolder.getConnection();
      		}
      
      		if (!allowCreate) {
      			throw new IllegalArgumentException("No connection found and allowCreate = false");
      		}
      
      		if (log.isDebugEnabled()) {
      			log.debug("Opening RedisConnection");
      		}
      
              //获取 RedisConnection
      		RedisConnection conn = factory.getConnection();
      
      		if (bind) {
      
      			RedisConnection connectionToBind = conn;
      			if (transactionSupport && isActualNonReadonlyTransactionActive()) {
      				connectionToBind = createConnectionProxy(conn, factory);
      			}
      
      			connHolder = new RedisConnectionHolder(connectionToBind);
      
      			TransactionSynchronizationManager.bindResource(factory, connHolder);
      			if (transactionSupport) {
      				potentiallyRegisterTransactionSynchronisation(connHolder, factory);
      			}
      
      			return connHolder.getConnection();
      		}
      
      		return conn;
      	}
      }
      
    • public class JedisConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory {
      	
      	/*
      	 * (non-Javadoc)
      	 * @see org.springframework.data.redis.connection.RedisConnectionFactory#getConnection()
      	 */
      	public RedisConnection getConnection() {
      
      		if (isRedisClusterAware()) {
      			return getClusterConnection();
      		}
      		//获取redis 连接
      		Jedis jedis = fetchJedisConnector();
      		JedisConnection connection = (getUsePool() ? new JedisConnection(jedis, pool, getDatabase(), getClientName())
      				: new JedisConnection(jedis, null, getDatabase(), getClientName()));
      		connection.setConvertPipelineAndTxResults(convertPipelineAndTxResults);
      		return postProcessConnection(connection);
      	}
          
          protected Jedis fetchJedisConnector() {
      		try {
      
      			if (getUsePool() && pool != null) {
      				return pool.getResource();
      			}
      
      			Jedis jedis = createJedis();
                  //强制初始化,这里会获取连接
      			// force initialization (see Jedis issue #82)
      			jedis.connect();
      
      			potentiallySetClientName(jedis);
      			return jedis;
      		} catch (Exception ex) {
      			throw new RedisConnectionFailureException("Cannot get Jedis connection", ex);
      		}
      	}
      }
      
    • public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKeyBinaryCommands,
          AdvancedBinaryJedisCommands, BinaryScriptingCommands, Closeable {
        public void connect() {
          client.connect();
        }
      public class BinaryClient extends Connection {
          	@Override
            public void connect() {
              if (!isConnected()) {
                super.connect();
                if (user != null) {
                  auth(user, password);
                  getStatusCodeReply();
                } else if (password != null) {
                  auth(password);
                  getStatusCodeReply();
                }
                if (db > 0) {
                  select(db);
                  getStatusCodeReply();
                }
              }
            }
          }
      }
      
      
      
    • public class Connection implements Closeable {
            public String getStatusCodeReply() {
              flush();
              final byte[] resp = (byte[]) readProtocolWithCheckingBroken();
              if (null == resp) {
                return null;
              } else {
                return SafeEncoder.encode(resp);
              }
            }
         	  protected Object readProtocolWithCheckingBroken() {
              if (broken) {
                throw new JedisConnectionException("Attempting to read from a broken connection");
              }
      
              try {
                return Protocol.read(inputStream);
              } catch (JedisConnectionException exc) {
                broken = true;
                throw exc;
              }
            }
      }
      
    • public final class Protocol {
      	public static Object read(final RedisInputStream is) {
          	return process(is);
        	}
          private static Object process(final RedisInputStream is) {
              final byte b = is.readByte();
              switch (b) {
              case PLUS_BYTE:
                return processStatusCodeReply(is);
              case DOLLAR_BYTE:
                return processBulkReply(is);
              case ASTERISK_BYTE:
                return processMultiBulkReply(is);
              case COLON_BYTE:
                return processInteger(is);
              case MINUS_BYTE:
                processError(is);
                return null;
              default:
                throw new JedisConnectionException("Unknown reply: " + (char) b);
          }
        }
      }
      
      public class RedisInputStream extends FilterInputStream {
        public byte readByte() throws JedisConnectionException {
          ensureFill();
          return buf[count++];
        }
          
      	private void ensureFill() throws JedisConnectionException {
              if (count >= limit) {
                try {
                  limit = in.read(buf);
                  count = 0;
                  if (limit == -1) {
                    throw new JedisConnectionException("Unexpected end of stream.");
                  }
                } catch (IOException e) {
                  throw new JedisConnectionException(e);
                }
              }
        	}
      }
      
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个错误表示在执行 Redis 命令时超时了。RedisCommandTimeoutExceptionLettuce 客户端库中的异常类,它指示 Redis 命令执行超时。 在默认情况下,Lettuce 客户端库设置了一个命令执行的超时时间,如果 Redis 服务器在该时间内没有返回结果,则会抛出这个异常。在你的情况下,命令执行时间超过了 100 秒。 有几个可能的原因导致命令执行超时: 1. Redis 服务器过载:如果 Redis 服务器处理大量请求或者数据量过大,可能导致命令执行时间增长。可以通过监控 Redis 服务器的负载情况来验证这一点。 2. 网络延迟:如果 Redis 服务器Lettuce 客户端之间的网络延迟增加,命令执行时间会增加。可以通过检查网络连接和延迟来排除这个问题。 3. 命令复杂性:某些复杂的 Redis 命令(如聚合操作或大规模数据操作)可能需要更长的执行时间。可以检查你正在执行的命令是否包含复杂操作。 为了解决这个问题,你可以尝试以下几个步骤: 1. 检查 Redis 服务器的性能和负载情况,确保它没有过载。 2. 检查网络连接和延迟,确保网络通畅。 3. 优化你的 Redis 命令,尽量减少复杂操作或者将其拆分成多个较小的操作。 4. 调整 Lettuce 客户端的命令执行超时时间,可以根据你的实际需求增加超时时间。 如果问题仍然存在,你可能需要进一步调查和诊断,可能需要检查日志以获取更多细节,或者考虑升级 Redis 服务器的硬件配置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值