uwsgi响应超时配置问题:如何避免处理已被客户端丢弃的请求
问题根因分析
你当前配置的超时参数未生效、压测100%失败的核心原因如下:
- 你配置的
http-connect-timeout仅作用于TCP三次握手阶段,和请求建立后的处理超时完全无关 - 你配置的
http-timeout是连接空闲超时,仅当连接上无任何数据传输超过阈值才会触发,请求处理过程中连接属于活跃状态,因此不会生效 - 压测失败是因为你固定了2个单线程worker,每个请求需要4秒处理,满负载下每秒仅能处理0.5个请求,当locust并发超过1后,8长度的监听队列很快被占满,后续请求直接被uwsgi拒绝,导致100%失败
- 你注释的
uwsgi.is_connected判断未生效是因为仅做了单次检测,没有在耗时逻辑执行过程中轮询状态
解决方案
1. 调整uwsgi配置
按以下内容修改uwsgi.ini,即可满足你“请求进入Flask前丢弃队列超时请求、固定worker数、不主动杀worker”的需求:
[uwsgi] strict = true module = flask:app master = true processes = 2 # 固定worker数,按需调整为你的目标值即可 threads = 1 enable-threads = true listen = 128 # 调大监听队列长度,注意要同时修改内核参数net.core.somaxconn为对应值,否则不生效 so-keepalive = true # 开启TCP保活,及时检测客户端断开的连接 listen-queue-timeout = 5 # 核心参数:请求在监听队列中等待超过5秒未被处理直接丢弃,阈值可按需调整 need-app = true lazy = true http = 0.0.0.0:5000
如果你可以接受worker被超时重建,也可以打开harakiri = 8配置,自动杀掉处理时间超过8秒的worker,不需要修改业务代码,master进程会自动拉起新的worker,不会影响服务可用性。
2. 修正Flask连接检测逻辑
如果不想用harakiri杀worker,只需要把原有整块的耗时逻辑拆分为小步循环,每次循环检测连接状态即可,修改后的代码如下:
from flask import Flask, request import requests import json import time import uwsgi app = Flask(__name__) @app.route('/') def test_request(): # 将4秒耗时拆分为40次100ms的小等待,每次检测连接状态 for _ in range(40): if not uwsgi.is_connected(uwsgi.connection_fd()): print("客户端已断开,终止处理") return "" time.sleep(0.1) return "Done" if __name__ == "__main__": app.run(host='0.0.0.0')
3. 压测参数调整
如果要避免压测100%失败,要么把locust的并发用户数调整到2以内,要么按上面的配置调大listen队列长度即可。
备选方案
如果觉得uwsgi配置过于繁琐,也可以改用Gunicorn,对应配置更简洁,通过backlog参数配置监听队列长度、timeout参数配置请求处理超时,也能完全满足你的需求。
内容的提问来源于stack exchange,提问作者Constantine
相关产品推荐
相关产品推荐

