Nodejs 对于Comet技术的有趣选择,论 Is node.js best for Comet?

Nodejs 对于Comet技术的有趣选择,论 Is node.js best for Comet?

首先要声明,我对Comet技术只了解皮毛,下面的评论如果有错误欢迎各位看官指出。本文相关博客地址:<a title=“http://amix.dk/blog/post/19577#Is-node-js-best-for-Comet” href=“http://amix.dk/blog/post/19577#Is-node-js-best-for-Comet”>http://amix.dk/blog/post/19577#Is-node-js-best-for-Comet</a> <br/> <br/>amix在这篇博客中谈论他们在Plurk中Comet技术选择的变迁。 <br/> <br/>说句题外话,他有另外一篇博客 <br/><a title=“http://amix.dk/blog/post/19581#The-main-issue-with-non-blocking-servers” href=“http://amix.dk/blog/post/19581#The-main-issue-with-non-blocking-servers”>http://amix.dk/blog/post/19581#The-main-issue-with-non-blocking-servers</a> <br/>里面用两张图形象的介绍了阻塞式服务器与非阻塞式服务器的工作方式,感兴趣的可以去瞅瞅。amix关于node.js和v8的介绍可以看这里<a title=“http://amix.dk/blog/post/19484#Comet-with-node-js-and-V8” href=“http://amix.dk/blog/post/19484#Comet-with-node-js-and-V8”>http://amix.dk/blog/post/19484#Comet-with-node-js-and-V8</a> <br/> <br/>关于Comet技术,可以参考维基百科<a title=“http://en.wikipedia.org/wiki/Comet_(programming)” href=“http://en.wikipedia.org/wiki/Comet_(programming)”>http://en.wikipedia.org/wiki/Comet_(programming) <br/></a>国人有个开源项目<a title=“http://code.google.com/p/eurasia/” href=“http://code.google.com/p/eurasia/”>http://code.google.com/p/eurasia/</a> 好像是做类似工作。 <br/> <br/>回到这篇博客上来,amix提到他们在项目中针对comet技术的选择,一开始是使用fast polling with C memcached nginx libevent,实现代码可以参考 <br/><a title=“http://amix.dk/blog/post/19414#Fast-polling-using-C-memcached-nginx-and-libevent” href=“http://amix.dk/blog/post/19414#Fast-polling-using-C-memcached-nginx-and-libevent”>http://amix.dk/blog/post/19414#Fast-polling-using-C-memcached-nginx-and-libevent</a> <br/>后来这个方案碰到局限了,不知什么局限,总之是不好用了。 <br/> <br/>于是实验了很多其它的comet方案,但是都不成熟。所以他们用Java与Netty实现一套comet方案,可以参考 <br/><a title=“http://amix.dk/blog/post/19456#Plurk-Comet-Handling-of-100-000-open-connections” href=“http://amix.dk/blog/post/19456#Plurk-Comet-Handling-of-100-000-open-connections”>http://amix.dk/blog/post/19456#Plurk-Comet-Handling-of-100-000-open-connections</a> <br/>文章里提到Twisted缺点是太耗CPU而且不易扩展;Jetty太耗内存;Tomcat也是很耗费内存;apache Mina文档不行,而且也不易扩展。最后选择了Netty,amix没有提到他们如何用Netty实现的,所以估计想用这个方案的朋友得单独联系他了。 <br/> <br/>后来amix发现node.js不错,他把java方案移植到nodejs上,只用了2天时间。在过去8个月(从2010年2月到10月)nodejs方案每天可以服务几百万用户的comet提醒。 <br/> <br/>但是,总有但是,随着网站用户增多,nodejs方案也碰到瓶颈了。即使试着做了一些优化和增加硬件,效果并不明显。amix他们又回到Netty方案,经过一些代码优化后,尽管内存使用量大于nodejs方案,但是性能要好于后者。Netty方案每秒可以为10000个客户端提供约6000个comet提醒,而Nodejs方案只能每秒服务500个,所以可以说新的Netty方案有10倍以上改进。 <br/> <br/>amix总结道,node.js是一个非常棒的方案,至少撑了8个月,而且实现起来也很快。但是nodejs有致命的缺陷。这个缺陷来自nodejs的基石-V8 JavaScript引擎。 <br/> <br/>V8引擎不支持线程或者进程机制-每件事都是主进程处理,甚至包括垃圾收集。 <br/> <br/>对于浏览器而已,这个限制是一个聪明的选择,大家知道每个Chrome页面就是一个单独的进程,所以V8引擎这种方案很好用。但是对于服务器架构就不一样了,这种单进程单线程的限制就变得麻烦。(具体为何麻烦我也不知道,也没写过nodejs项目)关于V8在服务器端使用的局限性,Nginx作者也有一篇博客介绍Why is Google V8 is not suitable for embedding in servers<a title=“http://sysoev.ru/prog/v8.html” href=“http://sysoev.ru/prog/v8.html”>http://sysoev.ru/prog/v8.html</a> 大家可以通过google翻译成英语阅读(翻译成中文后读起来很奇怪,还不如英语好懂),主要也是抱怨异常处理、进程模型、垃圾收集这几个方面。对于浏览器比较适合的V8方案,在服务器端就变成无法承受之重。 <br/> <br/>后面的回复也值得参考,其中有人提到使用nginx建立Nodejs集群然后分发,有人建议说重写nodejs的http模块很好用,也有人建议fugue这个方案<a href=“http://github.com/pgte/fugue”>http://github.com/pgte/fugue</a> ,nodejs作者Ryan Dahl也留言说明前面版本某个bug可能导致性能问题。 <br/> <br/>偶个人的感想:即使amix有这样的抱怨,但可以看出nodejs依然是服务器端实现comet的很好选择,异步编程、高并发、低功耗,而且作者非常活跃,社区膨胀的非常快,个人感觉nodejs活跃度已经超过Lua。Lua社区有些程序员也试图用libevent或者libev来为Lua加上非阻塞异步服务器端编程的能量,但是影响力都不够,成熟度也不如nodejs。接下来偶会对nodejs做更多的探究,从源代码到小程序编写应用,希望能通过nodejs提高一下自己对服务器端编程的理解。 <br/> <br/>作者sunwei个人博客: http://sunxiunan.com/


