超时与重试
profile
很多故障是超时引起的、eg. 若应用不设置超时、则可能会导致请求响应慢、慢请求积累会导致连锁反应、甚至造成应用雪崩、而有些中间件或者框架在超时后进行重试(eg. 重试设置两次)、读服务天然适合重试、而写服务太多不能重试(eg. 写订单、如果写服务是幂等的、则重试是允许的)、重试次数太多、会导致多倍流量请求、模拟了ddos攻击、后果可能是灾难、所以必须设置合理的重试机制
在代码review时进行超时和重试的review
超时分类
1. 前端ajax超时
2. 代理层超时与重试
1) 客户端超时:
a. 获取请求头超时:client_header_timeout读取客户端请求头超时时间、默认60s
若超过该时间未发送完请求头、则响应408
b. 读取请求体超时:client_body_timeout设置读取客户端内容超时时间、默认60s
是指连续两次读操作间隔是假、不是发送整个请求体的超时时间、若在此时间内客户端未发送任何请求体、则响应为408
c. 发送响应超时时间:send_timeout time设置发送响应到客户端的超时时间、默认60s
指两次连续写之间的时间间隔、若此时间内未收到客户端任何响应、则nginx关闭此连接
d. 长连接超时时间:keepalive_timeout timeout [header_timeout]
第一个参数timeout告诉nginx长连接超时时间是多少、默认为75s、
第二个参数header_timeout用来设置响应头 "Keep-Alive: timeout-time"
即告诉客户端长连接超时时间、两个参数可以不一样、
2) DNS 超时时间
resolver_timeout 30s: dns超时解析世界、默认30s、配合 resolver address ... [valid=time] 进行dns域名解析、当在nginx中使用域名时、就需要考虑设置超时
使用域名配置、nginx会在解析配置文件的阶段被解析成ip地址并记录到upstream上、当这两个域名对应的ip地址发生变化时、该upstream不会更新、而nginx的商业版可以支持动态更新
解决:1. 使用proxy_pass+变量方式实现动态域名解析
location /test {
set $backend "http://test.cc"
proxy_pass $backend;
}
这种方式在多域名的情况下、很难优雅的实现
2. 若使用opresty、则可以使用lua库lua-resty-dns来进行dns解析
local resolver = require "resty.dns.resolver"
local r, err = resolver:new {
nameservers = {"8.8.8.8", {"8.8.8.4", 53}},
retrans = 5, -- retransmissions on receive timeout
timeout = 2000, -- 2s
}
3) 代理超时设置
与上游server的超时: 连接/读/写、失败重试机制、upstream存活超时设置
max_fails 和 fail_timeout 配置什么时候nginx将上游服务器认定为不可用/不存活
当上游服务器在fail_timeout时间内失败了max_fails次、就认为不可用
什么情况下认为失败呢 ? proxy_next_upstream定义
这种机制只会在访问上游server时才会惰性检查、还可以使用ngx_http_upstream_check_module来主动检查配置
max_fails设置为0表示不检测是否可用、认为一直可用
4) ngx_lua超时设置
使用ngx_lua时、也应该考虑设置连接/读/写超时
lua_socket_connect_timeout 100ms;
lua_socket_send_timeout 200ms;
lua_socket_read_timeout 500ms;
3. web容器超时
eg. tomcat
4. 中间件与客户端服务超时
5. nosql客户端超时
6. 数据库客户端超时
7. 业务超时
8. 代理层超时与重试