Контроллер RESTful Rails и net / http как клиент - медленный на многих запросах - PullRequest
1 голос
/ 29 сентября 2011

У меня есть массив, заполненный потенциально большим количеством записей.Все записи должны быть сохранены сервером в RESTful RecordsController.Мое решение в данный момент выглядит следующим образом:

def self.send! options = nil
  records = fetch_records
  records.each do |r|
    send_data!(r) ? records = records.delete_if{|rec| rec == r } : break
  end
  storage.save! records

  true
end

private

def self.send_data! record, options = nil
  begin
    response = Net::HTTP.Proxy(configuration.proxy_host, configuration.proxy_port).start(configuration.host, configuration.port) do |http|
      request = Net::HTTP::Post.new(request_path options)
      request.body = record.to_json
      http.request request
    end
    raise StandardError unless response.code == "200"
  rescue Exception => e
    return false
  end

  true
end

Преимущество этого решения заключается в том, что если происходит ConnectionError, ConnectionTimeout или ServerError, неотправленные записи сохраняются локально и могут быть отправлены позже.Соответствующий контроллер - это стандартный контроллер Rails.

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

Вопрос теперь в том, может ли это помочь создать экземпляр клиента HTTP только один раз и отправить все записи по одному соединению.Я не нашел решения для реализации этого, потому что мне нужно поведение save_or_store кода здесь.

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

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

Есть идеи?

С уважением, Феликс

Ответы [ 2 ]

2 голосов
/ 04 октября 2011

Переключение на em-http-request - HTTP-клиент на основе EventMachine - и использование его мультиинтерфейса для одновременной отправки нескольких запросов может немного увеличить пропускную способность.

Но преимущество лучшего клиента HTTPнезначительно.Поскольку вы ничего не делаете с ответом HTTP, полученным от вашего контроллера - что означает, что вы не используете HTTP в качестве протокола приложения - лучшее решение для вашей проблемы - фактически отправить весь массив для обработки на стороне сервера.,В конце концов, вам не нужно платить цену за создание одного запроса для каждой отдельной записи.

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

И я бы добавил MessagePack в микс, чтобы сериализовать массив и уменьшить размер полезной нагрузки.и ускорить обмен сообщениями.

0 голосов
/ 29 сентября 2011

Если я читаю отправку! правильно, вы просматриваете каждую запись, а внутри этого цикла просто удаляете текущую запись из массива и отправляете все остальное? Чтобы сэкономить немного усилий на вычислительной стороне, используйте метод delete () класса Array вместо delete_if.

def self.send! options = nil
  records = fetch_records
  records.each do |r|
    if send_data!(r)
      records.delete(r)
    else
      break
    end
  end
  storage.save! records

  true
end

Хотя я не уверен, куда вы передаете параметр записи для send_data! метод. Так как терминация будет использовать результат этого метода.

Net http может занять некоторое время для выполнения всех своих запросов. Я знаю, когда я запустил несколько сотен URL-адресов, чтобы проверить их коды ответов, это заняло где-то 5-10 минут. Я сам этим мало пользовался, но взгляните на: https://github.com/jnunemaker/httparty. Может быть, это будет работать лучше для вас.

...