记一次 某智能制造MES系统CPU 爆高分析

这篇具有很好参考价值的文章主要介绍了记一次 某智能制造MES系统CPU 爆高分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一:背景

1. 讲故事

前段时间有位朋友找到我,说他 docker 中的web服务深夜cpu被打满,让我帮忙看一下,很多朋友问docker中怎么抓dump,我一般都推荐使用 procdump 这款自动化工具,谁用谁知道,有了 dump 之后,接下来就是分析了。

二:WinDbg 分析

1. cpu 真的爆高吗

有很多朋友问 linux 上的dump可以用 windbg 分析吗?这里统一回复下,是可以的,现在的 WinDbg 可以全平台分析,不信看下图:

记一次 某智能制造MES系统CPU 爆高分析

不过有一点吐槽的是,Linux 不是微软的,所以在 操作系统层级 上的调试支持是不够的,也不是 WinDbg 能力所触及范围之内,所以相比 Windows 有很多的不便。

接下来我们用 !tp 看一下当前的 cpu 到底是多少?


0:000> !tp
CPU utilization: 393 %
Worker Thread: Total: 19 Running: 5 Idle: 10 MaxLimit: 32767 MinLimit: 4
Work Request in Queue: 0
--------------------------------------
Number of Timers: 4
--------------------------------------
Completion Port Thread:Total: 0 Free: 0 MaxFree: 8 CurrentLimit: 0 MaxLimit: 1000 MinLimit: 4

从卦中看当前的 cpu=393% ,这表示什么意思呢?在Linux上是这样的,一个核占用 100%,可以理解成当前有 4 个核被打满。

那当前 docker 中给了多少 cpu 核呢?在 Windows 平台上可以用 !cpuid,在 Linux 上肯定用不了了,没关系,熟悉 CLR 的朋友应该知道,ServerGC 的heap个数默认按照cpu 的个数来的,也就是说当前多少个heap,也就有多少个 cpu core。

有了这个思路,使用 !eeversion 来看下 gc 模式吧。


0:000> !eeversion
4.700.21.56803 (3.x runtime)
4.700.21.56803 @Commit: 28bb6f994c28bc91f09bc0ddb5dcb51d0f066806
Server mode with 4 gc heaps
SOS Version: 7.0.8.10101 retail build

从卦中的 Server mode with 4 gc heaps 来看,当前docker使用 4 个 cpu 核,所以 393% 就表示了当前被完全打满。

2. 为什么会被打满

一般来说cpu的跌宕起伏都是由 thread 诱发的,一个好的思路就是看下此时各个线程都在做什么,可以使用 ~*e !clrstack 观察,经过仔细对比发现有 4 处 SqlDataReader 貌似在读什么东西,刚好对应到了 CPU 核数,输出如下:


0:000> ~*e !clrstack
OS Thread Id: 0x3f89 (24)
        Child SP               IP Call Site
