Publié le 25/04/2018 Par Nicolas Latrille

.Net Core contre .Net Framework

Si vous êtes encore un peu perdus sur ce qu’est le .Net Core et le .Net Framework, je vous conseille d’aller lire cet article de Gaël.
Microsoft a publié un article listant un certain nombre de comparaisons de performance entre le framework classique et le .Net Core. Les deux technologies étant celles de Microsoft et le Core étant open source, j’ai considéré qu’il n’était pas nécessaire d’en refaire d’autres, leurs résultats étant certainement fiables. Par contre, je vous en propose une synthèse :

Synthèse du benchmark .Net vs .Net Core
Synthèse du benchmark .Net vs .Net Core

Grâce à cette synthèse, on voit que Microsoft a beaucoup travaillé pour améliorer les performances sur le .Net Core par rapport au .Net Framework. Certains sujets restent encore à la traîne, mais d’autres ont été revus en profondeur. LINQ devenu omniprésent ces dernières années a pris une bonne dose de stéroïdes. La sérialisation, la compression, le networking, la concurrency eux aussi très actuels à l’heure des Web API sont bien plus rapides en .Net Core.

Face à Node.js

Il y a de nombreuses raisons de comparer une application Web .Net Core à Node.js. La simplicité de mise en oeuvre d’un service web dans les deux technologies. Quelques lignes de codes suffisent. Elles sont un peu plus nombreuses en C#, mais elles sont générées par une simple ligne de commande. De plus, il ne fait aucun doute que Microsoft vise à concurrencer Node.js avec son .Net Core. Mais la principale raison de les comparer est que les applications web sont hébergées par Kestrel en .Net Core. Or Kestrel est basé sur libuv, comme Node.js. Je vous propose donc de comparer .Net Core et Node.js sur des exemples simples : deux helloworld.

Le code

Les deux exemples auront le code minimal pour répondre un 200(OK) à un GET. En un mot un HelloWorld ! tout simple. Vous trouverez le code plus bas.

Node.js

La version utilisée est la v8.9.4 sur tous les OS. Le code est le plus simple possible. Le voici:

var http = require("http");
http.createServer(function (request, response) {
  response.writeHead(200, {'Content-Type': 'text/plain'});
  response.end('Hello Worldn');
}).listen(8081);

ASP.Net Core

La version utilisée est la 2.0.5 avec SDK 2.1.4. sur tous les OS.
Le serveur est le projet web de base créé avec la ligne de commande dotnet new web.
La web application Node.js ne donne aucun log, or par défaut la web application .Net Core donne plusieurs lignes par requête. Les sorties ralentissant beaucoup un process, on a coupé les logs en .Net Core en insérant la ligne suivante dans le corps du WebHostBuilder de program.cs:

.ConfigureLogging( (lb) => { lb.AddFilter((ll) => false); })

Cette ligne ajoute un filtre au log builder, le filtre se basant sur le log level et renvoyant false quel qu’il soit.
Il est compilé en mode release spécifiquement pour l’OS avec la commande suivante.
Ex :

$ dotnet build --configuration Release --runtime ubuntu.16.04-x64

Vous pouvez trouver la liste des runtimes ici.

Le contexte

Le client de test est bombardier. C’est une application écrite en GO. J’ai utilisé les binaires déjà compilés que l’on peut trouver ici : https://github.com/codesenberg/bombardier/releases en V1.1.1

Le nombre de requêtes

Ce paramètre influe peu sur les mesures sauf dans des cas particuliers. Donc j’ai pris des valeurs différentes entre Linux et Windows, Windows étant beaucoup plus lent. L’autre raison de ce choix vient de la durée des tests (entre 5 et 8 minutes), ce qui éloigne les perturbations dues à des phénomènes transitoires.

Nombre de connexions

Pour les tests j’ai choisi un nombre de 512 connexions. Ce paramètre a une grande influence sur les chiffres mesurés. Par exemple en doublant ce chiffre le nombre de requêtes traitées à la seconde augmente d’un facteur 4. Mais cette influence est à peu près la même sur tous les types de projet.

Remarques diverses

  • Lors des tests le monitoring system était ouvert et a vérifié que le CPU était bien consommé par l’appli .Net Core ou Node.js et pas bombardier.
  • L’impact sur la mémoire étant peu significatif, il n’a pas été mesuré précisément.
  • Pour chaque test vous trouverez une capture de la sortie de bombardier. C’est une parmi plusieurs autres, car on a réalisé les expériences plusieurs fois. J’en ai choisi une dans la moyenne. Sachant qu’il peut y avoir des écarts de 30% entre la meilleure et la moins bonne.

 

