iisiis-7.5applicationhost

Why does AppHostSvc ocassionally get stuck using up 100% CPU?


I have a Windows Server 2008 R2 server running IIS 7.5 and serving web applications.

I've noticed that a svchost.exe process is consuming a lot of CPU (an entire cpu core was at 100%). That specific process was hosting the IIS Application Host Helper Service (AppHostSvc). Once the problem starts, it doesn't matter what the server is doing (it could be completely idle otherwise and the service will stake eat up CPU).

If I kill the process the problem goes away - after the service is restarted automatically by IIS it uses a minimal amount of CPU.

The AppHostSvc service is responsible for IIS Host History Configuration and automatically backs up the configuration (I believe every two minutes by default), I thought maybe the problem starts after an IIS configuration change. I tried to change some configuration settings and it had no effect (even after several minutes of waiting).

Eventually I found what triggers it, but it seems like a bug. See my own answer below.


Solution

  • Turns out the trigger was "bad" permissions on the history directory used by AppHostSvc (by default, it's %windir%\system32\inetsrv\History)

    After making sure the permissions match the default settings, I ran icacls /T /reset on that directory (and on a few others, including inetsrv\config) and the problem disappeared - AppHostSvc stopped going crazy with CPU.


    More details

    I took a dump of the svchost.exe process when AppHostSvc was stuck in the bad state. One of the threads had the following call stack:

    ntdll.dll!NtClose()
    KERNELBASE.dll!FindClose()
    apphostsvc.dll!CONFIG_HISTORY_ENTITY::ScanHistoryDirectory(void)
    apphostsvc.dll!CONFIG_HISTORY_ENTITY::TrimHistory(void)
    apphostsvc.dll!CONFIG_HISTORY_ENTITY::SnapshotConfig(void)
    apphostsvc.dll!CONFIG_HISTORY::SnapshotConfigFilesWorkItem(void)
    apphostsvc.dll!CONFIG_HISTORY::ExecuteWorkItem(class MULTI_WORK_ITEM *)
    apphostsvc.dll!MultiWorkQueueWorkCallback(struct _TP_CALLBACK_INSTANCE *,void *)
    ntdll.dll!TppSimplepExecuteCallback()
    ntdll.dll!TppWorkerThread()
    kernel32.dll!BaseThreadInitThunk()
    ntdll.dll!RtlUserThreadStart()
    

    The function name ScanHistoryDirectory suggests it's trying to scan the history directory (duh). I suspected that some permissions were fiddled with in that directory, so I tried to reset them back to default.