简体   繁体   English

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

[英]How can I provide real-time notifications without tying up resources?

I'm using AJAX to implement long polling on a page which I want to update whenever new rows are inserted into the database. 我正在使用AJAX在页面上实施长轮询 ,每当将新行插入数据库时​​我都希望更新该页面。 The way this is done is with jQuery's .ajax() calling, for example, poll.php?ky=41 , which queries the database a number of times for rows with an ID of > 41 (with a small wait in between) until a specified timeout. 完成此操作的方式是使用jQuery的.ajax()调用,例如poll.php?ky=41 ,该查询多次查询数据库以查找ID > 41 (之间poll.php?ky=41等待),直到指定的超时时间。 It will fulfil the request immediately if there is a result, or after the given timeout. 如果有结果,或在给定的超时后,它将立即满足请求。

In effect, this keeps a hidden connection always open to the server, waiting for it to respond, in order to get notifications. 实际上,这将使隐藏连接始终与服务器保持打开状态,等待服务器响应以获取通知。

This works, but I'm using DreamHost and after 8 php53.cgi worker processes are spawned, no requests to my site are fulfilled (ie forever loading) until one times out. php53.cgi ,但是我使用DreamHost,并且在生成8个php53.cgi worker进程后,直到一次超时,才完成对我的网站的请求(即永久加载)。 This affects every other page on my website. 这会影响我网站上的所有其他页面。 The HTTP Server is Apache 2.2.22-14. HTTP服务器是Apache 2.2.22-14。

To alleviate the problem, I have reduced the delays and the timeouts so it is closer to regular polling, and added longer delays when there have been no updates for a while. 为了缓解该问题,我减少了延迟和超时,使其更接近常规轮询,并且在一段时间没有更新时增加了更长的延迟。 This means notifications may come a few seconds late, but so far my server has been running fine. 这意味着通知可能会延迟几秒钟,但是到目前为止我的服务器运行良好。

What I'm worried about is how well (or rather, how poorly) this will scale. 我担心的是扩展的效果如何(或更确切地说,效果有多差)。

My question is: given that I'm on a shared host (DreamHost), and this page must be compatible with as many browsers as possible (except mobile), is there a more efficient way to get instant "push" notifications from the server? 我的问题是:鉴于我位于共享主机(DreamHost)上,并且此页面必须与尽可能多的浏览器(移动设备除外)兼容,是否有更有效的方法从服务器获取即时“推送”通知?

Or, what other options do I have? 或者,我还有什么其他选择? Should I switch back to regular polling? 我应该切换回常规轮询吗?

TL; TL; DR DR

Polling is fast, but long-polling (waiting before fulfilling the AJAX request) ties up resources. 轮询速度很快,但是长轮询(在满足AJAX请求之前等待)会占用资源。 The difference is that long-polling will get the result as soon as it arrives, whereas polling will only pick it up the next time an AJAX request is sent after the new information comes in. Ideally, I would like the advantage of long-polling without tying up threads & causing other users to wait before pages are served. 区别在于,长轮询将在到达后立即获得结果,而轮询仅在新信息传入后下一次发送AJAX请求时才进行选择。理想情况下,我想长轮询的优点而不会占​​用线程数,也不会导致其他用户等待页面投放。

In this case, the solution is to simply use regular polling (eg an AJAX call every 500 ms) to get quick notifications rather than using long-polling and tying up threads. 在这种情况下,解决方案是仅使用常规轮询(例如,每500毫秒进行一次AJAX调用)来获取快速通知,而不是使用长轮询和占用线程。

From Dave, 从戴夫

Many requests are better handled than long requests. 许多请求比长请求要好处理。 As the threads never really die they just get reused. 由于线程从未真正死亡,因此它们只是被重用。 It will also allow the system to skip a cycle if there's no available threads in the end. 如果最后没有可用线程,它还将允许系统跳过一个周期。 Now at some point you'll hit apache+php configuration issues being on shared hosting. 现在,您将遇到共享主机上的apache + php配置问题。 After that go with perhaps a small vps and swap to nginx or my personal fave cherokee and use phpfpm then you can build an actual worker thread thats reserved for your poll loop 之后,可以使用一个小的vps并交换到nginx或我的个人最爱切诺基,并使用phpfpm,然后可以构建为轮询循环保留的实际工作线程

and

Since the threads are always open there's no overhead for you allowing your poll script to complete and then restart (if the db connection is done right there'll be little additional db load either between pooled conns and prep-statements even better memcached or similar) means you only lock the thread for the duration of the run then immediately release it for other processes to pickup and use it this is how you can support more than 8 users on 8 threads as they're recycled. 由于线程始终处于打开状态,因此无需任何开销即可让轮询脚本完成然后重新启动(如果数据库连接正确完成,则池conns和prep语句之间几乎没有额外的数据库负载,甚至更好的内存缓存或类似语句也是如此)意味着您仅在运行期间锁定线程,然后立即将其释放以供其他进程使用并使用它,这是在回收8个线程时可以为8个以上的用户提供支持的方式。 Don't worry about recalling its always more efficient than longpoll unless you use realtime sockets and daemons 除非使用实时套接字和守护程序,否则不必担心调用它总是比longpoll更有效。

As of now the problem is resolved. 到目前为止,问题已解决。

I think in php every open connection means a running thread. 我认为在php中每个打开的连接都意味着一个正在运行的线程。 You have to make the connected time quite short and to use polling. 您必须使连接时间很短并使用轮询。

The only help would be to organize the polling as fast as possible, so I would try to store a very simple information queue for every session, say in apc_fetch/apc_store (if there is only one apache running for your app). 唯一的帮助是尽可能快地组织轮询,因此我将尝试为每个会话存储一个非常简单的信息队列,例如在apc_fetch/apc_store (如果您的应用程序仅运行一个apache)。 A very simple page has_update.php?session_id just reads that status line and returns 0 or 1, and 0 most of the time, in the smallest format possible. 一个非常简单的页面has_update.php?session_id会读取状态行,并以尽可能最小的格式返回0或1,大多数情况下返回0。 So 5x per second should not be an performance issue too soon. 因此,每秒5x不应太早成为性能问题。

If and only if has_update.php returns 1 the normal ajax-call should fire. 当且仅当has_update.php返回1时,正常的ajax调用才会触发。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM