Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread management in asp.net core / kestrel

I'm troubleshooting performance / scalability issues with an asp.net app we've migrated to asp.net core 2.0. Our app is hosted on azure as an app service, and is falling over far too easily with any moderate traffic.

One thing that's puzzling me is how multiple concurrent requests are handled. From what I've read here, Kestrel uses multiple event loops to handle your requests. But the actual user code is handled on the .net thread pool (that's from here).

So, as an experiment - I've created a new asp.net core 2.0 MVC app, and added a rather nasty action method:

    [AllowAnonymous]
    public ActionResult Wait1()
    {
        System.Threading.Tasks.Task.Delay(1000).Wait();
        return new StatusCodeResult((int)HttpStatusCode.OK);
    }     

Now, when I push this to azure, I'd expect that if I send say 100 requests at the same time, then I should be OK, because 100 requests sounds like minor load, right? And the waiting will happen on the thread pool threads, right?

So - I do just this and get some rather poor results - sample highlighted in red:

enter image description here

Hmm, not what I expected, about 50 seconds per request... If however I change the frequency so the requests are spaced a second apart, then the response time is fine - back to just over 1000ms as you'd expect. It seems if I go over 30 requests at the same time, it starts to suffer, which seems somewhat low to me.

So - I realise that my nasty action method blocks, but I'd have expected it to block on a thread pool thread, and therefore be able to cope with more than my 30.

Is this expected behaviour - and if so is it just a case of making sure that no IO-bound work is done without using async code?

like image 501
Matt Roberts Avatar asked Nov 16 '17 15:11

Matt Roberts


People also ask

Is Kestrel single threaded?

libuv uses a single threaded event loop model. Kestrel supports multiple event loops. Kestrel does only IO work on the libuv event loops. All non IO work (including anything related with HTTP like parsing, framing, etc) is done in managed code on standard .

What is Kestrel in ASP.NET Core?

Kestrel is a cross-platform web server for ASP.NET Core. Kestrel is the web server that's included and enabled by default in ASP.NET Core project templates. Kestrel supports the following scenarios: HTTPS. HTTP/2 (except on macOS†)

Is ASP.NET Core multithreaded?

ASP.NET Core already runs app code on normal Thread Pool threads, so calling Task. Run only results in extra unnecessary Thread Pool scheduling. Even if the scheduled code would block a thread, Task.


Video Answer


1 Answers

Is this expected behaviour - and if so is it just a case of making sure that no IO-bound work is done without using async code?

Based on my experience, it seems that is as expected behaviour. We could get answer from this blog.

Now suppose you are running your ASP.Net application on IIS and your web server has a total of four CPUs. Assume that at any given point in time, there are 100 requests to be processed. By default the runtime would create four threads, which would be available to service the first four requests. Because no additional threads will be added until 500 milliseconds have elapsed, the other 96 requests will have to wait in the queue. After 500 milliseconds have passed, a new thread is created.

As you can see, it will take 100*500ms intervals to catch up with the workload.

This is a good reason for using asynchronous programming. With async programming, threads aren’t blocked while requests are being handled, so the four threads would be freed up almost immediately.

I recommand that you could use async code to improve the performance.

public async Task<ActionResult> Wait1()
{
    await Task.Delay(TimeSpan.FromSeconds(15));
    return new StatusCodeResult((int)HttpStatusCode.OK);
}

I also find another SO thread, you could refernce to it.

like image 64
Tom Sun - MSFT Avatar answered Sep 20 '22 15:09

Tom Sun - MSFT