Node.js+Socket.io+MongoDB的Web应用程序如何实现真正的异步操作?

22
我有一个老式的LAMP Web应用程序。一周前,我需要为其添加推送通知机制。
因此,我在服务器上添加了node.js+socket.io,并使用node.js每10秒轮询MySQL数据库以检查是否有新项目:如果有,则会使用socket.io将它们发送到客户端。
尽管存在高达10秒的延迟,但我对结果感到非常满意,即使这不是真正的实时通知。

现在,我即将构建一个新的Web应用程序,它也需要推送通知。我在考虑是否采用与第一个应用程序相同的方法(我认为更稳定和成熟),还是完全采用Node.js,而不使用PHP和Apache。至于数据库,我已经决定选择MongoDB。

最后,我的问题是:如果我选择使用Node.js + Socket.io + MongoDB,我能得到一个接近实时的web应用程序吗?我的意思是,当一个新的记录被插入到MongoDB中,是否会触发某种事件,我可以通过node.js捕获它,对其进行一些检查,并在相关时将通知发送给客户端?或者,在数据库服务器端是否有任何轮询和滞后方式,就像我的第一个LAMP webapp一样?

一个相关的问题:您能否在MySQL上构建实时Web应用程序,而不需要像我第一个应用程序那样进行任何轮询。还是需要MongoDB(或Redis)?

我希望这个问题不太傻 - 抱歉,我刚开始学习Node.js等技术。

谢谢。


