一:背景

1. 讲故事

上一篇跟大家聊到了 UI Freeze 的问题,让大家感受到了时间轴的强大和美观,这个是 perfview 所不具备的,本篇跟大家聊一下用 dottrace 诊断Windows子系统模块(File,SQL),虽然perfivew也能做这些,毕竟都是基于ETW机制,但前者占据了可观性,后者占据了信息的完整性,大家在实践上根据需要综合使用吧。

二:子系统模块诊断

1. 如何寻找 慢File

有一天你发现自己的生产程序有一段时间特别卡,一时也找不到原因,后来你通过监控发现程序在卡的时候,磁盘使用量明显变高,读取达到了 125M+/s ,截图如下:

找到了蛛丝马迹之后,接下来就可以上 dottrace 了,为了防止信息有遗漏,我们选用 External .NET Process 模式,然后输入我们监控的 ConsoleApp4.exe程序, 即程序后启动模式,截图如下:

故障复现之后可立即停止收集,打开收集文件,选择 File Operations 之后观察时间轴,可以看到主线程上有大片的深蓝色,说明3~22s这个时间段有大量的文件读写,接下来选中这个时间段,截图如下:

从卦象上可以看到很多信息。

  • SubSystems:File I/O 占比 99.9%
  • Direction: 只有读没有写,看样子读很猛。
  • FileName:原来是对 1GB_LogFile.log 文件的读取。
  • Hotspots:TestInefficientReading 方法占比 99.9%,问题方法无疑了。

找到问题方法之后,在方法上右键选择 Show Code 即可观察到源代码,参考如下:


static void TestInefficientReading(string filePath)
{
Stopwatch sw = Stopwatch.StartNew();
long totalBytesRead = 0; // 最差的实现方式:逐字节读取
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
int b;
while ((b = fs.ReadByte()) != -1) // 逐字节读取
{
totalBytesRead++;
}
} sw.Stop();
Console.WriteLine($"\n低效方式读取完成,总字节数: {totalBytesRead}");
Console.WriteLine($"总耗时: {sw.Elapsed.TotalSeconds:F2}秒");
Console.WriteLine($"读取速度: {(totalBytesRead / (1024 * 1024) / sw.Elapsed.TotalSeconds):F2} MB/s");
}

从卦中代码看,这是对文件按逐字节读取的方式,有些朋友可能有疑问,现在的 SSD 读取不都是 几G几G 的读取吗?怎么才1G的文件要读取 5.8s,说不通哈,其实这里还有一些干扰因素,第一个是SSD都有理论值,第二个是dottrace在开启ETW时会有额外开销,不然你的诊断数据从哪里得来的?

接下来关掉 ETW,直接运行程序,你会发现程序有 近3倍 的提升,截图如下:

2. 如何诊断慢 SQL

很多时候做程序的性能优化,有一个不容忽视的点就是观察下程序没有没出现一些慢SQL,慢SQL的危害很多,如果是同步访问容易引发线程饥饿,如果是异步访问容易导致托管堆产生过多的 Overlapped 引发托管堆碎片,进而导致内存占用过高,内存过高又会引发程序频繁的GC,最终导致程序的性能低下,有一句话叫 蝴蝶效应,就是这样的真实再现。。。

接下来就是如何诊断慢SQL,如果在 SERVER 端直接开启那这个影响面就比较大,谨慎起见还是在 Client 端临时开启来点对点的针对优化,当然这东西的本质也是借助 ETW 的,而这个 ETW 只针对微软自家的 SQL SERVER,这个是有些遗憾。。。

使用 dottrace 的 timeline 模式,打开追踪文件,选择 SQL Queries 事件,观察多个线程之间的时序,看样子 SQL 都是异步哈,截图如下:

为了寻找慢SQL,观察 SQL Queries: Command 筛选器中的SQL列表,很快就找到了一个 2s 的SQL,同时也看到了它是由 FullTableScanAsync 方法产生的,截图如下:

可以点击右键 Show Code 观察方法的源代码,参考如下:


