node.js と ASP.NET Core のパフォーマンス テストの予期しない結果 質問する

node.js と ASP.NET Core のパフォーマンス テストの予期しない結果 質問する

私は2つの(ちょっと)Hello Worldプロジェクトで簡単なストレステストを行っています。そしてどちらもプロダクション モードで実行されており、ロガーは接続されていません。結果は驚くべきものでした。ASP.NET Core は、追加の作業を行った後でも node.js アプリよりもパフォーマンスが優れていますが、node.js アプリはビューをレンダリングするだけです。

アプリ1:http://localhost:3000/nodejs node.js

使用: node.js、express、vash レンダリング エンジン。

Node.js アプリ

このエンドポイントのコードは

router.get('/', function(req, res, next) {
  var vm = {
    title: 'Express',
    time: new Date()
  }
  res.render('index', vm);
});

ご覧timeのとおり、変数を介して現在の日付をビューに送信する以外は何も行いません。

アプリ2:http://localhost:5000/aspnet-core asp.net core

使用: ASP.NET Core、既定のテンプレート ターゲットdnxcore50

ただし、このアプリは日付が記載されたページをレンダリングするだけではありません。さまざまなランダムなテキストの 5 つの段落を生成します。理論的には、このアプリは nodejs アプリよりも少し重くなるはずです。

asp.net コア アプリ

このページをレンダリングするアクションメソッドは次のとおりです

[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
[Route("aspnet-core")]
public IActionResult Index()
{
    var sb = new StringBuilder(1024);
    GenerateParagraphs(5, sb);

    ViewData["Message"] = sb.ToString();
    return View();
}

ストレステストの結果

Node.js アプリのストレステスト結果

アップデート:ゴルギ・コセフの提案に従って

使用npm install -g recluster-cli && NODE_ENV=production recluster-cli app.js 8

Node.js テスト 2

ASP.NET Core アプリのストレス テスト結果

asp.net コア ストレス テスト結果

信じられない!この基本的なテストでasp.net coreがnodejsよりはるかに速いというのは本当ではない。もちろん、これはこれら2つのWebテクノロジーのパフォーマンスを測定するために使用される唯一の指標ではありませんが、私は疑問に思っています。node.js 側で何が間違っているのでしょうか?

私はプロの asp.net 開発者であり、個人のプロジェクトに node.js を採用したいと考えていますが、パフォーマンスについては少し心配なので、これは私にとっては気が進みません。私は、node.js は asp.net core よりも高速だと思っていました (一般的に、他のさまざまなベンチマークで見られるように)。私はただそれを自分自身に証明したいだけです (node.js を採用する勇気づけるため)。

さらにコード スニペットを追加して欲しい場合は、コメントで返信してください。

アップデート: .NET Core アプリの時間分布

aspnetcore アプリの時間分布

サーバー応答

HTTP/1.1 200 OK
Cache-Control: no-store,no-cache
Date: Fri, 12 May 2017 07:46:56 GMT
Pragma: no-cache
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
Server: Kestrel

ベストアンサー1

多くの人がほのめかしているように、この比較には文脈が欠けています。
リリース当時、node.js の非同期アプローチは革命的でした。それ以来、他の言語や Web フレームワークは、主流となったアプローチを採用してきました。

この違いが何を意味するかを理解するには、データベース要求などの IO ワークロードを表すブロッキング要求をシミュレートする必要があります。要求ごとのスレッド システムでは、これによりスレッドプールが使い果たされ、新しい要求は使用可能なスレッドを待機するキューに入れられます。
非ブロッキング IO フレームワークでは、これは発生しません。

応答する前に1秒待つNode.jsサーバーを考えてみましょう

const server = http.createServer((req, res) => {
  setTimeout(() => {
    res.statusCode = 200;
    res.end();
  }, 1000);
});

ここで、10 秒間に 100 件の同時接続を実行してみましょう。つまり、約 1000 件のリクエストが完了すると予想されます。

$ wrk -t100 -c100 -d10s http://localhost:8000
Running 10s test @ http://localhost:8000
  100 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.01s    10.14ms   1.16s    99.57%
    Req/Sec     0.13      0.34     1.00     86.77%
  922 requests in 10.09s, 89.14KB read
Requests/sec:     91.34
Transfer/sec:      8.83KB

ご覧のとおり、922 個が完了し、ほぼ目標を達成しました。

ここで、async/await がまだサポートされていなかったかのように記述された、つまり node.js のリリース時代にまで遡る次の asp.net コードを検討してください。

app.Run((context) =>
{
    Thread.Sleep(1000);
    context.Response.StatusCode = 200;
    return Task.CompletedTask;
});

$ wrk -t100 -c100 -d10s http://localhost:5000
Running 10s test @ http://localhost:5000
  100 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.08s    74.62ms   1.15s   100.00%
    Req/Sec     0.00      0.00     0.00    100.00%
  62 requests in 10.07s, 5.57KB read
  Socket errors: connect 0, read 0, write 0, timeout 54
Requests/sec:      6.16
Transfer/sec:     566.51B

62! ここでスレッドプールの制限がわかります。これを調整することで、より多くの同時リクエストを実行できるようになりますが、サーバー リソースのコストが増えます。

これらの IO バウンドのワークロードの場合、処理スレッドのブロックを回避する動きは非常に劇的でした。

さて、今日ではその影響が業界全体に波及し、dotnet がその改善点を活用できるようにしてみましょう。

app.Run(async (context) =>
{
    await Task.Delay(1000);
    context.Response.StatusCode = 200;
});

$ wrk -t100 -c100 -d10s http://localhost:5000
Running 10s test @ http://localhost:5000
  100 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.01s    19.84ms   1.16s    98.26%
    Req/Sec     0.12      0.32     1.00     88.06%
  921 requests in 10.09s, 82.75KB read
Requests/sec:     91.28
Transfer/sec:      8.20KB

驚くことではありませんが、node.js と一致しました。

それで、これは何を意味するのでしょうか?

node.js が「最速」であるという印象は、私たちがもう生きていない時代から来ています。さらに、node/js/v8 が「高速」だったことは一度もありません。リクエストごとのスレッド モデルが破壊されたのです。他の誰もが追いついています。

単一のリクエストを可能な限り高速に処理することが目標の場合は、真剣なベンチマーク独自の言語を作成するのではなく、単に現代の標準に合わせてスケーリングできるものが必要な場合は、好きな言語を選択して、それらのスレッドをブロックしないようにします。

免責事項: すべてのコードは、眠い日曜日の朝に古い MacBook Air で作成され、テストが実行されました。コードを入手して Windows で試したり、必要に応じて調整したりしてください。https://github.com/csainty/nodejs-vs-aspnetcore

おすすめ記事