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

2023-10-27

记录服务器上,不定时出现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);
                }
              }
        	}
      }
      
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • 如何使用 FileChannel 将一个文件的内容附加到另一个文件的末尾?

    File a txt好像 ABC File d txt好像 DEF 我正在尝试将 DEF 附加到 ABC 所以a txt好像 ABC DEF 我尝试过的方法总是完全覆盖第一个条目 所以我总是最终得到 DEF 这是我尝试过的两种方法 File
  • ElasticBeanstalk Java,Spring 活动配置文件

    我正在尝试通过 AWS ElasticBeanstalk 启动 spring boot jar 一切正常 配置文件为 默认 有谁知道如何为 java ElasticBeanstalk 应用程序 不是 tomcat 设置活动配置文件 spri
  • Java程序中的数组奇怪的行为[重复]

    这个问题在这里已经有答案了 我遇到了这个 Java 程序及其以意想不到的方式运行 以下程序计算 int 数组中元素对之间的差异 import java util public class SetTest public static void
  • 线程自动利用多个CPU核心?

    假设我的应用程序运行 2 个线程 例如渲染线程和游戏更新线程 如果它在具有多核 CPU 当今典型 的移动设备上运行 我是否可以期望线程在可能的情况下自动分配给不同的核心 我知道底层操作系统内核 Android linux内核 决定调度 我的
  • Convert.FromBase64String 方法的 Java 等效项

    Java 中是否有相当于Convert FromBase64String http msdn microsoft com en us library system convert frombase64string aspx which 将指
  • HDFS:使用 Java / Scala API 移动多个文件

    我需要使用 Java Scala 程序移动 HDFS 中对应于给定正则表达式的多个文件 例如 我必须移动所有名称为 xml从文件夹a到文件夹b 使用 shell 命令我可以使用以下命令 bin hdfs dfs mv a xml b 我可以
  • 如何为 Gson 编写自定义 JSON 反序列化器?

    我有一个 Java 类 用户 public class User int id String name Timestamp updateDate 我收到一个包含来自 Web 服务的用户对象的 JSON 列表 id 1 name Jonas
  • 如何在jsp代码中导入java库?

    我有以下jsp代码 我想添加 java io 等库 我怎样才能做到这一点
  • OnClick 事件中的 finish() 如何工作?

    我有一个Activity一键退出Activity 通过layout xml我必须设置OnClick事件至cmd exit调用 this finish 效果很好 public void cmd exit View editLayout thi
  • Prim 的迷宫生成算法:获取相邻单元格

    我基于 Prim 算法编写了一个迷宫生成器程序 该算法是 Prim 算法的随机版本 从充满墙壁的网格开始 选择一个单元格 将其标记为迷宫的一部分 将单元格的墙壁添加到墙壁列表中 While there are walls in the li
  • 无法理解 Java 地图条目集

    我正在看一个 java 刽子手游戏 https github com leleah EvilHangman blob master EvilHangman java https github com leleah EvilHangman b
  • Clip 在 Java 中播放 WAV 文件时出现严重延迟

    我编写了一段代码来读取 WAV 文件 大小约为 80 mb 并播放该文件 问题是声音播放效果很差 极度滞后 你能告诉我有什么问题吗 这是我的代码 我称之为doPlayJframe 构造函数内的函数 private void doPlay f
  • 尝试使用 Ruby Java Bridge (RJB) gem 时出现错误“无法创建 Java VM”

    我正在尝试实现 Ruby Java Bridge RJB gem 来与 JVM 通信 以便我可以运行 Open NLP gem 我在 Windows 8 上安装并运行了 Java 所有迹象 至少我所知道的 都表明 Java 已安装并可运行
  • 应用程序关闭时的倒计时问题

    我制作了一个 CountDownTimer 代码 我希望 CountDownTimer 在完成时重新启动 即使应用程序已关闭 但它仅在应用程序正在运行或重新启动应用程序时重新启动 因此 如果我在倒计时为 00 10 分钟 秒 时关闭应用程序
  • 将 JSON 参数从 java 发布到 sinatra 服务

    我有一个 Android 应用程序发布到我的 sinatra 服务 早些时候 我无法读取 sinatra 服务上的参数 但是 在我将内容类型设置为 x www form urlencoded 之后 我能够看到参数 但不完全是我想要的 我在
  • 如何测试 spring-security-oauth2 资源服务器安全性?

    随着 Spring Security 4 的发布改进了对测试的支持 http docs spring io spring security site docs 4 0 x reference htmlsingle test我想更新我当前的
  • KeyPressed 和 KeyTyped 混淆[重复]

    这个问题在这里已经有答案了 我搜索过之间的区别KeyPressedand KeyTyped事件 但我仍然不清楚 我发现的一件事是 Keypressed 比 KeyTyped 首先被触发 请澄清一下这些事件何时被准确触发 哪个适合用于哪个目的
  • JAVA - 如何从扫描仪读取文件中检测到“\n”字符

    第一次海报 我在读取文本文件的扫描仪中读取返回字符时遇到问题 正在读取的文本文件如下所示 test txt start 2 0 30 30 1 1 90 30 0 test txt end 第一行 2 表示两个点 第二行 位置索引 0 xp
  • Jackson 将单个项目反序列化到列表中

    我正在尝试使用一项服务 该服务为我提供了一个带有数组字段的实体 id 23233 items name item 1 name item 2 但是 当数组包含单个项目时 将返回该项目本身 而不是包含一个元素的数组 id 43567 item
  • Swagger/Openapi-Annotations:如何使用 $ref 生成 allOf?

    我正在生成 Rest 端点 包括添加OpenAPI Swagger对生成的代码进行注释 虽然它对于基本类型运行得很好 但我在自定义类方面遇到了一些问题 现在我有很多自定义类的重复架构条目 使用 Schema 实现 MyClass class