00007F9FA14A0628 00007fa4803e2a93 System.Data.SqlClient.TdsParser.TrySkipValue(System.Data.SqlClient.SqlMetaDataPriv, Int32, System.Data.SqlClient.TdsParserStateObject) [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs @ 4399]
00007F9FA14A0640 00007fa47f9a5e03 System.Data.SqlClient.TdsParser.TrySkipRow(System.Data.SqlClient._SqlMetaDataSet, Int32, System.Data.SqlClient.TdsParserStateObject) [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs @ 4334]
00007F9FA14A0670 00007fa4803d2fba System.Data.SqlClient.SqlDataReader.TryCleanPartialRead() [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs @ 760]
00007F9FA14A0690 00007fa47f99e424 System.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean, Boolean ByRef) [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs @ 3286]
00007F9FA14A06F0 00007fa4804742e5 System.Data.SqlClient.SqlDataReader+c__DisplayClass190_0.b__1(System.Threading.Tasks.Task) [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs @ 4448]
00007F9FA14A0720 00007fa480a239ea System.Data.SqlClient.SqlDataReader+c__DisplayClass194_0`1[[System.Boolean, System.Private.CoreLib]].b__0(System.Threading.Tasks.Task`1<System.Object>) [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs @ 4804]
00007F9FA14A0770 00007fa4803fa6ce System.Threading.Tasks.ContinuationResultTaskFromResultTask`2[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].InnerInvoke() [/_/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs @ 191]
00007F9FA14A07B0 00007fa4803d5551 System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) [/_/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs @ 315]
00007F9FA14A07F0 00007fa4803d1c2c System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread) [/_/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @ 2421]
00007F9FA14A0870 00007fa4803b99a9 System.Threading.ThreadPoolWorkQueue.Dispatch() [/_/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs @ 699]
00007F9FA14A0C80 00007fa4f11512df [DebuggerU2MCatchHandlerFrame: 00007f9fa14a0c80] 
OS Thread Id: 0x3f8a (25)
        Child SP               IP Call Site
00007F9FA3154580 00007fa4803bc857 System.Data.SqlClient.TdsParser.TryGetTokenLength(Byte, System.Data.SqlClient.TdsParserStateObject, Int32 ByRef) [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs @ 5889]
...
00007F9FA3154670 00007fa4803d2fba System.Data.SqlClient.SqlDataReader.TryCleanPartialRead() [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs @ 760]
00007F9FA3154690 00007fa47f99e424 System.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean, Boolean ByRef) [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs @ 3286]
...
00007F9FA3154870 00007fa4803b99a9 System.Threading.ThreadPoolWorkQueue.Dispatch() [/_/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs @ 699]
00007F9FA3154C80 00007fa4f11512df [DebuggerU2MCatchHandlerFrame: 00007f9fa3154c80] 
OS Thread Id: 0x5211 (37)
        Child SP               IP Call Site
00007F9FD2FFC570 00007fa4803bc921 System.Data.SqlClient.TdsParserStateObject.TryReadUInt16(UInt16 ByRef) [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObject.cs @ 1519]
00007F9FD2FFC580 00007fa4803bc891 System.Data.SqlClient.TdsParser.TryGetTokenLength(Byte, System.Data.SqlClient.TdsParserStateObject, Int32 ByRef) [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs @ 5889]
00007F9FD2FFC5C0 00007fa4803e2c06 System.Data.SqlClient.TdsParser.TrySkipValue(System.Data.SqlClient.SqlMetaDataPriv, Int32, System.Data.SqlClient.TdsParserStateObject) [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs @ 4399]
00007F9FD2FFC640 00007fa47f9a5e03 System.Data.SqlClient.TdsParser.TrySkipRow(System.Data.SqlClient._SqlMetaDataSet, Int32, System.Data.SqlClient.TdsParserStateObject) [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs @ 4334]
...
00007F9FD2FFC870 00007fa4803b99a9 System.Threading.ThreadPoolWorkQueue.Dispatch() [/_/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs @ 699]
00007F9FD2FFCC80 00007fa4f11512df [DebuggerU2MCatchHandlerFrame: 00007f9fd2ffcc80] 
OS Thread Id: 0x5212 (38)
        Child SP               IP Call Site
00007F9FB3FFE580 00007fa4803bc839 System.Data.SqlClient.TdsParser.TryGetTokenLength(Byte, System.Data.SqlClient.TdsParserStateObject, Int32 ByRef) [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs @ 5889]
00007F9FB3FFE5C0 00007fa4803e2c06 System.Data.SqlClient.TdsParser.TrySkipValue(System.Data.SqlClient.SqlMetaDataPriv, Int32, System.Data.SqlClient.TdsParserStateObject) [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs @ 4399]
00007F9FB3FFE640 00007fa47f9a5e03 System.Data.SqlClient.TdsParser.TrySkipRow(System.Data.SqlClient._SqlMetaDataSet, Int32, System.Data.SqlClient.TdsParserStateObject) [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs @ 4334]
00007F9FB3FFE670 00007fa4803d2fba System.Data.SqlClient.SqlDataReader.TryCleanPartialRead() [/_/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs @ 760]
...
00007F9FB3FFE7F0 00007fa4803d1c2c System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread) [/_/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @ 2421]
00007F9FB3FFE870 00007fa4803b99a9 System.Threading.ThreadPoolWorkQueue.Dispatch() [/_/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs @ 699]
00007F9FB3FFEC80 00007fa4f11512df [DebuggerU2MCatchHandlerFrame: 00007f9fb3ffec80] 

从卦中看,虽然异步写的很爽,可逆向分析起来真的是上刀山下火海。。。 接下来思路在哪里呢?可以这么想,既然是和 SqlDataReader 有关系,那就挖一挖,看看里面有什么sql。


0:025> !dso
OS Thread Id: 0x3f8a (25)
RSP/REG          Object           Name
rdx              00007fa128ad9c08 System.Data.SqlClient.SNI.TdsParserStateObjectManaged
rdi              00007fa128ad9c08 System.Data.SqlClient.SNI.TdsParserStateObjectManaged
r9               00007fa128ad9c08 System.Data.SqlClient.SNI.TdsParserStateObjectManaged
r12              00007fa128ad9c08 System.Data.SqlClient.SNI.TdsParserStateObjectManaged
r13              00007fa128ad9b70 System.Data.SqlClient.TdsParser
...
00007F9FA31546B0 00007fa3297b8fb8 System.Data.SqlClient.SqlDataReader
...

0:025> !DumpObj /d 00007fa3297b84d0
Name:        System.String
MethodTable: 00007fa477db0f90
EEClass:     00007fa477d1e230
Size:        2496(0x9c0) bytes
File:        /usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.22/System.Private.CoreLib.dll
String:      select xxx,xxx,xxx,xxx from template_xxxreport where 1=1 
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007fa477daa0e8  400022a        8         System.Int32  1 instance             1237 _stringLength
00007fa477da6f00  400022b        c          System.Char  1 instance               73 _firstChar
00007fa477db0f90  400022c      108        System.String  0   static 00007fa027fff360 Empty

从 sql 看貌似是读了 template_xxxreport 表, 而且还没有筛选条件,看样子是深夜跑什么数据把 CPU 给抬起来了,那接下里的问题是什么地方会执行这条sql呢?

3. 到底在哪里执行的

刚才的线程栈看不到一句用户代码,我们还可以用 !gcroot 追踪下这个 sql 的祖宗,可能会有新的发现哦。


0:025> !gcroot 00007fa3297b84d0
    00007F9FA3154770 00007FA4803FA6CE System.Threading.Tasks.ContinuationResultTaskFromResultTask`2[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].InnerInvoke() [/_/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs @ 191]
        rbx: 
            ->  00007FA233579680 System.Threading.Tasks.ContinuationResultTaskFromResultTask`2[[System.Object, System.Private.CoreLib],[System.Threading.Tasks.Task`1[[System.Boolean, System.Private.CoreLib]], System.Private.CoreLib]]
            ->  00007FA233579748 System.Threading.Tasks.UnwrapPromise`1[[System.Boolean, System.Private.CoreLib]]
            ...
            ->  00007FA329BE4BB0 System.Threading.Tasks.StandardTaskContinuation
            ->  00007FA329BE4B18 System.Threading.Tasks.ContinuationTaskFromResultTask`1[[System.Boolean, System.Private.CoreLib]]
            ->  00007FA329BE4AD8 System.Action`1[[System.Threading.Tasks.Task`1[[System.Boolean, System.Private.CoreLib]], System.Private.CoreLib]]
            ->  00007FA329BE2AE8 System.Data.SqlClient.SqlDataReader+<>c__DisplayClass195_0`1[[System.Boolean, System.Private.CoreLib]]
            ->  00007FA32982AE50 System.Threading.Tasks.TaskCompletionSource`1[[System.Boolean, System.Private.CoreLib]]
            ->  00007FA32982AE68 System.Threading.Tasks.Task`1[[System.Boolean, System.Private.CoreLib]]
            ->  00007FA3297B91B0 System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[xxx.xxx.Template_xxxxReport, xxx.xxx],[Dapper.SqlMapper+<QueryRowAsync>d__34`1[[xxx.xxxx.Template_xxxxReport, xxx.xxxx]], Dapper]]
            ->  00007FA3297B84D0 System.String

