Как ускорить передачу данных между клиентом и сервером с помощью веб-сокетов?

В настоящее время я использую веб-сокеты, чтобы отправить изображение на мой сервер, обработать его, а затем отправить обратно. В частности, я использую Ruby с Sinatra и sinatra-websocket.

На моем сервере разработки требуется ~2 секунды, чтобы отправить изображение на сервер и получить точное изображение без обработки.

В экземпляре AWS-EC2 это занимает ~15 секунд. Файл изображения, который я отправляю, составляет ~500 КБ. Моя скорость загрузки и скачивания намного выше.

Как я могу ускорить этот процесс? Это наивный способ отправки изображений туда и обратно?

Изменить: чтобы повторить мою проблему, вы можете клонировать и запустить мое репо в бесплатном экземпляре уровня AWS-EC2.

1 ответ

Это скорее помощник по тестированию, чем ответ, поскольку в вопросе недостаточно подробностей, чтобы сузить проблему.


Я написал простое тестовое приложение, используя Plezi. Так как я автор плези, мне было легче, чем выучить свой стек.

Он отлично работает на моем компьютере, 79 мс для файла ~ 3 Мб.

Обход ~3Mb к Heroku занял у моей системы 3 секунды и уменьшился до ~2,5 секунд после завершения прогрева TCP/IP...

... но мои скорости интернета, вероятно, влияют на тест (мой прием в настоящее время низкий, поэтому я могу быть медленным).

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

Если поездка туда и обратно занимает больше 10 секунд, это может быть стек EC2. Я не думаю, что 10 секунд было бы разумно для ~500Kb.

С другой стороны, если это более короткое и обратно, это может быть способ тестирования приложения или стека Ruby... в этом случае, возможно, решение состоит в том, чтобы переключиться на plezi (или собственный дизайн веб-сокета с йодом).

Вы можете вставить следующий код в config.ru (помните, вам также понадобится гем-файл с plezi драгоценный камень и, возможно, Gemfile.lock):

# The roundtrip html client
ROUNDTRIP_CLIENT = <<CLIENT_EFO
<html>
  <head>
    <script src = '/client.js'></script>
  </head>
  <body>
  <input type='file' id='test_f' lable='file to upload'></input>
  <button id='test_b'>run test</button>
  <div id='output'></div>
  <script>
  var client;
  window.onload = function (e) {
    client = new PleziClient();
    client.autoreconnect = true;
    client.roundtrip = (e) => {
      var d = new Date();
      e.completed_at = d.getTime();
      console.log(e);
      document.getElementById('output').innerHTML += "<p>Test for " +
        "<a href='" + e.data + "' target='_blank'>" + Math.round(e.data.length / 1024)+ "Kb encoded file</a>" +
        " completed in " + (e.completed_at - e.time) + "ms</p>";
    }
    client.onopen = (e) => console.log("Websocket client open", e);
  }

  function run_test(e) {
    console.log("File submitted.");
    reader = new FileReader();
    reader.onloadend = function(e)
    {
      console.log("File loaded, " + e.target.result.length + "bytes... starting test.")
      var d = new Date();
      client.emit({event: "roundtrip", data: e.target.result, time: d.getTime() });
    }
    reader.readAsDataURL(document.getElementById('test_f').files[0]);
    return false;
  }
  document.getElementById('test_b').onclick = run_test;
  </script>
  </body>
</html>
CLIENT_EFO

# require plezi
require 'plezi'
# For security, Iodine limists websocket messages.
# We update the default limit from ~250Kb to ~4Mb.
# This replaces the commandline option: iodine -v -maxms 4194304
Iodine::Rack.max_msg_size = 4194304

# the roundtrip controller... quite simple.
class RoundTrip
  # return the roundtrip client.
  def index
    ROUNDTRIP_CLIENT
  end
  # echo back the websocket message - we're just testing the round trip.
  def on_message data
    write data
  end
