我读过很多关于Node.js速度快,能够容纳大量负载的文章。有人有任何现实世界的证据来证明它与其他框架,特别是。net的区别吗?我读过的大多数文章都是趣闻轶事,或者没有与。net进行比较。


我同意Marcus Granstrom的观点这里的场景非常重要。

老实说,这听起来像是你在做一个影响很大的架构决策。 我的建议是将关注的领域分离出来,并在您正在考虑的任何堆栈之间进行“烘烤”。

在一天结束的时候,你要为这个决定负责,我不认为这个借口 “有人在Stackoverflow上给我看了一篇文章,说这没问题” 会让你老板满意的。


我在nodejs和IIS之间做了一个基本的性能测试。 IIS在发送“hello, world!”时比nodejs快2.5倍。 下面的代码。

我的硬件: 戴尔Latitude E6510,酷睿i5(双核),8gb内存,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上)。这是一个非常基本的测试,绝不是决定性的。但我相信这是一个很好的起点。Nodejs可能在其他web服务器上,在其他平台上更快,但在Windows IIS上是赢家。开发人员希望将他们的ASP。NET MVC到nodejs应该暂停并三思而后行。

更新(5/17/2012) Tomcat(在windows上)似乎轻而易举地打败了IIS,在分发静态html方面大约比IIS快3倍。

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

更新结论:我多次运行基准程序。在WINDOWS上,Tomcat似乎是分发静态HTML最快的服务器。

更新(5/18/2012) 在此之前,我总共有100,000个请求和10,000个并发请求。我将其增加到1,000,000个总请求和100,000个并发请求。IIS是赢家,Nodejs是最差的。我将结果列成表格如下:

.


速度快和处理大量负载是两回事。如果你每秒发送500个请求(在LOAD状态下),一个每秒处理一个请求速度非常快的服务器可能会完全崩溃。

您还必须考虑静态(和缓存的)页面与动态页面。如果您担心静态页面,那么IIS可能会打败节点,因为IIS使用内核模式缓存,这意味着请求静态页面的请求甚至不会从内核中获得。

我猜您正在寻找ASP和ASP之间的比较。NET和node。在这种情况下,在编译/解释完所有内容之后,您的性能可能会非常接近。也许。net更快一点,或者node更快一点,但它可能已经足够接近了,所以你不必在意。我打赌是。net,但我不确定。

The place that node is really compelling is for handling LOAD. This is where the technologies really differ. ASP.NET dedicates a thread for each request from its thread pool, and once ASP.NET has exhausted all the available threads requests begin to get queued up. If you're serving "Hello World" apps like the example by @shankar, then this might not matter that much because the threads aren't going to be blocked and you're going to be able to handle a lot of requests before you run out of threads. The problem with the ASP.NET model comes when you start making I/O requests that block the thread (call to a DB, make an http request to a service, read a file from disk). These blocking requests mean that your valuable thread from the thread pool is doing nothing. The more blocking you have, the less LOAD your ASP.NET app is going to be able to serve.

To prevent this blocking, you use I/O completion ports which don't require holding a thread while you wait for a response. ASP.NET supports this, but unfortunately many of the common frameworks/libraries in .NET DON'T. For example, ADO.NET supports I/O completion ports, but Entity Framework doesn't use them. So you can build an ASP.NET app that's purely asynchronous and handles lots of load, but most people don't because it isn't as easy as building one that's synchronous, and you might not be able to use some of your favorite parts of the framework (like linq to entities) if you do.

The problem is that ASP.NET (and the .NET Framework) were created to be un-opinionated about asynchronous I/O. .NET doesn't care if you write synchronous or asynchronous code, so it's up to the developer to make this decision. Part of this is because threading and programming with asynchronous operations was thought to be "hard", and .NET wanted to make everyone happy (noobs and experts). It got even harder because .NET ended up with 3-4 different patterns for doing async. .NET 4.5 is trying to go back and retrofit the .NET framework to have an opinionated model around async IO, but it may be a while until the frameworks you care about actually support it.

The designers of node on the other hand, made an opinionated choice that ALL I/O should be async. Because of this decision, node designers were also able to make the decision that each instance of node would be single threaded to minimize thread switching, and that one thread would just execute code that had been queued. That might be a new request, it might be the callback from a DB request, it might be the callback from a http rest request you made. Node tries to maximize CPU efficiency by eliminating thread context switches. Because node made this opinionated choice that ALL I/O is asynchronous, that also means that all it's frameworks/add-ons support this choice. It's easier to write apps that are 100% async in node (because node forces you to write apps that are async).

同样,我没有任何确切的数字来证明一种方式或另一种方式,但我认为node将赢得典型的web应用程序的LOAD竞争。一个高度优化(100%异步)的. net应用程序可能会给等效的node.js应用程序一个运行它的钱,但如果你把所有的。net和所有的节点应用程序的平均,平均node可能处理更多的LOAD。


我看到的主要区别是node .js是动态编程语言(类型检查),所以类型必须在运行时派生。从理论上讲,像c# . net这样的强类型语言在与Node .js(和PHP等)的斗争中具有更大的潜力,特别是在需要大量计算的地方。顺便说一下,. net与C/ c++的本机互操作应该比node .js更好。


NIO服务器(Node.js等)往往比BIO服务器更快。(IIS等等)。为了支持我的说法,TechEmpower是一家专门从事web框架基准测试的公司。他们是非常开放的,并且有一个测试所有框架的标准方法。

第九轮测试目前是最新的(2014年5月)。已经测试了许多IIS版本,但aspnet- stripping似乎是最快的IIS版本。

以下是每秒响应数的结果(越高越好):

JSON序列化 nodejs: 228887 aspnet-stripped: 105272 单查询 nodejs-mysql: 88597 aspnet-stripped-raw: 47066 多个查询 nodejs-mysql: 8878 aspnet-stripped-raw: 3915 纯文本 nodejs: 289578 aspnet-stripped: 109136

在所有情况下,Node.js往往比IIS快2倍。