Nginx配置中一些细节坑

来自三线的随记
Admin讨论 | 贡献2022年5月10日 (二) 14:11的版本 (创建页面,内容为“=== 反代 - proxy reverse === ==== 后端处理时间非常长(>3分钟 >5分钟 等) ==== * 一般来说个人建议如果后端处理某个请求需要很久才…”)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)

反代 - proxy reverse

后端处理时间非常长(>3分钟 >5分钟 等)

  • 一般来说个人建议如果后端处理某个请求需要很久才返回response,应该将请求设计为异步请求,即通过不断得请求某个state接口获取处理状态,而不是一直holding等待返回

首先这种情况下,proxy_connect_timeout, proxy_read_timeout 和 proxy_send_timeout 参数值都要根据实际情况调大

然后需要注意nginx -> upstream的链路上是否有防火墙策略配置,特别是有状态型防火墙

nginx默认对client和 upstream都没有开启 TCP keepalive,即TCP会话存活检查 (不是HTTP keepalive,不是TCP会话复用!!!)

这种情况下,如果nginx -> upstream的链路上部署了有状态防火墙策略配置且该防火墙配置了300s timeout

若一个请求后端处理需要530秒,nginx将处理请求转发给upstream,nginx就会一直hold着会话(ESTABLISHED)

在等候后端处理完毕回包期间,该TCP会话上nginx<->upstream之间不会有额外的流量

这样就容易导致链路上的有状态防火墙判定该会话已经失效,然后拦截

当后端处理完毕回包时,报文无法被nginx接收到,然后待nginx 到达 proxy_connect_timeout阈值后,nginx向请求方抛出504 timeout错误

且此时在nginx error.log中可见 upstream timed out (110: Connection timed out) while reading response header from upstream 错误字样

这种情况下,需要启用nginx对upstream的tcp keepalive (即socket中的SO_KEEPALIVE option),proxy_socket_keepalive on;

开启后,nginx就会在会话中根据内核参数中的 net.ipv4.tcp_keepalive_intvl , net.ipv4.tcp_keepalive_probes 以及 net.ipv4.tcp_keepalive_time 配置的规则对 upstream 发送keepalive probe packet 探测会话存活,同时避免链路有状态防火墙拦截请求


ps: 如果需要nginx对client发送tcp keepalive probe,需要在listen指令中配置 so_keepalive=on (忽略此参数的话,操作系统的设置将对套接字有效,而linux下TCP KeepAlive并不是默认开启的,在Linux系统上没有一个全局的选项去开启TCP的KeepAlive。需要开启KeepAlive的应用必须在TCP的socket中单独开启)


参考:

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_socket_keepalive

https://mailman.nginx.org/pipermail/nginx/2020-November/060173.html

https://nginx.org/en/docs/http/ngx_http_core_module.html#listen

upstream / 后端 是https, 即 proxy_pass https://servers;

如果nginx配置了多个https域名到同一个upstream则需要配置

proxy_ssl_server_name on;
proxy_ssl_name $ssl_server_name;
proxy_ssl_session_reuse off;

否则很有可能会因为ssl 会话复用引发https证书检验错误的问题