Node.js与.Net的性能

我已经阅读了很多有关Node.js快速且能够容纳大量负载的信息。有没有人比其他框架有任何现实世界的证据,特别是.Net?我读过的大多数文章都是轶事,或者没有与.Net的比较。

谢谢

米亚逆天2020/03/24 10:57:46

我必须同意Marcus Granstrom的观点,在这里非常重要。

To be honest it sounds like you’re making a high impact architectural decision. My advice would be to isolate the areas of concern and do a "bake off" between whatever stacks you are considering.

At the end of the day you are responsible for the decision and I don’t think the excuse "Some guy on Stackoverflow showed me an article that said it would be fine" Will cut it with your boss.

猪猪2020/03/24 10:57:46

我在nodejs和IIS之间进行了基本的性能测试。抛出“ hello,world!”时,IIS的速度大约是nodejs的2.5倍。下面的代码。

我的硬件:Dell Latitude E6510,Core i5(双核),8 GB RAM,Windows 7 Enterprise 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上)。这是一个非常基本的测试,绝不是结论性的。但是我相信这是一个很好的起点。在其他Web服务器和其他平台上,Node.js可能更快,但是在Windows IIS上胜出。希望将ASP.NET MVC转换为nodejs的开发人员应该暂停并三思而后行。

已更新(5/17/2012)Tomcat(在Windows上)似乎击败了IIS,在抛出静态html方面比IIS快约3倍。

雄猫

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

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

Updated (5/18/2012) Previously I had 100,000 total requests with 10,000 concurrent requests. I increased it to 1,000,000 total requess and 100,000 concurrent requests. IIS comes out as the screaming winner, with Nodejs fairing the worst. I have tabularized the results below:

NodeJS vs IIS vs Tomcat在Windows上提供静态HTML.

梅番长2020/03/24 10:57:46

作为FAST和处理大量的负载是两回事。如果您每秒发送500个请求(在LOAD之下,那么实际上每秒处理一个请求的速度非常快的服务器可能完全崩溃

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

我猜想您正在寻找ASP.NET与节点之间的比较。在这场战斗中,在对所有内容进行编译/解释之后,您的性能可能会非常接近。也许.NET有点更快或许节点是一个小更快,但它可能接近,以至于你不在乎。我会在.NET上下注,但我不确定。

节点真正引人注目的地方是处理LOAD这就是技术真正不同之处。ASP.NET为来自其线程池的每个请求专用一个线程,一旦ASP.NET用尽了所有可用线程的请求,便开始排队。如果您像@shankar的示例一样在提供“ Hello World”应用程序,那么这可能没什么大不了的,因为不会阻塞线程,并且您将能够处理很多请求,然后再处理用完线程。当您开始发出阻止线程的I / O请求(调用DB,向服务发出http请求,从磁盘读取文件)时,ASP.NET模型就会出现问题。这些阻塞请求意味着您来自线程池的宝贵线程无所作为。您拥有的障碍越多,加载您的ASP.NET应用即可。

为了防止这种阻塞,请使用I / O完成端口,这些端口在等待响应时不需要保持线程。ASP.NET支持此功能,但是不幸的是,.NET中的许多常见框架/库都不支持。例如,ADO.NET支持I / O完成端口,但是Entity Framework不使用它们。因此,您可以构建一个纯异步的ASP.NET应用程序并处理大量负载,但是大多数人不会这样做,因为它不像构建同步的应用程序那样容易,并且您可能无法使用某些喜欢的部分框架(如linq到实体)。

问题在于,ASP.NET(和.NET Framework)是针对异步I / O创建的。.NET不在乎您编写同步代码还是异步代码,因此,由开发人员决定是什么。部分原因是因为使用异步操作进行线程和编程被认为是“困难的”,.NET希望让每个人都感到高兴(新手和专家)。变得更加困难,因为.NET最终以3-4种不同的模式进行异步处理。.NET 4.5试图回过头来对.NET框架进行改造,使其具有围绕异步IO的自以为是的模型,但是直到您关心的框架实际支持它时,可能还需要一段时间。

另一方面,node的设计者做出了明智的选择,即ALL I / O应该是异步的。由于这一决定,节点设计者还能够做出以下决定:每个节点实例都是单线程的,以最大程度地减少线程切换,并且一个线程将仅执行已排队的代码。那可能是一个新请求,可能是来自数据库请求的回调,也可能是来自您发出的http rest请求的回调。节点尝试通过消除线程上下文切换来最大化CPU效率。因为节点选择所有I / O都是异步的,所以这也意味着它的所有框架/附加组件都支持该选择。在节点中编写100%异步的应用程序比较容易(因为节点会强制您编写异步的应用程序)。

同样,我没有任何硬性数字可以证明一种方法,但是我认为节点将赢得典型Web应用程序的LOAD竞争。高度优化的(100%异步).NET应用程序可能会花钱让等效的node.js应用程序运行,但是,如果您平均提取所有.NET和所有节点应用程序,则平均而言,节点可能会处理更多加载。

希望能有所帮助。

凯西里2020/03/24 10:57:46

我看到的主要区别是node .js是动态编程语言(类型检查),因此类型必须在运行时派生。从理论上讲,像C#.NET这样的强类型语言在与Node .js(和PHP等)的对抗中具有更大的潜力,尤其是在计算成本很高的地方。顺便说一下,.NET与C / C ++的本地互操作性应优于节点.js。

西里Near2020/03/24 10:57:46

NIO服务器(Node.js等)往往比BIO服务器要快。(IIS等)。为了证明我的观点,TechEmpower是一家专门从事Web框架基准测试的公司它们非常开放,并且具有测试所有framewrks的标准方法。

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

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

  • JSON序列化
    • nodejs: 228,887
    • aspnet剥离: 105,272
  • 单一查询
    • nodejs-mysql: 88,597
    • aspnet-stripped-raw: 47,066
  • 多重查询
    • nodejs-mysql: 8,878
    • aspnet-stripped-raw: 3,915
  • 纯文本
    • nodejs: 289,578
    • aspnet剥离: 109,136

在所有情况下,Node.js的速度往往都比IIS快2倍以上。