代理 IP 并发数指某一时刻仍在发送、等待或接收响应的代理请求数量。它不等于线程数、不等于代理 IP 数量,也不等于每秒完成的请求数。用于初步估算时,可以采用:理论在途并发 ≈ 稳定成功 QPS × 平均端到端响应时间(秒)。真正上线前,还要用自己的目标地址、地区和请求内容做阶梯测试。
例如,一个合规数据任务希望稳定完成 30 个请求/秒,实测平均端到端响应时间为 0.8 秒,那么理论在途并发约为 24;如果响应时间升到 2 秒,即使目标成功 QPS 不变,也需要约 60 个并发。并发不是越大越好:超过链路或目标服务的承受点后,常见结果是延迟上升、超时和重试增加,实际成功吞吐反而下降。
文章目录
一、代理数量、线程、连接、并发与 QPS
很多容量估算出错,不是公式不会算,而是一开始把不同指标当成了同一件事。一个脚本可以启动 100 个线程,但其中一部分可能在等待任务;一个浏览器页面也可能为了图片、字体和接口同时建立多条请求。反过来,启用连接复用后,多次请求又可能共用同一条 TCP 连接。
| 指标 | 实际含义 | 常见误解 | 应该怎样统计 |
|---|---|---|---|
| 代理 IP 数量 | 任务可使用的出口地址数量 | 一个 IP 就等于一个并发 | 记录实际出现过的出口 IP,并按会话或任务关联 |
| 线程或协程数 | 客户端安排任务的执行单元数量 | 开了 100 个线程,就一定有 100 个请求同时进行 | 从程序运行器或连接池配置中读取 |
| 并发请求数 | 同一时刻尚未完成的在途请求数量 | 并发越高,成功 QPS 一定越高 | 按请求开始与结束时间计算峰值和稳定区间 |
| 连接数 | 客户端、代理和目标之间建立的网络连接数量 | 一个请求始终对应一条新连接 | 结合客户端连接池、Keep-Alive 和系统连接状态观察 |
| QPS / RPS | 每秒完成的请求量;业务上更应关注成功请求量 | 只要提高线程数,QPS 就会按比例增加 | 用完成请求数除以稳定测试时长,并单列成功 QPS |
| 带宽 | 单位时间能够传输的数据量 | 带宽足够就不会超时 | 同时记录上行、下行、峰值和持续吞吐 |
MDN 的 HTTP 连接管理说明指出,持久连接可以被多次请求复用,而且客户端到代理、代理到目标服务可能采用不同的连接方式。因此,“请求并发”和“TCP 连接数”通常有关联,但不能直接画等号。
二、代理 IP 并发数的估算公式
在请求到达率和完成率相对稳定、系统没有明显排队积压时,可以用下面的关系做初步估算:
理论在途并发 ≈ 稳定成功 QPS × 平均端到端响应时间(秒)
稳定成功 QPS ≈ 理论在途并发 ÷ 平均端到端响应时间(秒)
AWS 关于并发计算的官方说明使用“平均每秒请求数 × 平均请求时长”估算同时在途的任务数量。套用到代理容量规划时,本文把 QPS 进一步限定为稳定完成且通过结果校验的请求率;响应时间则从客户端发起请求开始计算到完整接收结果为止,而不是只看代理节点的 Ping 值。
| 目标成功 QPS | 平均响应时间 | 理论在途并发 | 解读 |
|---|---|---|---|
| 5 | 0.4 秒 | 约 2 | 先从低并发验证,不需要直接开大量线程 |
| 20 | 0.8 秒 | 约 16 | 适合从 10、15、20 逐级观察稳定点 |
| 20 | 2 秒 | 约 40 | 目标速度不变,但响应变慢会占用更多并发槽位 |
| 50 | 1.5 秒 | 约 75 | 应同步核查客户端、带宽、代理和目标服务限制 |
上表是计算示例,不是任何套餐的性能承诺。平均值适合估算理论关系,p95 延迟更适合观察慢请求是否开始堆积。若平均响应时间看起来正常,但 p95 已明显上升,就不宜仅凭平均值继续提高并发。
三、并发、QPS 与带宽的关系
并发解决的是“同时有多少请求在路上”,带宽解决的是“这些请求每秒要传多少数据”。文本接口响应很小,几十个并发也可能占用不了多少带宽;图片、文件或完整网页响应较大,即使 QPS 不高,也可能先把链路推到瓶颈。
纯业务数据带宽(Mbps)≈ QPS × 单次请求平均总传输量(MB)× 8
假设一次请求的上行和下行合计约 1.5 MB,稳定完成 12 QPS,纯业务数据约为 144 Mbps。这个数字还没有计入协议开销、连接握手、重定向、重传和失败重试,不能直接当成采购带宽。浏览器页面还会加载图片、字体和接口请求,流量通常不只是一份 HTML;如果实际用量高于预期,可以继续查看代理流量消耗过快的排查方法。
因此,估算时至少要同时保留四组数据:成功 QPS、平均与 p95 响应时间、单次请求平均传输量、测试期间峰值带宽。只记录“开了多少线程”,无法判断瓶颈发生在哪一层。
四、单个代理 IP 的并发边界
单个代理 IP 没有一个适用于所有业务的固定并发值。同一出口访问一个轻量接口和加载一个包含大量资源的网页,连接时长与数据量完全不同;同样是 20 并发,不同地区、目标地址和网络路径也可能得到不同结果。
真正限制成功吞吐的通常是以下几层中最先达到上限的一层:
- 客户端:CPU、内存、线程池、连接池、文件描述符和本地网络;
- 代理入口:账号、网关、端口、并行会话及服务约定;
- 代理出口:出口 IP、服务器资源、线路带宽与地区质量;
- 目标服务:接口容量、公开的速率限制和服务端响应时间;
- 请求内容:返回体大小、重定向次数、TLS 建连与失败重试。
因此,不要根据代理 IP 数量直接分配线程。例如有 20 个出口 IP,并不表示“每个 IP 开 10 线程,总并发一定是 200”。应该先按目标服务允许的访问规则设定总体请求节奏,再观察不同出口、不同连接池之间的成功率和延迟。
五、阶梯测试与记录方法
容量测试只应针对自有系统、测试环境或已经获得授权的目标地址进行。不要用公开第三方接口做高并发压测,也不要为了绕过对方限速而更换 IP。一个更可靠的过程,是先固定请求内容和地区,再逐级增加并发。
- 建立单请求基线:用并发 1 测出正常响应时间、状态码和返回内容;
- 设置阶梯:可以从 1、5、10、20 开始,每一级运行到数据进入稳定区间;
- 固定变量:同一轮不要同时更换地区、目标地址、请求内容和代理类型;
- 记录结果:统计总 QPS、成功 QPS、成功率、平均延迟、p95、错误码、超时和传输量;
- 找到拐点:当并发继续增加但成功 QPS 不再提高,或者 p95 与错误率明显恶化,就回退到前一个稳定档位;
- 分目标复测:不同地区和目标服务分别建档,不把某个地址的结果套用到所有任务。
Grafana k6 的指标文档建议从请求量、错误率和请求时长三个方向观察性能。对于代理测试,还应再补充出口 IP、代理错误码、流量和业务结果校验,避免把“HTTP 返回了结果”直接算成业务成功。
| 测试轮次 | 并发 | 总 QPS | 成功 QPS | 成功率 | 平均 / p95 | 407 / 429 / 5xx / 超时 | 流量或带宽 | 结论 |
|---|---|---|---|---|---|---|---|---|
| 基线 | 1 | 填写实测值 | 填写实测值 | 填写实测值 | 填写实测值 | 分别记录 | 填写实测值 | 基准 |
| 阶梯 A | 填写并发 | 填写实测值 | 填写实测值 | 填写实测值 | 填写实测值 | 分别记录 | 填写实测值 | 继续 / 回退 |
| 阶梯 B | 填写并发 | 填写实测值 | 填写实测值 | 填写实测值 | 填写实测值 | 分别记录 | 填写实测值 | 继续 / 回退 |
可复制的 Python 小规模测试脚本
这个示例刻意保持简单,不模拟生产环境中的持久连接池和复杂连接复用,因此结果只适合作为低并发基线,不应直接作为正式容量上限。示例使用 HTTP 代理,只用于你拥有或已获授权的测试地址。把代理地址和目标地址替换为真实测试参数,并从较低并发开始。
from concurrent.futures import ThreadPoolExecutor, as_completed
import time
import requests
PROXY = "http://username:password@proxy-host:port"
TARGET_URL = "https://your-authorized-test-endpoint.example/health"
CONCURRENCY = 10
TOTAL_REQUESTS = 100
TIMEOUT_SECONDS = 15
proxies = {"http": PROXY, "https": PROXY}
def send_one(request_id):
started = time.perf_counter()
try:
response = requests.get(
TARGET_URL,
proxies=proxies,
timeout=TIMEOUT_SECONDS,
)
elapsed_ms = (time.perf_counter() - started) * 1000
return {
"http_ok": 200 <= response.status_code < 400,
"status": response.status_code,
"elapsed_ms": elapsed_ms,
}
except requests.RequestException as exc:
elapsed_ms = (time.perf_counter() - started) * 1000
return {
"http_ok": False,
"status": type(exc).__name__,
"elapsed_ms": elapsed_ms,
}
test_started = time.perf_counter()
with ThreadPoolExecutor(max_workers=CONCURRENCY) as executor:
futures = [executor.submit(send_one, i) for i in range(TOTAL_REQUESTS)]
results = [future.result() for future in as_completed(futures)]
total_seconds = time.perf_counter() - test_started
latencies = sorted(item["elapsed_ms"] for item in results)
http_success_count = sum(1 for item in results if item["http_ok"])
p95_index = max(0, int(len(latencies) * 0.95) - 1)
print("concurrency:", CONCURRENCY)
print("total_qps:", round(len(results) / total_seconds, 2))
print("http_success_qps:", round(http_success_count / total_seconds, 2))
print("http_success_rate:", f"{http_success_count / len(results):.2%}")
print("average_ms:", round(sum(latencies) / len(latencies), 2))
print("p95_ms:", round(latencies[p95_index], 2))
print("status_counts:", {
str(status): sum(1 for item in results if item["status"] == status)
for status in set(item["status"] for item in results)
})
代码中的 http_success_qps 和 http_success_rate 只表示状态码处于 200—399,不能自动证明业务结果正确。实际任务还应增加响应内容校验,例如检查目标字段、JSON 业务状态或页面特征。这个脚本能做小规模基线核对,但不能代替完整压测平台;正式容量测试还要控制到达率、连接复用、预热时间、结果校验和测试中止条件,并由目标系统负责人确认允许的测试范围。
六、常见瓶颈与错误信号
| 测试现象 | 优先判断 | 处理方向 |
|---|---|---|
| 并发提高,成功 QPS 基本不变,p95 快速上升 | 某一层已经饱和,请求开始排队 | 回退并发,分别检查客户端、代理、带宽和目标响应 |
| 429 明显增加 | 目标服务正在执行速率限制 | 降低请求速率,遵守对方规则,并按 Retry-After 等提示等待 |
| 407 持续出现 | 代理认证信息缺失、错误或不完整 | 核对账号、密码、认证方式、有效期和配置位置 |
| 超时增加,但 CPU 与带宽仍有余量 | 地区链路、代理出口或目标服务响应可能波动 | 固定变量分地区复测,不要立即扩大线程池 |
| CPU、内存或连接池先满 | 客户端先于代理达到容量上限 | 优化客户端资源和连接复用,再重新评估代理容量 |
| 错误率上升,同时流量消耗异常增加 | 失败重试、重定向或重复下载正在放大用量 | 限制重试次数,记录原始错误并核对单次请求大小 |
RFC 6585 对 429 的定义是单位时间内请求过多,响应还可能携带 Retry-After;它不等于“代理 IP 数量不够”。RFC 9110 对 407 的定义则指客户端需要向代理完成认证。把错误码分清,才能避免用增加 IP 或线程的方式处理一个认证问题。
七、测出瓶颈后,应该扩什么资源
扩容应跟着已经确认的瓶颈走。出口地址不够就扩 IP 池,持续吞吐碰到带宽上限就扩网络容量,需要固定出口或资源隔离时再调整代理类型;如果限制来自目标服务,继续增加代理和线程并不能解决问题。
| 已经确认的瓶颈或需求 | 应该调整的资源 | 增加什么可能无效 | 可考虑的方案 |
|---|---|---|---|
| 出口数量或地区覆盖不足 | IP 池、地区资源和请求调度 | 单纯提高线程数 | 动态住宅代理 |
| 带宽持续接近上限,且客户端和目标服务仍有余量 | 网络带宽、服务器资源和连接配置 | 只增加出口 IP 数量 | 无限流量住宅代理 |
| 共享资源波动明显,需要可控的机房出口 | 独享出口、服务器、带宽及扩容方式 | 继续堆共享端口 | 独享数据中心代理 |
| 任务需要长期保持同一网络出口 | IP 固定性、会话连续性和地区一致性 | 增加动态出口数量 | 静态住宅或其他固定出口方案 |
| 目标服务返回429或明确限制请求频率 | 降低到达率、遵守Retry-After并调整任务计划 | 增加IP、带宽或线程 | 不应通过代理扩容规避目标规则 |
确认瓶颈确实在出口数量和地区覆盖后,可以用 IPWeb 的动态住宅代理扩展轮换出口和并行会话;但“不限制并行会话数”不代表客户端、带宽和目标服务也没有边界。如果瓶颈是持续传输量和网络容量,无限流量住宅代理可以按服务器、带宽和 IP 数量等资源配置,再结合实际吞吐规划扩容。
如果重点是独享机房出口与可控资源,可以评估独享数据中心代理,并在询价时分别确认 IP、端口、带宽和服务器的资源边界。关于这四层资源为什么不能互相替代,可参考独享 IP、带宽、端口与服务器的区别。
八、代理 IP 并发数常见问题
1. 100 个线程就等于 100 个代理并发吗?
不一定。线程可能在等待任务、执行解析或已经空闲,真正的代理并发要看同一时刻有多少请求尚未完成。异步程序中的协程数也不能直接等同于在途请求数。
2. 一个代理 IP 最多能开多少并发?
没有适用于所有目标和产品的统一数字。请求大小、响应时间、目标服务限制、代理网关、出口带宽和客户端资源都会影响结果。应从低并发开始,用真实授权目标做阶梯测试。
3. 无限并发是不是等于无限 QPS?
不是。代理服务不限制并行会话,只代表不会在该维度设置固定额度;实际 QPS 仍可能受客户端、网络带宽、代理出口、目标响应时间和目标服务规则限制。
4. 为什么带宽没有跑满,请求还是很慢?
带宽只是容量的一部分。高延迟、连接建立、目标处理时间、连接池等待和慢请求都可能让 QPS 先达到平台期,即使链路还有剩余带宽。
5. 提高并发以后出现 429,是代理不够吗?
通常不能这样判断。429 表示请求频率触发了目标服务的限制。应该降低到达率、读取对方返回说明并遵守 Retry-After,而不是继续增加线程或轮换出口。
6. 407 错误是并发过高造成的吗?
407 的标准含义是需要向代理完成认证。应先核对代理账号、密码、认证方式和资源状态;只有服务商明确说明并发超限也会返回该错误时,才按具体产品规则处理。
7. 代理 IP 数量增加后,并发能力会按比例增加吗?
不保证。增加出口 IP 可以改善任务分配和地址覆盖,但如果瓶颈位于客户端、共享网关、总带宽或目标服务,成功 QPS 不会随 IP 数量线性增长。扩容前应先通过测试确认真正的限制层。
计算代理 IP 并发时,先确定成功 QPS,再测端到端响应时间,最后用阶梯测试确认稳定点。如果并发继续增加却没有带来更多成功结果,就应该寻找瓶颈,而不是继续堆线程和出口 IP。