一、为什么要设置超时与重试
平时开发过程中,可能很多人都不会意识到设置超时的重要性。如果利用不设置超时,调用的服务接口可能会因为各种起因(异样、连接池/线程池耗尽、SQL慢查问等)导致响应慢,一旦慢申请累积地越来越多,导致的结果就是连锁反应,即咱们常说的雪崩效应。超时后,咱们能够抉择重试几次。读服务重试没有问题,但写服务重试可能会造成反复,如下订单,除非业务方做了幂等解决。重试的频率和次数如果过多,也会造成申请流量过大,对系统造成冲击。因而必须依据理论业务场景设置正当的超时重试机制,必要时应该熔断疾速失败,而不是一直重试。
二、超时的链路档次
通常咱们的利用会像下图的构造,申请开始到返回响应会通过一条残缺的链路:浏览器/app客户端 -> 代理层(负载平衡) -> Web容器层(Tomcat等) -> 业务逻辑层(Future等) -> 中间件层(Redis等) -> 数据库层(Mysql等)。每一层都能够设置超时与重试机制。上面开展细说。
1.代理层超时
这里以nginx为例。nginx次要有客户端超时、DNS解析超时、代理超时。
①客户端超时
client_header_timeout time: 设置读取客户端申请头超时工夫,默认60s。
client_body_timeout time: 设置读取客户端内容体超时工夫,默认60s。
send_timeout time:设置发送响应到客户端的超时工夫,默认60s。
keepalive_timeout timeout [header_timeout]:设置HTTP长连贯超时工夫。第一个参数timeout是通知nginx长连贯超时工夫是多少,默认75s,第二个参数header_timeout用于设置响应头“Keep-Alive: timeout=time”,即告知客户端长连贯超时工夫。
②DNS解析超时
resolver_timeout time:设置DNS解析超时工夫,默认30s。
③代理超时
proxy_connect_timeout time:与后端/上游服务器建设连贯的超时工夫,默认60s。
proxy_read_timeout time:设置从后端/上游服务器读取响应的超时工夫,默认60s。
proxy_send_timeout time:设置往后端/上游服务器发送申请的超时工夫,默认60s。
nginx除了超时参数设置,也有重试参数设置。
proxy_next_upstream error|timeout|invalid_header|http_500|http_502|http_503
配置什么状况下须要申请下一台上游服务器进行重试。
proxy_next_upstream_tries number:设置重试次数,默认0示意不限度。
proxy_next_upstream_timeout time:设置重试最大超时工夫,默认0示意不限度。
max_fails和fail_timeout:配置什么时候nginx将上游服务器认定为不可用/不存活。当上游服务器在fail_timeout工夫内失败了max_fails次,则认为该上游服务器不可用,并在接下来的fail_timeout工夫内从upstream摘除该节点。
2.Web容器超时
以Tomcat8.5版本为例。
connectionTimeout:配置与客户端建设连贯的超时工夫,默认60s
socket.soTimeout:从客户端读取申请数据的超时工夫,默认60s
asyncTimeout:servlet3异步申请的超时工夫,默认30s
keepAliveTimeout和maxKeepAliveRequests:和nginx长连贯相似,keepAliveTimeout默认为-1示意永不超时,maxKeepAliveRequests默认为100
3.业务超时
在多线程编程中,咱们常常会应用Future接口,来异步接管线程的执行后果,咱们能够设置超时工夫,而不是始终阻塞上来,即应用Future.get(timeout, TimeUnit)。
4.中间件超时
以Dubbo为例。
<dubbo:consumer timeout="1000"></dubbo:consumer>
<dubbo:provider timeout="1000"></dubbo:provider>
其实像zookeeper,redis,kafka等中间件都有相应的超时设置,感兴趣地能够去翻下官网文档。
5.数据库超时
以dpcp连接池为例
<bean id=”dataSource” class=”org.apache.commons.dbcp2.BaseDataSource” destroy-method=”close”>
<!– Statement默认超时工夫–>
<property name=”defaultQueryTimeout” value=”3″ />
<!– socket连贯/读超时–>
<property name=”connectionProperties” value=”connectTimeout=2000; socketTimeout=2000″ />
<!– 期待获取连接池连贯最大超时工夫–>
<property name=”maxWaitMillis” value=”500″ />
</bean>
三、总结
本文介绍了超时的重要性。超时后的策略能够是重试(等一会再试,重试其余分组服务,重试其余机房服务等)、摘掉不可用节点,返回托底数据和页面等等。
对于非幂等的写服务应该防止重试,或者能够思考提前生成惟一流水号来保障写服务操作的幂等性。
超时重试尽管进步了可用性,但也必然会导致RT即响应工夫减少,重试次数过多可能会影响用户体验,因而在理论开发中要依据业务场景思考用户的容忍最长等待时间。
参考资料
《亿级流量网站架构核心技术》
发表回复