使用PHP的Comet技术?

84
我在考虑使用PHP后端实现实时聊天,但在讨论Comet的网站上看到了这个评论:
引用: 我的理解是,PHP对于Comet来说是一个可怕的语言,因为Comet要求你对每个浏览器客户端保持持久连接。使用mod_php意味着为每个客户端绑定一个Apache子进程,这在规模上根本无法扩展。我认识的做Comet的人大多使用Twisted Python,它专门设计用于处理数百或数千个同时连接。
这是真的吗?还是有办法可以解决这个问题?

4
你可以将PHP作为FastCGI运行... - Itay Moav -Malimovka
5
使用NodeJS作为服务器来维持客户端连接,使用JavaScript中的WebSockets从浏览器连接到服务器。PHP在这种情况下可以作为一个特权客户端连接到NodeJS,推送一些服务数据,在客户端上进行处理。 - Artjom Kurapov
1
@ArtjomKurapov 你可以将 PHP 改造成一个 Web 服务器,从而绕过 Apache 处理请求的方法 - 就像一个真正的 PHP 服务器只处理长连接请求一样。 - Christian
@Christian,如果您指的是自 PHP 5.4 起内置的 Web 服务器,则仅用于开发目的,将其用于生产环境是一个不好的主意。 - Artjom Kurapov
2
@ArtjomKurapov 不,我指的是使用PHP套接字编写一个真正的PHP服务器,通过监听端口80并无限期地阻塞输入来实现 - 这实际上就是服务器的工作原理。这已经在像phpwebsocket这样的项目中得到了应用。 - Christian
11个回答

62
同意/扩展已经说过的,我不认为FastCGI会解决问题。

Apache

每个进入Apache的请求将使用一个工作线程,直到请求完成,对于COMET请求可能需要很长时间。

这篇关于Ajaxian的文章提到在Apache上使用COMET,并且这很困难。这个问题不是特定于PHP的,适用于您想要在Apache上使用的任何后端CGI模块。

建议的解决方案是使用'event' MPM模块,它改变了请求分派给工作线程的方式。

这种MPM试图修复HTTP中的“保持活动问题”。 在客户端完成第一个请求之后,客户端可以保持连接打开,并使用相同的套接字发送进一步的请求。这可以节省创建TCP连接的显着开销。但是,Apache传统上会保持整个子进程/线程等待来自客户端的数据,这带来了自己的缺点。为了解决这个问题,这个MPM使用一个专用线程来处理监听套接字和所有处于保持活动状态的套接字。

不幸的是,这也行不通,因为它只会在请求完成后“休眠”,等待客户端的新请求。

PHP

现在,考虑问题的另一面,即使您解决了每个彗星请求占用一个线程的问题,您仍然需要每个请求一个PHP线程 - 这就是为什么FastCGI无法帮助的原因。
您需要类似Continuations的东西,它允许在观察到触发它们的事件时恢复彗星请求。据我所知,这在PHP中不可能。我只在Java中看到过 - 请参阅Apache Tomcat server编辑: 有一篇文章介绍如何使用负载均衡器(HAProxy)允许您在同一服务器的80端口上运行apache服务器和启用彗星的服务器(例如Java的jetty,tomcat)。

20
我明白这并不能完全提供解决方案 :/ - Kothar
+1 是因为Apache/PHP不是扩展出一个彗星解决方案的好选择。对于PHP用户来说,可选方案有:1)如你所提到的,采用额外服务器和代理的疯狂配置或2)使用SaaS解决方案并通过类似WebSync On-Demand的东西卸载彗星内容。 - Jerod Venema
1
这里有几个方面是错误的。如果想要离开每个用户一个线程的方法,可以通过移除 Apache 作为中介并让 PHP 处理这些请求来轻松实现。当然,Apache 在提供内容方面效果更好,因此我会在不提供任何内容的子域上运行这个无 Apache 的 PHP 服务器。 - Christian
@MikeHouston 你觉得在IIS中尝试使用PHP的Comet怎么样? - ravi404
@ravz,这里有一些关于IIS和Comet的内容:https://dev59.com/KkrSa4cB1Zd3GeqPZc-B,但我怀疑Fast-CGI PHP模块与Apache存在相同的限制。它在这里提到了单线程环境:http://www.microsoft.com/web/platform/phponwindows.aspx - 我自己不使用Windows服务器,所以我不确定线程模型。 - Kothar
HAProxy的建议非常好。 HAProxy每GB内存广告30000个会话,可以将彗星/长轮询重定向到自定义进程/cometd服务器。仅使用apache/mod_php进行彗星操作,考虑到apache的内存占用,1GB服务器将扩展到约50个并发连接。 NGINX+php-fpm没有更好的表现,我进行了测试。 - sivann

