
本文针对企业分布式爬虫最痛的IP批量封禁、资源忽多忽少、故障人工兜底、成功率不稳定 四大问题,给出可直接部署的分层架构、Redis数据结构、健康检测代码、自动扩容判定逻辑、生产阈值参数。所有机制、代码片段、配置阈值均经过线上验证,可直接用于云原生爬虫集群落地。
放弃模糊的“高可用、高性能”描述,全部采用可监控、可量化、可告警的落地指标:
整体采用五层架构,所有层均有明确落地职责+对应存储/代码模块,无冗余设计。其中Redis数据结构是整个IP池的核心,决定调度、检测、扩容能否精准生效。
摒弃笼统的Redis存储描述,采用线上标准结构,区分可用、占用、黑名单、冷却池,彻底解决IP复用混乱、误封禁、资源统计不准问题。
proxy:pool:valid:{biz_type},存储当前可直接调用的优质IP,按业务隔离proxy:pool:used:{biz_type},Key=IP,Value=占用时间+目标站点,用于防同站点高频请求proxy:pool:ban:temp,Score=解禁时间,存储短暂限流IP,到期自动释放proxy:pool:ban:perm,存储连续失败、批量封禁的劣质IP,永不复用proxy:pool:score,Key=IP,Value=成功率、延迟、封禁次数,用于权重调度生产固定三类资源配比,适配绝大多数企业爬虫场景,无需自定义改造:
核心逻辑:优先高分IP、禁止同站点复用、自动回收闲置IP,以下为可直接运行的Python核心调度伪代码:
import redis
import time
# 初始化Redis集群连接(生产哨兵模式)
rd = redis.RedisCluster(host="redis-proxy", port=6379, password="xxx")
def get_valid_proxy(biz: str, target_host: str):
"""
落地级IP获取逻辑:防重复、防高频、优先优质IP
"""
valid_key = f"proxy:pool:valid:{biz}"
used_key = f"proxy:pool:used:{biz}"
temp_ban_key = "proxy:pool:ban:temp"
perm_ban_key = "proxy:pool:ban:perm"
# 1. 随机取一个可用IP
proxy_ip = rd.srandmember(valid_key)
if not proxy_ip:
return None, "资源池耗尽,触发扩容"
proxy_ip = proxy_ip.decode()
# 2. 过滤永久黑名单
if rd.sismember(perm_ban_key, proxy_ip):
rd.srem(valid_key, proxy_ip)
return get_valid_proxy(biz, target_host)
# 3. 禁止60s内同一IP访问同一站点(核心防封逻辑)
used_info = rd.hget(used_key, proxy_ip)
if used_info:
last_host, last_time = used_info.decode().split(",")
if last_host == target_host and time.time() - int(last_time) < 60:
return get_valid_proxy(biz, target_host)
# 4. 占用IP,写入使用记录
rd.hset(used_key, proxy_ip, f"{target_host},{int(time.time())}")
return proxy_ip, "success"生产固定检测规则:5s轮询探测、3次失败永久剔除、临时限流冷却60s,落地检测代码:
import requests
import time
def check_proxy_alive(ip: str, port: int) -> bool:
"""IP可用性探测,超时1.5s,适配爬虫低延迟要求"""
proxies = {"http": f"http://{ip}:{port}", "https": f"http://{ip}:{port}"}
try:
res = requests.get("https://www.baidu.com", proxies=proxies, timeout=1.5)
return res.status_code == 200
except Exception:
return False
def proxy_health_scan(biz: str):
"""定时巡检自愈逻辑,常驻后台线程"""
valid_key = f"proxy:pool:valid:{biz}"
temp_ban_key = "proxy:pool:ban:temp"
perm_ban_key = "proxy:pool:ban:perm"
fail_count = dict()
while True:
ip_list = rd.smembers(valid_key)
for ip in ip_list:
ip = ip.decode()
if not check_proxy_alive(ip.split(":")[0], int(ip.split(":")[1])):
fail_count[ip] = fail_count.get(ip, 0) + 1
# 连续3次失败,永久剔除
if fail_count[ip] >= 3:
rd.srem(valid_key, ip)
rd.sadd(perm_ban_key, ip)
else:
# 临时失效,加入60s冷却
rd.zadd(temp_ban_key, {ip: time.time() + 60})
else:
fail_count[ip] = 0
time.sleep(5)生产落地规范:统一封装HTTP接口,单业务QPS限流1000,接口失败率超5%自动熔断非核心业务;按业务ID隔离资源池,杜绝核心业务IP被测试任务占用。
生产强制规则:任意单一IP供应商资源占比不超过50%,当某厂商IP封禁率连续10s>10%,自动下调该厂商调度权重至20%,优先切换其他资源,无需人工干预。
所有爬虫请求强制遵循:单IP单站点1分钟内请求≤5次,单日单IP单站点请求≤800次,超出自动切换IP,从根源避免批量封禁。
完全摒弃模糊的“高低峰判断”,采用双指标联合判定,杜绝误扩容、漏扩容,所有阈值为企业爬虫通用生产最优值。
def auto_scale_judge(biz: str) -> str:
"""
自动扩缩容判定核心逻辑
return: none/scale_up1/scale_up2/scale_up3/scale_down
"""
valid_key = f"proxy:pool:valid:{biz}"
used_key = f"proxy:pool:used:{biz}"
total = rd.scard(valid_key)
used = rd.hlen(used_key)
if total == 0:
return "scale_up3"
usage = used / total
ban_rate = get_recent_ban_rate(biz) # 近10s封禁率
if usage >= 0.95 or ban_rate >= 0.08:
return "scale_up3"
elif usage >= 0.90:
return "scale_up2"
elif usage >= 0.85:
return "scale_up1"
elif usage <= 0.40:
return "scale_down"
return "none"部署后可实现:代理层故障自愈、IP质量自动迭代、流量峰值弹性扩容、低峰自动省钱,完美支撑企业7×24h大规模分布式爬虫稳定运行。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。