【问题标题】:Is Comet (server push) the answer I'm looking for?Comet(服务器推送)是我正在寻找的答案吗?
【发布时间】:2012-06-23 16:16:03
【问题描述】:

我有一个 Web 应用程序,我试图通过减少它运行的数据库查询的数量来提高效率。我倾向于实现某种 Comet 风格的解决方案,但我在该部门缺乏经验,这让我怀疑是否存在更简单的解决方案。

为简洁起见,假设我有一个数据库,其中包含网络上的系统列表及其当前状态(无论它们是启动还是关闭)。用户可以登录 Web 应用程序并选择她有兴趣监控的系统。之后,她可以访问显示当前关闭的系统数量的监控页面。

到目前为止,计数是使用 Ajax 刷新的……客户端每分钟向服务器发送一个请求,服务器依次对数据库运行查询以获取当前计数并将结果返回给客户端。我知道这效率低下;对于每个登录的客户端,每分钟都会对数据库运行另一个查询。 O(n) = 不好!

我知道我可以使用某种类型的缓存,例如 memcached,但这仍然意味着每个用户每分钟都有一个请求。更好,但我仍然觉得这不是最好的解决方案。

我设想的更像是这样的:

  • 服务器每分钟运行一次查询,以获取当前关闭的所有系统的计数。
  • 然后服务器将此数据推送给感兴趣的客户端。

这样,无论有多少用户登录并观看监控页面,服务器每分钟只运行一次查询。 O(1) = 好!问题是,即使在我完成了所有研究之后,我也无法完全弄清楚如何实现这一点。老实说,我并不完全理解我在寻找什么,因此很难研究解决方案。所以我希望更多开明的开发者能带领我走向正确的方向。

【问题讨论】:

    标签: javascript ajax performance optimization comet


    【解决方案1】:

    你可以用 Comet 做到这一点。但是您也可以只使用一个 JavaScript 计时器,每分钟左右轮询一次服务器。这取决于您希望获得反馈的速度。不需要一直保持 TCP 连接打开。

    此外,您了解服务器状态的方式与客户端获取此信息的方式无关。您不希望每次客户端请求时都更新服务器的状态。相反,您将在应用服务器上有一个计时器,它会轮询服务器状态,然后将其存储。客户端请求将从这个存储的状态而不是实际的实时状态中获取。

    【讨论】:

    • 我相信你第一次提到的被称为长轮询,不是吗?在任何一种情况下,客户端仍在发送导致服务器采取行动的请求,这是我试图避免的。此外,系统的状态不会在每次客户端请求时更新。该数据已保存在数据库中,并独立于该过程进行更新。当客户端发送请求时,服务器正在数据库上运行查询以提取每个系统最近存储的状态。
    • 好的,所以我的答案的第二部分已经被清除了。回覆。第一部分:彗星解是一种长轮询。我的建议是不要进行长轮询,而是在特定间隔内进行短请求。这意味着客户端不会立即收到有关服务器状态更改的通知,而只会通知每个时间间隔。
    【解决方案2】:

    使用名为Pusher 的应用程序可以轻松解决此问题,这是一个托管的发布/订阅 API。简而言之,Pusher 提供了两个库,一个用于客户端(订阅者),一个用于服务器(发布者)。

    发布者可以是您服务器上的单个脚本 (there are quite a few languages available),设置为以您希望的任何时间间隔运行。每次运行时,它都会连接到一个通道并发布它生成的任何数据。客户端是通过您的 Web 应用程序中的一些 JavaScript 创建的,每当用户导航到您的页面时,客户端都会订阅您的服务器脚本发布到的同一频道,并在数据可用时立即接收数据,然后可以操作无论你认为合适。

    服务器:

    #!/usr/bin/php
    <?php
    require('Pusher.php');
    
    $dbh = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
    foreach($dbh->query('SELECT hostname FROM systems WHERE status = 0') as $row) {
        $systems[] = $row['hostname'];
    }
    $pusher = new Pusher($pusher_key, $pusher_secret, $pusher_app_id);
    $pusher->trigger(
        'my-channel',
        'my-event',
        array('message' => implode('<br />', $systems))
    );
    

    客户:

    <!DOCTYPE html>
    <html>
      <head>
        <title>Pusher Test</title>
        <script src="http://code.jquery.com/jquery.min.js" type="text/javascript"></script>
        <script src="http://js.pusher.com/1.12/pusher.min.js" type="text/javascript"></script>
        <script type="text/javascript">
          var pusher = new Pusher(key);
          var channel = pusher.subscribe('my-channel');
          channel.bind('my-event', function(data) {
            $('#systems').html(data.message);
          });
        </script>
      </head>
      <body>
        <div id="systems"></div>
      </body
    </html>
    

    因此,在这种情况下,无论有多少客户端访问该页面,都只会运行一个数据库查询,并且在每个时间间隔,所有订阅的客户端都将使用新数据进行更新。

    还有一个用 Ruby 编写的 Pusher 协议的开源服务器实现,称为 Slanger

    【讨论】:

      猜你喜欢
      • 2011-08-17
      • 1970-01-01
      • 2011-05-16
      • 2010-11-16
      • 2019-05-13
      • 1970-01-01
      • 2010-09-25
      • 2013-05-23
      • 2011-08-26
      相关资源
      最近更新 更多