node.js VS .NET性能比较

Node.js vs .Net performance

我已经读了很多关于node.js的内容,它们速度快,能够容纳大量的负载。有没有人有任何现实世界的证据证明这与其他框架,特别是.NET相比?我读过的大多数文章都是奇闻轶事,或者与.NET没有比较。

谢谢


快速和处理大量的负载是两件不同的事情。如果您每秒发送500个请求(在负载下),那么一个每秒服务一个请求的速度非常快的服务器可能会完全发出吱吱声。好的。

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

我猜您正在寻找ASP.NET和节点之间的比较。在这场战斗中,在编译/解释了所有内容之后,您的性能可能会非常接近。也许.NET有点快,或者节点有点快,但它可能足够近以至于你不在乎。我会在.NET上下注,但我不确定。好的。

节点真正引人注目的地方是处理负载。这就是技术真正不同的地方。ASP.NET为来自其线程池的每个请求指定一个线程,一旦ASP.NET耗尽了所有可用的线程请求,就会开始排队。如果你在提供类似@shankar例子的"hello world"应用程序,那么这可能没什么关系,因为线程不会被阻塞,你可以在线程用完之前处理很多请求。当您开始发出阻塞线程的I/O请求(对数据库的调用、对服务的HTTP请求、从磁盘读取文件)时,ASP.NET模型就会出现问题。这些阻塞请求意味着来自线程池的有价值的线程什么也不做。你的阻塞越多,你的ASP.NET应用程序的负载就越少。好的。

为了防止这种阻塞,您使用I/O完成端口,在等待响应时不需要保持线程。ASP.NET支持这一点,但不幸的是.NET中的许多公共框架/库不支持。例如,ADO.NET支持I/O完成端口,但实体框架不使用它们。因此,您可以构建一个纯异步的、处理大量负载的ASP.NET应用程序,但大多数人不会这样做,因为它不像构建一个同步的应用程序那么简单,而且如果这样做的话,您可能无法使用框架中一些您最喜欢的部分(如Linq to Entities)。好的。

问题是,(ASP.NET和.NET Framework)是一个联合国opinionated创建异步I/O和网络不在乎,如果你写的代码的同步或异步,它让这个新开发的决策。这是因为一部分线程和异步操作和编程思想是什么"硬",让每个人都快乐的和。NET通缉(新手和专家)。它有点难,因为.NET来有3~4个做异步模式。.NET 4.5是试图去改造的。NET框架有向弧opinionated异步IO模型,但它可能是一段时间直到你真的关心支持框架。

设计师协会的节点在另一手制造的所有选择,在opinionated应异步I/O。因为这是决策节点的设计师,所以能够使决策实例,每个节点将切换到单线程的线程的减少,这是一个线程执行的代码只是一个已排队。这可能是一个新的请求,它可能是从一个数据库请求的回调,回调的信息可能是从HTTP请求你剩下的蛆。最大限度地提高商务效率由CPU节点交换机方式线程上下文。因为这是所有制造opinionated节点选择一个异步I/O,那么它意味着所有的插件支持这个框架/选择。它容易写的应用程序是100%异步节点(节点部队因为你写程序是异步)。

再次,我没有任何硬编码为了证明一个或另一种方式,但我认为会赢得竞争的节点负载为典型的Web应用程序。高度优化的应用程序(100%异步)。node.js可能给应用程序一运行它的等效的钱,但如果你把一切网络平均节点和所有的应用程序在那里,更多的可能是在平均节点的处理负载。

希望这帮助。

好的。


我在nodejs和iis之间做了一个初步的性能测试。当发出"你好,世界!"的时候,iis比nodejs快2.5倍。.下面的代码。

我的硬件:Dell Latitude E6510、Core I5(双核)、8 GB RAM、Windows 7 Enterprise 64位操作系统

节点服务器

1
2
3
4
5
6
7
8
9
10
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);

缺省HTM

1
2
3
4
hosted by iis at http://localhost/test/
<p>
hello, world!
</p>

我自己的使用任务并行库的基准程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
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);
        }
    }

}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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倍。

雄猫

1
2
3
4
index.html at http://localhost:8080/test/
<p>
hello, world!
</p>

Tomcat结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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)以前我有100000个请求,同时有10000个请求。我把它增加到了1000000个请求和100000个并发请求。我是尖叫的胜利者,诺德斯的表现最差。我已将结果制表如下:

NodeJS vs IIS vs Tomcat serving STATIC HTML on WINDOWS


NIO服务器(node.js等)往往比bio服务器更快。(IIS等)。为了支持我的说法,TechEmpower是一家专门研究Web框架基准的公司。它们非常开放,并且有一种标准的方法来测试所有框架。

第9轮测试目前是最新的(2014年5月)。有许多IIS风格测试,但aspnet剥离似乎是最快的IIS变体。

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

  • JSON序列化
    • nodejs:228,887
    • ASPNET剥离:105,272
  • 单一查询
    • nodejs mysql:88,597
    • ASPNET剥皮生料:47,066
  • 多个查询
    • nodejs mysql:8,878
    • ASPNET剥皮生料:3,915
  • 纯文本
    • nodejs:289,578
    • ASPNET剥离:109,136

在所有情况下,node.js都比IIS快2倍以上。


我必须同意马库斯·格兰斯特罗姆的观点,这里的情况非常重要。

老实说,这听起来像是你在做一个影响很大的架构决策。我的建议是隔离关注的区域,在你考虑的任何堆栈之间进行"烘烤"。

一天结束的时候,你要对这个决定负责,我不认为这是个借口"StackOverflow上的一个家伙给我看了一篇文章,说没问题。"会和你老板断绝关系的。


我看到的主要区别是node.js是动态编程语言(类型检查),因此类型必须是在运行时派生的。理论上,C.NET等强类型语言更有可能赢得与node.js(和php等)的斗争,尤其是在计算成本高昂的地方。顺便说一下,.NET应该有更好的本地C/C++交互,而不是No.js。