14

你可以使用Nginx和JavaScript实现一个基于Comet的聊天系统,它非常可扩展,占用很少的内存和CPU资源。

我这里有一个非常简单的例子,可以让你开始。它涵盖了使用NHPM模块编译Nginx以及在jQuery、PHP和Bash中实现简单发布者/订阅者角色的代码。

http://blog.jamieisaacs.com/2010/08/27/comet-with-nginx-and-jquery/


10

PHP

我发现了这个有趣的屏幕录像,解释了简单的Comet。顺便说一句,在任何真正的负载下,我真的认为这会使您的服务器崩溃。当只有几个用户时,我建议您选择这个解决方案。这个解决方案非常容易实现(屏幕录像只需要花费您5分钟的时间:))。但是,正如我之前所说,我认为它不适合许多并发用户(猜测您应该对其进行基准测试;)),因为:

  1. 它使用文件I/O,比仅从内存中获取数据要慢得多。例如,函数filemtime(),
  2. 其次,但我认为最不重要的是,PHP没有像样的线程模型。无论如何,PHP都不是为此而设计的,因为它采用了共享无模型。就像幻灯片上说的那样,“共享数据被推送到数据存储层”,例如MySQL。

替代方案

如果您想执行任何Comet /长轮询操作,我真的认为您应该尝试替代方案。您可以使用许多语言,例如:

  • Java/JVM: Jetty的continuations
  • Python: Dustin的slosh
  • Erlang: 用于comet等的流行语言。
  • Lua、Ruby、C、Perl只是其中几个例子。

进行简单的谷歌搜索,会显示出许多替代方案,还有PHP(我认为在任何大负载下都会使您的服务器崩溃)。


7

6
您也可以尝试使用https://github.com/reactphp/react

React是一个用于PHP事件驱动编程的低级库。它的核心是事件循环,除此之外,它还提供了一些低级工具,例如:流抽象、异步DNS解析器、网络客户端/服务器、HTTP客户端/服务器以及与进程的交互。第三方库可以使用这些组件来创建异步网络客户端/服务器等。

事件循环基于反应器模式(因此得名),并受到诸如EventMachine(Ruby)、Twisted(Python)和Node.js(V8)等库的强烈启发。

入门示例展示了一个简单的HTTP服务器侦听端口1337:

<?php

$i = 0;

$app = function ($request, $response) use (&$i) {
    $i++;

    $text = "This is request number $i.\n";
    $headers = array('Content-Type' => 'text/plain');

    $response->writeHead(200, $headers);
    $response->end($text);
};

$loop = React\EventLoop\Factory::create();
$socket = new React\Socket\Server($loop);
$http = new React\Http\Server($socket);

$http->on('request', $app);

$socket->listen(1337);
$loop->run();

4
我遇到了类似的问题。我发现有一个有趣的选择是使用现有的Comet服务器,比如cometd-java或cometd-python,作为核心消息中心。然后你的PHP代码只是Comet服务器的客户端--它可以像其他客户端一样在通道中发布或读取消息。
这里链接了一个有趣的代码片段:http://morglog.org/?p=22=1,实现了这种方法的部分功能(尽管还有一些调试代码散布在周围)。

3
我正在使用socket函数实现可扩展的PHP Comet服务器,它被称为“phet”([ph]p com[et])。
项目页面:http://github.com/Tim-Smart/phet 欢迎加入开发。我已经完成了大部分服务器逻辑,只需要完成客户端相关内容。
编辑:最近使用pcntl_fork方法添加了“多线程”功能 :)

目前还没有可用于如何使用这个库的示例。 - ftrotter

3

由于PHP本身是单线程的,因此在实现comet时可能会遇到困难。

请查看Websync On-Demand - 该服务允许您通过服务器端发布将PHP集成,卸载繁重的并发连接工作,并使您能够快速创建实时聊天应用程序。


1

1

你需要在PHP中创建自己的服务器。使用Apache/mod_php或者fastcgi都无法扩展。这是几年前的技术,但可以帮助你入门:

PHP-Comet-Server: http://sourceforge.net/projects/comet/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接