これが私が達成しようとしていることです。データベースに100,000個のURLが保存されていて、それぞれのURLでhttpステータスを確認し、そのステータスを保存するとします。かなり短い時間でこれを同時に実行できるようにしたいと思います。
これを行うための最良の方法は何でしょうか。ある種のキューをワーカー/コンシューマーまたはある種のイベントモデルで使用することを考えましたが、このシナリオで何が最適に機能するかを知るのに十分な経験がありません。
アイデア?
これが私が達成しようとしていることです。データベースに100,000個のURLが保存されていて、それぞれのURLでhttpステータスを確認し、そのステータスを保存するとします。かなり短い時間でこれを同時に実行できるようにしたいと思います。
これを行うための最良の方法は何でしょうか。ある種のキューをワーカー/コンシューマーまたはある種のイベントモデルで使用することを考えましたが、このシナリオで何が最適に機能するかを知るのに十分な経験がありません。
アイデア?
非常に有能なTyphoeusとHydraのコンボを見てください。この2つにより、複数のURLを同時に処理することが非常に簡単になります。
「Times」の例では、すぐに起動して実行できるはずです。on_complete
ブロックにコードを入れて、ステータスをDBに書き込みます。スレッドを使用して、キューに入れられたリクエストを正常なレベルで構築および維持するか、設定された番号をキューに入れ、すべてを実行して完了させてから、別のグループにループすることができます。それはあなた次第です。
原作者のPaulDixは、彼のブログで彼のデザイン目標について話しました。
これは、アーカイブされたメールリストをダウンロードしてローカル検索を実行できるようにするために作成したサンプルコードです。人々がコードを実行し始めた場合にサイトがDOS攻撃を受けないように、意図的にURLを削除しました。
#!/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
私の数年前のMacBookProでコードを実行すると、ワイヤレスからDSLまで、20秒弱で合計11MBの76個のファイルが取り込まれました。リクエストのみを行う場合はHEAD
、スループットが向上します。同時実行セッションを増やすと速度が低下し、リソースを不必要に使用する可能性があるため、同時実行設定をいじくりまわす必要があります。
私はそれに10のうち8を与えます。それは素晴らしいビートを持っていて、私はそれに合わせて踊ることができます。
編集:
URLの削除を確認するときは、HEADリクエストを使用するか、。を使用してGETを使用できますIf-Modified-Since
。URLの鮮度を判断するために使用できる応答を提供できます。
私はRubyでマルチスレッド化したことは何もしていませんが、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