Deploying one application pool per website is indeed a recommended practice in IIS 7.x environments. This approach provides process-level isolation between applications, preventing one misbehaving site from affecting others. However, there are important caveats:
- Resource Consumption: Each pool creates additional w3wp.exe worker processes, increasing memory overhead
- CPU Throttling: While pools don't directly "hog" CPU, you should implement CPU limits via configuration:
The decision to enable multiple worker processes (web garden) depends on specific scenarios:
Use Case | Recommendation |
---|---|
CPU-bound applications | Enable web garden (set maxProcesses > 1) |
Memory-intensive apps | Single worker process recommended |
Session-dependent apps | Avoid web garden (session affinity issues) |
Private memory limits (privateBytesLimit) are effective for preventing single pools from consuming all available memory:
appcmd set apppool /apppool.name:MyAppPool /recycling.privateMemory:1000000
Key considerations:
- Setting limits too low (e.g., <500MB) may cause premature recycling
- Monitor Event Logs for event ID 5189 (memory-based recycling)
- Virtual memory limits (virtualMemoryLimit) include shared DLLs and are less precise
Exceptions to the isolation rule include:
- Resource-constrained servers where overhead exceeds benefits
- Related microservices that require shared in-process state
- Legacy applications with dependencies on specific runtime versions
Example of shared pool configuration:
<applicationPool name="SharedLegacyApps" managedRuntimeVersion="v2.0" managedPipelineMode="Classic"> <processModel identity="NetworkService" /> </applicationPool>
Implement PowerShell monitoring to track pool health:
# Get memory usage per pool Get-WmiObject -Namespace "root\WebAdministration" -Class WorkerProcess | Select-Object AppPoolName, ProcessId, @{Name="PrivateBytes(MB)";Expression={[math]::Round($_.PrivateBytes/1MB,2)}}
Combine with Performance Counters for comprehensive analysis:
- \Process(w3wp)\Private Bytes
- \ASP.NET Applications\Requests/Sec
- \Web Service\Current Connections
When deploying multiple websites on IIS 7.x, the one-application-pool-per-site approach provides maximum isolation but comes with tradeoffs:
<applicationPools>
<add name="Site1Pool" managedRuntimeVersion="v4.0" />
<add name="Site2Pool" managedRuntimeVersion="v4.0" />
</applicationPools>
Pro tip: Use PowerShell to automate pool creation:
Import-Module WebAdministration
1..10 | ForEach-Object {
New-WebAppPool -Name "Site${_}Pool"
Set-ItemProperty "IIS:\AppPools\Site${_}Pool" -Name managedRuntimeVersion -Value "v4.0"
}
Multiple worker processes (web gardens) should be considered when:
- Handling CPU-bound workloads with high concurrency
- Needing to isolate requests within the same application
Configuration example:
<applicationPools>
<add name="HighTrafficPool">
<processModel maxProcesses="4" />
</add>
</applicationPools>
Private memory limits (privateBytesLimit) are effective for containment:
<applicationPools>
<add name="ContainedApp">
<recycling periodicRestart="true">
<privateMemory limit="1000000" /> <!-- 1GB -->
</recycling>
</add>
</applicationPools>
Key differences between memory types:
Memory Type | Description | Impact |
---|---|---|
Private | Process-exclusive memory | Triggers recycling when exceeded |
Virtual | Total address space | Hard limit causes 503 errors |
For high-density hosting, consider these optimizations:
<applicationPools>
<add name="OptimizedPool">
<cpu limit="90" action="Throttle" />
<processModel idleTimeout="00:20:00" />
<recycling disallowOverlappingRotation="true" />
</add>
</applicationPools>
Monitor pools using performance counters:
Counter "\Process(w3wp*)\% Processor Time"
Counter "\Process(w3wp*)\Private Bytes"