Node.js与.Net的性能
我已经读了很多关于Node.js快速并能够容纳大量的负载。 有没有人有这个vs其他框架的真实世界证据,尤其是.Net? 我读过的大多数文章都是轶事,或者没有与.Net进行比较。
谢谢
快速处理大量的LOAD是两件不同的事情。 如果每秒发送500个请求(在LOAD下),那么服务器每秒处理一个请求的速度可能会非常快 。
你也必须考虑静态(和caching)与dynamic页面。 如果你担心静态页面,那么IIS可能会打败节点,因为IIS使用内核模式caching,这意味着请求一个静态页面的请求甚至不会离开内核。
我猜你正在寻找ASP.NET和节点之间的比较。 在这场战斗中,所有的东西都被编译/解释之后,你的performance可能会非常接近。 也许.NET稍微快一点,或者也许节点稍快一些,但是可能已经足够接近你不关心了。 我敢打赌,但是我不确定。
节点真正引人注目的地方是处理LOAD 。 这是技术真正不同的地方。 ASP.NET为其线程池中的每个请求分配一个线程,一旦ASP.NET耗尽了所有可用的线程,请求就开始排队。 如果你正在使用像@shankar这个例子那样的“Hello World”应用程序,那么这可能没有什么关系,因为线程不会被阻塞,你将能够在你之前处理很多请求用尽线程。 当您开始制作阻塞线程的I / O请求(调用数据库,向服务发出http请求,从磁盘读取文件)时,ASP.NET模型的问题就出现了。 这些阻塞请求意味着您的线程池中的宝贵线程无所事事。 你有越多的阻塞,你的ASP.NET应用程序将能够服务的负载越less。
为了防止这种阻塞,您使用I / O完成端口,在等待响应时不需要占用线程。 ASP.NET支持这一点,但不幸的是.NET中的许多常见框架/库不。 例如,ADO.NET支持I / O完成端口,但entity framework不使用它们。 所以你可以构build一个纯粹的asynchronous处理大量负载的ASP.NET应用程序,但是大多数人并不这样做,因为它不像构build同步的那样简单,而且你可能无法使用一些你喜欢的部分的框架(如linq实体),如果你这样做。
问题在于,ASP.NET(和.NET Framework)被创build为对asynchronousI / O毫不留情。 如果您编写同步代码或asynchronous代码,.NET并不关心,所以开发人员需要做出这个决定。 部分原因是因为线程和asynchronous操作编程被认为是“困难的”,而.NET希望让每个人都感到高兴(noobs和专家)。 它变得更加困难,因为.NET最终以3-4种不同的模式来完成asynchronous。 .NET 4.5正在试图恢复和改进.NET框架,以便围绕asynchronousIObuild立一个自发的模型,但是在你关心的框架实际上支持它之前可能还需要一段时间。
另一方面,节点的devise者提出了所有I / O都应该是asynchronous的意见select。 由于这个决定,节点devise者也能够做出每个节点实例都是单线程的决定,以最小化线程切换,并且一个线程只执行已经排队的代码。 这可能是一个新的请求,它可能是一个数据库请求的callback,它可能是您从一个httprest请求callback。 节点通过消除线程上下文切换来尝试最大化CPU效率。 因为节点使得所有I / O都是asynchronous的,所以它的框架/附加组件都支持这个select。 编写节点中100%asynchronous的应用程序更容易(因为节点会强制您编写asynchronous的应用程序)。
再次,我没有任何硬性的数字来certificate这种或那种,但我认为节点将赢得典型的Web应用程序的LOAD竞争。 一个高度优化(100%asynchronous)的.NET应用程序可能会让等价的node.js应用程序运行起来,但如果将所有.NET和所有节点应用程序的平均值都计算在内,平均节点可能会处理更多加载。
希望有所帮助。
我在nodejs和IIS之间做了一个基本的性能testing。 当“hello,world!”出现时,IIS比nodejs快大约2.5倍。 下面的代码。
我的硬件:戴尔Latitude E6510,Core i5(双核),8 GB内存,Windows 7企业版64位操作系统
节点服务器
runs at http://localhost:9090/ /// <reference path="node-vsdoc.js" /> var http = require("http"); http.createServer(function (request, response) { response.writeHead(200, { "Content-Type": "text/html" }); response.write("<p>hello, world!</p>"); response.end(); }).listen(9090);
的default.htm
hosted by iis at http://localhost/test/ <p>hello, world!</p>
我自己的基准程序使用任务并行库:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Threading; using System.Threading.Tasks; using System.Diagnostics; namespace HttpBench { class Program { private int TotalCount = 100000; private int ConcurrentThreads = 1000; private int failedCount; private int totalBytes; private int totalTime; private int completedCount; private static object lockObj = new object(); /// <summary> /// main entry point /// </summary> static void Main(string[] args) { Program p = new Program(); p.Run(args); } /// <summary> /// actual execution /// </summary> private void Run(string[] args) { // check command line if (args.Length == 0) { this.PrintUsage(); return; } if (args[0] == "/?" || args[0] == "/h") { this.PrintUsage(); return; } // use parallel library, download data ParallelOptions options = new ParallelOptions(); options.MaxDegreeOfParallelism = this.ConcurrentThreads; int start = Environment.TickCount; Parallel.For(0, this.TotalCount, options, i => { this.DownloadUrl(i, args[0]); } ); int end = Environment.TickCount; // print results this.Print("Total requests sent: {0}", true, this.TotalCount); this.Print("Concurrent threads: {0}", true, this.ConcurrentThreads); this.Print("Total completed requests: {0}", true, this.completedCount); this.Print("Failed requests: {0}", true, this.failedCount); this.Print("Sum total of thread times (seconds): {0}", true, this.totalTime / 1000); this.Print("Total time taken by this program (seconds): {0}", true, (end - start) / 1000); this.Print("Total bytes: {0}", true, this.totalBytes); } /// <summary> /// download data from the given url /// </summary> private void DownloadUrl(int index, string url) { using (WebClient client = new WebClient()) { try { int start = Environment.TickCount; byte[] data = client.DownloadData(url); int end = Environment.TickCount; lock (lockObj) { this.totalTime = this.totalTime + (end - start); if (data != null) { this.totalBytes = this.totalBytes + data.Length; } } } catch { lock (lockObj) { this.failedCount++; } } lock (lockObj) { this.completedCount++; if (this.completedCount % 10000 == 0) { this.Print("Completed {0} requests.", true, this.completedCount); } } } } /// <summary> /// print usage of this program /// </summary> private void PrintUsage() { this.Print("usage: httpbench [options] <url>"); } /// <summary> /// print exception message to console /// </summary> private void PrintError(string msg, Exception ex = null, params object[] args) { StringBuilder sb = new System.Text.StringBuilder(); sb.Append("Error: "); sb.AppendFormat(msg, args); if (ex != null) { sb.Append("Exception: "); sb.Append(ex.Message); } this.Print(sb.ToString()); } /// <summary> /// print to console /// </summary> private void Print(string msg, bool isLine = true, params object[] args) { if (isLine) { Console.WriteLine(msg, args); } else { Console.Write(msg, args); } } } }
和结果:
IIS: httpbench.exe http://localhost/test Completed 10000 requests. Completed 20000 requests. Completed 30000 requests. Completed 40000 requests. Completed 50000 requests. Completed 60000 requests. Completed 70000 requests. Completed 80000 requests. Completed 90000 requests. Completed 100000 requests. Total requests sent: 100000 Concurrent threads: 1000 Total completed requests: 100000 Failed requests: 0 Sum total of thread times (seconds): 97 Total time taken by this program (seconds): 16 Total bytes: 2000000 nodejs: httpbench.exe http://localhost:9090/ Completed 10000 requests. Completed 20000 requests. Completed 30000 requests. Completed 40000 requests. Completed 50000 requests. Completed 60000 requests. Completed 70000 requests. Completed 80000 requests. Completed 90000 requests. Completed 100000 requests. Total requests sent: 100000 Concurrent threads: 1000 Total completed requests: 100000 Failed requests: 0 Sum total of thread times (seconds): 234 Total time taken by this program (seconds): 27 Total bytes: 2000000
结论:IIS比nodejs快大约2.5倍(在Windows上)。 这是一个非常基本的testing,决不是定论。 但我相信这是一个很好的起点。 在其他networking服务器上,其他平台上的Nodejs可能更快,但在Windows上,IIS是胜利者。 想要将他们的ASP.NET MVC转换为nodej的开发人员应该暂停一下,然后继续思考。
更新(5/17/2012)Tomcat(在Windows)似乎击败了IIS的手,大约比IIS快3倍的静态HTML。
tomcat的
index.html at http://localhost:8080/test/ <p>hello, world!</p>
tomcat结果
httpbench.exe http://localhost:8080/test/ Completed 10000 requests. Completed 20000 requests. Completed 30000 requests. Completed 40000 requests. Completed 50000 requests. Completed 60000 requests. Completed 70000 requests. Completed 80000 requests. Completed 90000 requests. Completed 100000 requests. Total requests sent: 100000 Concurrent threads: 1000 Total completed requests: 100000 Failed requests: 0 Sum total of thread times (seconds): 31 Total time taken by this program (seconds): 5 Total bytes: 2000000
更新的结论:我多次运行基准testing程序。 在WINDOWS上,Tomcat似乎是最快速的静态HTML服务器。
更新(5/18/2012)以前,我有100,000个并发请求的总请求。 我把它增加到了100万个请求和100,000个并发请求。 IIS作为尖叫的胜利者而出现,而Nodejs则是最差的。 我已经把下面的结果列表化了:
。
我必须同意马库斯·格兰斯特罗姆(Marcus Granstrom)的说法,这里非常重要。
说实话,这听起来像是你正在做一个高影响的架构决定。 我的build议是隔离所关注的区域,并在你正在考虑的任何堆栈之间进行“烘烤”。
在这一天结束的时候,你要对这个决定负责,我不认为这个理由“Stackoverflow上的一些人向我展示了一篇文章,说这样会好的”。
NIO服务器(nodejs等)往往比BIO服务器更快。 (IIS等)。 为了支持我的说法,
Techempower是专门针对Web框架基准的公司。 他们是非常开放的,并有一个标准的方式来testing所有的framewrks。 检出http://www.techempower.com/benchmarks/
第9轮testing目前是最新的。 有很多IIS的味道testing,但ASPNET剥离似乎是最快的IIS变种。 下面是结果:Json序列化:NodeJS:228,887,aspnet-stripped:105,272单个查询:nodejs-mysql:88,597,aspnet-stripped-raw:47,066多个查询:nodejs-mysql:8,878,aspnet-stripped-raw:3,915 Plain文本:nodejs:289,578,aspnet-stripped:109,136
在所有情况下,NodeJS往往比IIS快2倍以上。
我看到的主要区别是节点.js是dynamic编程语言(types检查),所以types必须在运行时派生。 像C#.NET这样的强types语言在理论上有更多的潜力胜过Node.js(和PHP等),特别是在昂贵的计算中。 顺便说一下,.NET应该比C / C ++有更好的本地互操作性,而不是节点.js。