When requests get stuck in IIS's SendResponse state, we're typically looking at one of three core issues:
- Network-level transmission delays
- Application-level response processing
- IIS/ASP.NET pipeline interference
First, let's verify some often-overlooked network settings:
netsh int tcp show global
netsh interface ipv4 show subinterfaces
Key settings to check:
- Receive Window Auto-Tuning should be "normal"
- ECN capability should be disabled
- RSS (Receive Side Scaling) should be enabled
Even with autoConfig, we might need explicit thread pool settings in machine.config:
<system.web>
<processModel
autoConfig="false"
maxWorkerThreads="100"
maxIoThreads="100"
minWorkerThreads="50"
minIoThreads="20"/>
</system.web>
Add this to applicationHost.config to verify caching behavior:
<system.webServer>
<caching enabled="true" enableKernelCache="true">
<profiles>
<add extension=".aspx" policy="CacheUntilChange"/>
</profiles>
</caching>
</system.webServer>
Create a custom ETW trace to catch SendResponse delays:
logman create trace IIS_SendResponse -ow -o c:\traces\iis_sendresponse.etl -p {0811c1af-7a07-4a06-82ed-869455cdf713} 0xffffffff -nb 16 16 -bs 1024 -ft 1 -ets
For dynamic content that can be cached, implement output caching:
// In Global.asax
protected void Application_BeginRequest()
{
if (Request.Url.AbsolutePath.EndsWith(".aspx"))
{
Response.Cache.SetCacheability(HttpCacheability.Server);
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetValidUntilExpires(true);
}
}
When all else fails, these advanced checks often reveal the culprit:
- Run
appcmd list wp
to check worker process health - Verify ARR (Application Request Routing) settings if configured
- Check for SSL/TLS renegotiation delays
- Monitor with PerfView for CLR stalls
When requests mysteriously hang during the SendResponse phase in IIS 7.5/ASP.NET 4.0 environments, even on robust infrastructure, we're typically dealing with one of these underlying issues:
// Sample PowerShell to monitor stuck requests
Get-WebRequest -State "SendResponse" |
Where-Object { $_.TimeElapsed -gt 20000 } |
Format-Table -Property TimeElapsed, Url, ClientIP
Despite disabling TCP offloading, we need deeper network diagnostics:
- Check for NIC driver compatibility issues (particularly with virtualization)
- Validate RSS (Receive Side Scaling) configuration
- Monitor TCP retransmits with netstat -s
The integrated pipeline introduces subtle threading behaviors that aren't always apparent:
// Recommended thread configuration for high-throughput scenarios
<system.web>
<processModel autoConfig="false"
maxWorkerThreads="100"
maxIoThreads="100"
minWorkerThreads="50"
minIoThreads="50"/>
</system.web>
Hyper-V virtual machines require additional scrutiny:
- Check for VMQ (Virtual Machine Queue) conflicts
- Validate synthetic vs. legacy network adapter usage
- Monitor for host-level resource contention
Beyond appcmd, we need deeper instrumentation:
# ETW tracing for HTTP.sys and IIS
logman start IIS_Trace -p Microsoft-Windows-HttpService 0xFFFF -o trace.etl -ets
# Reproduce issue
logman stop IIS_Trace -ets
Even with low CPU usage, watch for:
- Private bytes accumulation
- Gen 2 garbage collection frequency
- AppDomain recycling events
Despite fast SAN connectivity, consider:
- MPIO policy configuration (failover vs. round robin)
- Storage latency spikes during backup windows
- Virtual disk fragmentation
Immediate actions while investigating:
// web.config tweaks for transient issues
<system.webServer>
<serverRuntime enabled="true"
frequentHitThreshold="1"
frequentHitTimePeriod="00:00:10"/>
</system.webServer>