如何在不占用资源的情况下提供实时通知?

时间:2013-05-17 13:03:10

标签: php mysql jquery push-notification

我正在使用AJAX在我想要在将新行插入数据库时​​更新的页面上实现long polling。这样做的方法是使用jQuery的.ajax()调用,例如,poll.php?ky=41,它会对ID为> 41的行多次查询数据库(两者之间的等待时间较短) )直到指定的超时。如果有结果,或者在给定的超时后,它将立即满足请求。

实际上,这会使一个隐藏的连接始终对服务器开放,等待它响应,以便收到通知。

这是有效的,但是我正在使用DreamHost,并且在生成8个php53.cgi工作进程之后,没有完成对我的站点的请求(即永远加载),直到一次超时。这会影响我网站上的每个其他页面。 HTTP服务器是Apache 2.2.22-14。

为了缓解这个问题,我减少了延迟和超时,因此它更接近定期轮询,并且在一段时间没有更新时增加了更长的延迟。这意味着通知可能会延迟几秒钟,但到目前为止我的服务器运行正常。

我担心的是这会有多好(或者更确切地说,有多差)。

我的问题是:鉴于我在共享主机(DreamHost)上,并且此页面必须与尽可能多的浏览器兼容(移动设备除外),是否有更有效的方式来获取即时“推送”通知从服务器?

或者,我还有其他选择吗?我应该切换回常规轮询吗?

TL; DR

轮询很快,但长轮询(在完成AJAX请求之前等待)会占用资源。不同之处在于,长轮询一旦到达就会得到结果,而轮询只会在新信息进入后下次发送AJAX请求时才会获取。理想情况下,我希望长轮询的优势没有捆绑线程&导致其他用户在提供页面之前等待。

2 个答案:

答案 0 :(得分:1)

在这种情况下,解决方案是简单地使用常规轮询(例如每500毫秒一次AJAX调用)来获得快速通知,而不是使用长轮询和捆绑线程。

来自Dave,

  

许多请求比长请求更好地处理。由于线程永远不会真正死亡,它们只是被重用。如果最后没有可用的线程,它还将允许系统跳过一个循环。现在在某些时候你会遇到共享主机上的apache + php配置问题。在那之后可能会有一个小的vps并交换到nginx或我的个人最喜欢的切诺基并使用phpfpm然后你可以构建一个为你的轮询循环保留的实际工作线程

  

由于线程总是打开,所以没有开销允许轮询脚本完成然后重新启动(如果db连接正确完成,那么在池化的conns和prep-statements之间几乎没有额外的db加载甚至更好的memcached或类似的)意味着你只在运行期间锁定线程然后立即释放它以供其他进程拾取并使用它这就是你可以在8个线程上支持超过8个用户的方式,因为它们被回收。除非你使用实时套接字和守护进程,否则不要担心它会比longpoll更有效率

截至目前,问题已得到解决。

答案 1 :(得分:0)

我认为在php中,每个开放连接都意味着一个正在运行的线程。您必须使连接时间很短并使用轮询。

唯一的帮助是尽可能快地组织轮询,所以我会尝试为每个会话存储一个非常简单的信息队列,比如在apc_fetch/apc_store中(如果你的app只运行一个apache) )。一个非常简单的页面has_update.php?session_id只读取该状态行,并以尽可能小的格式返回0或1,大多数时间返回0。因此,每秒5次不应该太快成为性能问题。

当且仅当has_update.php返回1时,才会触发正常的ajax调用。