Aiohttp会话关闭后连接仍存活,导致代理连接数持续增长问题
问题分析与解决方案
问题根源
你的代码中,每个异步任务的fetch_data函数在while True循环内反复创建新的ClientSession,每次会话关闭后,底层TCP连接因HTTP Keep-Alive机制会保持约10秒才销毁。30个任务持续循环创建会话,导致代理连接数不断累积,最终引发连接过载。
修复方案
1. 每个任务复用单一ClientSession
既然需求是每个任务保持同一代理IP,就应该让每个任务对应一个持久的ClientSession,在会话生命周期内循环执行请求,而非频繁创建销毁会话。修改后的核心逻辑如下:
import aiohttp import asyncio async def fetch_data(): # 每个任务仅创建一次ClientSession,会话内保持固定代理IP async with aiohttp.ClientSession( connector=aiohttp.TCPConnector(keepalive_timeout=5) # 缩短Keep-Alive超时加速连接回收 ) as session: while True: try: response = await session.get( 'https://example.com/', params=params, headers=headers, timeout=5, proxy=proxys ) result = await do_some(session) response = await session.get( 'https://example.com/', params=params, headers=headers, timeout=5, proxy=proxys ) # 添加适当延迟,避免请求过于频繁 await asyncio.sleep(0.5) except Exception as e: # 异常处理:打印错误、短暂重试 print(f"请求出错: {str(e)}") await asyncio.sleep(1) continue async def main(): tasks = [asyncio.create_task(fetch_data()) for _ in range(30)] await asyncio.gather(*tasks) # 等待所有任务执行,原代码未处理任务等待逻辑 if __name__ == "__main__": asyncio.run(main())
2. 关键优化点说明
- 会话复用:每个任务的会话在
while True外部创建,整个任务生命周期内复用同一个会话,避免频繁创建销毁带来的连接残留。 - 调整Keep-Alive超时:通过
TCPConnector的keepalive_timeout参数缩短闲置连接的存活时间,让代理端更快回收无效连接。 - 完善任务等待:原
main函数仅创建任务未等待执行,添加await asyncio.gather(*tasks)确保任务正常运行。 - 添加请求延迟:在请求后加入短暂延迟,避免短时间内发送过多请求导致连接数激增。
额外建议
如果遇到代理IP失效需要切换的场景,可在异常分支中关闭当前会话并重新创建,而非一直复用失效的会话:
async def fetch_data(): while True: try: async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(keepalive_timeout=5)) as session: while True: # 执行请求逻辑 await session.get(...) await asyncio.sleep(0.5) except Exception as e: print(f"会话异常,将重新创建: {str(e)}") await asyncio.sleep(2)
内容的提问来源于stack exchange,提问作者rdy4sv
相关产品推荐
相关产品推荐