static async Task FullTableScanAsync(SqlConnection connection)
{
var cmd = new SqlCommand(
@"-- 添加2秒延迟
WAITFOR DELAY '00:00:02'; SELECT *
FROM Orders
WHERE OrderStatus = 'Processing'
ORDER BY OrderDate DESC", connection); using (var reader = await cmd.ExecuteReaderAsync())
{
int count = 0;
while (await reader.ReadAsync())
{
count++;
if (count % 100 == 0) Console.Write(".");
}
Console.WriteLine($"\n找到 {count} 条处理中的订单");
}
}

到这里可能有人会提一个问题, Command 面板中的 SQL 是截断的,我想观察 SQL 的全貌怎么办?毕竟这是真实项目的切实需求,可以点击 View -> SQL Queries 打开,找到目标SQL之后可以copy出来,截图如下:

三:总结

用 dottrace 对程序做性能优化,效率其实还是蛮高的,而且对容易引发性能瓶颈的IO和SQL这两大模块也处理的非常好,点赞!

作为JetBrains社区内容合作者,如有购买jetbrains的产品,可以用我的折扣码 HUANGXINCHENG,有25%的内部优惠哦。

DotTrace系列:5. 诊断程序的 慢File 和 慢SQL的更多相关文章

  1. 安装SQL2008时遇到"未能加载文件或"file:///d:microsoft..sql.chainer.packagedata.dll"或它的某个依赖项

    安装SQL2008时遇到"未能加载文件或"file:///d:microsoft..sql.chainer.packagedata.dll"或它的某个依赖项,如下图所示 ...

  2. Spring Boot干货系列:(八)数据存储篇-SQL关系型数据库之JdbcTemplate的使用

    Spring Boot干货系列:(八)数据存储篇-SQL关系型数据库之JdbcTemplate的使用 原创 2017-04-13 嘟嘟MD 嘟爷java超神学堂 前言 前面几章介绍了一些基础,但都是静 ...

  3. Stream系列(十五)File方法使用

    文件读写 视频讲解:https://www.bilibili.com/video/av78612785/ EmployeeTestCase.java package com.example.demo; ...

  4. 搞懂前端二进制系列(二):🍈File、FileReader与Base64

    参考资料: JavaScript高级程序设计第四版:File API https://juejin.cn/post/7046313942938812424[前端二进制一次搞清楚] 一.File 类型 ...

  5. [每天解决一问题系列 - 0002] Xcopy cannot copy file with long directory

    现象: 当xcopy的文件的全名(包括目录和文件名)的长度超过255字符时,会copy失败,得到insufficient memory错误 解决方法: 在Server 版的OS中,有robcopy命令 ...

  6. 《Entity Framework 6 Recipes》中文翻译系列 (12) -----第三章 查询之使用SQL语句

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-2使用原生SQL语句更新 问题 你想在实体框架中使用原生的SQL语句,来更新底层 ...

  7. 数据分页处理系列之一:Oracle表数据分页检索SQL

      关于Oracle数据分页检索SQL语法,网络上比比皆是,花样繁多,本篇也是笔者本人在网络上搜寻的比较有代表性的语法,绝非本人原创,贴在这里,纯粹是为了让"数据分页专题系列"看起 ...

  8. Pyspark中遇到的 java.io.IOException: Not a file 和 pyspark.sql.utils.AnalysisException: 'Table or view not found

    最近执行pyspark时,直接读取hive里面的数据,经常遇到几个问题: 1.  java.io.IOException: Not a file —— 然而事实上文件是存在的,是 hdfs 的默认路径 ...

  9. MySql系列:中文写入数据库出现错误java.sql.SQLException: Incorrect string value: '\xE5\xxxx' for column 'xxxx' at row 1及其解决方法

    在将kft-activiti-demo的数据库连接改为mysql之后,可以正常登陆,但是在新建请假流程的时候出现如下错误:   Caused by: java.sql.SQLException: In ...

  10. MySQL学习系列一---命令行连接mysql和执行sql文件

    1.命令行连接mysql #mysql -h(主机) -u(用户名) -p (数据库名) mysql -hlocalhost -uroot -p testdb Enter password: **** ...

随机推荐

  1. emlog 制作一个小插件(截取正文生成 xx 字摘要)的过程

    blockquote { background: rgba(255, 255, 0, 1); color: rgba(255, 0, 0, 1) !important } 如果熟悉其他 PHP 平台的 ...

  2. Wyn商业智能V8.0 Update1版本发布

    智启未来,Wyn商业智能V8.0 Update1版本深度融合AI技术.工业物联网与数据工程能力,带来三大核心亮点及100+新特性,致力于为企业打造全场景智能分析平台,助力构建从数据加工到智能决策的全链 ...

  3. VSCode 中 Json 文件介绍

    Visual Studio Code 官方文档 1. Json 配置文件 Editing JSON with Visual Studio Code settings.json 分类 defaultse ...

  4. Python 潮流周刊#95:像人类一样使用计算机(摘要)

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  5. 浅谈Ubuntu中的软件包

    1. 前言 还记得大学第一次接触Ubuntu和Linux的时候,觉得用apt安装想要的软件非常方便.但是有时候出现了问题,各种报错,自己又不懂原理,就会非常抓狂.现在稍微理解一点了,故以较为容易理解的 ...

  6. 使用Nginx反向代理本地服务(无固定公网IP通过端口映射公开的服务)的坑

    使用Nginx反向代理本地服务(无固定公网IP通过端口映射公开的服务)的坑 前言:之前公司的服务器都是云服务器,性能比较差,而我们有一些内部使用的系统和极少数外部用户使用的系统,对资源有一定的要求,也 ...

  7. Codeforces Round 971 (Div. 4)

    C. The Legend of Freya the Frog 因为是从x开始跳,贪心的取肯定是直接用max(a,b)/d向上取整然后再乘2,但是要注意,如果再x到达之前,y已经是到达了,也就是某次以 ...

  8. JMeter跨线程传参总结

  9. Redis 持久化——混合持久化

    1.Redis 持久化--混合持久化 RDB 和 AOF 持久化各有利弊,RDB 可能会导致一定时间内的数据丢失,而 AOF 由于文件较大则会影响 Redis 的启动速度,为了能同时使用 RDB 和 ...

  10. 【李宏毅机器学习笔记】生成式对抗网络GAN

    [ 李宏毅机器学习]生成式对抗网络GAN 在传统的神经网络任务中,我们通常把一个网络当作一个函数f(x),给定输入x,网络就会输出一个对应的结果 y.比如图像分类任务中,输入是一张图片,输出是一个分类 ...