大多数容量问题问反了。有人问要运行多少个线程,或者要买多少带宽,但在你把实际需求翻译出来之前,这两者都是无法知道的,而实际需求通常是这样的话:“五万条产品记录,每天刷新,08:00前准备就绪”。这句话包含了你需要的一切。以下是如何把它转化为请求量、并发数和套餐规模,以及真正的瓶颈在哪里。
从记录出发,而不是从请求出发
第一步转换是人们最容易跳过的一步,也是估算出现数倍偏差的地方。
一条记录很少等于一个请求。一条产品记录可能需要一个列表页加一个详情页,那就是两个。如果列表分页,而你需要抓取每一项,就要加上分页请求,并将其平摊到它们产生的记录数上。如果详情页要从第二次调用中加载数据,那又是一个请求。而如果你是在浏览器中渲染页面,而不是抓取数据接口,一个逻辑请求会变成数十个资源请求,这对带宽的影响极大,即使它不改变逻辑请求数。
所以要把它明确写出来:
requests_per_record = detail_pages + (listing_pages / records_per_listing) + extra_calls
对于五万条记录,假设每条平均1.2个请求,那就是每次运行60,000个请求。然后要加上失败余量,因为你的验证成功率不会是100%。按90%计算,你大约需要67,000次尝试才能获得60,000次成功,而如果你还要重试瞬时失败,实际数字会再高一些。按成功次数而不是尝试次数来做计划,是第二常见的估算错误。
并发数由速率和延迟决定
现在来看令人意外的部分。并发数不是你随意选择的一个数字;它由你需要多快完成以及每个请求耗时多久决定。
如果你必须在四小时窗口内完成67,000个请求,那就是每秒约4.7个请求的持续速率。住宅请求比直连请求慢,所以假设端到端平均耗时两秒。你需要的在途请求数,就是速率乘以延迟:
concurrency = requests_per_second x average_latency_seconds
= 4.7 x 2
~ 10 concurrent requests
这个关系值得牢记,因为它同时解释了两件事。目标越慢,达到同样吞吐量所需的并发数就越高,这就是为什么一个悄悄变慢的目标会在没有任何错误出现的情况下拖垮整个计划。而如果拖慢速度的是目标本身,提高并发数并不会提高吞吐量;它只会增加等待中的请求数量。
反过来推也是一样。如果你把并发数限制在10,而延迟从两秒漂移到五秒,你的吞吐量就会从每秒5个请求降到2个,原本四小时的任务会变成十小时。以留有余量而不是压线运行的方式来搭建计划,才能防止延迟漂移变成错过截止时间。
瓶颈是目标,而不是你的机器
这就是计划遇上现实的地方。你的基础设施能承受的并发数几乎从来不是限制所在。真正的限制,是目标能容忍什么。
速率限制是按每个IP执行的,而且越来越多地是按目标总体执行的。使用IP池能让你把每个IP的负载分散开,但到达单一源站的总量仍然是可见的,所以你要规划的数字,是该网站能接受的量,而不是你的工作进程能发出的量。节奏控制的机制在速率限制与请求节流中有介绍,而随之而来的分布问题,即你的量需要多大的分散度,则在你到底需要多少个代理IP中有详细说明。
实际操作上,这意味着你的计划应该按每个目标设定并发上限和速率,而不是设一个全局值。五十个目标各自适度并发,和把同样的总量都指向一个网站,完全是两码事,只有后者才会让你被封锁。
带宽才是你真正要购买的数字
由于住宅代理是按传输的数据量计费的,套餐规模应该由字节数决定,而不是由请求数或地址数决定。
monthly_bandwidth = attempts_per_run x runs_per_month x average_bytes_per_response
起决定作用的变量是最后一个,而这完全在你的掌控之中。一个JSON响应或精简的HTML页面是几十KB;而一个包含图片、字体和第三方脚本的完整渲染页面则是几MB。以每天60,000个请求计算,50 KB的响应每月大约是90 GB,而2 MB的渲染页面每月大约是3.6 TB,同样的逻辑工作量却相差如此之大。这就是普通套餐和企业级套餐之间的区别,而这取决于你是抓取数据还是渲染页面,详见何时需要无头浏览器和削减带宽成本。
在确定套餐规模之前先做这项优化,因为它常常能让你降低一个档次。更完整的预测方法在估算每月带宽中,产品层面的选择在选择合适的套餐中。
调度安排:分散优于突发
两个每日总量相同的任务,可能因为运行时间不同而表现完全不同。
把所有工作压缩到一小时窗口内,会把你瞬时速率对每个目标同时放大,而这正是触发防御机制的典型形态。把同样的工作分散到可用窗口内,能免费降低每个目标的速率,并且还能让失败的请求在运行过程中有空间被重试,而不是全都堆积到最后。
新鲜度要求决定了这个约束条件。如果数据必须在08:00之前保持最新,你就需要在那之前完成采集,但这是一个截止时间,而不是要求你在07:00才开始的指令。只要调度允许,把工作分散到整个窗口内,并优先处理波动性最大的数据源,严格来说总是更好的做法。
提交前先用试点验证
上面的每一个数字在你测量出你所假设的这两个变量之前,都只是一个假设:通过住宅出口访问实际目标的真实平均延迟,以及在你的抓取策略确定后每个响应的真实字节数。这两者都很容易在小规模运行中测量出来,而且两者都会对计划产生实质影响。
用大约预定量的百分之五进行试点运行,记录验证过的成功率、延迟百分位数,以及每个目标每次请求的字节数,然后重新计算。预计结果会与你的估算在两个方向上都有出入。测量方法在测试速度、成功率和位置准确性中,而这些数字的持续版本正是代理KPI中的指标。
一个实例总结
需求:每天50,000条记录,08:00前准备就绪,采集窗口为04:00到08:00。
每条记录1.2个请求,得出60,000次成功。按90%的验证成功率,大约需要67,000次尝试。在四小时内,那就是每秒4.7次。按平均延迟两秒计算,大约需要10个并发在途请求,然后你要把它分散到多个目标上,而不是指向单一目标。按每个响应平均80 KB计算,每次运行约5.4 GB,每月大约160 GB。在并发数和带宽两方面都要留有余量,因为延迟会漂移,成功率会下降,并在试点之后重新推算。
结论
反向规划:从记录到请求,从请求到考虑失败余量后的尝试次数,从窗口内的尝试次数到速率,从速率乘以延迟得到并发数,从尝试次数乘以响应大小得到带宽。按每个目标设定并发和速率上限,而不是设全局值,因为真正的限制是每个网站能容忍什么,而不是你的基础设施能产出什么。在确定套餐规模之前先优化你要抓取的内容,因为渲染页面和抓取数据之间的选择可能会让带宽答案相差两个数量级。把工作分散到可用窗口内,而不是集中爆发。然后进行试点运行,因为延迟和每个响应的字节数是两个在你确定套餐之前最值得用实测数据取代的假设。
容量本身来自住宅代理,在那里并发数不是套餐规模所依据的限制条件,并配有按GB计费,这样你推算出的带宽数字,就是你真正要购买的数字。