A while back, Jose blogged about the CPU throttling feature in ASP.NET 4.5. As described in the original post, this feature is intended to correct negative scaling in server throughput when handling async requests on a server with saturated CPU.
Now, for the next chapter to this story: CPU throttling under stress scenarios.
This feature was tested during development in the ASP.NET performance lab. Performance testing, unlike stress, tends to be very homogenous: measure server throughput under full load (CPU) when handling a specific scenario or request. When this feature entered the stress lab, it encountered more real-world applications: longer run times, various requests and bursty traffic. Under these conditions it became clear that CPU throttling had a problem with recovery.
PROBLEM: As Jose mentioned, ASP.NET throttles requests by adding them to a native queue until the managed layer is ready to process them. This is the same native queue used when MaxConcurrentRequestsPerCpu or MaxConcurrentThreadsPerCpu is exceeded. ASP.NET attempts to dequeue when other requests enter or complete the pipeline. This behavior is fine for requests queued due to high concurrency, since a large number of requests are executing and headed for completion. However, CPU throttling is not based on number of requests but on how expensive they are. As a result, there could be just a few CPU-intensive requests causing a backup in the native queue with no way to empty it aside from incoming requests.
SOLUTION: ASP.NET CPU throttling was modified just prior to RTM. ASP.NET now supports more aggressive dequeuing from the native queue both with incoming/completing requests and via a timer. Also, a second configuration, “percentCpuLimitMinActiveRequestPerCpu” was added to ensure a minimum number of requests are being served before throttling kicks in. The default throttling limit was also lowered from 99% to 90% in order to detect high pressure and avoid negative scaling earlier.
In conclusion, it is highly recommended that you don’t run your web servers at full capacity. Enabled by default, this feature is primarily intended as a safety net to prevent degradation in performance when serving async requests under load. If you find that requests are sitting in the queue (see: “ASP.NET\Requests in Native Queue”) even after the CPU has normalized, try disabling the feature by setting percentCpuLimit to 0.
<configuration> <system.web> <applicationPool percentCpuLimit=”90” percentCpuLimitMinActiveRequestPerCpu=”100”> </system.web> </configuration>
Many thanks to Konst Khurin for his work on this feature and blog review.