同时检查数据库中多个URL的URL(状态即200,301,404)的最佳方法

这就是我想要完成的事情。 假设我有100,000个url存储在数据库中,我想检查每个URL的http状态并存储该状态。 我希望能够在相当短的时间内同时完成这项工作。

我想知道这样做的最佳方式是什么。 我考虑过与工人/消费者或某种模型一起使用某种队列,但我真的没有足够的经验来了解在这种情况下哪种方法最有效。

想法?

看看非常有能力的Typhoeus和Hydra组合。 这两个使得同时处理多个URL变得非常容易。

“ 时代 ”示例应该让您快速启动并运行。 在on_complete块中,输入代码将状态写入数据库。 您可以使用一个线程来构建和维护一个健康级别的排队请求,或者排队一组号码,让它们全部运行完成,然后循环另一个组。 由你决定。

原作者保罗迪克斯在他的博客上谈到了他的设计目标 。

这是我写的一些示例代码,用于下载存档邮件列表,以便我可以进行本地搜索。 如果人们开始运行代码,我故意删除URL以防止网站遭受DOS攻击:

 #!/usr/bin/env ruby require 'nokogiri' require 'addressable/uri' require 'typhoeus' BASE_URL = '' url = Addressable::URI.parse(BASE_URL) resp = Typhoeus::Request.get(url.to_s) doc = Nokogiri::HTML(resp.body) hydra = Typhoeus::Hydra.new(:max_concurrency => 10) doc.css('a').map{ |n| n['href'] }.select{ |href| href[/\.gz$/] }.each do |gzip| gzip_url = url.join(gzip) request = Typhoeus::Request.new(gzip_url.to_s) request.on_complete do |resp| gzip_filename = resp.request.url.split('/').last puts "writing #{gzip_filename}" File.open("gz/#{gzip_filename}", 'w') do |fo| fo.write resp.body end end puts "queuing #{ gzip }" hydra.queue(request) end hydra.run 

在我已有几年历史的MacBook Pro上运行代码,在不到20秒的时间内通过无线连接到76个文件,共计11MB。 如果您只是在做HEAD请求,那么您的吞吐量会更好。 你会想要搞乱并发设置,因为有一个点,让更多的并发会话只会减慢你的速度并且不必要地使用资源。

我给它八分之一; 这是一个伟大的节拍,我可以跳舞。


编辑:

检查删除URL时,您可以使用HEAD请求,或使用If-Modified-Since的GET。 他们可以为您提供可用于确定url新鲜度的回复。

我没有在Ruby中做任何multithreading,只有Java,但它看起来非常简单: http : //www.tutorialspoint.com/ruby/ruby_multithreading.htm

根据你的描述,你不需要任何队列和工人(嗯,我相信你也可以这样做,但我怀疑你会得到很多好处)。 只需在几个线程之间划分您的URL,让每个线程执行每个块并使用结果更新数据库。 例如,创建100个线程,并为每个线程提供一系列1000个数据库行进行处理。

如果您更愿意处理进程而不是线程,您甚至可以创建100个单独的进程并将它们作为参数提供。

为了获取URL状态,我认为你做了一个HTTP HEAD请求,我想这是在ruby中的http://apidock.com/ruby/Net/HTTP/request_head 。

work_queue gem是在应用程序中异步和并发执行任务的最简单方法。

 wq = WorkQueue.new 10 urls.each do |url| wq.enqueue_b do response = Net::HTTP.get_response(uri) puts response.code end end wq.join