Ubuntu 16.0.4

  • Machine : PC portable Aspire V3-772G
  • OS : Ubuntu 16.04 Kernel~4.13.0-26-generic x86_64
  • CPU : Dual core Intel Core i5-6200U (-HT-MCP-) speed/max~2400/2800 MHz
  • Mémoire : 16Go

ASP.Net Core

$ ./bombardier-linux-amd64 -c 512 -n 10000000 https://localhost:5000
Bombarding https://localhost:5000 with 10000000 requests using 512 connections
 10000000 / 10000000 [============================================] 100.00% 2m8s
Done!
Statistics    	Avg  	Stdev    	Max
  Reqs/sec 	78111.42   12938.56  389665.82
  Latency    	6.59ms 	6.77ms  	1.28s
  HTTP codes:
	1xx - 0, 2xx - 10000000, 3xx - 0, 4xx - 0, 5xx - 0
	others - 0
  Throughput:	13.70MB/s

Node.js

$ ./bombardier-linux-amd64 -c 512 -n 10000000 https://localhost:8081
Bombarding https://localhost:8081 with 10000000 requests using 512 connections
 10000000 / 10000000 [============================================] 100.00% 7m0s
Done!
Statistics    	Avg  	Stdev    	Max
  Reqs/sec 	23784.13	2946.99   32254.90
  Latency   	21.52ms 	3.94ms  	1.13s
  HTTP codes:
	1xx - 0, 2xx - 10000000, 3xx - 0, 4xx - 0, 5xx - 0
	others - 0
  Throughput: 	4.94MB/s

.Net Core est largement en tête, il y a un facteur 2,7 sur le débit de données et même de 3,2 sur le nombre de requêtes.

 

Amazon Linux AWS Lightsail

J‘ai pris l’offre de base à 5$ (gratuit 1 mois) à savoir une machine 1 coeur, 512 de RAM et un SSD de 20Go.
Pour la version exacte de l’OS :