随机推荐

  • 复习向 C/C++ 编程语言简介和概括(C++复习向p1)

    文章目录 C 编程语言 C 和 C 关系 标准的 C 组成 ANSI 标准 比较重要的标准化时间 C 编程语言 是一种静态类型的 编译式的 通用式的 大小写敏感 不规则的编程语言 支持过程化编程 面向对象 泛型编程 C 和 C 关系 C 是
  • mybatis-plus Invalid bound statement (not found):

    1 若是使用了多数据源配置 请检查 DataSourceConfig配置类 将SqlSessionFactoryBean改为mybatis plus里面的MybatisSqlSessionFactoryBean Bean name test
  • 一键磨皮插件:DR5白金版(支持ps 2022)中文版

    Delicious Retouch 5简称DR5 这里为大家分享最新激活的DR5白金版 for mac 这是非常受欢迎的一款PS一键磨皮插件 dr5插件提供了人像磨皮 平滑皮肤 去除瑕疵 美白牙齿 美白皮肤 修饰眼部等功能 一键点击即可使用
  • win10+CPU+Anaconda3 环境下pytorch安装

    本文主要对win10环境下 仅CPU运行 Anaconda3中安装pytorch的步骤进行了记录 主要包括以下内容 1 conda 创建虚拟环境 2 conda 添加镜像源 3 pytorch 安装 4 pytorch 成功安装验证 con
  • Unity官网打不开,试试新地址吧!

    今年6月份发现unity官网进不去了 unity3d com unity com cn 下载历史版本的地址也打不开 网上也有很多人求助 新域名如下 不需要挂vpn 新地址 https unity cn 历史版本下载 https unity
  • Python多线程的理解和使用(一)Threading中join()函数的理解

    转载自 https blog csdn net zhuzuwei article details 80927554 多线程的概念 多线程类似于同时执行多个不同程序 多线程运行有如下优点 使用线程可以把占据长时间的程序中的任务放到后台去处理
  • python操作redis

    目录 python操作redis 安装redis模块 基本链接 连接池连接 redis字符串操作 redis hash操作 redis 列表操作 redis 其它操作 redis管道 django中集成redis python操作redis
  • 为本地项目配置git地址,并推送到远程仓库

    1 进入该项目文件夹 cd Users kk Desktop project k demo 将上面项目路径换成你自己的项目路径 2 初始化git 使用git init 将该项目变成一个可以通过git管理的项目 git init 3 通过gi
  • vue-cli使用指南

    目录 vue全家桶 技术栈 使用vue cli搭建Vue项目 单页的编写 axios的使用 vuex的使用 vuex中数据的保留时间 axios的全局拦截 axios的跨域问题 全局常量 使用Mock模拟后端接口返回数据 嵌套路由 路由守卫
  • 95-38-030-Buffer-Java NIO中-关于DirectBuffer,HeapBuffer的疑问

    文章目录 1 说明 2 疑问 3 RednaxelaFX 1 说明 本文摘要 https www zhihu com question 57374068 2 疑问 Java NIO中 关于DirectBuffer HeapBuffer的疑问
  • CUDA的几种Synchronize

    首先对这三个函数做一下解释 cudaDeviceSynchronize 等待所有线程都处理完成 kernel function处理完成 用在cpu的c code中 cudaThreadSynchronize 功能和cudaDeviceSyn
  • Pycharm的使用技巧与效率提升

    总第010篇 本文主要梳理了pycharm在使用过程中的一些技巧 便于提升工作效率 pycharm主要分为两个版本 一个是专业版本 此版本功能强大 主要是为python和web开发者准备的 需要付费 另一个是社区版本 比较轻量级 主要是为p
  • 读别人写的代码 VS 自己写代码

    概述 专业程序员非常重要的一项技能是读别人写的代码 这项技能甚至比自己写代码更重要 分析 这让我想到很多程序员讨厌去阅读代码 来接受它吧 人人都喜欢编写代码 写代码是很有乐趣的事 但阅读代码却是一种困难的工作 它不仅仅繁重 而且很无聊 让我
  • 使用Docker进行模型部署

    文章目录 1 思路 2 实现步骤 2 1 数据 模型准备 2 2 镜像制作 2 3 使用 1 思路 因为多数公司正式集群都不能使用公网环境 对于模型部署比较麻烦 所以想这在公网环境下完成模型调试 然后根据相关环境和参数直接制作一个docke
  • C++中static_cast/const_cast/dynamic_cast/reinterpret_cast的区别和使用

    C风格的强制转换较简单 如将float a转换为int b 则可以这样 b int a 或者b int a C 类型转换分为隐式类型转换和显示类型转换 隐式类型转换又称为标准转换 包括以下几种情况 1 算术转换 在混合类型的算术表达式中 最
  • gsonformat java代码_插件GsonFormat快速實現JavaBean

    寫在前面的話 本文章只適合使用AndroidStudio的小伙伴觀看 還在糾結eclipse的小伙伴趕緊洗洗睡吧 最近看見一篇快速實現javaBean的屎丟丟插件 這是一個根據JSONObject格式的字符串 自動生成實體類參數 如果想要使
  • windows编程中wParam和lParam消息

    windows编程中wParam和lParam消息 1 WM PAINT消息 LOWORD lParam 是客户区的宽 HIWORD lParam 是客户区的高 2 滚动条WM VSCROLL或WM HSCROLL消息 LOWORD wPa
  • 【Vim】Vim 常用编辑操作

    目录 正则表达式 vim 命令 vim的工作模式 撤销修改 重做与保存 光标移动命令 文本插入操作 文本删除操作 文本复制 剪切与粘贴 文本的修改与替换 多窗口操作 正则表达式 简单地说 正则表达式是一种符号表示法 用于识别文本模式 在某种
  • 神经网络中epoch、batch、batch_size、epoch、iteration理解

    1 epoch 当一个完整的数据集通过神经网络一次并且返回一次的过程称为一个epoch 然而 当一个epoch对于计算机太过庞大时 就需要把它分成多个小块 2 batch 在不能将数据一次性通过神经网络的适合 就需要将数据集分成几个batc
  • 记录服务器上,不定时出现io.lettuce.core.RedisCommandTimeoutException: Command timed out after xxx millisecond(s)

    记录服务器上 不定时出现io lettuce core RedisCommandTimeoutException Command timed out after 12 millisecond s 日志 org springframework