问题
最近,我一直在考虑如何抓取某个大型跨国网站的内容,以获取有关该公司销售产品的具体细节。该网站没有API,但您可以通过向产品ID发送带有特定URL的GET请求,为每个产品下载一些XML。至少那是什么。
问题在于可能存在数亿个潜在的产品ID(例如,在000000001和500000000之间),但实际上只存在几十万个产品。并且无法知道哪些产品ID有效。
方便地,根据产品ID是否有效(即产品实际存在),向产品URL发送HEAD请求会产生不同的响应。一旦我们知道该产品确实存在,我们就可以下载完整的XML并抓取所需的数据。
如果要在单个服务器上运行,显然发送数亿个HEAD请求将需要花费大量时间才能完成,所以我想借此机会学习如何开发某种分布式应用程序(对我来说是全新的领域)。此时,我应该提一下,这个特定的网站可以轻松处理每秒大量的传入请求,而不会有DOS的风险。我不想为网站命名,但每天很容易获得数百万次点击。这种刮刀对网站的性能影响微乎其微。但是,如果公司抱怨,我会立即停止它。
设计
我不知道这是否是正确的方法,但我目前的想法是启动单个"协调服务器",以及一些节点与该服务器通信并执行抓取,所有运行作为EC2实例。
每个节点将启动一些进程,并且协调服务器将每个进程指定一个作业,该协调服务器包含要刮取的不同范围的潜在产品ID(例如,产品ID 00001到10000)。这些作业将存储在协调服务器上的数据库表中。每项工作都将包含以下信息:
启动节点时,将向协调服务器发送查询,询问某些配置数据以及要处理的作业。当节点完成作业时,将发送一个查询,更新刚刚完成的作业的状态,以及另一个请求新作业处理的查询。每个作业都有一个到期时间,因此如果进程崩溃,或者节点因任何原因失败,另一个节点可以接管过期作业再次尝试。
为了最大限度地提高系统性能,我需要确定应该一次启动多少个节点,每个节点有多少个进程,发送的HTTP请求速率以及哪个EC2实例类型将提供最物超所值(我猜测高网络性能,高CPU性能和高磁盘I / O将是关键因素?)。
目前,计划是在Python中编写刮刀,在Ubuntu EC2实例上运行,可能在Docker容器中启动,以及某种键值存储数据库来保存协调服务器上的作业(MongoDB?) 。关系数据库也应该可以工作,因为作业表应该是相当低的I / O.
我很想知道更有经验的工程师是否这是正确的方法,或者我是否完全忽略了更好的方法来完成这项任务?
非常感谢,谢谢!
答案 0 :(得分:3)
您正在尝试设计一个分布式工作流程系统,这实际上是一个已解决的问题。我建议您不要重新发明轮子,而是查看AWS的SWF,它可以轻松地为您完成所有状态管理,让您可以自由地担心编写业务逻辑。
这是使用SWF设计的系统的样子(在这里,我将使用SWF的标准术语 - 您可能需要通过文档来完全理解这些术语):
productID
开始一个工作流程。productID
是否有效。您可以轻松更改上述设计,让一个工作流程处理一批产品ID。
我建议你记住一些其他观点: