找回密码
 立即注册
首页 业界区 业界 记一次 .NET 某人力资源网 CPU爆高分析

记一次 .NET 某人力资源网 CPU爆高分析

卢铃语 昨天 09:47
一:背景

1. 讲故事

前段时间微信里有一位非训练营学员找到我,说他们的系统在某些时段会cpu爆高,并伴有网络带宽的激增,不知道是什么情况,让我帮忙看下怎么回事,哈哈,说这个故障之前,我先吐槽一下,地狱不空,在社区里我一个人的力量太微弱了,这5年来我给行业内开发朋友都是全免费分析,这也让自己不堪重负,不得不考虑收缩,目前非学员首单免费,也只有我的训练营学员才会永久免费分析。给自己的学员分析dump还是比较轻松的,毕竟大家都是有一定的调试体系知识,同根同源。
吐槽完毕,开始本篇的dump分析之旅。
二:CPU爆高分析

1. 为什么会cpu爆高

关于cpu爆高的dump,最好用procdump自动去抓,因为在我的分析之旅中,有不少人手工去抓cpu爆高往往都不大准,还有一点一定要相信数据而不是人言,使用 !tp 观察cpu的利用率。
  1. 0:000> !tp
  2. CPU utilization: 100%
  3. Worker Thread: Total: 20 Running: 5 Idle: 7 MaxLimit: 32767 MinLimit: 12
  4. Work Request in Queue: 0
  5. --------------------------------------
  6. Number of Timers: 2
  7. --------------------------------------
  8. Completion Port Thread:Total: 1 Free: 1 MaxFree: 24 CurrentLimit: 1 MaxLimit: 1000 MinLimit: 12
复制代码
从卦中看确实cpu被打爆,恰好昨天分析了一个 .net2.0 的dump,可气的是没有 !tp 命令,这就非常考验我们的clr知识了,需要知道 CPU utilization 这个值 sos 是从哪里取得的?如果你看过sscli源代码,应该知道它是 win32threadpool.cpp 的一个全局变量。
  1. SVAL_IMPL(long,ThreadpoolMgr,cpuUtilization);
复制代码
接下来用 windbg 验证下。
  1. 0:000> x  clr!ThreadpoolMgr::cpuUtilization
  2. 00007ffb`08541558 clr!ThreadpoolMgr::cpuUtilization = <no type information>
  3. 0:000> dp clr!ThreadpoolMgr::cpuUtilization L1
  4. 00007ffb`08541558  00000000`00000064
  5. 0:000> ? 0x64
  6. Evaluate expression: 100 = 00000000`00000064
复制代码
从卦中看完全对上了,所以dump分析多了,不能对 sos 有太多的依赖。
接下来我们看下cpu的能力,因为自我分析过2core cpu程序之后,我对cpu的健壮性一直都非常好奇,有时候cpu爆高不是业务问题,是 cpu 真的太弱了,接下来使用 !cpuid 观察便知。
  1. 0:000> !cpuid
  2. CP  F/M/S  Manufacturer     MHz
  3. 0  6,85,7  <unavailable>   2500
  4. 1  6,85,7  <unavailable>   2500
  5. 2  6,85,7  <unavailable>   2500
  6. 3  6,85,7  <unavailable>   2500
  7. 4  6,85,7  <unavailable>   2500
  8. 5  6,85,7  <unavailable>   2500
  9. 6  6,85,7  <unavailable>   2500
  10. 7  6,85,7  <unavailable>   2500
  11. 8  6,85,7  <unavailable>   2500
  12. 9  6,85,7  <unavailable>   2500
  13. 10  6,85,7  <unavailable>   2500
  14. 11  6,85,7  <unavailable>   2500
