• 记一次 .NET 某车零件MES系统 登录异常分析


    一:背景

    1. 讲故事

    这个案例有点特殊,以前dump分析都是和软件工程师打交道,这次和非业内人士交流,隔行如隔山,从指导dump怎么抓到问题解决,需要一个强大的耐心。

    前几天有位朋友在微信上找到我,说他们公司采购的MES系统登录的时候出现了异常,让我帮忙看一下,我在想解铃还须系铃人,怎么的也不应该找到我呀,据朋友反馈项目已经验收,那边给了回馈是网络的问题,可能没有帮他们更深入的分析吧,找我的目的应该就是验证下对方公司说的对不对 😂😂😂

    二:WinDbg 分析

    1. 真的是网络问题吗

    在没有项目源代码和日志的情况下,最好的方式就是抓dump,一样可以找出问题所在,让朋友在程序登录卡死的时候抓了一个dump,接下来看下是不是对方工程师所说的网络问题。

    因为有卡死发生,必然有一个线程在等待什么,我们可以用 ~*e !clrstack 看下所有的线程的线程栈。

    
    0:000:x86> ~*e !clrstack
    ...
    OS Thread Id: 0x2094 (14)
    Child SP       IP Call Site
    0f94e888 0000002b [GCFrame: 0f94e888] 
    0f94e938 0000002b [HelperMethodFrame_1OBJ: 0f94e938] System.Threading.Monitor.ObjWait(Boolean, Int32, System.Object)
    ...
    0f94ead0 6b53d7b6 System.Threading.Tasks.Task.Wait(Int32, System.Threading.CancellationToken) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 3167]
    0f94eae0 1468ae6b MySql.Data.Common.Ssl.StartSSL(System.IO.Stream ByRef, System.Text.Encoding, System.String)
    0f94eb38 14687a55 MySql.Data.MySqlClient.NativeDriver.Open()
    0f94ec04 14686e63 MySql.Data.MySqlClient.Driver.Open()
    0f94ec28 14686ac7 MySql.Data.MySqlClient.Driver.Create(MySql.Data.MySqlClient.MySqlConnectionStringBuilder)
    0f94ec50 146869ec MySql.Data.MySqlClient.MySqlPool.CreateNewPooledConnection()
    0f94ec58 14686957 MySql.Data.MySqlClient.MySqlPool.GetPooledConnection()
    0f94ec8c 146863e9 MySql.Data.MySqlClient.MySqlPool.TryToGetDriver()
    0f94ecac 146862ca MySql.Data.MySqlClient.MySqlPool.GetConnection()
    0f94ece0 146817c1 MySql.Data.MySqlClient.MySqlConnection.Open()
    0f94ed18 0ca28753 xxx.GetMySqlConnection()
    ...
    0f94efec 0ca21902 xxx.UserLogin(System.String, System.String)
    ...
    0f94f4ac 6b4ae9db System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 1161]
    0f94f6cc 6c500556 [DebuggerU2MCatchHandlerFrame: 0f94f6cc] 
    ...
    
    

    通过观察发现 14 号线程在一个 xxx.UserLogin 方法中,应该就是朋友点击的登录按钮的逻辑,通读一下线程栈可以看到它是在 MySql.Data.Common.Ssl.StartSSL 方法中等待,看样子是在这里超时了。

    一般来说 mysql 是内网的话,不会特别去配什么 ssl 证书,这个太麻烦了,接下来验证下 mysql 是内网还是外网,可以用 !dso 查看mysql 的连接串。

    从上面的 192.168 前缀来看果然是内网,这时候猜测走 SSL 肯定是意料之外的场景。

    2. 真的要走 SSL

    记得大概3-4年前在上海上班的时候,曾经有一个项目升级之后使用了nuget上的 mysql 8.0,然后项目就无法访问了,报了什么授权错误,看样子应该就是目前这个项目遇到的场景。

    接下来要验证下这个 mysql 的sdk 是 8.0 的版本吗? 可以用 lm 找下 MySQL.Data 模块。

    
    0:014:x86> lm
    start    end        module name
    ...
    12b40000 12ca6000   MySql_Data   (deferred)    
    ...
    
    0:014:x86> lm vm MySql_Data
    Browse full module list
    start    end        module name
    12b40000 12ca6000   MySql_Data   (deferred)             
        Image path: C:\Users\xxxx\MySql.Data.dll
        Image name: MySql.Data.dll
        Browse all global symbols  functions  data
        Has CLR image header, track-debug-data flag not set
        Image was built with /Brepro flag.
        Timestamp:        95CE4983 (This is a reproducible build file hash, not a timestamp)
        CheckSum:         001611FF
        ImageSize:        00166000
        File version:     8.0.29.0
        Product version:  8.0.29.0
        File flags:       0 (Mask 3F)
        File OS:          4 Unknown Win32
        File type:        2.0 Dll
        File date:        00000000.00000000
        Translations:     0000.04b0
        Information from resource tables:
            CompanyName:      Oracle
            ProductName:      MySql.Data.Core
            InternalName:     MySql.Data.dll
            OriginalFilename: MySql.Data.dll
            ProductVersion:   8.0.29
            FileVersion:      8.0.29.0
            FileDescription:  MySql.Data
            LegalCopyright:   Copyright © 2016, 2020, Oracle and/or its affiliates. All rights reserved.
            LegalTrademarks:  
            Comments:         ADO.Net driver for MySQL for .Net Framework and .Net Core
    
    

    从上面的 Product version 来看果然是 8.0 版本,验证了我的猜想,接下来就是让朋友在连接串中加上 SslMode=None 标记,类似下面这样。

    
    <add key="上报平台1" value="mysql|Database = drp; Data Source = 192.168.xx.xx; port = 3306; User Id = xxx; Password = xxx;SslMode=None" />
    
    

    把结果告诉朋友之后,朋友第二天反馈问题搞定。

    不过他做了一个大胆的操作,禁用了 MySQL 的 hava_openssl

    说实话这个影响面太大了,副作用小一点的话加上一个后缀就好,不管怎么样解决了问题就行。

    三:总结

    总的来说这个问题对一个开发来说很简单,但如果沟通对象是一个非开发,没有源码,没有日志 还能准确定位问题,是一件挺有挑战的事情。

    图片名称
  • 相关阅读:
    《嵌入式虚拟化技术与应用》:深入浅出阐述嵌入式虚拟机原理,实现“小而能”嵌入式虚拟机!
    深入理解Java虚拟机:Jvm性能调优
    中间件MQ面试题之Rabbitmq
    图论——基础概念
    972信息检索 | 第八章 移动搜索
    WPF编程宝典:使用C# 2012和.NET 4.5 第4版---1.4 WPF体系结构
    单窗口单IP适合炉石传说游戏么?
    给网页添加背景音乐
    SLAM从入门到精通(ROS和底盘Stm32的关系)
    操作系统(2)进程管理(上)进程与线程
  • 原文地址:https://www.cnblogs.com/huangxincheng/p/17380634.html