从引用链条看,这条sql使用 Dapper 的 QueryRowAsync 查询,实体类是 xxx.xxxx.Template_xxxxReport,有了这些信息就好办了,反馈给朋友后,让朋友看下这是哪里的sql和model。

据朋友调查后,说是用的某商业数据访问sdk 内部逻辑不严谨造成的,参考代码如下:


    public async Task<T> FindEntity<T>(object param) where T : class
    {
        //核心问题
        if (param == null)
        {
            param = new { };
        }

        var parameters = param.ToObject();

        //参数拼接
        foreach (var item in parameters)
        {
            // xxxxx
        }
    }

param =null 时,底层用 param = new { }; 当无参数处理,这就导致全表sql的发生,朋友说现在想想都有点后怕。。。

记一次 某智能制造MES系统CPU 爆高分析

三:总结

这次事故主要是由 某商业数据访问sdk 在异常参数处理时逻辑不严谨所致,毕竟 抛异常全量查询 要好得多,大家在买商业组件的时候,且行且珍惜。
记一次 某智能制造MES系统CPU 爆高分析文章来源地址https://www.toymoban.com/news/detail-440879.html

到了这里,关于记一次 某智能制造MES系统CPU 爆高分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 记一次 .NET某游戏后端API服务 CPU爆高分析

    前几天有位朋友找到我,说他们的API服务程序跑着跑着CPU满了降不下去,让我帮忙看下怎么回事,现在貌似民间只有我一个人专注dump分析,还是申明一下我dump分析是免费的,如果想学习.NET高级调试的分析技术,可以来我的训练营看看,话不多说,dump分析走起! 昨天录了一

    2024年03月21日
    浏览(30)
  • 记一次 .NET 某工厂无人车调度系统 线程爆高分析

    前些天有位朋友找到我,说他程序中的线程数爆高,让我帮忙看下怎么回事,这种线程数爆高的情况找问题相对比较容易,就让朋友丢一个dump给我,看看便知。 别人说的话不一定是真,得自己拿数据出来说话,可以用 !t 命令观察一下便知。 从卦中信息看确实有 4600+ 的线程

    2024年02月06日
    浏览(37)
  • 记一次 .NET 某车零件MES系统 登录异常分析

    这个案例有点特殊,以前dump分析都是和软件工程师打交道,这次和非业内人士交流,隔行如隔山,从指导dump怎么抓到问题解决,需要一个强大的耐心。 前几天有位朋友在微信上找到我,说他们公司采购的MES系统登录的时候出现了异常,让我帮忙看一下,我在想 解铃还须系铃

    2024年02月03日
    浏览(30)
  • 记一次 .NET某新能源MES系统 非托管泄露

    前些天有位朋友找到我,说他们的程序有内存泄露,跟着我的错题集也没找出是什么原因,刚好手头上有一个 7G+ 的 dump,让我帮忙看下是怎么回事,既然找到我了那就给他看看吧,不过他的微信头像有点像 二道贩子 ,不管到我这里是不是 三道 ,该分析的还得要分析呀。😄

    2024年02月08日
    浏览(28)
  • 【启扬方案】助力智能制造,MES系统解决方案

    近年来,智能制造席卷全球,越来越多的制造企业开始采用智能化的生产制造方式,智能工厂作为智能制造的核心之一,成为了制造业发展的重要趋势之一。然而,要实现智能工厂的建设,需涵盖从生产计划、生产调度到生产执行等全过程的管理和控制,这就需要一种集成化

    2024年02月07日
    浏览(26)
  • 亿发数字化生产工厂MES管理系统,助力云南工厂实现智能制造

    近年来,云南省将制造业数字化作为“工业强省”战略的关键和打造现代产业体系的重中之重,而随着工业4.0时代的来临,数字化转型已成为制造企业企业蓬勃发展之路。在这个过程中,MES精益制造管理系统显露出潜力,成为云南省实现智能工厂的关键部分。 接下来,本文将

    2024年02月15日
    浏览(33)
  • 记一次 .NET某MES自动化桌面程序 卡死分析

    前些天有位朋友在微信上找到我,说他们的客户端程序卡死了,让我帮忙看下是什么原因导致的?dump也拿到了手,既然有了dump就开始正式分析吧。 客户端的程序卡死比较好找原因,入手点就是主线程,看下它此时正在做什么,可以用 k 命令。 从卦中信息看,代码正在托管层

    2024年01月16日
    浏览(32)
  • 智能家电制造MES工厂数据采集物联网解决方案

    家电制造的MES工厂在建设数据采集物联网系统时,会面对到生产线上的设备数量多且型号不统一、网络条件复杂且协议多样等痛点。通过搭建5G工业物联网系统所具备的高带宽、低时延、广泛接入等优势,能够保证数据高速传输与控制指令及时下发,;此外,通过边缘计算网

    2024年02月20日
    浏览(32)
  • 记一次javaMetaspace导致CPU200%的排查

    insertMotionDataByWxCallBack方法并发多(其实也没多少,可能就3个?)就导致CPU200%了,本地没法复现。 看报错是:java.lang.OutOfMemoryError: Metaspace,刚开始的时候眼挫,忽略了后面的Metaspace,只看到了OutOfMemoryError,就各种找代码问题。 https://arthas.aliyun.com/doc/install-detail.html 然后发现

    2023年04月24日
    浏览(40)
  • 食品制造行业云MES系统解决方案

    食品饮料行业大致可以分为初级产品加工、二次加工、食品制造、食品分装、调味品和饲料加工等几大类。由于处于产业链不同的位置,其管理存在一定的差异,那么食品行业的MES应该怎么建设呢? 食品饮料行业生产管理特点: 食品饮料行业大致可以分为初级产品加工、二

    2024年02月11日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包