复制代码
从卦中看当前是一个 8core 的cpu,能力方面还算说的过去,接下来使用 ~*e !clrstack 观察下每个线程都在做什么?
  1. 0:000> ~*e !clrstack
  2. OS Thread Id: 0x77fc (0)
  3. Unable to walk the managed stack. The current thread is likely not a
  4. managed thread. You can run !threads to get a list of managed threads in
  5. the process
  6. Failed to start stack walk: 80070057
  7. ...
  8. OS Thread Id: 0x74c4 (58)
  9.         Child SP               IP Call Site
  10. 0000002f9c85e4c8 00007ffb14ea058a [HelperMethodFrame_1OBJ: 0000002f9c85e4c8] System.Threading.Thread.JoinInternal(Int32)
  11. 0000002f9c85e5d0 00007ffb06def9fe System.Threading.Thread.Join(System.TimeSpan) [f:\dd\ndp\clr\src\BCL\system\threading\thread.cs @ 701]
  12. 0000002f9c85e610 00007ffaaaa62f42 FreeRedis.Internal.IdleBus`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].ThreadJoin(System.TimeSpan)
  13. 0000002f9c85e6d0 00007ffaaaa62422 FreeRedis.Internal.IdleBus`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].ThreadScanWatchHandler()
  14. ...
  15. OS Thread Id: 0x6618 (63)
  16.         Child SP               IP Call Site
  17. 0000002f9bffcff8 00007ffb14ea001a [InlinedCallFrame: 0000002f9bffcff8] System.Net.UnsafeNclNativeMethods+OSSOCK.recv(IntPtr, Byte*, Int32, System.Net.Sockets.SocketFlags)
  18. 0000002f9bffcff8 00007ffb057310b2 [InlinedCallFrame: 0000002f9bffcff8] System.Net.UnsafeNclNativeMethods+OSSOCK.recv(IntPtr, Byte*, Int32, System.Net.Sockets.SocketFlags)
  19. 0000002f9bffcfd0 00007ffb057310b2 DomainNeutralILStubClass.IL_STUB_PInvoke(IntPtr, Byte*, Int32, System.Net.Sockets.SocketFlags)
  20. 0000002f9bffd080 00007ffb056ae48f System.Net.Sockets.Socket.Receive(Byte[], Int32, Int32, System.Net.Sockets.SocketFlags, System.Net.Sockets.SocketError ByRef) [f:\dd\NDP\fx\src\net\System\Net\Sockets\Socket.cs @ 1780]
  21. 0000002f9bffd100 00007ffb056ac845 System.Net.Sockets.NetworkStream.Read(Byte[], Int32, Int32) [f:\dd\NDP\fx\src\net\System\Net\Sockets\NetworkStream.cs @ 513]
  22. 0000002f9bffd170 00007ffb056ac6b1 System.Net.PooledStream.Read(Byte[], Int32, Int32) [f:\dd\NDP\fx\src\net\System\Net\_PooledStream.cs @ 469]
  23. 0000002f9bffd1d0 00007ffb056ad4a1 System.Net.Connection.SyncRead(System.Net.HttpWebRequest, Boolean, Boolean) [f:\dd\NDP\fx\src\net\System\Net\_Connection.cs @ 3346]
  24. 0000002f9bffd230 00007ffb056d07bb System.Net.ConnectStream.ProcessWriteCallDone(System.Net.ConnectionReturnResult) [f:\dd\NDP\fx\src\net\System\Net\_ConnectStream.cs @ 450]
  25. 0000002f9bffd270 00007ffb056c4ea9 System.Net.HttpWebRequest.CheckDeferredCallDone(System.Net.ConnectStream) [f:\dd\NDP\fx\src\net\System\Net\HttpWebRequest.cs @ 2109]
  26. ...
复制代码
从卦象中看,只有几个线程有调用栈,并且大多都挂在 event 事件上,这些并不能导致 cpu 爆高,这就让人很迷茫了,难道这个也是手工抓取的不准吗?
2. 走出迷雾

在思考了若干秒之后,马上就意识到既然托管层没问题,或许非托管有问题呢?毕竟 ~*e !clrstack 是一个肌肉记忆命令,接下来使用 ~* k 观察各个非托管栈,果然发现有多处 ipFilter 外来模块,截图如下:
1.png

