云计算之路-阿里云上:“黑色1秒”最新线索——w3tp与w3dt
向大家分享一下最近排查“黑色1秒”问题的进展,“黑色1秒”的问题表现详见什么是黑色1秒。
1. 发生在w3wp进程内
判断依据:“黑色1秒”期间,http.sys的HTTP Service Request Queues\ArriveRate正常,W3SVC_W3WP\Requests/Sec正常。
2. 请求未进入.NET线程池
判断依据:“黑色1秒”期间静态文件的请求也不能被处理,如果“黑色1秒”发生在.NET线程执行过程中,静态文件是由非托管模块处理的,应该不受影响。
3. 发生在处于user-mode的IIS核心模块
http.sys处于kernel-mode,处于user-mode的处理请求的IIS核心模块有:w3tp->w3dt->iiscore->webengine->wbhst_pm,在C:\Windows\System32\inetsrv中都有对应的dll文件。
IIS核心模块请求处理流程如下(自下而上,来自application pool crashes in IIS 7.5):
clr!ClrCreateManagedInstance webengine4!LegacyActivationShim::ClrCreateManagedInstance webengine4!GetIsapiProcessHost webengine!GetIsapiProcessHost wbhst_pm wbhst_pm!GetProtocolManager w3wphost!AppHostInitialize w3wphost!IPM_MESSAGE_PIPE::operator= iiscore!W3_SERVER::GetProtocolManagerCustomInterface webengine4!InitClrHost webengine4!CMgdEngGlobalModule::OnGlobalApplicationResolveModules iiscore!VIRTUAL_MODULE::GlobalDoWork iiscore!W3_SERVER::GlobalNotify iiscore!W3_APPLICATION::ResolveModules iiscore!W3_APPLICATION::SetupNotificationContext iiscore!W3_CONTEXT::SetupStateMachinePhase2 iiscore!W3_CONTEXT::SetupStateMachine iiscore!W3_MAIN_CONTEXT::StartNotificationLoop iiscore!W3_MAIN_CONTEXT::OnNewRequest w3dt!UL_NATIVE_REQUEST::DoStateProcess w3dt!UL_NATIVE_REQUEST::DoWork w3dt!OverlappedCompletionRoutine w3tp!THREAD_POOL_DATA::ThreadPoolThread w3tp!THREAD_MANAGER::ThreadManagerThread
4. w3tp与w3dt
w3tp(w3 thread pool)是IIS的线程池,在注册表(HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\InetInfo\Parameters)中有一个设置项ThreadPoolStartDelay,默认值是1秒。
ThreadPoolStartDelay is how long the thread pool should set the timer for when zero threads are waiting on the completion port.
如果有线程在等待完成端口,是这样的情况(以下截图来自Process Explorer):
w3dt(可能是w3 data transfer的缩写)是一个完成端口(Completion Port)处理程序,从http.sys的队列(kernel-mode)中将请求取出至w3wp进程(user-mode)的本地队列。
5. 猜想
在w3dt将请求从http.sys的队列搬至w3wp本地队列后,本应触发iiscore!W3_MAIN_CONTEXT::OnNewRequest;可是这时某种未知原因(怀疑是CPU的原因)造成w3tp认为"zero threads are waiting on the completion port",将Timer频率改为了1秒,结果1秒后才触发OnNewRequest,将队列中请求转交至后续处理环节;而在这1秒期间,ASP.NET由于没有收到请求,于是QPS为0。
感慨:网上关于IIS核心模块的资料实在太少了,IIS又不开源,只能靠“蒙猜试”了。