4 回复

Nodejs 对于Comet技术的有趣选择,论 Is node.js best for Comet?

首先,我对Comet技术的理解有限,因此如果我的评论中有任何错误,请大家指正。

Comet技术背景

Comet是一种Web应用程序模型,它允许服务器向客户端推送数据,而无需客户端发起请求。这使得实时应用(如即时通讯或股票交易系统)成为可能。Comet技术通常依赖于长时间轮询、流式传输等方法。

Node.js与Comet

在讨论Node.js是否适合用于Comet之前,让我们先看看Node.js的基本原理。Node.js是一个基于Chrome V8引擎的JavaScript运行环境,它非常适合构建高并发的网络应用。Node.js的核心优势在于其事件驱动、非阻塞I/O模型,这使得它可以高效地处理大量并发连接。

实际案例:Plurk的Comet实现

在实际应用中,Plurk团队在开发过程中尝试了多种Comet技术方案。最初,他们采用了C语言结合memcached、nginx和libevent的组合,但随着用户数量的增长,这种方法遇到了瓶颈。随后,他们转向Java和Netty的解决方案,但最终发现Node.js是一个更好的选择。

示例代码:简单的Node.js Comet应用

以下是一个简单的Node.js Comet应用示例,使用Express框架和Socket.IO库来实现实时通信:

const express = require('express');
const http = require('http');
const socketIo = require('socket.io');

// 创建Express应用
const app = express();
const server = http.createServer(app);

// 启动WebSocket服务
const io = socketIo(server);

// 监听客户端连接
io.on('connection', (socket) => {
    console.log('A user connected:', socket.id);

    // 发送消息给客户端
    setInterval(() => {
        socket.emit('message', { text: 'Hello, client!' });
    }, 1000);

    // 监听客户端断开连接
    socket.on('disconnect', () => {
        console.log('User disconnected:', socket.id);
    });
});

// 启动服务器
server.listen(3000, () => {
    console.log('Server listening on port 3000');
});

在这个示例中,我们创建了一个简单的WebSocket服务器,它每隔一秒钟向所有连接的客户端发送一条消息。客户端可以通过Socket.IO库接收这些消息,并进行相应的处理。

Node.js的优势与挑战

优势

  • 事件驱动:Node.js采用事件驱动的方式处理请求,能够高效地处理大量并发连接。
  • 异步I/O:Node.js的异步I/O模型避免了阻塞操作,提高了系统的响应速度。
  • 社区活跃:Node.js拥有一个庞大的社区,提供了丰富的第三方库和工具。

挑战

  • 单线程限制:Node.js的单线程模型在某些场景下可能会遇到性能瓶颈。
  • V8引擎限制:V8引擎不支持多线程或多进程,这对于需要处理大量计算任务的应用来说是个挑战。

总结

尽管Node.js在实现Comet技术方面表现出色,但在处理极高并发和复杂计算任务时,它可能会遇到瓶颈。因此,选择合适的解决方案需要根据具体应用场景进行权衡。对于大多数实时应用而言,Node.js仍然是一个非常不错的选择,尤其是在并发连接较多的情况下。

希望这篇文章能帮助你更好地理解Node.js在Comet技术中的应用。如果你有任何疑问或建议,请随时留言交流!


其实Plurk 那篇博客已经看过很久了,终于看到国内有人深入翻译和研究。 <br/>用node.js实现服务器端comet也许真的不是一个很好的选择,我用node.js开发了一个小型实时监控系统,大概700多并发。在容错(典型的如apache的多进程)、垃圾收集上确实遇到了不少问题。

如果现在再让amix选,不知道他会不会再次选择nodejs。

Node.js 是一种适合 Comet 技术的有趣选择,因为它采用了事件驱动的非阻塞 I/O 模型,这使得它非常适合处理长连接和实时通信的需求。尽管 Node.js 在某些情况下可能遇到性能瓶颈,但它依然是一种高效且易于实现的方案。

以下是一个简单的 Node.js 实现 Comet 技术的示例代码:

const http = require('http');
const fs = require('fs');

const server = http.createServer((req, res) => {
    if (req.url === '/comet') {
        // 设置响应头以保持连接打开
        res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' });
        
        // 发送初始消息
        res.write(`data: Hello, this is a comet message\n\n`);
        
        // 定时发送新消息
        setInterval(() => {
            res.write(`data: New message at ${new Date().toISOString()}\n\n`);
        }, 3000);
    } else {
        fs.readFile('index.html', (err, data) => {
            if (err) throw err;
            res.writeHead(200, { 'Content-Type': 'text/html' });
            res.end(data);
        });
    }
});

server.listen(3000, () => {
    console.log('Server running on port 3000');
});

在这个例子中,当客户端请求 /comet 路径时,服务器会保持连接打开,并定时发送新的消息给客户端。客户端可以通过 EventSource 接口监听这些消息。

然而,正如案例中的 Plurk 所描述的那样,Node.js 在处理大量并发连接时可能会遇到性能瓶颈。因此,如果需要处理非常高并发的场景,可能需要考虑其他方案,如使用 Netty 或者通过负载均衡器来分发请求。

回到顶部