IIS7’s performance slower than IIS6

 

As Support Engineer, I have the possibility to work with many customers around the world with different configurations. A couple of mounts ago, I was surprised to work with one of them who sustained that after the migration to IIS7 from IIS6, the IIS7’s performance was worse than IIS6. The servers’ goal was the same: both of them access on the same remote share in order to provide images to final users. It means no custom code was in execution: final users have the possibility to get their images simply opening urls like this one https://serverName/myImage.jpg on their brewers.

How was it possible? Was really IIS7 performing worse than IIS6? Of course no! The remote server (where the images were stored on) was the same for both web servers: IIS6 and II7. The network was working properly, let’s say with the same bandwidth, so where the issue was!?!

After collecting a memory dump, everything was clear (as in most of cases Winking smile). Well the threads were like this one:

 

 0:087> k
# ChildEBP RetAddr  
00 0671ed44 75c63bc8 ntdll!ZwDelayExecution+0x15
01 0671edac 75c64498 KERNELBASE!SleepEx+0x65
02 0671edbc 73c48765 KERNELBASE!Sleep+0xf
03 0671edf0 73c443c4 iisutil!CReaderWriterLock3::_LockSpin+0xfb
04 0671ee10 73beeb73 iisutil!CReaderWriterLock3::ReadLock+0x3c
05 0671ee18 73bf1b1b nativerd!CONFIG_CACHE::ReadLock+0x11
06 0671ee28 73bdaad0 nativerd!CONFIG_CACHE::GetConfigFileList(class PATH * pConfigPath = 0x0671ef14, unsigned long dwParseMode = 0x2a, class CONFIG_FILE_LIST * pConfigFileList = 0x0671ee4c, class PARSE_ERROR_INFO * pParseErrorInfo = 0x0671f0b8)+0xe
07 0671f26c 73bb896d nativerd!CONFIG_SYSTEM::GetUniqueConfigPath(wchar_t * bstrConfigPath = 0x0671f598 "MACHINE/WEBROOT/APPHOST/SFTBS.SL.PT/auto/media/000561/Viaturas/000714130/166x125/Renault-Laguna-2357165.jpg", wchar_t ** pbstrUniquePath = 0x0671f290)+0xba
08 0671f294 730a3ca5 nativerd!CONFIG_SYSTEM::GetUniqueConfigPath(wchar_t * pszConfigPath = 0x0671f598 "MACHINE/WEBROOT/APPHOST/SFTBS.SL.PT/auto/media/000561/Viaturas/000714130/166x125/2357165.jpg", wchar_t * pszUniqueConfigPath = 0x0671f798 "", unsigned long * pcchUniqueConfigPath = 0x0671f2c0, class INativeSectionException ** ppException = 0x0671f9c4)+0x2809 0671f99c 730a547d iiscore!W3_CONTEXT::SetupMetadata+0x22b
0a 0671f9d0 730a5ab3 iiscore!W3_CONTEXT::SetupStateMachinePhase2+0x7e
0b 0671fa44 730a61c3 iiscore!W3_CONTEXT::SetupStateMachine+0x241
0c 0671fa58 730a6642 iiscore!W3_MAIN_CONTEXT::StartNotificationLoop+0x3f
0d 0671fa70 72ea1568 iiscore!W3_MAIN_CONTEXT::OnNewRequest+0x47
0e 0671fa7c 72ea14e6 w3dt!UL_NATIVE_REQUEST::DoStateProcess+0x26
0f 0671fa88 72ea154c w3dt!UL_NATIVE_REQUEST::DoWork+0x60
10 0671fa9c 7324265a w3dt!OverlappedCompletionRoutine+0x1a
11 0671fad4 7324289a w3tp!THREAD_POOL_DATA::ThreadPoolThread+0x89
12 0671fae8 73241e95 w3tp!THREAD_POOL_DATA::ThreadPoolThread+0x24
13 0671fb00 75b533aa w3tp!THREAD_MANAGER::ThreadManagerThread+0x39
14 0671fb0c 778a9ef2 kernel32!BaseThreadInitThunk+0xe
15 0671fb4c 778a9ec5 ntdll!__RtlUserThreadStart+0x70
16 0671fb64 00000000 ntdll!_RtlUserThreadStart+0x1b

What were they doing? They were trying to get a configuration file. The fact is this one:

  • Starting form IIS 7, the web server’s pipeline changed including new features and new integration with .NET.

    Even if customer was not using any feature of ASP.Net (consider that his app is sharing images over the web) IIS was looking for web.config files at every content level on the file server.

  • The problem was there, customer file server was hosting hundreds and hundreds of folders, so the constant work to research web.config files caused the bottleneck.

What was the resolution? We have two possible resolutions here:

  1. We could configure IIS in order to research webConfig file every 10 minutes for example. To do that we have to set the following registry key as mentioned below:

    HKLM\System\CurrentControlSet\Services\W3SVC\Parameters\ConfigPollMilliSeconds = 600000

    Further details here:
    https://support.microsoft.com/kb/954864
    Of course this setting is not related to a single web application, it has an impact on web server.

    This solution could not work for all web applications installed on your IIS, furthermore a new change on your webConfig will be not reflected

    immediately.

  2. This is my preferred solution, read here: https://www.iis.net/configreference/system.applicationhost/sites/site/application/virtualdirectory

“Optional Boolean attribute.

Specifies whether IIS looks for Web.config files in content directories lower than the current level (true) or does not look for Web.config files in content directories lower than the current level (false).

The default value is true.”

If you change the value of allowSubDirConfig to false in every application’s root, our goal is achieved: IIS will stop to research for web config file stored on application’s subfolder.

What happened at the end… J IIS7 worked 5 times faster than IIS6 on customer’s environment.

Thx,

Carmelo

Comments

  • Anonymous
    December 27, 2012
    This issue happened to me too, I don't know why this setting persisted true in IIS 8.
  • Anonymous
    March 23, 2014
    IIS has an annoying (sometimes) feature for low traffic websites. It recycles unused worker processes – which cause the first user to the site; sometimes extremely long delay (30+ seconds). dotnettimes.wordpress.com/.../fixing-slow-initial-load-for-iis-web-site