我们如何使用websockets加速客户端和服务器之间的传输?

时间:2017-04-11 23:16:55

标签: ruby web amazon-ec2 sinatra em-websocket

目前,我正在使用websockets将图像发送到我的服务器,处理它,然后将其发回。具体来说,我使用Ruby与Sinatra和sinatra-websocket。

在我的开发服务器上,将图像发送到服务器并在不进行处理的情况下检索确切的图像需要大约2秒钟。

在AWS-EC2实例上,这需要大约15秒。我发送的图像文件是~500kb。我的上传和下载速度远高于此值。

如何加快这个过程?这是一种来回传送图像的天真方式吗?

编辑:要复制我的问题,您可以在AWS-EC2免费套餐实例中克隆并运行我的repo

1 个答案:

答案 0 :(得分:0)

这不仅仅是一个测试助手而是一个测试助手,因为这个问题没有提供足够的细节来缩小问题范围。

我使用Plezi编写了一个简单的测试应用程序。由于我是plezi的作者,所以对我来说比学习堆栈更容易。

它在我的计算机上完美运行,对于~3Mb文件,它可以达到79毫秒。

~3Mb到Heroku的往返使我的系统耗时3秒,并在TCP / IP预热完成后下降到~2.5秒......

...但我的互联网速度可能正在影响测试(此刻我的接收速度很低,所以我可能会很慢)。

我不确定我是否可以复制此问题,但您可以使用此答案中的代码来测试您的服务器。

如果往返时间仍然超过10秒,则可能是EC2堆栈。我不认为10秒是合理的~500Kb。

另一方面,如果它是一个更短的往返,它可能是你测试你的应用程序或Ruby堆栈的方式......在这种情况下,也许解决方案是切换到plezi(或{ {3}})。

您可以将以下代码粘贴到config.ru中(请记住,您还需要一个包含plezi gem的宝石文件,可能还需要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命令(它将启动Plezi所需的iodine服务器。

修改

从链接到git-repo(在评论中),我意识到服务器会解析JSON,然后重新发出它。

为了模仿这个,我更新了示例代码。

这应该与repo中的代码似乎相似,并且它为往返增加了一些时间,因为JSON解析和重新格式化创建了数据的副本,这需要内存分配以及CPU时间。

代码中唯一的变化是在RoundTrip控制器类中,但我为了您的复制+粘贴方便而粘贴整个内容。

将以下代码放入app.rb文件中(记得编辑install.sh以安装plezi gem):

# 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命令,与repo对现有应用程序的命令相同。

虽然旧代码只是简单地提供了&#34; echo&#34;响应,新代码(看起来几乎相同)还有一些步骤:

  • 使用Auto-Dispatch,Plezi框架现在自动解析JSON并将事件(&#34;往返&#34;)路由到控制器的方法(roundtrip)。 / p>

  • 该方法接收带有解析数据的哈希并将哈希返回给Plezi。

  • 框架收集Hash,格式化JSON对象并发回结果(忽略非String或Hash结果)...

......这与回购的行为相似。