从卦中看 ipFilter 貌似是一个 ip过滤器,正在忙碌的处理,看样子正在高频计算导致的cpu临时性爆高,那 ipFilter 是何方神圣呢?使用 lmvm ipFilter 观察一下便知。
  1. 0:079> lmvm ipFilter
  2. Browse full module list
  3. start             end                 module name
  4. 00007ffb`041c0000 00007ffb`041f0000   ipFilter   (export symbols)       ipFilter.dll
  5.     Loaded symbol image file: ipFilter.dll
  6.     Image path: D:\软件\安全软件\YunSuoAgent\x64\ipFilter.dll
  7.     Image name: ipFilter.dll
  8.     Browse all global symbols  functions  data
  9.     Timestamp:        Wed Feb  5 19:14:48 2020 (5E3AA3A8)
  10.     CheckSum:         000367C5
  11.     ImageSize:        00030000
  12.     Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4
  13.     Information from resource tables:
复制代码
接下来拿 YunSuoAgent 到 bing上搜一下,原来是 云锁 这款安全软件,截图如下:
2.png

3. 云锁为什么会拦截

云锁为什么会拦截,这个真搞不清楚,只能简单猜测下,拿其中的 79号线程 具体来说,使用 k 和 !dso 命令。
  1. 0:079> k
  2. # Child-SP          RetAddr               Call Site
  3. 00 0000002f`915ed080 00007ffb`041c89a7     ipFilter+0x12bd
  4. 01 0000002f`915ed0b0 00007ffb`041c81ab     ipFilter+0x89a7
  5. 02 0000002f`915ed130 00007ffb`041c87e9     ipFilter+0x81ab
  6. 03 0000002f`915ed350 00007ffb`041c3298     ipFilter+0x87e9
  7. 04 0000002f`915ed440 00007ffb`041c9050     ipFilter+0x3298
  8. 05 0000002f`915ed5b0 00007ffb`041c920d     ipFilter+0x9050
  9. 06 0000002f`915ed670 00007ffb`043201de     ipFilter+0x920d
  10. 07 0000002f`915ed6c0 00007ffb`04320219     FilterKernel+0x501de
  11. 08 0000002f`915ed730 00007ffb`04320219     FilterKernel+0x50219
  12. 09 0000002f`915ed7a0 00007ffb`04330c92     FilterKernel+0x50219
  13. 0a 0000002f`915ed810 00007ffb`044f4524     FilterKernel+0x60c92
  14. 0b 0000002f`915ed850 00007ffb`045a297f     agent_iis7_module!RegisterModule+0x1594
  15. ...
  16. 0:079> !dso
  17. OS Thread Id: 0x74e4 (79)
  18. RSP/REG          Object           Name
  19. 0000002F915ED9B8 0000002e062ccb60 System.Web.HttpContext
  20. 0000002F915ED9C0 0000002e062cc800 System.Web.Hosting.IIS7WorkerRequest
  21. 0000002F915EDEE8 0000002e062d0558 System.String    /WebResource.axd
  22. 0000002F915EDF00 0000002d058ed588 ASP.global_asax
  23. 0000002F915EDF08 0000002d058ed588 ASP.global_asax
  24. 0000002F915EDF20 0000002e062d0558 System.String    /WebResource.axd
  25. 0000002F915EDF40 0000002e062d0558 System.String    /WebResource.axd
  26. ...
复制代码
从卦中可以看到 ipFilter.dll 是注册到 iis 的一个 httpmodule,同时也看到了一个比较特殊的 /WebResource.axd 文件,熟悉 asp.net 的朋友应该知道,它其实是一个 httphandler,专用来动态产生 css,js 资源的,不需要将 css,js 放到物理文件中,在网上也有很多关于 /WebResource.axd 的漏洞注入案例,所以这东西是 ipfilter 的重点监控之处,不过直接导致 cpu 爆高,这就有点让人无语了。
将结果告诉朋友之后,让朋友将 云锁 关掉,CPU 终于下去了。
三:总结

今年遇到了好几起 安全软件 导致的各种问题,内存泄露,程序卡死,程序崩溃,以及本篇的 CPU 爆高,也是无语了。。。
3.jpeg

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册