Starting from version 2.2, ASP.NET Core allow you to use the InProcess mode to improve performance under IIS. Rick Strahl has a detailed article on this. Three years have passed, and now ASP.NET Core has reached version 5.0, how the performance diffs between servers? Let's take a look together.

Rick's Test Result


In the original article, Rick Strahl tested the performance of ASP.NET Core 2.2 in Kestrel, IIS InProcess, and IIS Out of Process under Windows. The metric is request per second. The conclusion was IIS InProcess> Kestrel> IIS Out of Process

Today's Experiment


Rick did not test the difference between running ASP.NET Core on Windows servers and Linux servers. Many friends want to know whether Windows or Linux is good for running ASP.NET Core 5.0 in 2021, so I decided to use a similar method to re-run the ASP.NET Core 5.0 request per second metric on Windows and Linux to find out.

Testing Environment


Since Windows 10, Ubuntu Desktop and other desktop systems do not truly represent the server environment, I chose the server version of these OS for testing. All systems are freshly installed with the latest patch, and they have been rebooted once before running test.

Windows Server

  • Provider: Microsoft Azure East Asia Region
  • OS: Windows Server 2019 Data Center
  • Size: B2S / 2 vCPU, 4GB RAM, Premium SSD
  • Environment: IIS with Static and Dynamic compression, no ASP.NET 3.5 or 4.x integration, installed ASP.NET Core 5.0.2 Runtime

Linux Server

  • Provider: Microsoft Azure East Asia Region
  • OS: Ubuntu Server 20.04 LTS
  • Size: B2S / 2 vCPU, 4GB RAM, Premium SSD
  • Environment: BBR Enabled, installed Nginx, Caddy and ASP.NET Core 5.0.2 Runtime

Test Tool

Rick used West Wind Web Surge, but this tool is only available on the Windows platform, which cannot meet our needs. So I used bombardier, an open source, cross-platform testing tool, which was also appeared on Microsoft’s official .NET blog once.

Testing Application


I created a new ASP.NET Core 5.0 Web API project with only one method:

[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
    [HttpGet]
    public string Get()
    {
        return $"Test {DateTime.UtcNow}";
    }
}

For simplicity, I will not test Json serialization and other operations this time, feel free to explore these testings for yourself.

The project is compiled with Release configuration and published using FDD. Log configuration is left as default:

"LogLevel": {
  "Default": "Information",
  "Microsoft": "Warning",
  "Microsoft.Hosting.Lifetime": "Information"
}

Test Method


Use Kestrel, IIS In Process, IIS Out of Process, Nginx reverse proxy, Caddy reverse proxy to run the test project, and then use bombardier to access the localhost test address with 2 connections, and 10 seconds duration, after a warm-up round, run for 3 consecutive rounds and take the average of Request per Second data.

Please note that in an ideal environment, it is best not to use a performance test tool to test the localhost address, because the operating system itself will have a certain impact on the network resources between scheduling the test tool and the Web server. But since network in the cloud environment is not so stable, in order to eliminate the network influence as much as possible, I have to visit localhost for the testing.

Test Result


Windows + Kestrel

Avg RPS: 18808

Windows + IIS In Process

Avg RPS: 10089

Windows + IIS Out of Process

Avg RPS: 2820

Linux + Kestrel

Avg RPS: 10667

Linux + Nginx

Avg RPS: 3509

Linux + Caddy

Avg RPS: 3485

Conclusion


Ranking of test results (from fast to slow):

  1. Windows + Kestrel (18808)

  2. Linux + Kestrel (10667)

  3. Windows + IIS In Process (10089)

  4. Linux + Nginx (3509)

  5. Linux + Caddy (3485)

  6. Windows + IIS Out of Process (2820)

The result is different from Rick's test for ASP.NET Core 2.2. In Rick's test, the performance of IIS In Process can surpass Kestrel. But today, IIS In Process is slammed by Kestrel, which seems quite reasonable.

But what I didn't expect is that the performance of Windows server is higher than Linux with both Kestrel server. I was surprised. 

In the reverse proxy mode, the performance of Nginx and Caddy are basically the same, and both are higher than IIS Out of Process.

Of course, a single output string test does not represent all the performance of ASP.NET Core 5.0 and each server. In actual projects, there are many factors that affect performance. The design of this experiment does not cover all scenarios, and there must be some flaws. Welcome to leave a message to point out.

Addition

A friend pointed out that DateTime.UtcNow may have performance problem in .NET 5, thus I replaced it with Activity.Current?.Id ?? HttpContext.TraceIdentifier, I get a slight better throughput on each ever, and testing result are almost the same.

By increasing connection number from 2 to 125, kestrel on each platform can have much higer throughput.