我们现在具体分析,为何客户端发送账号,驱动版本,操作系统信息到数据库端这么慢。这部分的代码在Connector/NET MySQLAuthenticationPlugin.cs文件中。 我们修改这部分代码,进行时间埋点,来进一步定位问题。下面是根据时间埋点,打印出来的跟踪信息。
从跟踪的Trace来看,有30秒左右的操作延时。返回MySQLDefs::OSDetails的时候。这部分代码如下:
[DisplayName("_os_details")]public string OSDetails
{
get
{
string os = string.Empty;
try
{
var searcher = new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem");
var collection = searcher.Get();
foreach (var mgtObj in collection)
{
os = mgtObj.GetPropertyValue("Caption").ToString();
break;
}
}
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); }
return os;
}
}
这段代码是通过WMI查询,来获得Caption信息。也就是操作系统的版本信息。由于是WMI调用,所以依赖的关系比较多。
【问题验证】我们把这段代码抽出来。下面是一段简短的Repro代码:
static void Main(string[] args){
Stopwatch watch = new Stopwatch();
while (true)
{
watch.Restart();
var searcher = new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem");
var collection = searcher.Get();
foreach (var mgtObj in collection)
{
string os = mgtObj.GetPropertyValue("Caption").ToString();
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);
if (watch.ElapsedMilliseconds >= 1000)
{
Console.WriteLine("-------------");
File.AppendAllText("abc.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") +","+ watch.ElapsedMilliseconds + "\r\n");
}
}
}
在有问题的应用服务器上,我们运行上述代码,确实可以发现WMI查询有超时:下面这些点是我们抓到的超过30秒的点:
2017-11-21 17:19:30.208, 336382017-11-21 17:20:09.193, 33199
2017-11-21 17:20:53.086, 33201
2017-11-21 17:27:05.114, 32976
2017-11-21 17:28:19.178, 33635
2017-11-21 17:30:07.130, 65977
2017-11-21 17:30:49.051, 40478
2017-11-21 17:31:15.126, 26072
2017-11-21 17:38:16.048, 66671
2017-11-21 17:38:49.204, 33152
2017-11-21 17:39:53.161, 33828
2017-11-21 17:40:38.121, 33549
2017-11-21 17:47:09.179, 33775
2017-11-21 17:47:57.174, 33164
【解决思路】
WMI查询慢,可能是由于多种原因所致。如操作系统CPU高,或者查询本身有死锁。这个问题有待于进一步分析。但看代码,我们知道做这个WMI查询,只是为了获得操作系统的信息。这个信息完全可以缓存起来。而不必要每次连接的时候,去进行WMI查询。
此处确定该错误的根本原因在于MySQL的C# connector中对操作系统信息的获取时间过久,导致触发服务器的连接超时。注释掉该部分(可能导致长时间的操作),进行进一步的验证,再无任何的超时错误出现。
public string OSDetails { get { dbglog.dolog("MysqlDefs::OSDetails1"); string os = string.Empty; /*try { var searcher = new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem"); var collection = searcher.Get(); foreach (var mgtObj in collection) { os = mgtObj.GetPropertyValue("Caption").ToString(); dbglog.dolog(String.Format("MysqlDefs::OSDetails::foreach{0}", os.ToString())); break; } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); }*/ dbglog.dolog("MysqlDefs::OSDetails2"); return os; } }Linux公社的RSS地址:https://www.linuxidc.com/rssFeed.aspx