You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python eventlet协程配合requests每次仅处理10个请求问题排查

问题背景
  • 运行环境:Python 2.7.5
  • 实现目标:使用eventlet提供的Greenthreads协程配合requests库,提升REST API请求处理效率
  • 已完成配置:
    • 将urllib3模块poolmanager对象的DEFAULT_POOLSIZE参数设置为1000
    • 在项目__init__.py中完成eventlet的monkeypatch操作
  • 测试逻辑:启动1000个greenthread向F5 BIGIP设备发送PATCH类型REST API请求,该设备标称请求处理能力为50req/s,本次测试总请求量为36个。
异常现象
  • 日志显示所有greenthread看似一次性全部启动,但统计requests.sessions.send方法耗时发现:请求每10个为一批返回响应,每批请求的响应延迟比上一批高约6秒。
  • 初步排查排除项:
    • monkeypatch配置正常,未失效
    • 已配置的连接池大小1000远大于10,无法解释批量阻塞现象
  • 补充测试结果:
    将requests的HTTPAdapter初始化参数pool_connections、pool_maxsize均修改为1后,日志出现「连接池已满、丢弃到目标IP连接」的警告,但整体请求处理速度反而更快——每次重新建立与设备的连接,比复用连接池的处理效率更高。
  • 核心疑问:该异常现象是F5 REST服务端的机制问题,还是自身代码实现存在问题。
根因分析

这个问题是配置未生效叠加F5服务端限制共同导致的,和monkeypatch逻辑无关:

  1. 之前修改的urllib3.poolmanager.DEFAULT_POOLSIZE没有实际作用:requests的HTTPAdapter在初始化urllib3连接池时,会显式传入连接数参数覆盖类默认值,Python 2.7环境下requests默认给单个目标主机分配的长连接上限刚好是10,所有协程的请求都会被调度到这10个长连接上。
  2. F5 BIGIP(v12/v13等主流部署版本)的iControl REST服务对单个TCP长连接存在硬限制:单连接上最多同时处理10个未完成响应的流水线请求,超出的请求会直接在服务端缓冲区排队,不会进入业务处理逻辑,直到前面的请求响应完成才会按顺序处理,和观察到的每10个请求一批返回、每批延迟累加6秒的现象完全吻合。
  3. 把pool_maxsize改成1之后,连接池无法保留可复用的长连接,每个请求都会新建独立TCP连接,刚好绕开了F5单连接的请求排队限制,所以即使存在TCP建连开销,整体处理速度反而比复用10个长连接的场景更快。
修复方案
  • 优先方案:不要修改urllib3的全局默认参数,在初始化requests.Session后,给目标F5地址挂载自定义的HTTPAdapter,将单主机连接池上限pool_maxsize设置为和F5处理能力匹配的值(比如50),同时设置pool_block=False,避免请求在连接池层面排队。参考代码片段:
import requests
from requests.adapters import HTTPAdapter

s = requests.Session()
# 针对F5的HTTPS接口挂载自定义适配器
adapter = HTTPAdapter(pool_connections=50, pool_maxsize=50, pool_block=False)
s.mount('https://<F5设备地址>', adapter)
  • 轻量方案:如果不想调整连接池配置,可以在每个发送的PATCH请求头中添加Connection: close,强制请求处理完成后立即断开TCP连接,绕开单连接的请求排队限制,该方案在请求量不大的场景下几乎没有额外开销。

内容的提问来源于stack exchange,提问作者Pzhang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 12:01:48