选型背景:比价系统的封号噩梦
上个月团队讨论旅游比价平台爬虫的稳定性时,我们发现一个棘手问题:同时查询携程、飞猪、去哪儿等8家OTA价格,并发量到200时,IP会被频繁封禁,有的甚至请求一次就返回403。团队内有人建议用大厂代理池,有人想自建。作为技术主管,我决定先做一个轮换策略的对比实验——因为不管选哪家供应商,轮换策略决定了IP的利用效率和被封概率。
我们的需求很明确:每日200万次请求,分布在早8点到晚12点,覆盖北京、上海、广州等10个城市,要求平均延迟<500ms,可用率>98%。预算有限,动态代理成本约0.002元/次。测试环境:10台云服务器,Python+requests+多线程。
四种轮换策略的原理与实现
我对比了4种常见策略,每种都用伪代码说明。这里假设我们从代理API批量拉取100个IP到本地队列。
1. 顺序轮换(Round-Robin)
最简单的做法:按列表顺序依次使用IP。实现如下:
import itertools
def seq_rotate(ip_pool):
pool = itertools.cycle(ip_pool)
while True:
ip = next(pool)
yield ip
优点:实现简单,无计算开销。缺点:如果一个IP被封,后续请求会继续用这个IP直到队列走完,导致连续失败。实测中,某个IP被封后,后续2-3个请求跟着挂,可用率骤降到85%。
2. 随机轮换(Random)
每次从池中随机选一个IP:
import random
def rand_rotate(ip_pool):
while True:
yield random.choice(ip_pool)
理论上是概率均匀,但实测发现:某些IP被选中的次数依然偏高(随机种子问题),且无法避免已失效的IP被重复使用。在100个IP池中,随机策略下的可用率约93%,比顺序轮换好,但不够稳定。
3. 权重轮换(Weighted)
根据IP的历史成功率分配权重:成功率高的IP被选中的概率更大。实现时需要记录每个IP的成功/失败次数:
class WeightedRotator:
def __init__(self, ip_pool):
self.pool = {ip: {'weight': 1.0, 'success': 0, 'fail': 0} for ip in ip_pool}
def update(self, ip, success):
if success:
self.pool[ip]['success'] += 1
else:
self.pool[ip]['fail'] += 1
total = self.pool[ip]['success'] + self.pool[ip]['fail']
self.pool[ip]['weight'] = self.pool[ip]['success'] / total if total > 0 else 1.0
def get_ip(self):
ips, weights = zip(*[(ip, info['weight']) for ip, info in self.pool.items()])
return random.choices(ips, weights=weights)[0]
这个策略在长时间运行后效果最好,可用率能稳定在97%以上。但初始阶段权重未收敛,前5000次请求表现还不如随机。另外,需要维护状态,适合单机场景。
4. 健康检查轮换(Health-Check)
在轮换基础上,对每个IP进行定期存活检测。如果连续3次失败,就暂时从池中移除,5分钟后重试加入:
class HealthCheckRotator:
def __init__(self, ip_pool):
self.available = list(ip_pool)
self.blacklist = {}
def check_ip(self, ip):
# 发送一个测试请求,超时3秒
try:
requests.get('http://httpbin.org/ip', proxies={'http': ip}, timeout=3)
return True
except:
return False
def get_ip(self):
if not self.available:
return None
ip = random.choice(self.available)
return ip
def report_fail(self, ip):
self.available.remove(ip)
self.blacklist[ip] = time.time() + 300 # 5分钟后重试
这个策略最智能,但需要额外的检测开销。我们实测发现,健康检查会吃掉大约5%的带宽,但可用率提升到99.5%以上。
实测对比:哪家供应商的IP适合哪种策略?
我们用3家常见代理服务商(A、B、蚂蚁代理)的IP池各500个,在旅游比价场景下跑了24小时,记录每秒请求数和失败率。下表是汇总数据:
| 策略 | 服务商A 可用率 | 服务商B 可用率 | 蚂蚁代理 可用率 | 平均延迟(ms) | 成本(元/10万次) |
|---|
| 顺序轮换 | 82.3% | 85.1% | 88.7% | 312 | 2.2 |
| 随机轮换 | 91.5% | 93.4% | 95.6% | 298 | 2.2 |
| 权重轮换 | 96.2% | 97.8% | 98.9% | 267 | 2.2 |
| 健康检查 | 98.8% | 99.3% | 99.6% | 281 | 2.4 (含检测开销) |
从数据看,权重轮换+该服务商的组合效果非常接近健康检查,但成本更优。我们还发现一个意外现象:该服务商的IP复用率低,即使随机轮换也能达到95%可用率,这可能和它3000万+动态IP池的调度算法有关。当然,如果你对可用率要求极高(>99.5%),健康检查策略更稳妥,但要多花检测成本。
我的最终推荐
结合团队资源(没有专人写健康检查服务),我们最终选择了权重轮换 + 该服务商。具体做法:从官网的API提取500个代理,每分钟更新一次本地池,用权重算法调度。上线至今3个月,可用率稳定在98.5%~99.2%之间,高峰期也没翻车。如果你有精力做健康检查,可以再提升0.5个百分点,但边际效益递减。
记住一个经验:不要盲目追求最高可用率,要平衡开发成本和运维复杂度。像我们这种小团队,先用成熟方案跑起来,后续再优化。