end
# Set the plezi root route to the RoundTrip controller
Plezi.route '/', RoundTrip
# Set the client javascript route - I'm using it as a heler.
Plezi.route '/client.js', :client
# Set Rack to run the Plezi application
run Plezi.app

Чтобы запустить код из терминала, используйте iodine команда (это запустит iodine сервер, который требует Plezi.


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

По ссылке на git-repo (в комментариях) я понял, что JSON анализируется сервером, а затем переиздается.

Чтобы подражать этому, я обновил пример кода.

Это должно быть похоже на то, что, по-видимому, выполняет код в репозитории, и это добавляет некоторое время к циклу, так как анализ и переформатирование JSON создают копии данных, что требует выделения памяти, а также времени ЦП.

Единственное изменение в коде в RoundTrip класс контроллера, но я вставляю все это для вашего удобства копирования + вставки.

Поместите следующий код в свой app.rb файл (не забудьте отредактировать install.sh установить plezi драгоценный камень):

# The roundtrip html client
ROUNDTRIP_CLIENT = <<CLIENT_EFO
<html>
  <head>
    <script src = '/client.js'></script>
  </head>
  <body>
  <input type='file' id='test_f' lable='file to upload'></input>
  <button id='test_b'>run test</button>
  <div id='output'></div>
  <script>
  var client;
  window.onload = function (e) {
    client = new PleziClient();
    client.autoreconnect = true;
    client.roundtrip = (e) => {
      var d = new Date();
      e.completed_at = d.getTime();
      console.log(e);
      document.getElementById('output').innerHTML += "<p>Test for " +
        "<a href='" + e.data + "' target='_blank'>" + Math.round(e.data.length / 1024)+ "Kb encoded file</a>" +
        " completed in " + (e.completed_at - e.time) + "ms</p>";
    }
    client.onopen = (e) => console.log("Websocket client open", e);
  }

  function run_test(e) {
    console.log("File submitted.");
    reader = new FileReader();
    reader.onloadend = function(e)
    {
      console.log("File loaded, " + e.target.result.length + "bytes... starting test.")
      var d = new Date();
      client.emit({event: "roundtrip", data: e.target.result, time: d.getTime() });
    }
    reader.readAsDataURL(document.getElementById('test_f').files[0]);
    return false;
  }
  document.getElementById('test_b').onclick = run_test;
  </script>
  </body>
</html>
CLIENT_EFO

# require plezi
require 'plezi'
# For security, Iodine limists websocket messages.
# We update the default limit from ~250Kb to ~4Mb.
# This replaces the commandline option: iodine -v -maxms 4194304
Iodine::Rack.max_msg_size = 4194304

# the roundtirp controller... quite simple.
class RoundTrip
  @auto_dispatch = true
  # return the roundtrip client.
  def index
    ROUNDTRIP_CLIENT
  end
  # Using Auto-Dispatch, the JSON is parsed and this event is invoked.
  def roundtrip msg
    # Hash results are automatically converted into JSON and emitted
    msg
  end
end
# Set the plezi root route to the RoundTrip controller
Plezi.route '/', RoundTrip
# Set the client javascript route - I'm using it as a heler.
Plezi.route '/client.js', :client
# Plezi will start automatically when the script exits

Чтобы запустить код из терминала, используйте ruby app.rb Команда, так же, как ваш репо для существующего приложения.

В то время как старый код просто предлагал ответ "эхо", новый код (который выглядит почти так же) имеет еще несколько шагов:

  • Используя Auto-Dispatch, платформа Plezi теперь автоматически анализирует JSON и маршрутизирует событие ("туда-обратно") метода контроллера (roundtrip).

  • Метод получает хэш с проанализированными данными и возвращает этот хэш обратно в Plezi.

  • Фреймворк собирает Hash, форматирует объект JSON и выдает результат (не String или Hash игнорируются)...

... это похоже на поведение репо.

Другие вопросы по тегам