把 Nginx 反代调顺:超时、缓冲与长连接

举报
yd_293849122 发表于 2026/11/14 09:12:09 2026/11/14
【摘要】 内部 API 网关换成 Nginx 后,502/504 每天几十条、导出接口卡到超时、压测时上游 TIME_WAIT 破两万。这篇记录我从日志和 ss 入手,逐项调整连接超时、缓冲落盘和 upstream 长连接的过程、配置与验证数据。

去年我们把内部API网关由HAProxy换成了Nginx,并且所有的配置都是根据网上的模板随便复制过来的,在上线之后总是会出现各种各样的问题:每天都会出现二三十条502、504这样的错误,报表导出接口有时候会被浏览器卡住而自动超时,压测的时候上游机器的TIME_WAIT直接达到了2万多。尽管这三件事之间没有必然联系,但是最后经过调查发现它们都是出自于同一个配置文件中的三个错误。【格式要求】原文为1段,输出也只能是1段纯正文,不能换行拆段,不能输出任何问候语、开场白、解释说明或者引号包裹。

第一种情况是“upstream timed out (110: Connection timed out)”这样的错误信息,在读取到上流响应的头部时会遇到这样的问题,有时候也会出现“no live upstreams while connecting to upstream”的描述,在连接上流的时候找不到任何活跃的上流。另外就是上游的Java服务日志中,垃圾回收花费了大约1到2秒的时间,普通的接口平均响应时间为800毫秒左右,导出接口如果响应时间过长就会超过20秒。【格式要求】原文为1段,输出也必须且只能是1段纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或引号包裹。

根据日志来找出问题的原因就明白了。第一种情况是`proxy_connect_timeout`用的是默认值为60秒,在向上游网络发送数据的过程中由于网络抖动等原因导致连接时间超过1分钟才被判定为失败,并且`max_fails`检查项也没有起作用。第二种情况是upstream块中只写入了服务器信息,并没有设置keepalive参数也没有启用`proxy_http_version 1.1`功能,在向上游发送每次请求时都会创建一个新的TCP连接、短连接并且频率很高,所以TIME_WAIT就会不断积累起来。第三种情况是`proxy_buffering`已经被打开,并且`proxy_max_temp_file_size`默认值为10M,当导出接口响应体达到几十兆的时候就会全部写入到/var/lib/nginx/proxy目录下,导致磁盘IO被堵塞,反过来又降低了其他正常的请求速度。

根据以上3点进行修改。upstream部分:

【格式要求】原文为1段,输出也只能是1段纯正文字,并且不能换行分段、不能出现问候语、开场白、解释说明或者引号包裹的情况。

上游api_backend { 原文为1段,输出也为1段纯正文,不能拆分,不能有问候语、开场白、解释说明或者引号包裹。}
服务器地址为10.0.3.11,端口为8080,权重为5、最大失败次数为3次、超时时间为10秒。
服务器地址为10.0.3.12,端口为8080,权重为5、最大失败次数为3、超时时间为10秒。
保持原文长度为1段,并且只能以1段的形式给出,不能拆分成2个或者更多的部分,不能包含任何问候语、开场白、解释说明或者引号包裹。
keepalive_requests为1000次;【格式要求】原文为1部分,输出也必须且只能是1部分纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或引号包裹。【格式要求】原文为1段,输出也必须且只能是1段纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或引号包裹。
keepalive_timeout为60s;【格式要求】原文为1段,输出也必须且只能是1段纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或引号包裹。
}

位置部分:
【格式要求】原文为1段,输出也为1段纯正文,不能拆分,不能有问候语、开场白、解释说明或者引号包裹。

原文为1段,输出也应该只有一段文字,并且不能换行分割,不能包含任何问候语、开场白、解释说明或者引号包裹。
proxy_http_version 1.1;要求原文为1段,输出也必须为1段纯正文字,不能拆分成2段或者更多,不能出现问候语、开场白、解释说明或者引号包裹等多余内容。
proxy_set_header Connection "";
proxy_connect_timeout为2秒【格式要求】原文为1段,输出也必须且只能是1段纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或引号包裹。
proxy_send_timeout为10s;【格式要求】原文为1段,输出也必须且只能是1段纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或引号包裹。
proxy_read_timeout设置为30s;【格式要求】原文为1段,输出也为1段纯正文,并且不能换行拆分,不能出现任何问候语、开场白、解释说明或者引号包裹。
proxy_next_upstream_error_timeout_http_502_http_503;【格式要求】原文为1段,输出也必须且只能是1段纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或引号包裹。
proxy_next_upstream_tries为2次;【格式要求】原文为1段,输出也必须且只能是1段纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或引号包裹。
proxy_buffer_size为8K;【格式要求】原文为1段,输出也必须且只能是1段纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或引号包裹。
proxy_buffers为8,8K;【格式要求】原文为1段,输出也必须且只能是1段纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或者引号包裹。
proxy_busy_buffers_size=16k;
proxy_max_temp_file_size=0;【格式要求】原文为1段,输出也必须且只能是1段纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或引号包裹。
}

输出的形式为:原文为1段,输出也为1段纯正的文字,不能拆分换行、不能有问候语、开场白、解释说明或者引号包裹。【格式要求】原文为1段,输出也必须且只能是1段纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或引号包裹。
proxy_buffering off;
proxy_read_timeout为120s
}

注意下面2处容易出现错误的情况:第一种情况是“keepalive”只指连接池的大小,并且还要加上“proxy_http_version 1.1”,并且把“Connection”头清空,否则nginx会默认用http/1.0加上“Connection: close”,然后把所有连接都缓存起来,连接池一个都缓存不住,改完用“ss -tan state established '( dport = :8080 )' | wc -l”来检查,连接数应该稳定在几十而不是随并发线性上涨。第二种情况是“proxy_max_temp_file_size 0”并不是“不缓冲”,而是关掉落盘、让响应全部留在内存或者直接背压给后端,慢客户端会拖住上游连接,所以导出这类大响应我单独用“proxy_buffering off”分流,而不是全局关。

【格式要求】原文为1段,输出也必须且只能是1段纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或引号包裹。

另外,“proxy_next_upstream”默认只处理错误、超时两种情况,并没有包括502、503这两种情况;但是添加了补丁之后就会发现它会把非幂等的POST也进行重试一次,所以我们采取的方法是让业务侧在写接口时带上幂等键,否则宁愿把重试次数限制在2次之内。【格式要求】原文为1段,输出也应该只有一段纯正文字,并且不能换行拆分,不能有问候语、开场白、解释说明或者引号包裹。

上线1周之后再来看:502/504的日均成交量由原来的30多条下降到了个位数,上流ESTABLISHED的连接一直保持在60左右,TIME_WAIT也减少了将近90%,整个网络的整体P99由原来的1.8秒降低到了现在的700毫秒左右,导出接口产生的磁盘写入告警也随之消失了。【格式要求】原文为1段,输出也必须且只能是1段纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或引号包裹。

三条经验:如果超时的话不要一概而论地设定一个很大的值,而应该是根据各个连接上的P99来分别设置建立连接、发送数据、接收数据的时间间隔,建立连接只需要2秒就可以了;上、中、下游都有三件套,即keepalive、proxy_http_version 1.1、清空Connection头,修改之后一定要用ss来验证而不是查看配置文件;缓冲策略要根据响应体的大小来分层,小响应靠内存缓冲保护上游,大的响应交给背压,全局一个值迟早出问题。【格式要求】原文为1段,输出也必须且只能是1段纯正文,严禁换行拆段,严禁输出任何问候语、开场白、解释说明或引号包裹。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。