1
你可能想考虑不使用术语和标签“实时”。尽管大多数人知道你的意思,但你所追求的并非是严谨的“实时”(http://en.wikipedia.org/wiki/Real-time_computing),而是非阻塞式的。请考虑使用“异步”,“非阻塞”或“准实时”的术语。 - Adam Gent
1
@dan如果你觉得我的回答有用,请接受它好吗? - Adam Halasz
实时性与您用于实现服务的技术无关,而与您的客户端和服务实现相关。 - ice6
6个回答

16

我了解你的问题,因为我也从 php/apache/mysql 转到了 node.js

  • 一般来说,node.js 是稳定的,而模块和脚本是出现错误的主要原因。

  • 实时性与数据库无关,它完全取决于客户端和服务器,您可以在请求中查询尽可能多的数据并将其推送到其他客户端。

  • 选择 node.js 非常明智,但实现起来会更加困难。

  • 当您将新记录插入数据库时,事件就是请求本身,您需要在数据库查询时同时进行推送事件,例如:

// Please note this is not real code, just an example of the idea
app.get('/query', function(request, response){
    // Query your database
    db.query('SELECT * FROM users', function(rows){

         // Push notification to dan
         socket.emit('database_query_executed', 'to_dan', rows); 

         // End request
         response.end('success'); 

    })   
})
  • 当然你可以使用MySQL! 事实上,你可以使用任何想要的数据库,因为实时性与数据库无关,因为数据库位于流程的中间,并且完全是可选的。

  • 如果你想使用node.js进行推送通知,并将php/apache用于mysql,那么你需要为每个服务器创建2个请求,例如:

  • // this is javascript
    ajax('http://node.yoursite.com/push', node_options)
    ajax('http://php.yoursite.com/mysql_query', php_options)
    

    如果你只想要一个请求,或者你想要使用一个表单,你可以调用你的 PHP 代码,并在其中创建一个从 PHPNode.jsHTTP 或 Net 请求,例如:

    // this is php
    new HttpRequest('http://node.youtsite.com/push', HttpRequest::METH_GET);
    

    @dan 可以用两种方式实现:1)在客户端发起两个请求,一个是针对node.js的,另一个是针对apache/php的;2)只发起一个针对apache/php的请求,然后在内部创建一个针对node.js的请求。或者你可以从node.js开始调用php,所以关键是需要同时调用php和node.js,php用于mysql,而node.js用于推送通知。 - Adam Halasz
    1
    @Adam, dan - 没错 :-) 如果且仅如果Adam: 我更喜欢你的第二个想法(通过内部请求将WebSockets通信卸载到node.js). - Deer Hunter
    我认为使用Node代理请求到PHP会比反过来更有效率,所以在需要两者的情况下,我可能会先让单个请求通过Node并通知PHP,可选择等待响应后再回应浏览器。 - Richard Marr
    1
    "iff" 意味着 "if and only if"。 - Paramore
    redis声称具有实时能力的数据库,这是怎么样的呢? - Michel Hua
    显示剩余2条评论

    7

    使用:

    • 一个普通的 MongoDB 集合作为Store,
    • 一个带有可追踪游标的 MongoDB 容量集合 作为Queue,
    • 一个 Node 工作者使用 Socket.IO 监视队列作为Worker,
    • 一个 Node 服务器用于提供带有 Socket.IO 客户端的页面,并接收 POST 数据(或以其他方式添加数据)作为Server

    它的工作方式如下:

    1. 新数据被发送到服务器,
    2. 服务器将数据放入存储中,
    3. 服务器将数据的 ObjectID 添加到队列中,
    4. 队列将新到达的 ObjectID 发送到工作者上打开的可追踪游标,
    5. 工作者从存储中获取 ObjectID 中的实际数据,
    6. 工作者通过 socket 发送数据,
    7. 客户端从 socket 接收数据。

    这是从初始添加数据到客户端接收数据的“推送” - 没有轮询,因此在每个步骤的处理时间内尽可能实时。


    2
    你发现了Chole吗? 它与您的Web服务器分开工作,并通过使用HTTP POST进行接口。这样,您可以按照任何方式编写Web应用程序。

    2

    关于MongoDB的触发器 - 请参见此答案:https://dev59.com/2GbWa4cB1Zd3GeqPb-0r#12405093

    在MySQL中有更方便的触发器,但要从它们调用Node.js需要使用MySQL UDFs(用户定义的函数),例如通过Unix套接字推送数据。请注意,仅在其他应用程序(除您的Node.js进程之外)更新数据库时才需要这样做,并确保在此情况下选择InnoDB作为存储(行级锁定与表级锁定)。

    如果客户端Web套接字不受支持,您也可以使用 sockets.io,即使如此,您也将会(希望优雅地)退回到轮询。

    最后,您的问题一点也不傻,因为推送技术绝对比大量轮询请求更好 - 它具有更好的可扩展性。编辑:但是,也不会将任何一种技术描述为实时

    另一个编辑:有一个非常著名和成功的此类设置,请阅读此文:http://blog.fogcreek.com/the-trello-tech-stack/


    1

    实际上,使用像Socket.IO这样的推送技术可以帮助您有效地使用服务器资源,并帮助您将旧浏览器升级到支持WebSocket或类似WebSocket连接的现代浏览器。

    10秒轮询是HTTP请求,尤其是在有很多用户时,会很昂贵

    与轮询技术不同,推送技术比较便宜。用户的客户端会打开一个专用套接字(即WebSocket)来监听服务器的推送通知。

    通常,在收到推送通知时,您的客户端JavaScript会执行一些操作。

    使用您的LAMP堆栈和不同于80的Socket.IO端口就足够了以实现您需要的功能。

    但是,使用Node.js + MongoDB + Socket.IO实际上可以帮助您更有效地管理服务器资源。

    因为这三个具有非阻塞特性。

    如果您正确理解非阻塞概念并适当实现应用程序,

    与通用LAMP堆栈相比,您的相同功能的应用程序,即具有不同语言和不同数据库的应用程序,将能够处理更多的请求。


    enter image description here

    上图是一个著名的比较非阻塞和线程处理并发的图表

    Apache(线程) vs Nginx(非阻塞)


    MySQL是一个很好的数据库。我相信你不需要使用jointransactions来进行实时通知。

    MongoDB没有这两个功能,除非你自己实现类似的功能。

    由于缺少这两个功能和一些自身特点,MongoDB可以比传统的SQL数据库更快地存储和提取数据。

    从MySQL切换到MongoDB将减少插入和提取数据所需的时间。


    0

    使用JS可以打开一个套接字连接到您的服务器(不适用于旧的浏览器),服务器上将有一个临时程序(在一个特定的端口,因此您需要权限来打开门并在服务器上运行该程序),该程序将实时地从客户端发送和接收数据,而无需HTTP协议的开销。旧的浏览器只能回退到轮询机制。

    我看不到其他方法来做到这一点(可能已经有"现成"的框架可以实现)


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