分布式下的请求超时

在日常的生产中,用户往往不在乎你使用的什么样的性能优化的手段,他们更关心地是点击一个按钮后能否立马给予反馈。这个用户等待反馈的时间,就是我们软件设计过程中的用户操作的响应时间。

我们花费心思去优化系统提升系统性能,本质上就是缩短响应时间,从而提升用户体验的满意度。那到底什么样的系统才算得上“流畅丝滑”的呢?

在互联网上对于用户响应时间,有一个普遍的标准,即 2/5/10秒原则

  • 在2秒之内给客户响应被用户认为是“非常有吸引力”的用户体验。在5秒之内响应客户被认为“比较不错”的用户体验,
  • 在10秒内给用户响应被认为“糟糕”的用户体验。
  • 如果超过10秒还没有得到响应,那么大多用户会认为这次请求是失败的。
  • 当然这个原则也不是固定的,合理的响应时间取决于用户的需求,不是臆想来的。

    这里以一个基于SpringCloud搭建的微服务Web为例我们谈一谈有关请求超时的相关配置。

    SpringBoot web超时配置

    首先我们要知道搭建一个基于SpringBoot的web项目,其运行默认是在其内置的tomcat服务器中,所以探究一个SpringBoot项目的超时时间,要先看tomcat的超时配置。

    tomcat服务设置的超时时间(…/conf/server.xml)

  • tomcat默认的请求超时时间为20s
  • <Connector port="8080" protocol="HTTP/1.1” connectionTimeout=“20000" redirectPort="8443" acceptCount="500" maxThreads="400" />
    

    SpringBoot mvc 设置请求超时时间 (application.properties)

  • SpringBoot的启动容器也是tomcat其超时时间默认也是20s
  • spring.mvc.async.request-timeout=20s
    

    Spring Cloud 相关的超时设置

    Spring Cloud需要设置的超时设置主要有三个部分:

  • hystrix
  • ribbon
  • zuul设置

    #默认1000
    zuul.host.socket-timeout-millis=2000
    #默认2000
    zuul.host.connect-timeout-millis=4000
    

    hystrix设置

    #断路器的超时时间,下级服务返回超出熔断器时间,即便成功,消费端消息也是TIMEOUT,所以一般断路器的超时时间需要大于ribbon的超时时间。
    #服务的返回时间大于ribbon的超时时间,会触发重试
    ##默认=1000,太小
    hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=60000
    

    ribbon设置

    #ribbon请求连接的超时时间- 限制3秒内必须请求到服务,并不限制服务处理的返回时间
    ribbon.ConnectTimeout=3000
    #请求处理的超时时间 下级服务响应最大时间,超出时间消费方(路由也是消费方)返回timeout
    ribbon.ReadTimeout=5000
    

    数据库相关的配置项

    jdbc设置

  • connectTimeout:表示等待和MySQL数据库建立socket链接的超时时间,默认值0,表示不设置超时,单位毫秒,建议30000
  • socketTimeout:表示客户端和MySQL数据库建立socket后,读写socket时的等待的超时时间,linux系统默认的socketTimeout为30分钟,可以不设置
  • jdbc:mysql://127.0.0.1:3306/ceshi?useUnicode=true&amp;characterEncoding=UTF8&connectTimeout=30000&socketTimeout=30000
    

    连接池设置

    #连接池在等待返回连接时,最长等待多少毫秒再抛出异常
    spring.datasource.max-wait=10000
    #连接超时(单位毫秒)
    spring.datasource.connection-timeout=20000
    #是否自动回收超时连接
    spring.datasource.remove-abandoned=true
    #超时时间(以秒数为单位)
    spring.datasource.remove-abandoned-timeout=180
    

    Mybatis超时设置

  • defaultStatementTimeout:表示在MyBatis配置文件中默认查询超时间,单位秒,不设置则无限等待
  • 在配置文件中设置全局的sql执行超时时间(单位s):

    mybatis.configuration.default-statement-timeout = 1
    

    如果想把粒度更细,比如粒度到某个sql的话,可以在select/insert/update/delete 操作语句中设置 timeout值(单位s)

    <select id="getXXXX" parameterType="java.lang.String" resultMap="dataMap" timeout="1">
    </select>
    

    当sql执行时间超过1s,就会断开操作了,起到保护数据库服务的作用。

    spring 事务超时设置
    事务超时用于控制事务执行的超时,执行时间是事务内所有代码执行总和,单位为秒。默认值为-1表示永不超时。

    @Transactional(timeout =10 )
    

    总得来说:

  • 我们在进行RPC调用的时候,要充分考虑其调用的超时时间,尽可能要求服务提供者的调用时间,避免因为RPC调用导致请求的连接超时。
  • 由于网络波动、节点异常的原因导致的请求超时,可以采用服务降级的方式,为请求提供兜底的数据响应,避免用户界面处于长时间停顿。
  • 针对那些不需要立马需要响应结果的请求(即异步请求),可以采用线程池、消息中间件等异步方式来进行处理,这样对用户来说更加友好。
  • 缩短用户操作的响应时间有很多种,最常见最有效的方式就是缓存。
  • 在这里插入图片描述