Лучший способ одновременной проверки URL-адресов (для статуса, т.е. 200,301,404) для нескольких URL-адресов в базе данных - PullRequest
0 голосов
/ 28 января 2011

Вот что я пытаюсь сделать.Допустим, у меня есть 100 000 URL-адресов, хранящихся в базе данных, и я хочу проверить каждый из них на статус http и сохранить этот статус.Я хочу быть в состоянии сделать это одновременно за довольно небольшое количество времени.

Мне было интересно, как лучше всего это сделать.Я думал об использовании какой-то очереди с работниками / потребителями или какой-то четной модели, но на самом деле у меня недостаточно опыта, чтобы знать, что будет лучше всего работать в этом сценарии.

Идеи?

Ответы [ 3 ]

4 голосов
/ 29 января 2011

Взгляните на очень способную комбинацию Typhoeus и Hydra .Эти два способа позволяют одновременно обрабатывать несколько URL-адресов.

Пример " Times " поможет вам быстро приступить к работе.В блоке 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 вытащил 76 файлов общим объемом 11 МБ всего задо 20 секунд, по беспроводной связи в DSL.Если вы выполняете только HEAD запросов, ваша пропускная способность будет лучше.Возможно, вы захотите поработать с параметром параллелизма, потому что есть момент, когда более параллельные сеансы только замедляют вас и бесполезно используют ресурсы.

Я даю ему 8 из 10;У него отличный ритм, и я могу танцевать под него.


РЕДАКТИРОВАТЬ:

При проверке URL-адресов удаления вы можете использовать запрос HEAD или GET с If-Modified-Since.Они могут дать вам ответы, которые вы можете использовать для определения актуальности ваших URL.

1 голос
/ 29 января 2011

Я не делал ничего многопоточного в Ruby, только в Java, но это кажется довольно простым: http://www.tutorialspoint.com/ruby/ruby_multithreading.htm

Из того, что вы описали, вам не нужны никакие очереди и рабочие (ну, яЯ уверен, что вы можете сделать это и так, но я сомневаюсь, что вы получите много пользы).Просто разделите ваши URL-адреса между несколькими потоками, и пусть каждый поток выполняет каждый чанк и обновляет базу данных с результатами.Например, создайте 100 потоков и дайте каждому потоку диапазон из 1000 строк базы данных для обработки.

Можно даже просто создать 100 отдельных процессов и дать им строки в качестве аргументов, если вы предпочитаете иметь дело с процессами, а не с потоками..

Чтобы получить статус URL, я думаю, что вы делаете запрос HTTP HEAD, который, я думаю, http://apidock.com/ruby/Net/HTTP/request_head в рубине.

0 голосов
/ 19 июня 2015

Gem work_queue - это самый простой способ асинхронного и одновременного выполнения задач в вашем приложении.

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
...