$ cat /etc/*-release
NAME="Amazon Linux AMI"
VERSION="2017.09"
ID="amzn"
ID_LIKE="rhel fedora"
VERSION_ID="2017.09"
PRETTY_NAME="Amazon Linux AMI 2017.09"
ANSI_COLOR="0;33"
CPE_NAME="cpe:/o:amazon:linux:2017.09:ga"
HOME_URL="https://aws.amazon.com/amazon-linux-ami/"
Amazon Linux AMI release 2017.09

ASP.Net Core

$ ./bombardier-linux-amd64 -c 512 -n 1000000 https://localhost:5000
Bombarding https://localhost:5000 with 1000000 requests using 512 connections
 1000000 / 1000000 [===================================================================================================================================] 100.00% 1m0s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec     16696.79    3887.70   38553.78
  Latency       30.69ms     3.32ms   181.37ms
  HTTP codes:
    1xx - 0, 2xx - 1000000, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:     2.94MB/s

Node.js

$ ./bombardier-linux-amd64 -c 512 -n 1000000 https://localhost:8081
Bombarding https://localhost:5000 with 1000000 requests using 512 connections
 1000000 / 1000000 [===================================================================================================================================] 100.00% 2m4s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec      8042.10     591.97   11051.52
  Latency       63.64ms    14.98ms      1.40s
  HTTP codes:
    1xx - 0, 2xx - 1000000, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:     1.49MB/s

.Net Core reste largement en tête d’environ un facteur 2.

Comparé à Ubuntu, .Net Core divise son débit de 4,6.

Node.js lui ne voit son débit diminuer que de 3,3.

Le fait que cette machine virtuelle soit mono core explique certainement les résultats, en effet on peut penser que .Net Core exploite mieux les 4 cores de l’aspire V3. Donc passer à une machine mono core le pénalise plus que Node.js.

 

Windows 10

La machine est la même que pour Ubuntu (dual boot) à savoir un PC portable V3-772G.

ASP.Net Core

> bombardier-windows-amd64.exe -c 512 -n 10000000 https://localhost:5000
Bombarding https://localhost:5000 with 10000000 requests using 512 connections
 10000000 / 10000000 [==================================================================================] 100.00% 2m32s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec     66191.11    9760.25  127907.27
  Latency        7.82ms     1.36ms   587.42ms
  HTTP codes:
    1xx - 0, 2xx - 10000000, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:    11.55MB/s

Node.js

> bombardier-windows-amd64.exe -c 512 -n 10000000 https://localhost:8081
Bombarding https://localhost:8081 with 10000000 requests using 512 connections
 10000000 / 10000000 [==================================================================================] 100.00% 7m46s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec     21435.67    1338.44   22884.21
  Latency       23.88ms     1.44ms   754.54ms
  HTTP codes:
    1xx - 0, 2xx - 10000000, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:     4.46MB/s

Encore une fois .Net Core reste meilleur que Node.js (x 2,6). Bien que le hardware soit identique que sur Ubuntu, sans surprise les résultats sont moins bons : .Net Core -20% Node.js -10%; mais finalement ce n’est pas tant le cas que cela. Si on regarde le StdDev assez important on peut estimer que les différences sont dans l’erreur de mesure.

 

Windows Server 2012 R2 sur le cloud Azure

Setup : virtual machine Quad core à 2.3GHz

ASP.Net Core

> bombardier-windows-amd64.exe -c 512 -n 10000000 https://localhost:5000
Bombarding https://localhost:5000 with 10000000 requests using 512 connections
 10000000 / 10000000 [==========================================] 100.00% 2m44s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec     60567.10   13705.29  164975.25
  Reqs/sec       8.40ms   334.47us   104.00ms
  HTTP codes:
    1xx - 0, 2xx - 10000000, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:    10.72MB/s

Node.js

> bombardier-windows-amd64.exe -c 512 -n 10000000 https://localhost:8081
Bombarding https://localhost:8081 with 10000000 requests using 512 connections
 10000000 / 10000000 [=========================================] 100.00% 11m46s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec     14166.61    1292.90   36872.50
  Reqs/sec      36.16ms     2.19ms   338.00ms
  HTTP codes:
    1xx - 0, 2xx - 10000000, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:     2.62MB/s

Encore une fois .Net Core est devant. Les résultats restent cohérents avec une version grand public de Windows. Le fait que la machine soit virtuelle reste un peu pénalisant, mais tant que l’on conserve un nombre de coeurs identique, la baisse reste raisonnable.

 

Conclusion

La première remarque est que le travail de Microsoft résumé dans la 1ère partie de l’article a payé. Et ce travail ne semble pas fini si on lit la road map du .Net Core 2.1.

Node.js est clairement dépassé quelque soit l’OS, le type de machine et le nombre de coeurs. Il aurait été dommage que les performances .Net Core soient en retrait, car c’est affiché clairement comme argument par Microsoft.
La petite demi surprise c’est les bons chiffres sur Ubuntu, on sent que la firme de Redmond a vraiment travaillé l’implémentation du .Net Core sur Linux.
Après même si cela n’apparaît pas dans les chiffres, il y a tout de même quelques bémols. En effet sans la désactivation des logs, les performances de l’application Web .Net Core sont divisées par environ 5. Ce qui, lors de nos tests sur windows, causait même des erreurs sur 1% à 2% des requêtes. Or une application sans log, n’est pas très réaliste en production. De même que sans authentification ou même sans requêter un autre service dans un univers SOA. Je vous conseille donc de faire vos propres tests. Je vous conseille aussi de considérer les fonctions facilitant vos développements comme le nouveau concept de Middleware et de Pipeline.

Vos commentaires

  1. Par Nico AD, le 20 Sep 2018

    Intéressant, je suis a la recherche de benchmarks sur des applications un peu plus élaborées. renvoyer un hello world au client n’ étant pas un véritable use case. curieux aussi de la vitesse d’itération sur du .NET core , ce qui me plait bien avec node c’est la rapidité avec laquelle tu peux développer.

  2. Par Yohan.S, le 13 Déc 2018

    L’équipe .Net Core utilise le benchmark de techempower pour comparer les performances entre framework webs : https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=fortune

    Voici le github :
    https://github.com/aspnet/Benchmarks

    Sur le github ils ont mis un petit comparatif avec justement Node.js VS AspNetCore :
    https://aka.ms/aspnet/benchmarks

Publier un commentaire

Auteur

Nicolas Latrille

Développeur avant tout. Nicolas travaille en finance de marché depuis 2000. Craftman passionné, Nicolas a aussi la réputation d’avoir un œil critique sur tout !