Python AIOHTTP多次请求后性能骤降问题排查与解决
问题分析与解决方案
核心原因推测
1. TCP端口耗尽/连接池资源未合理管理
默认情况下,aiohttp的ClientSession未限制并发连接数,每轮1000个请求会快速占用大量系统临时端口。端口释放后会进入TIME_WAIT状态(通常持续几十秒),轮次增多后可用端口被耗尽,新请求只能等待端口释放,直接导致请求速度暴跌。
2. 未设置请求超时,慢请求拖垮整轮
部分请求因网络波动或服务器响应缓慢卡住时,无超时限制会拉长整轮执行时间,轮次积累后问题被放大。
3. 潜在资源泄漏
未处理请求异常、未及时清理连接资源,可能导致连接池无效连接堆积,或内存占用持续升高引发GC频繁执行,拖慢整体性能。
针对性解决办法
1. 限制并发连接数,优化连接池配置
给ClientSession配置TCPConnector,限制全局及单域名并发数,同时开启关闭连接自动清理:
import asyncio import aiohttp async def get_response(session, url): async with session.get(url) as resp: response_json = await resp.json() return response_json async def main(): # 配置连接池:根据系统性能调整参数 connector = aiohttp.TCPConnector( limit=200, # 全局最大并发连接数 limit_per_host=50, # 单个域名的最大并发连接数 enable_cleanup_closed=True # 自动清理已关闭的连接 ) async with aiohttp.ClientSession(connector=connector) as session: for _ in range(num_rounds): tasks = [] # 给单轮请求设置统一超时 timeout = aiohttp.ClientTimeout(total=10) for i in range(1000): url = f"some_url_{i}" # 替换为实际URL生成逻辑 tasks.append(asyncio.create_task(get_response(session, url))) # 捕获异常,避免单个请求失败导致整轮崩溃 output = await asyncio.gather(*tasks, return_exceptions=True) # 可选:过滤异常结果 # valid_output = [res for res in output if not isinstance(res, Exception)] # 显式清理变量,释放内存 tasks.clear() output = None if __name__ == "__main__": num_rounds = 20 # 替换为实际轮次 asyncio.run(main())
2. 强制设置请求超时
可全局配置超时,或在单个请求中指定:
# 全局超时配置 async with aiohttp.ClientSession( connector=connector, timeout=aiohttp.ClientTimeout(total=10) ) as session: # 后续请求逻辑
3. 系统TCP参数优化(针对端口耗尽)
Linux系统可调整参数缩短TIME_WAIT时长、扩大可用端口范围(临时生效):
sysctl -w net.ipv4.tcp_tw_reuse=1 sysctl -w net.ipv4.ip_local_port_range="1024 65535"
注:tcp_tw_recycle在部分内核版本已废弃,优先使用tcp_tw_reuse。
4. 排查内存泄漏
若修改后仍有性能问题,可使用memory_profiler工具检测内存占用变化,定位是否存在未释放的大对象或循环引用。
验证效果
修改配置后观察每轮执行时间,若速度恢复稳定则说明是连接数/端口问题;若仍有波动,可通过tcpdump分析连接状态,进一步定位问题。
内容的提问来源于stack exchange,提问作者Grigori
相关产品推荐
相关产品推荐

