向同一主机发送多HTTP GET请求致aiohttp客户端卡顿问题排查
解决aiohttp持久连接下批量下载超时问题
从你的描述和日志来看,问题的核心在于HTTP/1.1持久连接的复用逻辑异常,具体是因为请求完成后没有正确读取完整响应体,导致连接无法被放回连接池,最终引发事件循环阻塞超时。下面是具体的分析和解决方案:
问题根源
- 响应体未完整读取:你的
download_site函数中,虽然用了async with response,但手动调用response.release()且没有读取响应体内容。在aiohttp的HTTP/1.1持久连接机制中,只有当响应体被完全读取后,连接才会被标记为可用并放回连接池。如果跳过这一步,连接会被一直占用,新请求只能等待空闲连接,最终触发超时。 - 连接池状态异常:当大量请求并发时,被占用的连接无法释放,连接池耗尽,事件循环在等待IO事件时出现超时日志
poll 14805.463 ms took 14808.587 ms: timeout。而HTTP/1.0没有持久连接,每个请求新建连接,所以不会出现这个问题。
解决方案
1. 修复响应体读取逻辑
修改download_site函数,确保读取完整的响应体,让aiohttp正确释放连接到池里:
async def download_site(session, url): # 注意给URL加上http://前缀,避免aiohttp解析错误 full_url = f"http://{url[0]}" async with session.request( method="GET", url=full_url, params=url[1], ssl=False, expect100=False ) as response: # 读取完整响应体,确保连接可以被复用 await response.read() return response.status
移除手动的
response.release(),因为async with上下文管理器会自动处理连接的释放逻辑,手动调用反而可能干扰正常流程。
2. 优化TCPConnector参数
调整连接池的配置,添加连接存活时间和自动清理机制,避免空闲连接长期占用资源:
async with aiohttp.ClientSession( headers={"Connection": "keep-alive"}, connector=aiohttp.TCPConnector( limit=6, # 保持你的6个连接限制 ttl=30, # 连接最大存活时间(秒) cleanup_interval=10, # 每10秒清理一次空闲连接 enable_cleanup_closed=True # 自动清理已关闭的连接 ), raise_for_status=True ) as session:
3. 修正代码中的语法错误
你的代码里存在几处可能导致异常的语法问题,建议一并修复:
- 导入
time模块:import time - 修正
__name__判断:if __name__ == "__main__": - 修正
retrieve_file调用的参数:await asyncio.wait_for(retrieve_file(_file, run), timeout=15.0) - 确保
num_main_obj和list_obj变量已正确定义
验证效果
修改后,Wireshark应该能看到连接被复用(同一TCP连接处理多个请求),同时不会再出现poll timeout日志,批量下载超过20个文件时也能正常完成。
内容的提问来源于stack exchange,提问作者Roci
相关产品推荐
相关产品推荐

