代理IP并发连接老超限?TCP连接池和线程池优化五条规则

Session复用TCP连接、连接池大小匹配并发、线程数控制和重试退避策略
发布于
1

代理IP用在高并发场景时最常见的报错:”Too many connections”(连接数超限)、”Connection reset by peer”(对端重置连接)、”Timeout”(超时)。不是你代码写得不好,是代理IP本身有连接数上限,加上TCP连接没复用导致的资源浪费。本文把几条并发优化的规则讲清楚。

代理IP为什么限制并发连接

代理服务器本质上是一台中转服务器,每有一个客户端连过来、它就要维持一条到目标网站的TCP连接。一台代理服务器能同时维持的TCP连接是有限的——取决于这台服务器的内存和操作系统的文件描述符上限。

共享代理IP的并发限制更严——同一个IP可能有几十个用户在用,代理服务器要保证每个用户都有可用连接。所以你看到的”连接数超限”,不是你一个人占了太多,是整个IP上所有用户加起来超了。

天行IP的独享代理(邀请码 blsj,月付6元起)没有共享用户的竞争,并发上限由代理服务器本身限制——通常单IP支持几十到上百并发连接。采集任务是够用的,但需要连接池优化才能发挥出来。

规则一:用requests.Session复用TCP连接

Python requests库最大的性能陷阱是每次请求都开新连接。正确的做法是用Session复用:

# 错误做法:每次请求都在TCP握手
for url in urls:
    requests.get(url, proxies=proxy)  # 每次新建TCP连接

# 正确做法:Session复用TCP连接
session = requests.Session()
session.proxies = proxy
for url in urls:
    session.get(url)  # 复用同一个TCP连接

Session背后是urllib3的连接池——默认每个host保持10个连接。改了Session之后,同一目标域名的请求都复用已有的TCP连接,省掉了三次握手和TLS握手的开销。

规则二:设置连接池大小匹配并发量

连接池默认10个连接,如果你的并发线程超过10,多出来的线程会排队等连接。根据并发线程数调大连接池:

from requests.adapters import HTTPAdapter

session = requests.Session()
# 每个host的连接池扩大到50个
adapter = HTTPAdapter(pool_connections=50, pool_maxsize=50)
session.mount('http://', adapter)
session.mount('https://', adapter)
session.proxies = proxy

pool_connections是总连接池大小,pool_maxsize是每个host的最大连接数。代理IP有连接限制的情况下,pool_connections不建议设超过代理的并发上限。

规则三:控制线程数和代理连接数的配比

如果代理IP支持最多50并发连接,你开了100个线程,多出来的50个线程在排队等连接——看起来是在跑但实际在空等。最佳配比:线程数 ≤ 代理IP并发上限 × 0.8。留20%余量,避免偶然的峰值把代理打满。

ThreadPoolExecutor设置并发:

from concurrent.futures import ThreadPoolExecutor

# 代理支持50并发,实际用40个线程
with ThreadPoolExecutor(max_workers=40) as executor:
    results = executor.map(fetch_with_proxy, urls)

规则四:断开不用的连接释放资源

有些场景下你用的是多个不同的代理IP轮流切换——每个代理的Session留在那儿占用着连接但不一定在用。定期清理空闲连接:

# 每处理完一批请求后,关闭空闲连接
session.close()  # 关闭所有连接
# 或者只清理空闲连接
adapter = session.get_adapter('http://')
adapter.poolmanager.clear()

长时间运行的服务建议设连接keep-alive超时——超过30秒没活动的连接自动关闭,避免占着连接不干活。

规则五:加上重试和退避策略

高并发时偶尔的连接超时是正常的,不能因为一次失败就整个任务停了。加上重试机制:

from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

retry_strategy = Retry(
    total=3,                # 最多重试3次
    backoff_factor=0.5,     # 每次重试间隔翻倍: 0.5s, 1s, 2s
    status_forcelist=[429, 500, 502, 503, 504]  # 这些状态码才重试
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount('http://', adapter)

backoff_factor=0.5表示第1次重试等0.5秒、第2次等1秒、第3次等2秒——给了代理服务器喘息的时间。别不加退避直接狂重试,等于自己对自己DDoS。

常见问题

加了连接池为什么还是慢?

连接池优化TCP连接复用,解决的是连接建立的开销问题。如果加了连接池还是慢,问题不在连接而在延迟——代理IP本身的延迟高,每个请求都要等几秒。解决方案是换延迟更低的节点或地区。

共享代理和独享代理的并发差距多大?

共享代理通常限制5-20并发连接,独享代理可以到50-200。差距是数量级的。采集任务选独享——鲸云IP的独享住宅代理(客服x31471626改价)和天行IP的独享静态都能撑更高并发。

代理并发不够能不能多买几个IP并行?

可以,而且这是横向扩展的正确思路。10个代理IP各跑20线程,总并发200。比买一个”支持200并发”的高价套餐便宜且容错更好——一个IP挂了不影响另外9个。

本文由作者原创/授权发布于极跃圈(jiyueip.com)未经许可,禁止转载。题图来自Unsplash,基于CC0协议。

声明:极跃圈(JIYUEIP.com)内网友所发表的所有内容及言论仅代表其本人,并不反映任何极跃圈(JIYUEIP.com)之意见及观点。

0 讨论
热门最新
总结
暂无总结
0 / 600

数据采集被封IP的根本原因不是用了代理,是请求频率不像正常人。人浏览网页是几秒一个页面+随机停顿,你的脚本是每秒100个请求+毫秒级响应。频率控制的目标是用尽可能快的速度完成采集任务同时让请求模式看起来像人。 什么样的频率会被判定为异常 风

同一个代理商标的”100M带宽”,共享版到手5M、独享版能跑满80M——差的是线路上有几个人在跟你抢。本文从带宽、IP纯净度、并发连接和安全性四个维度讲清共享和独享的实际差距。 共享代理IP的真实使用体验 共享代理IP的意思是这个IP上不止

公司或学校的网络管理员封了大部分端口、只开放80和443——这种情况下很多代理协议连不上。本文讲清企业网络环境下的代理穿透策略,包括常见的限制手段和对应的绕过方法。 企业/校园网常见限制方式 防火墙白名单:只开放80(HTTP)和443(H