Как правильно использовать потоки для подключения пинг URL-адреса? - PullRequest
1 голос
/ 11 февраля 2020

Я пытаюсь пропинговать большое количество URL-адресов и получить информацию о сертификате URL-адреса. Как я читал в этой статье ThinkBot здесь Thoughtbot Threads и другие, я читал, что лучший способ сделать это с помощью потоков. Однако, когда я реализую потоки, я продолжаю сталкиваться с ошибками тайм-аута и другими проблемами для URL, которые я могу успешно извлечь самостоятельно. В другом связанном вопросе, который я задавал ранее, мне сказали, что я не должен использовать Timeout with Threads. Тем не менее, примеры, которые я вижу, обертывают вызовы API /NET :: HTTP / TCPSocket в блоке Timeout и, основываясь на том, что я прочитал, весь вызов API /NET :: HTTP / TCP Socket будет вложен в поток. Вот мой код:

class SslClient
  attr_reader :url, :port, :timeout

  def initialize(url, port = '443', timeout = 30)
    @url = url
    @port = port
    @timeout = timeout
  end

  def ping_for_certificate_info
    context = OpenSSL::SSL::SSLContext.new
    certificates = nil
    verify_result = nil
    Timeout.timeout(timeout) do
      tcp_client = TCPSocket.new(url, port)
      ssl_client = OpenSSL::SSL::SSLSocket.new tcp_client, context
      ssl_client.hostname = url
      ssl_client.sync_close = true
      ssl_client.connect
      certificates = ssl_client.peer_cert_chain
      verify_result = ssl_client.verify_result
      tcp_client.close
    end
    {certificate: certificates.first, verify_result: verify_result }
  rescue => error
    puts url
    puts error.inspect
  end
end

  [VERY LARGE LIST OF URLS].map do |url|
      Thread.new do
        ssl_client = SslClient.new(url)
        cert_info = ssl_client.ping_for_certificate_info
        puts cert_info
      end
    end.map(&:value)

Если вы запустите этот код в своем терминале, вы увидите много ошибок тайм-аута и ошибок ERNNO: TIMEDOUT для таких сайтов, как fandan go .com, fandom.com, mcaffee. com, google.de et c, который должен возвращать информацию. Когда я запускаю их индивидуально, я получаю необходимую информацию. Когда я запускаю их в потоке, они имеют тенденцию терпеть неудачу, особенно для доменов, имеющих чужое доменное имя. Я спрашиваю, правильно ли я использую Threads. Этот фрагмент кода, который я вставил, является частью большего фрагмента кода, который взаимодействует с объектами ActiveRecord в рельсах в зависимости от полученных результатов. Я правильно использую Timeout и Threads? Что мне нужно сделать, чтобы сделать эту работу? Почему пинг работает индивидуально, а не завернут в нить? Помощь будет принята с благодарностью.

1 Ответ

0 голосов
/ 11 февраля 2020

Существует несколько проблем:

  • Вы бы не породили тысячи потоков, используйте пул соединений (например, https://github.com/mperham/connection_pool), чтобы у вас было максимум 20-30 одновременных количество запросов (это максимальное число должно быть определено путем тестирования, при котором производительность сети падает, и вы получаете эти тайм-ауты).
  • Трудно гарантировать, что ваш код не будет взломан при использовании потоков, поэтому я предлагаю вам используйте что-то, где другие поняли это для вас, например https://github.com/httprb/http (с примерами безопасности потоков и параллельными запросами, такими как https://github.com/httprb/http/wiki/Thread-Safety). Существуют и другие либы (Тайфей, покровитель), но этот чистый Ruby, поэтому проще всего добиться безопасности нитей c.
  • Вам не следует использовать Timeout (см. https://jvns.ca/blog/2015/11/27/why-rubys-timeout-is-dangerous-and-thread-dot-raise-is-terrifying и https://medium.com/@adamhooper / in ruby -dont-use-timeout-77d9d4e5a001 ). Используйте IO.select или что-то еще.

Кроме того, я предлагаю вам узнать о проблемах с многопоточностью, таких как взаимоблокировки, голодание и все ошибки. В вашем случае вы делаете нехватку сетевых ресурсов, потому что все потоки борются за пропускную способность / сеть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...