关于性能分析:mperf移动嵌入式平台算子性能调优利器

作者:旷视 MegEngine 架构师 张孝斌疾速理解 mperf在挪动/嵌入式平台,为了最大水平施展硬件算力,对算子极致性能的谋求变成必然,不同于桌面/服务器平台,挪动/嵌入式平台在算子性能调优方面可抉择的工具很少。 MegEngine 团队始终在摸索什么样的工具可能在算子调优流程中带来助益,来帮忙达成如下的算子性能调优反馈回路,这也是 mperf 诞生的背景。 <p align=center><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/db65dd714a724afd943a3860cc041974~tplv-k3u1fbpfcp-zoom-1.image" alt="图1 算子性能调优反馈回路" /></p><p align=center>图1 算子性能调优反馈回路</p> mperf 是一个微架构档次的算子性能调优工具箱,次要面向挪动/嵌入式平台的 CPU/GPU 外围,指标是“为构建一个更靠近闭环的算子调优反馈回路”提供系列根底工具。 外围性能: [根底能力] 测试微架构档次的各类罕用性能剖析参数(GFLOPS/Multi-level Bandwidth/Latency...)[根底能力] 提供 PMU(Performance Monitoring Unit) 数据获取能力[性能剖析] 绘制 Hierarchical Roofline[问题定位] 加工 PMU 数据失去各种指标(如 IPC, Instructions per cycle)、TMA(Top-Down Microarchitecture Analysis Method)剖析能力,能够作为局部 vendor 提供的 GUI 剖析工具的平替[优化指引] 提供 OpenCL Linter 计划(后续版本提供)...作为一个 C++ API 级别的工程,mperf 内部依赖少,能够简略不便(侵入式)集成到指标工程中,目前曾经开源到 GitHub,欢送大家试用交换。 应用办法参考 README 文档;疾速上手指南见 Tutorial 文档 对 mperf 的实现原理感兴趣的同学,能够持续往下看~~ 开展说说 mperf 的工程实现缘起算子调优目前还是一个难以闭环的工作,须要开发者对指标硬件架构个性、算子优化程度评估、性能瓶颈定位、丰盛的优化技巧等都有很深的理解之后能力变得熟能生巧。同时随着 CPU/GPU 架构越来越多,越来越简单,一般的开发者很少有精力去深刻了解各个架构的个性,问题变得更加辣手。 现实中的调优过程是可能造成如上图所示的闭环,甚至能够走向编译器全自动化调优计划,过程中往往须要依赖工具实现,在桌面/服务器平台的工具较为齐备,如 linux perf, lmbench/stream,NVIDIA NSight Compute,Intel vtune/Advisor/pmu-tools 等开闭源工具等都提供了一部分能力,通过人为组合还是能失去比拟全的能力;与此同时,在挪动/嵌入式平台,也有 simpleperf、Arm mali streamline、snapdragon profiler、MegPeak、ArchProbe、HWCPipe 等优良的开闭源工具,然而齐备性和易用性方面都存在很多问题: ...

March 2, 2023 · 3 min · jiezi

关于性能分析:案例介绍使用AOps性能热点火焰图进行性能诊断

上篇文章A-Ops性能火焰图——实用于云原生的全栈继续性能监测工具分享了A-Ops性能火焰图的个性。 本文将分享基于A-Ops性能热点火焰图进行性能诊断的2个理论案例,介绍如何应用火焰图疾速定位系统或者利用的性能问题,加深大家对A-Ops火焰图个性的了解。 案例1 云原生场景下Java类利用性能问题诊断 1. 场景及案例介绍 某Kafka producer客户端Java利用版本升级后性能呈现降落,性能从222W TPS降落到65W TPS,吞吐量从337MB/s降落到95.9MB/s,如下图所示(为了便于比拟,在不同POD里同时启动降级前后的两个利用): 可见,Kafka 客户端利用的性能呈现了显著的降落,但此时Kafka服务端较轻载,CPU 0.7%,内存16.8%,阐明性能劣化是因为客户端利用的问题导致。Kafka服务端资源状况如下: 2. 性能问题诊断 通过降级前后的火焰图比拟能够看出,降级后的CPU性能次要耗费在字符串format处理函数上。对于Kafka生成端利用,个别存在大量字符串操作,而字符串处理函数format性能较低,与StringBuilder办法相比有几倍甚至几十倍的性能差距,可见字符串format函数是导致性能升高的次要起因。 案例2 CPU抖动类性能故障诊断案例 1. 场景及案例介绍 在生产环境中常常会遇到一些偶发性的CPU抖动问题,这会对利用的性能造成肯定的影响,但因为没有必然的法则,故障发现及问题定位比拟难。 2. 性能问题诊断 为了模仿上述偶发性的故障,咱们通过iperf打流注入2分钟的故障,而后从多个角度剖析故障注入前后火焰图的数据,进而对CPU抖动类性能故障进行诊断。 在10:36-10:38通过 iperf3注入2分钟的流量,命令如下: iperf3 -c 192.168.122.115 -p 5201 -i 10 -t 120 -P 100 -N -M 100 -b 10000M流量注入前后,零碎利用指标及火焰图如下图所示: 从上图可见,流量注入期间,CPU使用率从均匀22%升高到33%,利用性能从232w tps降落到215w tps,火焰图中iperf3过程对CPU的占用为8.96%。 咱们能够通过火焰图比拟视图进一步剖析这个问题,下图右边的火焰图是注入故障前的火焰图,左边为注入故障期间的火焰图,比照能够看到故障注入期间多个iperf3这个过程。 另外,咱们还能够通过火焰图diff视图来剖析这个问题,参考下图,火焰图红色局部为故障注入期间新减少的过程,进而能够定位到iperf3是造成这次CPU抖动以及利用性能劣化的根因。 通过A-Ops性能热点火焰图,开发者和维护者能够很不便地预测潜在问题和定位已产生问题。 装置A-Ops性能热点火焰图 gala-ops是针对云基础设施灰度故障的利用级/零碎级在线诊断工具,火焰图探针stackprobe集成在其中的gala-gopher组件内,用户只需一键装置gala-gopher后,在配置文件中开启或敞开火焰图探针即可应用。 A-Ops装置部署手册: https://gitee.com/Vchanger/a-... gala-gophe组件装置部署阐明: https://gitee.com/openeuler/g... 欢送大家应用A-Ops性能热点火焰图,也欢送大家交换和反馈意见

February 22, 2023 · 1 min · jiezi

关于性能分析:教你如何衡量一个网页的性能

写作背景: 领有一个良好用户体验的网页对于前端开发同学来说是一件必须做,继续做的一件事件,其中首屏的渲染尤为重要,因为用户与网页产生的交互就是从首屏开始的。接下来将介绍网页性能的几个指标以及如何计算和度量这些指标,通过监控和优化这些性能数据来继续优化网页,以进步用户体验。 Navigation Timing API: 咱们先来看一组 API,Navigation Timing API 提供了用来掂量一个网站性能的数据指标。相比于咱们传统的根底伎俩应用这组 API 能够获取更有用、更准确的数据还能够做更多的数据统计。Navigation Timing API 的兼容性也是相当的不错,兼容咱们当初罕用的浏览器,包含让人厌恶的 IE9+。残缺的兼容性表见链接: 资源加载过程:当咱们的一个资源发动拜访(navigationStart)后到资源实现加载(loadEventEnd)经验如下过程: ① 首先就是当资源须要重定向的时候会进入 redirect阶段,不须要重定向将会跳过这个阶段;② 接着就会查看资源是否有HTTP缓存的存在,当资源没有缓存的状况下回进入下一步;③ DNS 寻址的过程;④ TCP 协定握手建设通信;⑤ 发动申请;⑥ 响应资源;⑦ 对响应的内容进行解决,如:对 DOM 资源加载并解析;⑧ 最初一步实现资源加载。 上面这张图将是对这个过程的规范形容,也是一道前端经典面试题的标准答案,你懂得~ [](https://www.w3.org/TR/navigat...) 上图是W3C第一版的 Navigation Timing 的解决模型(Level 1),从以后浏览器窗口卸载旧页面到加载实现新页面,整个过程一共分为 9 个阶段: 提醒卸载旧文档重定向/卸载利用缓存DNS 解析TCP 握手HTTP 申请解决HTTP 响应解决DOM 解决文档装载实现 Level 1 的标准从2012 年底进入候选倡议阶段应用已将近10年之久,也算实现了其历史使命,往年的3月20(2022年3月10日)正式进入Level2的标准( WorkingDraft ),Level2相比拟Level1精度更高。 Level2解决模型如下: Level2将整个过程划分为了11个阶段,各阶段指标明细: 序号指标解释1navigationStart示意从上一个文档卸载完结时的unix工夫戳,如果没有上一个文档,这个值将和fetchStart相等。2unloadEventStart示意前一个网页(与以后页面同域)unload的工夫戳,如果无前一个网页unload或者前一个网页与以后页面不同域,则值为0。3unloadEventEnd返回前一个页面unload工夫绑定的回掉函数执行结束的工夫戳。4redirectStart第一个HTTP重定向产生时的工夫。有跳转且是同域名内的重定向才算,否则值为0。5redirectEnd最初一个HTTP重定向实现时的工夫。有跳转且是同域名外部的重定向才算,否则值为0。6fetchStart浏览器筹备好应用HTTP申请抓取文档的工夫,这产生在查看本地缓存之前。7domainLookupStartdomainLookupEndDNS域名查问开始/完结的工夫,如果应用了本地缓存(即无DNS查问)或长久连贯,则与fetchStart值相等。8connectStartHTTP(TCP)开始/从新建设连贯的工夫,如果是长久连贯,则与fetchStart值相等9connectEndHTTP(TCP)实现建设连贯的工夫(实现握手),如果是长久接,则与fetchStart值相等。10secureConnectionStartHTTPS连贯开始的工夫,如果不是平安连贯,则值为0。11requestStartHTTP申请读取实在文档开始的工夫(实现建设连贯),包含从本地读取缓存。12responseStartHTTP开始接管响应的工夫(获取到第一个字节),包含从本地读取缓存。13responseEndHTTP响应全副接管实现的工夫(获取到最初一个字节),包含本地读取缓存。14domLoading开始解析渲染DOM树的工夫,此时Document..readyState变为loading,并将抛出readystatechange相干事件。15domlnteractive实现解析DOM树的工夫,Document..readyState变为interactive,并将抛出readystatechange相干事件,留神只是DOM树解析实现,这时候并没有开始加载网页内的资源。16domContentLoadedEventStartDOM解析实现后,网页内资源加载开始的工夫,在DOMContentLoaded事件抛出前产生。17domContentLoadedEventEndDOM解析实现后,网页内资源加载实现的工夫(如JS脚本加载执行结束)18domCompleteDOM树解析实现,且资源也准备就绪的工夫,Document..readyState变为complete,并将抛出readystatechange相干事件。19loadEventStartload事件发送给文档,也即load回调函数开始执行的工夫。20loadEventEndload事件的回调函数执行结束的工夫。计算页面加载的总时长: Navigation Timing API 为 window下挂的 Performance 对象减少了timing 和 navigation 属性,通过window.performance.timing能够失去 PerformanceTiming 接口,咱们能够应用接口外面提供的loadEventEnd减去navigationStart失去页面加载总的时长。 ...

May 26, 2022 · 2 min · jiezi

关于性能分析:性能分析之用户数线程数响应时间TPS的关系

最近在写一些货色的时候,把一些内容整顿了一下。在思考压力工具中的用户数(有些工具中称为线程数,本文后续都用“用户数”来阐明)、响应工夫、TPS三者之间的关系时,想到之前也有人问起过这样的问题,就是他们三者之间的共生的关系到底是什么样呢。这个公式我想谁都能晓得了:TPS = ( 1 / RT ) * user (其中,RT单位是秒,user是用户数) 先来画一下最简略的图(假如前提:每个user的事务定义都是统一的。):当有五个用户时,响应工夫都稳固放弃在0.2s,那这个场景的TPS显然是:TPS = (1/0.2)*5 = 25这是最简略的计算了。 (兴许你会说:“咳,不对,因为线画歪了!” 你过去,我保障揍不你。) 这个看似简略的公式,在理论的场景中却是会呈现千奇百怪的后果。因为大部分的场景都不会如此规整,例如:这种状况下怎么计算TPS呢:TPS = 2 + 4 + 6 + 4 + 1 = 17显然响应工夫也是变动较大的,可能每个用户的每个事务的响应工夫都是不一样的。在实在的场景中,这样的状况是必然会呈现的,所以在计算TPS的时候,压力工具采纳的是:先采集原始数据。即每个用户每个事务都记录下来。再依据粒度计算。TPS散点值 = 事务数 / 粒度这样的计算结果再通过曲线体现进去。就会受几个因素的影响:用户数、粒度、响应工夫。当粒度过大时,就会均匀掉毛刺的影响;当粒度过小时,就会产生过多的事务点,让人抓狂。 那到底什么样的TPS和响应工夫是让人称心的呢?像这样吗?响应工夫随用户数回升而回升,TPS达到下限后变平;这显然不是让人称心的曲线,因为咱们心愿的是响应工夫不要减少那么快。那这样的曲线呢?响应工夫有减少,然而减少的趋势并不快,TPS也始终有减少的趋势,这就显然零碎还有容量的空间,就看性能指标该如何确定了。 咱们如许心愿这三者的关系像这个图呀。响应工夫素来没有减少过,TPS始终在减少,零碎性能在测试范畴内没有衰减。当然,这是不可能的。通常状况下,咱们都要面对更简单点的场景。如下图:在这个非常简单的场景下,咱们也看到了响应工夫无理的跳动。还好幅度并不大。所以才保障了TPS在每个不同的用户梯度下绝对的稳固。然而显然前面TPS曾经达到下限了,响应工夫开始减少得十分快。对于这样的场景来说,曾经算是十分清晰的用户数、TPS、RT的关系了。而对于一些这三者关系基本找不到的性能场景,首先要做的就是要把场景判断清晰,让曲线变得稳固,再判断瓶颈,而后才是定位瓶颈及剖析根本原因。想让曲线变得稳固,就波及到场景的执行策略了。递增用户和场景的连续性是肯定要保障的,只是梯度要依据理论的状况来判断。 明天先聊这么多,当前碰到有人问相似的问题再接着聊。

June 24, 2021 · 1 min · jiezi

Linux-性能分析总结之-CPU-上下文切换二

0x00 前言上一篇笔记中我讲到了,在寻找 CPU 的性能瓶颈的问题的时候,首先会查看整台机器的平均负载是否高,然后再使用 pidstat 等工具判断到底是哪种情况导致的平均负载升高,主要情况有三种: CPU 密集型IO 密集型大量进程的场景前面两种情况我们都很好理解,但是大量的进程怎么也会导致 CPU 出现瓶颈呢?这是因为我们的 CPU 核心在执行任务的时候,仍然是单任务的,只不过它执行的很快,让每个进程交替着执行,所以在人类眼中看上去像是多个线程在并行执行。然而不同的线程交替的切换着执行时需要成本的,当进程数量很多的时候,CPU Context Swith 就很频繁了,那么就会导致 CPU 出现性能瓶颈。CPU Context Swith 可以分为以下几种场景: 进程上下文切换线程上下文切换中断上下文切换0x01 进程上下文切换首先,Linux 按照特权等级,把进程的运行空间分为内核态和用户态,CPU 特权等级为 0-3 数字越小权限越高。 那么问题来了,由于 Linux 现在只用到了两个特权等级,分别是 Ring 0 内核态和 Ring 3 用户态,所以运行在不同的特权等级上的进程上下文切换主要有两种: 用户态进程之间的切换用户态进程陷入到内核态,即系统调用那用户态进程陷入内核态进程与用户态空间之间的切换有何不同呢?不同之处在于用户态在进行系统调用的时候,会发生两次 CPU 的上下文切换,分别是: 用户态切陷入到内核态执行内核态进程执行完成后再恢复为原来的用户态的进程执行那么说明了在系统调用的时候并不会切换原本的用户态的进程,它只是进行了系统调用(即切换到内核态)又恢复了,所以我们把系统调用成为特权模式切换,用户态之间的进程成为上下文切换。 系统调用与上下文切换有何区别?上下文切换相比系统调用会保存进程的虚拟内存和栈,所以会消耗更多的时间 何时会进行进程上下文切换?CPU 时间片结束,CPU 是划分为多个时间片的给不同进程使用的进程运行需要的资源不够,如等待IO,Memory insufficient 等等进程主动挂起,如 sleep 函数有优先级更高的进程执行,如硬中断0x02 线程上下文切换线程与进程的区别是什么?线程是调度的基本单位,进程是资源拥有的基本单位。也就是说线程是实际上干活的,也是内核实际调度的对象,但是干活你需要工具和场地,而进程就是给线程提供了虚拟内存、全局变量等资源。所以可以这么理解: 进程 = 所有线程 + 资源如果进程只有一个线程,那么可以认为这个线程就代表整个进程如果一个进程有多个线程,所有线程共享这个进程的资源,在上下文切换的时候这些资源也不需要切换线程有自己的私有数据,如 stack,Register等,这些需要保存那么线程的情况分为两种: 前后线程属于一个进程,那么资源是共享的,所以只需要切换线程的私有数据如果前后线程属于不同的进程,那么切换的情况和进程是一样的0x03 中断上下文切换中断是外部事件对 CPU 执行过程打的打断,中断程序也是需要执行的,它会保存被打断的进程的状态,这样中断程序执行结束了后原来的进程就还能接着执行,那么自然中断也需要上下文切换,也会消耗 CPU 的资源。但是由于中断并不涉及到切换用户态进程,所以进程的资源是不需要保存和恢复的。 0x04 总结从上个笔记中我说到了根据 CPU 升高的情况下,会有三种原因导致 CPU使用情况升高。这里我接着针对的是第三种大量进程切换的情况,而这种情况又可以分为三种情况,分别是: ...

September 8, 2019 · 1 min · jiezi

Linux-性能分析总结之-CPU-平均负载一

0x00 前言作为一个程序猿,无论我们将来想要往哪个方向攀登,如果没有好的基础知识是会很吃力的,所以打下良好的基础必不可少。在我看来,从事 IT 行业的技术工种,有以下基础知识是刚需: 编程算法计算机原理计算机网络根据冯诺依曼计算机结构体系,计算机就是一个输入输出的设备,我们输入待处理的数据,经由计算机处理后得到我们想要的结果。那么说白了作为程序员我们就是通过各种手段操控这个设备,自然而然的,想要把这个机器玩的很溜是需要了解这个机器的原理的,所以我们需要学习计算机原理。 在了解了计算机的原理后,我们如何去操作他呢,当然是通过编程的手段了,这里我说的编程是广义上的编程,不要以为只有写段 C 的代码才是编程,命令行输入指令就不是编程了,命令其实也是编程,因为他们两者最终都是翻译成机器指令由计算机来执行。 同样地,这台机器他的性能是有限的,我们只知道怎么通过编程操作它远远不够,我们需要学一些骚操作来提升效率和速度,那么我们就需要学算法了。说白了,就好像两个工人操作一个机器,其中一个工人会搞一些很溜的操作,让这个机器的效率更高,执行速度更快,还能搞一些高阶玩法,如果这个工厂只能留下一个人,你觉得最终会留下谁呢? 在有了上面这三类基础知识后,我们对于单台机器的操作可以说是入门了,但是我们现在身处的世界是万物互联的世界,计算机需要与计算机之间进行协作,那么就需要学习计算机网络。 而我最近出于工作原因,一直在学习 Linux 的性能优化。Linux 性能优化的范围涉及非常广,从软件到硬件、从编程到网络都有涉及到,有很多的基础知识,而对于很广的知识,我觉得需要一条线来串联起来,才能形成一个体系的知识结构。所以我会把在这过程中学到的知识,加上平时工作中的实践,提炼成博客写出来。 0x01 详解A. 平均负载首先分析 CPU 的性能问题,当我们发现有 CPU 的性能问题,第一时间是干什么呢?当然是查看整体的 CPU 使用情况,当查看 CPU 的整体情况后,然后再分析到底是哪种情况导致 CPU 的负载很高,最后找到导致 CPU 负载升高的罪魁祸首。那么我们接下来就按照这个步骤来分析。 1. 查看整体的 CPU 使用情况常用的查看 CPU 的平均负载的命令有很多,如 uptime,top 等都可以查看。首先解释下什么是平均负载,总的来说平均负载可以理解为平均一段时间内 runnable 和 non-interruptable 进程的数量。 这里我们用 uptime 命令执行得到的结果如下: 分别是最近 1 min,5 min,15 min 的平均负载的情况,从这里我们可以看出最近系统的负载情况,从而可以对整体 CPU 的使用情况有一个大概的判断。 平均负载的详细介绍可以看: Understanding the Load Average on Linux and Other Unix-like Systems 2. 哪些进程会导致平均负载的升高呢一般有如下场景: ...

September 7, 2019 · 1 min · jiezi

Go-性能分析之案例一

思考相信大家在实际的项目开发中会遇到这么一个事,有的程序员写的代码不仅bug少,而且性能高;而有的程序员写的代码能否流畅的跑起来,都是一个很大问题。而我们今天要讨论的就是一个关于性能优化的案例分析。 案例分析我们先来构造一些基础数据(长度为10亿的切片,并赋上值): var testData = GenerateData()// generate billion slice datafunc GenerateData() []int { data := make([]int, 1000000000) for key, _ := range data { data[key] = key % 128 } return data}// get lengthfunc GetDataLen() int { return len(testData)}案例一// case onefunc CaseSumOne(result *int) { data := GenerateData() for i := 0; i < GetDataLen(); i++ { *result += data[i] }}// case twofunc CaseSumTwo(result *int) { data := GenerateData() dataLen := GetDataLen() for i := 0; i < dataLen; i++ { *result += data[i] }}执行结果$ go test -bench=.goos: windowsgoarch: amd64BenchmarkCaseSumOne-8 1 7439749000 ns/opBenchmarkCaseSumTwo-8 1 2529266700 ns/opPASSok _/C_/go-code/perform/case-one 14.059s问题分析CaseSumTwo执行效率是CaseSumOne的2.94倍,快了近三倍,这是为什么呢?其实很容易猜到,这里有一个连续的函数调用“GetDataLen()”,案例二// case threefunc CaseSumThree(result *int) { data := GenerateData() dataLen := GetDataLen() tmp := *result for i:= 0; i < dataLen; i++ { tmp += data[i] } *result = tmp}执行$ go test -bench=.goos: windowsgoarch: amd64BenchmarkCaseSumOne-8 1 7439749000 ns/opBenchmarkCaseSumTwo-8 1 2529266700 ns/opBenchmarkCaseSumThree-8 1 1657554600 ns/opPASSok _/C_/go-code/perform/case-one 15.717s待续

June 15, 2019 · 1 min · jiezi

前端关于JSON的stringifyparse和遍历的性能比较

在前端项目对数组,map的拷贝,比较中,我们往往会去用json.stringify、json.parse,那么这样做究竟好不好呢?经过一系列测试,发现用这种方式的性能是比较差的,下面是实验结果 1.数组拷贝const a1 = new Array(1000000).fill('').map((e, index) => index)function f1() { const start = new Date().getTime() const r = JSON.parse(JSON.stringify(a1)) console.log('json结果', new Date().getTime() - start)}function f2() { const start = new Date().getTime() const r = [...a1] console.log('array结果', r == a1, new Date().getTime() - start)}f1()f2()结果:json结果 104array结果 false 35 我们发现差距在四倍左右,当数组变大基本也维持在这个比例 2.遍历对比const map1 = {}const map2 = {}for (let i=0;i < 1000000;i++) { map1[i] = i map2[i] = i}function f1() { const start = new Date().getTime() const r = JSON.stringify(map1) == JSON.stringify(map2) console.log('json结果', r, new Date().getTime() - start)}function f2() { const start = new Date().getTime() const r = Object.keys(map1).every(key => { if (map2[key] || map2[key] === 0) { return true } else { return false } }) console.log('array结果', r, new Date().getTime() - start)}f1()f2()结果:json结果 true 506array结果 true 140 ...

May 29, 2019 · 1 min · jiezi

程序员笔记循序渐进解读Oracle-AWR性能分析报告

Oracle中的AWR,全称为Automatic Workload Repository,自动负载信息库。它收集关于特定数据库的操作统计信息和其他统计信息,Oracle以固定的时间间隔(默认为1个小时)为其所有重要的统计信息和负载信息执行一次快照,并将快照存放入AWR中。这些信息在AWR中保留指定的时间(默认为1周),然后执行删除。执行快照的频率和保持时间都是可以自定义的。 AWR的引入,为我们分析数据库提供了非常好的便利条件(这方面MySQL就相差了太多)。曾经有这样的一个比喻——“一个系统,就像是一个黑暗的大房间,系统收集的统计信息,就如同放置在房间不同位置的蜡烛,用于照亮这个黑暗大房间。Oracle,恰到好处地放置了足够的蜡烛(AWR),房间中只有极少的烛光未覆盖之处,性能瓶颈就容易定位。而对于蜡烛较少或是没有蜡烛的系统,性能优化就如同黑暗中的舞者。” 那如何解读AWR的数据呢?Oracle本身提供了一些报告,方便进行查看、分析。下面就针对最为常见的一种报告——《AWR数据库报告》进行说明。希望通过这篇文章,能方便大家更好地利用AWR,方便进行分析工作。 一、MAIN1、Database Information 2、Snapshot Information (1)Sessions 表示采集实例连接的会话数。这个数可以帮助我们了解数据库的并发用户数大概的情况。这个数值对于我们判断数据库的类型有帮助。 (2)Cursors/session 每个会话平均打开的游标数。 (3)Elapsed 通过Elapsed/DB Time比较,反映出数据库的繁忙程度。如果DB Time>>Elapsed,则说明数据库很忙。 (4)DB Time 表示用户操作花费的时间,包括CPU时间和等待事件。通常同时这个数值判读数据库的负载情况。 具体含义db time = cpu time + wait time(不包含空闲等待)(非后台进程) *db time就是记录的服务器花在数据库运算(非后台进程)和等待(非空闲等待)上的时间。对应于V$SESSION的elapsed_time字段累积。 "合集数据"需要注意的是AWR是一个数据合集。比如在1分钟之内,1个用户等待了30秒钟,那么10个用户等待事件就是300秒。CPU时间也是一样,在1分钟之内,1个CPU处理30秒钟,那么4个CPU就是120秒。这些时间都是以累积的方式记录在AWR当中的。 示例DB CPU——这是一个用于衡量CPU的使用率的重要指标。假设系统有N个CPU,那么如果CPU全忙的话,一秒钟内的DB CPU就是N秒。除了利用CPU进行计算外,数据库还会利用其它计算资源,如网络、硬盘、内存等等,这些对资源的利用同样可以利用时间进行度量。假设系统有M个session在运行,同一时刻有的session可能在利用CPU,有的session可能在访问硬盘,那么在一秒钟内,所有session的时间加起来就可以表征系统在这一秒内的繁忙程度。一般的,这个和的最大值应该为M。这其实就是Oracle提供的另一个重要指标:DB time,它用以衡量前端进程所消耗的总时间。 对除CPU以后的计算资源的访问,Oracle用等待事件进行描述。同样地,和CPU可分为前台消耗CPU和后台消耗CPU一样,等待事件也可以分为前台等待事件和后台等待事件。DB Time一般的应该等于"DB CPU + 前台等待事件所消耗时间"的总和。等待时间通过v$system\_event视图进行统计,DB Time和DB CPU则是通过同一个视图,即v$sys_time_model进行统计。 --"Load Profile"中关于DB Time的描述 *这个系统的CPU个数是8,因此我们可以知道前台进程用了系统CPU的7.1/8=88.75%。DB Time/s为11.7,可以看出这个系统是CPU非常繁忙的。里面CPU占了7.1,则其它前台等待事件占了11.7 – 7.1 = 4.6 Wait Time/s。DB Time 占 DB CPU的比重: 7.1/11.7= 60.68% --"Top 5 Timed Events"中关于DB CPU的描述按照CPU/等待事件占DB Time的比例大小,这里列出了Top 5。如果一个工作负载是CPU繁忙型的话,那么在这里应该可以看到 DB CPU的影子。 ...

April 29, 2019 · 5 min · jiezi

一文掌握 Linux 性能分析之内存篇

本文首发于我的公众号 CloudDeveloper(ID: cloud_dev),专注于干货分享,号内有大量书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫。前面我们已经学习了 CPU 篇,这篇来看下内存篇。01 内存信息同样在分析内存之前,我们得知到怎么查看系统内存信息,有以下几种方法。1.1 /proc/meminfo这个文件记录着比较详细的内存配置信息,使用 cat /proc/meminfo 查看。我们比较关心的是下面几个字段:MemTotal:系统总内存,由于 BIOS、内核等会占用一些内存,所以这里和配置声称的内存会有一些出入,比如我这里配置有 2G,但其实只有 1.95G 可用。MemFree:系统空闲内存。MemAvailable:应用程序可用内存。有人会比较奇怪和 MemFree 的区别,可以从两个层面来区分,MemFree 是系统层面的,而 MemAvailable 是应用程序层面的。系统中有些内存虽然被使用了但是有一部分是可以回收的,比如 Buffers、Cached 及 Slab 这些内存,这部分可以回收的内存加上 MemFree 才是 MemAvailable 的内存值,这是内核通过特定算法算出来的,是一个估算值。Buffers:缓冲区内存Cached:缓存上面信息没有 MemUsed 的值,虽然可以用现有的值大致估算出来,但是我们想一步到位,就用下面的 free 命令。1.2 free这个命令估计用的人就多了(我一般都是用这个命令)。这里存在一个计算公式:MemTotal = used + free + buff/cache(单位 K)几个字段和上面 /proc/meminfo 的字段是对应的。还有个 shared 字段,这个是多进程的共享内存空间,不常用。我们注意到 free 很小,buff/cache 却很大,这是 Linux 的内存设计决定的,Linux 的想法是内存闲着反正也是闲着,不如拿出来做系统缓存和缓冲区,提高数据读写的速率。但是当系统内存不足时,buff/cache 会让出部分来,非常灵活的操作。要看比较直观的值,可以加 -h 参数:1.3 dmidecode同样可以使用这个命令,对于内存,可以使用 dmidecode -t memory 查看:1.4 vmstat这个命令也是非常常用了。但对于内存,显示信息有限。它更多是用于进行系统全局分析和 CPU 分析。详细可以看 CPU 分析一文。02 进程内存使用情况分析最常用的两个命令 ps 和 top,虽然很简单的两个命令,但还是有不少学问的。2.1 top/htoptop 命令运行时默认是按照 CPU 利用率进行排序的,如果要按照内存排序,该怎么操作呢?两种方法,一种直接按 “M”(相应的按 “P” 是 CPU),另外一种是在键入 top 之后,按下 “F”,然后选择要排序的字段,再按下 “s” 确认即可。可以看到,我按照 “%MEM” 排序的结果。这个结果对于查看系统占用内存较多的哪些进程是比较有用的。然后这里我们会重点关注几个地方,上面横排区,和前面几个命令一样可以查看系统内存信息,中间标注的横条部分,和内存相关的有三个字段:VIRT、RES、SHR。VIRT:virtual memory usage,进程占用的虚拟内存大小。RES:resident memory usage,进程常驻内存大小,也就是实际内存占用情况,一般我们看进程占用了多少内存,就是看的这个值。SHR:shared memory,共享内存大小,不常用。2.2 psps 同样可以查看进程占用内存情况,一般常用来查看 Top n 进程占用内存情况,如:ps aux –sort=rss | head -n,表示按 rss 排序,取 Top n。这里也关注三个字段:%MEM:进程使用物理内存所占百分比。VSZ:进程使用虚拟内存大小。RSS:进程使用物理内存大小,我们会重点关注这个值。2.3 pmap这个命令用于查看进程的内存映像信息,能够查看进程在哪些地方用了多少内存。 常用 pmap -x pid 来查看。可以看到该进程内存被哪些库、哪些文件所占用,据此我们定位程序对内存的使用。几个字段介绍一下:Address:占用内存的文件的内存起始地址。Kbytes:占用内存的字节数。RSS:实际占用内存大小。Dirty:脏页大小。Mapping:占用内存的文件,[anon] 为已分配的内存,[stack] 为程序堆栈最后的 total 为统计的总值。我们可以使用 pmap -x pid | tail -1 这样只显示最后一行,循环显示最后一行,达到监控该进程的目的。使用:while true; do pmap -x pid | tail -1; sleep 1; doneOK,以上工具都是 Linux 自带的,当然还有很多高阶的工具,比如 atop、memstat 等等,对于内存泄漏有一个比较常用的检测工具 Valgrind,更多干货可以关注我的公众号。通过以上手段,我们基本上就能定位内存问题所在了,究竟是内存太小,还是进程占用内存太多,有哪些进程占用较多,这些进程又究竟有哪些地方占用较多,这些问题通过以上方法都能解决。最后简单总结下,以上不少工具可能有人会犯选择困难症了。对于我来说,查看系统内存用 free -h,分析进程内存占用用 ps 或者 top(首选 ps),深入分析选择 pmap,就酱。参考:Linux下查看内存使用情况的多种方法 http://stor.51cto.com/art/201…我的公众号 CloudDeveloper(ID: cloud_dev),号内有大量书籍和视频资源,后台回复「1024」即可领取,分享的内容包括但不限于云计算虚拟化、容器、OpenStack、K8S、雾计算、网络、工具、SDN、OVS、DPDK、Linux、Go、Python、C/C++编程技术等内容,欢迎大家关注。 ...

March 18, 2019 · 1 min · jiezi

一文掌握 Linux 性能分析之网络篇

本文首发于我的公众号 CloudDeveloper(ID: cloud_dev),专注于干货分享,号内有大量书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫。这是 Linux 性能分析系列的第四篇,前三篇在这里:一文掌握 Linux 性能分析之 CPU 篇一文掌握 Linux 性能分析之内存篇一文掌握 Linux 性能分析之 I/O 篇比较宽泛地讲,网络方向的性能分析既包括主机测的网络配置查看、监控,又包括网络链路上的包转发时延、吞吐量、带宽等指标分析。包括但不限于以下分析工具:ping:测试网络连通性ifconfig:接口配置ip:网络接口统计信息netsat:多种网络栈和接口统计信息ifstat:接口网络流量监控工具netcat:快速构建网络连接tcpdump:抓包工具sar:统计信息历史traceroute:测试网络路由pathchar:确定网络路径特征dtrace:TCP/IP 栈跟踪iperf / netperf / netserver:网络性能测试工具perf 性能分析神器本文先来看前面 7 个。pingping 发送 ICMP echo 数据包来探测网络的连通性,除了能直观地看出网络的连通状况外,还能获得本次连接的往返时间(RTT 时间),丢包情况,以及访问的域名所对应的 IP 地址(使用 DNS 域名解析),比如:我们 ping baidu.com,-c 参数指定发包数。可以看到,解析到了 baidu 的一台服务器 IP 地址为 220.181.112.244。RTT 时间的最小、平均、最大和算术平均差分别是 40.732ms、40.762ms、40.791ms 和 0.248。ifconfigifconfig 命令被用于配置和显示 Linux 内核中网络接口的统计信息。通过这些统计信息,我们也能够进行一定的网络性能调优。1)ifconfig 显示网络接口配置信息其中,RX/TX packets 是对接收/发送数据包的情况统计,包括错误的包,丢掉多少包等。RX/TX bytes 是接收/发送数据字节数统计。其余还有很多参数,就不一一述说了,性能调优时可以重点关注 MTU(最大传输单元) 和 txqueuelen(发送队列长度),比如可以用下面的命令来对这两个参数进行微调:ifconfig eth0 txqueuelen 2000ifconfig eth0 mtu 1500 2)网络接口地址配置ifconfig 还常用来配置网口的地址,比如:为网卡配置和删除IPv6地址:ifconfig eth0 add 33ffe:3240:800:1005::2/64 #为网卡eth0配置IPv6地址ifconfig eth0 del 33ffe:3240:800:1005::2/64 #为网卡eth0删除IPv6地址修改MAC地址:ifconfig eth0 hw ether 00:AA:BB:CC:dd:EE配置IP地址:ifconfig eth0 192.168.2.10ifconfig eth0 192.168.2.10 netmask 255.255.255.0ifconfig eth0 192.168.2.10 netmask 255.255.255.0 broadcast 192.168.2.255IPip 命令用来显示或设置 Linux 主机的网络接口、路由、网络设备、策略路由和隧道等信息,是 Linux 下功能强大的网络配置工具,旨在替代 ifconfig 命令,如下显示 IP 命令的强大之处,功能涵盖到 ifconfig、netstat、route 三个命令。netstatnetstat 可以查看整个 Linux 系统关于网络的情况,是一个集多钟网络工具于一身的组合工具。常用的选项包括以下几个:默认:列出连接的套接字-a:列出所有套接字的信息-s:各种网络协议栈统计信息-i:网络接口信息-r:列出路由表-l:仅列出有在 Listen 的服务状态-p:显示 PID 和进程名称各参数组合使用实例如下:netstat -at 列出所有 TCP 端口netstat -au 列出所有 UDP 端口netstat -lt 列出所有监听 TCP 端口的 socketnetstat -lu 列出所有监听 UDP 端口的 socketnetstat -lx 列出所有监听 UNIX 端口的 socketnetstat -ap | grep ssh 找出程序运行的端口netstat -an | grep ‘:80’ 找出运行在指定端口的进程1)netstat 默认显示连接的套接字数据整体上来看,输出结果包括两个部分:Active Internet connections :有源 TCP 连接,其中 Recv-Q 和 Send-Q 指的是接收队列和发送队列,这些数字一般都是 0,如果不是,说明请求包和回包正在队列中堆积。Active UNIX domain sockets:有源 UNIX 域套接口,其中 proto 显示连接使用的协议,RefCnt 表示连接到本套接口上的进程号,Types 是套接口的类型,State 是套接口当前的状态,Path 是连接到套接口的进程使用的路径名。2)netstat -i 显示网络接口信息接口信息包括网络接口名称(Iface)、MTU,以及一系列接收(RX-)和传输(TX-)的指标。其中 OK 表示传输成功的包,ERR 是错误包,DRP 是丢包,OVR 是超限包。这些参数有助于我们对网络收包情况进行分析,从而判断瓶颈所在。3)netstat -s 显示所有网络协议栈的信息可以看到,这条命令能够显示每个协议详细的信息,这有助于我们针对协议栈进行更细粒度的分析。4)netstat -r 显示路由表信息这条命令能够看到主机路由表的一个情况。当然查路由我们也可以用 ip route 和 route 命令,这个命令显示的信息会更详细一些。ifstatifstat 主要用来监测主机网口的网络流量,常用的选项包括:-a:监测主机所有网口-i:指定要监测的网口-t:在每行输出信息前加上时间戳-b:以 Kbit/s 显示流量数据,而不是默认的 KB/s-delay:采样间隔(单位是 s),即每隔 delay 的时间输出一次统计信息-count:采样次数,即共输出 count 次统计信息比如,通过以下命令统计主机所有网口某一段时间内的流量数据:可以看出,分别统计了三个网口的流量数据,前面输出的时间戳,有助于我们统计一段时间内各网口总的输入、输出流量。netcatnetcat,简称 nc,命令简单,但功能强大,在排查网络故障时非常有用,因此它也在众多网络工具中有着“瑞士军刀”的美誉。它主要被用来构建网络连接。可以以客户端和服务端的方式运行,当以服务端方式运行时,它负责监听某个端口并接受客户端的连接,因此可以用它来调试客户端程序;当以客户端方式运行时,它负责向服务端发起连接并收发数据,因此也可以用它来调试服务端程序,此时它有点像 Telnet 程序。常用的选项包括以下几种:-l:以服务端的方式运行,监听指定的端口。默认是以客户端的方式运行。-k:重复接受并处理某个端口上的所有连接,必须与 -l 一起使用。-n:使用 IP 地址表示主机,而不是主机名,使用数字表示端口号,而不是服务名称。-p:当以客户端运行时,指定端口号。-s:设置本地主机发出的数据包的 IP 地址。-C:将 CR 和 LF 两个字符作为结束符。-U:使用 UNIX 本地域套接字通信。-u:使用 UDP 协议通信,默认使用的是 TCP 协议。-w:如果 nc 客户端在指定的时间内未检测到任何输入,则退出。-X:当 nc 客户端与代理服务器通信时,该选项指定它们之间的通信协议,目前支持的代理协议包括 “4”(SOCKS v.4),“5”(SOCKS v.5)和 “connect” (HTTPs Proxy),默认使用 SOCKS v.5。-x:指定目标代理服务器的 IP 地址和端口号。下面举一个简单的例子,使用 nc 命令发送消息:首先,启动服务端,用 nc -l 0.0.0.0 12345 监听端口 12345 上的所有连接。然后,启动客户端,用 nc -p 1234 127.0.0.1 12345 使用 1234 端口连接服务器 127.0.0.1::12345。接着就可以在两端互发数据了。这里只是抛砖引玉,更多例子大家可以多实践。tcpdump最后是 tcpdump,强大的网络抓包工具。虽然有 wireshark 这样更易使用的图形化抓包工具,但 tcpdump 仍然是网络排错的必备利器。tcpdump 选项很多,我就不一一列举了,大家可以看文章末尾的引用来进一步了解。这里列举几种 tcpdump 常用的用法。1)捕获某主机的数据包比如想要捕获主机 200.200.200.100 上所有收到和发出的所有数据包,使用:tcpdump host 200.200.200.1002)捕获多个主机的数据包比如要捕获主机 200.200.200.1 和主机 200.200.200.2 或 200.200.200.3 的通信,使用:tcpdump host 200.200.200.1 and (200.200.200.2 or )同样要捕获主机 200.200.200.1 除了和主机 200.200.200.2 之外所有主机通信的 IP 包。使用:tcpdump ip host 200.200.200.1 and ! 200.200.200.23)捕获某主机接收或发出的某种协议类型的包比如要捕获主机 200.200.200.1 接收或发出的 Telnet 包,使用:tcpdump tcp port 23 host 200.200.200.14)捕获某端口相关的数据包比如捕获在端口 6666 上通过的包,使用:tcpdump port 66665)捕获某网口的数据包比如捕获在网口 eth0 上通过的包,使用:tcpdump -i eth0下面还是举个例子,抓取 TCP 三次握手的包:(具体抓包的过程请移步到我的公众号进一步了解,那里阅读体验好一点,谢谢。)总结:本文总结了几种初级的网络工具,基本的网络性能分析,通过组合以上几种工具,基本都能应付,但对于复杂的问题,以上工具可能就无能为力了。更多高阶的工具将在下文送上,敬请期待。参考:基础 http://kuring.me/post/linux_n… 讲 ip 和 ifconfig 很强大的一篇文章:https://blog.csdn.net/freekin…https://www.alibabacloud.com/…性能之巅:Linux网络性能分析工具http://www.infoq.com/cn/artic…抓包工具tcpdump用法说明 https://www.cnblogs.com/f-ck-...https://www.shiyanlou.com/cou...http://linuxtools-rst.readthe...https://www.shiyanlou.com/cou…我的公众号 CloudDeveloper(ID: cloud_dev),号内有大量书籍和视频资源,后台回复「1024」即可领取,分享的内容包括但不限于云计算虚拟化、容器、OpenStack、K8S、雾计算、网络、工具、SDN、OVS、DPDK、Linux、Go、Python、C/C++编程技术等内容,欢迎大家关注。 ...

March 15, 2019 · 2 min · jiezi

【原创】一文掌握 Linux 性能分析之 I/O 篇

本文首发于我的公众号 CloudDeveloper(ID: cloud_dev),专注于干货分享,号内有大量书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫。一文掌握 Linux 性能分析之 CPU 篇一文掌握 Linux 性能分析之内存篇这是 Linux 性能分析系列的第三篇,前两篇分别讲了 CPU 和 内存,本篇来看 IO。IO 和 存储密切相关,存储可以概括为磁盘,内存,缓存,三者读写的性能差距非常大,磁盘读写是毫秒级的(一般 0.1-10ms),内存读写是微妙级的(一般 0.1-10us),cache 是纳秒级的(一般 1-10ns)。但这也是牺牲其他特性为代价的,速度快的,价格越贵,容量也越小。IO 性能这块,我们更多关注的是读写磁盘的性能。首先,先了解下磁盘的基本信息。磁盘基本信息fdisk查看磁盘信息,包括磁盘容量,扇区大小,IO 大小等信息,常用 fdisk -l 查看:可以看到 /dev/ 下有一个 40G 的硬盘,一共 8K 多万个扇区,每个扇区 512字节,IO 大小也是 512 字节。df查看磁盘使用情况,通常看磁盘使用率:磁盘性能分析主要分析磁盘的读写效率(IOPS:每秒读写的次数;吞吐量:每秒读写的数据量),IO 繁忙程度,及 IO 访问对 CPU 的消耗等性能指标。vmstat第一个较为常用的还是这个万能的 vmstat:对于 IO,我们常关注三个部分:b 值:表示因为 IO 阻塞排队的任务数bi 和 bo 值:表示每秒读写磁盘的块数,bi(block in)是写磁盘,bo(block out)是读磁盘。wa 值:表示因为 IO 等待(wait)而消耗的 CPU 比例。一般这几个值偏大,都意味着系统 IO 的消耗较大,对于读请求较大的服务器,b、bo、wa 的值偏大,而写请求较大的服务器,b、bi、wa 的值偏大。iostatvmstat 虽然万能,但是它分析的东西有限,iostat 是专业分析 IO 性能的工具,可以方便查看 CPU、网卡、tty 设备、磁盘、CD-ROM 等等设备的信息,非常强大,总结下来,共有以下几种用法:1)iostat -c 查看部分 CPU 使用情况:这里显示的是多个 CPU 的平均值,每个字段的含义我就不多解释了,我一般会重点关注 %iowait 和 %idle,分别表示 CPU 等待 IO 完成时间的百分比和 CPU 空闲时间百分比。如果 %iowait 较高,则表明磁盘存在 IO 瓶颈,如果 %idle 较高,则 CPU 比较空闲,如果两个值都比较高,则有可能 CPU 在等待分配内存,瓶颈在内存,此时应该加大内存,如果 %idle 较低,则此时瓶颈在 CPU,应该增加 CPU 资源。2)iostat -d 查看磁盘使用情况,主要是显示 IOPS 和吞吐量信息(-k : 以 KB 为单位显示,-m:以 M 为单位显示):其中,几个参数分别解释如下:tps:设备每秒的传输次数(transfers per second),也就是读写次数。kB_read/s:每秒读磁盘的数据量kB_wrtn/s:每秒写磁盘的数据量kB_read:读取磁盘的数据总量kB_wrtn:写入磁盘的数据总量3)iostat -x 查看磁盘详细信息:其中,几个参数解释如下;rrqm/s 和 wrqm/s:分别每秒进行合并的读操作数和写操作数,这是什么意思呢,合并就是说把多次 IO 请求合并成少量的几次,这样可以减小 IO 开销,buffer 存在的意义就是为了解决这个问题的。r/s 和 w/s:每秒磁盘读写的次数。这两个值相加就是 tps。rkB/s 和 wkB/s:每秒磁盘读写的数据量,这两个值和上面的 kB_read/s、kB_wrnt/s 是一个意思。avgrq-sz:平均每次读写磁盘扇区的大小。avgqu-sze:平均 IO 队列长度。队列长度越短越好。await:平均每次磁盘读写的等待时间(ms)。svctm:平均每次磁盘读写的服务时间(ms)。%util:一秒钟有百分之多少的时间用于磁盘读写操作。以上这些参数太多了,我们并不需要每个都关注,可以重点关注两个:1)%util:衡量 IO 的繁忙程度这个值越大,说明产生的 IO 请求较多,IO 压力较大,我们可以结合 %idle 参数来看,如果 %idle < 70% 就说明 IO 比较繁忙了。也可以结合 vmstat 的 b 参数(等待 IO 的进程数)和 wa 参数(IO 等待所占 CPU 时间百分比)来看,如果 wa > 30% 也说明 IO 较为繁忙。2)await:衡量 IO 的响应速度通俗理解,await 就像我们去医院看病排队等待的时间,这个值和医生的服务速度(svctm)和你前面排队的人数(avgqu-size)有关。如果 svctm 和 await 接近,说明磁盘 IO 响应时间较快,排队较少,如果 await 远大于 svctm,说明此时队列太长,响应较慢,这时可以考虑换性能更好的磁盘或升级 CPU。4)iostat 1 2 默认显示 cpu 和 吞吐量信息,1 定时 1s 显示,2 显示 2 条信息进程 IO 性能分析有了以上两个命令,基本上能对磁盘 IO 的信息有个全方位的了解了。但如果要确定具体哪个进程的 IO 开销较大,这就得借助另外的工具了。iotop这个命令类似 top,可以显示每个进程的 IO 情况,有了这个命令,就可以定位具体哪个进程的 IO 开销比较大了。OK,最后还是总结下,fdisk -l 和 df 查看磁盘基本信息,iostat -d 查看磁盘 IOPS 和吞吐量,iostat -x 结合 vmstat 查看磁盘的繁忙程度和处理效率。参考:http://linuxtools-rst.readthe…http://rdc.hundsun.com/portal…我的公众号 CloudDeveloper(ID: cloud_dev),号内有大量书籍和视频资源,后台回复「1024」即可领取,分享的内容包括但不限于云计算虚拟化、容器、OpenStack、K8S、雾计算、网络、工具、SDN、OVS、DPDK、Linux、Go、Python、C/C++编程技术等内容,欢迎大家关注。 ...

March 14, 2019 · 1 min · jiezi

一文掌握 Linux 性能分析之内存篇

本文首发于我的公众号 CloudDeveloper(ID: cloud_dev),专注于干货分享,号内有大量书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫。前面我们已经学习了 CPU 篇,这篇来看下内存篇。01 内存信息同样在分析内存之前,我们得知到怎么查看系统内存信息,有以下几种方法。1.1 /proc/meminfo这个文件记录着比较详细的内存配置信息,使用 cat /proc/meminfo 查看。我们比较关心的是下面几个字段:MemTotal:系统总内存,由于 BIOS、内核等会占用一些内存,所以这里和配置声称的内存会有一些出入,比如我这里配置有 2G,但其实只有 1.95G 可用。MemFree:系统空闲内存。MemAvailable:应用程序可用内存。有人会比较奇怪和 MemFree 的区别,可以从两个层面来区分,MemFree 是系统层面的,而 MemAvailable 是应用程序层面的。系统中有些内存虽然被使用了但是有一部分是可以回收的,比如 Buffers、Cached 及 Slab 这些内存,这部分可以回收的内存加上 MemFree 才是 MemAvailable 的内存值,这是内核通过特定算法算出来的,是一个估算值。Buffers:缓冲区内存Cached:缓存上面信息没有 MemUsed 的值,虽然可以用现有的值大致估算出来,但是我们想一步到位,就用下面的 free 命令。1.2 free这个命令估计用的人就多了(我一般都是用这个命令)。这里存在一个计算公式:MemTotal = used + free + buff/cache(单位 K)几个字段和上面 /proc/meminfo 的字段是对应的。还有个 shared 字段,这个是多进程的共享内存空间,不常用。我们注意到 free 很小,buff/cache 却很大,这是 Linux 的内存设计决定的,Linux 的想法是内存闲着反正也是闲着,不如拿出来做系统缓存和缓冲区,提高数据读写的速率。但是当系统内存不足时,buff/cache 会让出部分来,非常灵活的操作。要看比较直观的值,可以加 -h 参数:1.3 dmidecode同样可以使用这个命令,对于内存,可以使用 dmidecode -t memory 查看:1.4 vmstat这个命令也是非常常用了。但对于内存,显示信息有限。它更多是用于进行系统全局分析和 CPU 分析。详细可以看 CPU 分析一文。02 进程内存使用情况分析最常用的两个命令 ps 和 top,虽然很简单的两个命令,但还是有不少学问的。2.1 top/htoptop 命令运行时默认是按照 CPU 利用率进行排序的,如果要按照内存排序,该怎么操作呢?两种方法,一种直接按 “M”(相应的按 “P” 是 CPU),另外一种是在键入 top 之后,按下 “F”,然后选择要排序的字段,再按下 “s” 确认即可。可以看到,我按照 “%MEM” 排序的结果。这个结果对于查看系统占用内存较多的哪些进程是比较有用的。然后这里我们会重点关注几个地方,上面横排区,和前面几个命令一样可以查看系统内存信息,中间标注的横条部分,和内存相关的有三个字段:VIRT、RES、SHR。VIRT:virtual memory usage,进程占用的虚拟内存大小。RES:resident memory usage,进程常驻内存大小,也就是实际内存占用情况,一般我们看进程占用了多少内存,就是看的这个值。SHR:shared memory,共享内存大小,不常用。2.2 psps 同样可以查看进程占用内存情况,一般常用来查看 Top n 进程占用内存情况,如:ps aux –sort=rss | head -n,表示按 rss 排序,取 Top n。这里也关注三个字段:%MEM:进程使用物理内存所占百分比。VSZ:进程使用虚拟内存大小。RSS:进程使用物理内存大小,我们会重点关注这个值。2.3 pmap这个命令用于查看进程的内存映像信息,能够查看进程在哪些地方用了多少内存。 常用 pmap -x pid 来查看。可以看到该进程内存被哪些库、哪些文件所占用,据此我们定位程序对内存的使用。几个字段介绍一下:Address:占用内存的文件的内存起始地址。Kbytes:占用内存的字节数。RSS:实际占用内存大小。Dirty:脏页大小。Mapping:占用内存的文件,[anon] 为已分配的内存,[stack] 为程序堆栈最后的 total 为统计的总值。我们可以使用 pmap -x pid | tail -1 这样只显示最后一行,循环显示最后一行,达到监控该进程的目的。使用:while true; do pmap -x pid | tail -1; sleep 1; doneOK,以上工具都是 Linux 自带的,当然还有很多高阶的工具,比如 atop、memstat 等等,对于内存泄漏有一个比较常用的检测工具 Valgrind,更多干货可以关注我的公众号。通过以上手段,我们基本上就能定位内存问题所在了,究竟是内存太小,还是进程占用内存太多,有哪些进程占用较多,这些进程又究竟有哪些地方占用较多,这些问题通过以上方法都能解决。最后简单总结下,以上不少工具可能有人会犯选择困难症了。对于我来说,查看系统内存用 free -h,分析进程内存占用用 ps 或者 top(首选 ps),深入分析选择 pmap,就酱。参考:Linux下查看内存使用情况的多种方法 http://stor.51cto.com/art/201…我的公众号 CloudDeveloper(ID: cloud_dev),号内有大量书籍和视频资源,后台回复「1024」即可领取,分享的内容包括但不限于云计算虚拟化、容器、OpenStack、K8S、雾计算、网络、工具、SDN、OVS、DPDK、Linux、Go、Python、C/C++编程技术等内容,欢迎大家关注。 ...

March 13, 2019 · 1 min · jiezi

一文掌握 Linux 性能分析之 CPU 篇

PS:欢迎大家关注我的公众号:CloudDeveloper(ID: cloud_dev),专注技术分享,努力打造干货分享平台,二维码在文末可以扫。平常工作会涉及到一些 Linux 性能分析的问题,因此决定总结一下常用的一些性能分析手段,仅供参考。说到性能分析,基本上就是 CPU、内存、磁盘 IO 以及网络这几个部分,本文先来看 CPU 这个部分。CPU 基础信息进行性能分析之前,首先得知道 CPU 有哪些信息,可以通过以下方法查看 CPU 配置信息。lscpu在 Linux 下,类似 lsxxx 这样的命令都是用来查看基本信息的,如 ls 查看当前目录文件信息,lscpu 就用来查看 CPU 信息,类似还有 lspci 查看 PCI 信息。可以看到我的机器配置很低,1 核 2.5GHz(在阿里云买的最低配的服务器)。/proc/cpuinfo/proc 目录是内核透传出来给用户态使用的,里面记录着很多信息文件,比如还有内存文件 meminfo 等。可以使用 cat /proc/cpuinfo 查看 CPU 信息。这里显示的信息可以具体到每个逻辑核上,由于我只有一个核,所以只显示一组信息。dmidecode这个命令是用来获取 DMI(Desktop Management Interface)硬件信息的,包括 BIOS、系统、主板、处理器、内存、缓存等等。对于 CPU 信息,可以使用 dmidecode -t processor 来查看。CPU 使用情况分析知道了 CPU 的基本信息,我们就可以使用另外的命令来对 CPU 的使用情况分析一通了。top相信大家对下面这玩意不陌生,Windows 的任务管理器,top 的作用和它是一样的。top 显示的效果虽说不像它这么华丽,但已然让人惊呼他俩怎么长得这么像。我们重点关注这么几个字段:load average:三个数字分别表示最近 1 分钟,5 分钟和 15 分钟的负责,数值越大负载越重。一般要求不超过核数,比如对于单核情况要 < 1。如果机器长期处于高于核数的情况,说明机器 CPU 消耗严重了。%Cpu(s):表示当前 CPU 的使用情况,如果要查看所有核(逻辑核)的使用情况,可以按下数字 “1” 查看。这里有几个参数,表示如下:- us 用户空间占用 CPU 时间比例- sy 系统占用 CPU 时间比例- ni 用户空间改变过优先级的进程占用 CPU 时间比例- id CPU 空闲时间比- wa IO等待时间比(IO等待高时,可能是磁盘性能有问题了)- hi 硬件中断- si 软件中断- st steal time每个进程的使用情况:这里可以罗列每个进程的使用情况,包括内存和 CPU 的,如果要看某个具体的进程,可以使用 top -p pid 查看。和 top 一样的还有一个改进版的工具:htop,功能和 top 一样的,只不过比 top 表现更炫酷,使用更方便,可以看下它的效果。ps可能很多人会忽略这个命令,觉得这不是查看进程状态信息的吗,其实非也,这个命令配合它的参数能显示很多功能。比如 ps aux。如果配合 watch,可以达到跟 top 一样的效果,如:watch -n 1 “ps aux”(-n 1 表示每隔 1s 更新一次)vmstat这个命令基本能看出当前机器的运行状态和问题,非常强大。可以使用 vmstat n 后面跟一个数字,表示每隔 ns 显示系统的状态,信息包括 CPU、内存和 IO 等。更多更详细的内容大家可以关注我的公众号查看,那里的阅读体验还更好一些。PS:更多干货可以关注我的微信公众号:CloudDeveloper(ID: cloud_dev),坚持分享干货。 ...

March 12, 2019 · 1 min · jiezi

线上大量CLOSE_WAIT原因深入分析

这一次重启真的无法解决问题了:一次 MySQL 主动关闭,导致服务出现大量 CLOSE_WAIT 的全流程排查过程。近日遇到一个线上服务 socket 资源被不断打满的情况。通过各种工具分析线上问题,定位到问题代码。这里对该问题发现、修复过程进行一下复盘总结。先看两张图。一张图是服务正常时监控到的 socket 状态,另一张当然就是异常啦!图一:正常时监控图二:异常时监控从图中的表现情况来看,就是从 04:00 开始,socket 资源不断上涨,每个谷底时重启后恢复到正常值,然后继续不断上涨不释放,而且每次达到峰值的间隔时间越来越短。重启后,排查了日志,没有看到 panic ,此时也就没有进一步检查,真的以为重启大法好。情况说明该服务使用Golang开发,已经上线正常运行将近一年,提供给其它服务调用,主要底层资源有DB/Redis/MQ。为了后续说明的方便,将服务的架构图进行一下说明。图三:服务架构架构是非常简单。问题出现在早上 08:20 左右开始的,报警收到该服务出现 504,此时第一反应是该服务长时间没有重启(快两个月了),可能存在一些内存泄漏,没有多想直接进行了重启。也就是在图二第一个谷底的时候,经过重启服务恢复到正常水平(重启真好用,开心)。将近 14:00 的时候,再次被告警出现了 504 ,当时心中略感不对劲,但由于当天恰好有一场大型促销活动,因此先立马再次重启服务。直到后续大概过了1小时后又开始告警,连续几次重启后,发现需要重启的时间间隔越来越短。此时发现问题绝不简单。这一次重启真的解决不了问题老,因此立马申请机器权限、开始排查问题。下面的截图全部来源我的重现demo,与线上无关。发现问题出现问题后,首先要进行分析推断、然后验证、最后定位修改。根据当时的表现是分别进行了以下猜想。ps:后续截图全部来源自己本地复现时的截图推断一socket 资源被不断打满,并且之前从未出现过,今日突然出现,怀疑是不是请求量太大压垮服务经过查看实时 qps 后,放弃该想法,虽然量有增加,但依然在服务器承受范围(远远未达到压测的基准值)。推断二两台机器故障是同时发生,重启一台,另外一台也会得到缓解,作为独立部署在两个集群的服务非常诡异有了上面的的依据,推出的结果是肯定是该服务依赖的底层资源除了问题,要不然不可能独立集群的服务同时出问题。由于监控显示是 socket 问题,因此通过 netstat 命令查看了当前tcp链接的情况(本地测试,线上实际值大的多)/go/src/hello # netstat -na | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}‘LISTEN 2CLOSE_WAIT 23 # 非常异常TIME_WAIT 1发现绝大部份的链接处于 CLOSE_WAIT 状态,这是非常不可思议情况。然后用 netstat -an 命令进行了检查。图四:大量的CLOSE_WAITCLOSED 表示socket连接没被使用。 LISTENING 表示正在监听进入的连接。 SYN_SENT 表示正在试着建立连接。 SYN_RECEIVED 进行连接初始同步。 ESTABLISHED 表示连接已被建立。 CLOSE_WAIT 表示远程计算器关闭连接,正在等待socket连接的关闭。 FIN_WAIT_1 表示socket连接关闭,正在关闭连接。 CLOSING 先关闭本地socket连接,然后关闭远程socket连接,最后等待确认信息。 LAST_ACK 远程计算器关闭后,等待确认信号。 FIN_WAIT_2 socket连接关闭后,等待来自远程计算器的关闭信号。 TIME_WAIT 连接关闭后,等待远程计算器关闭重发。然后开始重点思考为什么会出现大量的mysql连接是 CLOSE_WAIT 呢?为了说清楚,我们来插播一点TCP的四次挥手知识。TCP四次挥手我们来看看 TCP 的四次挥手是怎么样的流程:图五:TCP四次挥手用中文来描述下这个过程:Client: 服务端大哥,我事情都干完了,准备撤了,这里对应的就是客户端发了一个FINServer:知道了,但是你等等我,我还要收收尾,这里对应的就是服务端收到 FIN 后回应的 ACK经过上面两步之后,服务端就会处于 CLOSE_WAIT 状态。过了一段时间 Server 收尾完了Server:小弟,哥哥我做完了,撤吧,服务端发送了FINClient:大哥,再见啊,这里是客户端对服务端的一个 ACK到此服务端就可以跑路了,但是客户端还不行。为什么呢?客户端还必须等待 2MSL 个时间,这里为什么客户端还不能直接跑路呢?主要是为了防止发送出去的 ACK 服务端没有收到,服务端重发 FIN 再次来询问,如果客户端发完就跑路了,那么服务端重发的时候就没人理他了。这个等待的时间长度也很讲究。Maximum Segment Lifetime 报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃这里一定不要被图里的 client/server 和项目里的客户端服务器端混淆,你只要记住:主动关闭的一方发出 FIN 包(Client),被动关闭(Server)的一方响应 ACK 包,此时,被动关闭的一方就进入了 CLOSE_WAIT 状态。如果一切正常,稍后被动关闭的一方也会发出 FIN 包,然后迁移到 LAST_ACK 状态。既然是这样, TCP 抓包分析下:/go # tcpdump -n port 3306# 发生了 3次握手11:38:15.679863 IP 172.18.0.5.38822 > 172.18.0.3.3306: Flags [S], seq 4065722321, win 29200, options [mss 1460,sackOK,TS val 2997352 ecr 0,nop,wscale 7], length 011:38:15.679923 IP 172.18.0.3.3306 > 172.18.0.5.38822: Flags [S.], seq 780487619, ack 4065722322, win 28960, options [mss 1460,sackOK,TS val 2997352 ecr 2997352,nop,wscale 7], length 011:38:15.679936 IP 172.18.0.5.38822 > 172.18.0.3.3306: Flags [.], ack 1, win 229, options [nop,nop,TS val 2997352 ecr 2997352], length 0# mysql 主动断开链接11:38:45.693382 IP 172.18.0.3.3306 > 172.18.0.5.38822: Flags [F.], seq 123, ack 144, win 227, options [nop,nop,TS val 3000355 ecr 2997359], length 0 # MySQL负载均衡器发送fin包给我11:38:45.740958 IP 172.18.0.5.38822 > 172.18.0.3.3306: Flags [.], ack 124, win 229, options [nop,nop,TS val 3000360 ecr 3000355], length 0 # 我回复ack给它… … # 本来还需要我发送fin给他,但是我没有发,所以出现了close_wait。那这是什么缘故呢?src > dst: flags data-seqno ack window urgent optionssrc > dst 表明从源地址到目的地址flags 是TCP包中的标志信息,S 是SYN标志, F(FIN), P(PUSH) , R(RST) “."(没有标记)data-seqno 是数据包中的数据的顺序号ack 是下次期望的顺序号window 是接收缓存的窗口大小urgent 表明数据包中是否有紧急指针options 是选项结合上面的信息,我用文字说明下:MySQL负载均衡器 给我的服务发送 FIN 包,我进行了响应,此时我进入了 CLOSE_WAIR 状态,但是后续作为被动关闭方的我,并没有发送 FIN,导致我服务端一直处于 CLOSE_WAIR 状态,无法最终进入 CLOSED 状态。那么我推断出现这种情况可能的原因有以下几种:负载均衡器 异常退出了,这基本是不可能的,他出现问题绝对是大面积的服务报警,而不仅仅是我一个服务MySQL负载均衡器 的超时设置的太短了,导致业务代码还没有处理完,MySQL负载均衡器 就关闭tcp连接了这也不太可能,因为这个服务并没有什么耗时操作,当然还是去检查了负载均衡器的配置,设置的是60s。代码问题,MySQL 连接无法释放目前看起来应该是代码质量问题,加之本次数据有异常,触发到了以前某个没有测试到的点,目前看起来很有可能是这个原因查找错误原因由于代码的业务逻辑并不是我写的,我担心一时半会看不出来问题,所以直接使用 perf 把所有的调用关系使用火焰图给绘制出来。既然上面我们推断代码中没有释放mysql连接。无非就是:确实没有调用close有耗时操作(火焰图可以非常明显看到),导致超时了mysql的事务没有正确处理,例如:rollback 或者 commit由于火焰图包含的内容太多,为了让大家看清楚,我把一些不必要的信息进行了折叠。图六:有问题的火焰图火焰图很明显看到了开启了事务,但是在余下的部分,并没有看到 Commit 或者是Rollback 操作。这肯定会操作问题。然后也清楚看到出现问题的是:MainController.update 方法内部,话不多说,直接到 update 方法中去检查。发现了如下代码:func (c *MainController) update() (flag bool) { o := orm.NewOrm() o.Using(“default”) o.Begin() nilMap := getMapNil() if nilMap == nil {// 这里只检查了是否为nil,并没有进行rollback或者commit return false } nilMap[10] = 1 nilMap[20] = 2 if nilMap == nil && len(nilMap) == 0 { o.Rollback() return false } sql := “update tb_user set name=%s where id=%d” res, err := o.Raw(sql, “Bug”, 2).Exec() if err == nil { num, _ := res.RowsAffected() fmt.Println(“mysql row affected nums: “, num) o.Commit() return true } o.Rollback() return false}至此,全部分析结束。经过查看 getMapNil 返回了nil,但是下面的判断条件没有进行回滚。if nilMap == nil { o.Rollback()// 这里进行回滚 return false}总结整个分析过程还是废了不少时间。最主要的是主观意识太强,觉得运行了一年没有出问题的为什么会突然出问题?因此一开始是质疑 SRE、DBA、各种基础设施出了问题(人总是先怀疑别人)。导致在这上面费了不少时间。理一下正确的分析思路:出现问题后,立马应该检查日志,确实日志没有发现问题;监控明确显示了socket不断增长,很明确立马应该使用 netstat 检查情况看看是哪个进程的锅;根据 netstat 的检查,使用 tcpdump 抓包分析一下为什么连接会被动断开(TCP知识非常重要);如果熟悉代码应该直接去检查业务代码,如果不熟悉则可以使用 perf 把代码的调用链路打印出来;不论是分析代码还是火焰图,到此应该能够很快定位到问题。那么本次到底是为什么会出现 CLOSE_WAIR 呢?大部分同学应该已经明白了,我这里再简单说明一下:由于那一行代码没有对事务进行回滚,导致服务端没有主动发起close。因此 MySQL负载均衡器 在达到 60s 的时候主动触发了close操作,但是通过tcp抓包发现,服务端并没有进行回应,这是因为代码中的事务没有处理,因此从而导致大量的端口、连接资源被占用。在贴一下挥手时的抓包数据:# mysql 主动断开链接11:38:45.693382 IP 172.18.0.3.3306 > 172.18.0.5.38822: Flags [F.], seq 123, ack 144, win 227, options [nop,nop,TS val 3000355 ecr 2997359], length 0 # MySQL负载均衡器发送fin包给我11:38:45.740958 IP 172.18.0.5.38822 > 172.18.0.3.3306: Flags [.], ack 124, win 229, options [nop,nop,TS val 3000360 ecr 3000355], length 0 # 我回复ack给它希望此文对大家排查线上问题有所帮助。为了便于帮助大家理解,下面附上正确情况下的火焰图与错误情况下的火焰图。大家可以自行对比。正确情况下的火焰图错误情况的火焰图我参考的一篇文章对这种情况提出了两个思考题,我觉得非常有意义,大家自己思考下:为什么一台机器几百个 CLOSE_WAIR 就导致不可继续访问?我们不是经常说一台机器有 65535 个文件描述符可用吗?为什么我有负载均衡,而两台部署服务的机器确几乎同时出了 CLOSE_WAIR ?参考文章:又见CLOSE_WAITTCP 4-times close个人公众号:dayuTalk ...

December 10, 2018 · 2 min · jiezi

不改一行代码定位线上性能问题

背景最近时运不佳,几乎天天被线上问题骚扰。前几天刚解决了一个 HashSet 的并发问题,周六又来了一个性能问题。大致的现象是:我们提供出去的一个 OpenAPI 反应时快时慢,快的时候几十毫秒,慢的时候几秒钟才响应。尝试解决由于这种也不是业务问题,不能直接定位。所以尝试在测试环境复现,但遗憾的测试环境贼快。没办法只能硬着头皮上了。中途有抱着侥幸心里让运维查看了 Nginx 里 OpenAPI 的响应时间,想把锅扔给网络。结果果然打脸了;Nginx 里的日志也表明确实响应时间确实有问题。为了清晰的了解这个问题,我简单梳理了这个调用过程。整个的流程算是比较常见的分层架构:客户端请求到 Nginx。Nginx 负载了后端的 web 服务。web 服务通过 RPC 调用后端的 Service 服务。日志大法我们首先想到的是打日志,在可能会慢的方法或接口处记录处理时间来判断哪里有问题。但通过刚才的调用链来说,这个请求流程不短。加日志涉及的改动较多而且万一加漏了还有可能定位不到问题。再一个是改动代码之后还会涉及到发版上线。工具分析所以最好的方式就是不改动一行代码把这个问题分析出来。这时就需要一个 agent 工具了。我们选用了阿里以前开源的 Tprofile 来使用。只需要在启动参数中加入 -javaagent:/xx/tprofiler.jar 即可监控你想要监控的方法耗时,并且可以给你输出报告,非常方便。对代码没有任何侵入性同时性能影响也较小。工具使用下面来简单展示下如何使用这个工具。首先第一步自然是 clone 源码然后打包,可以克隆我修改过的源码。因为这个项目阿里多年没有维护了,还残留一些 bug,我在它原有的基础上修复了个影响使用的 bug,同时做了一些优化。执行以下脚本即可。git clone https://github.com/crossoverJie/TProfilermvn assembly:assembly到这里之后会在项目的 TProfiler/pkg/TProfiler/lib/tprofiler-1.0.1.jar 中生成好我们要使用的 jar 包。接下来只需要将这个 jar 包配置到启动参数中,同时再配置一个配置文件路径即可。这个配置文件我 copy 官方的解释。#log file namelogFileName = tprofiler.logmethodFileName = tmethod.logsamplerFileName = tsampler.log#basic configuration items# 开始取样时间startProfTime = 1:00:00# 结束取样时间endProfTime = 23:00:00# 取样的时间长度eachProfUseTime = 10# 每次取样的时间间隔eachProfIntervalTime = 1samplerIntervalTime = 20# 端口,主要不要冲突了port = 50000debugMode = falseneedNanoTime = false# 是否忽略 get set 方法ignoreGetSetMethod = true#file paths 日志路径logFilePath = /data/work/logs/tprofile/${logFileName}methodFilePath =/data/work/logs/tprofile/${methodFileName}samplerFilePath =/data/work/logs/tprofile/${samplerFileName}#include & excludes itemsexcludeClassLoader = org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader# 需要监控的包includePackageStartsWith = top.crossoverjie.cicada.example.action# 不需要监控的包excludePackageStartsWith = com.taobao.sketch;org.apache.velocity;com.alibaba;com.taobao.forest.domain.dataobject最终的启动参数如下:-javaagent:/TProfiler/lib/tprofiler-1.0.1.jar-Dprofile.properties=/TProfiler/profile.properties为了模拟排查接口响应慢的问题,我用 cicada 实现了一个 HTTP 接口。其中调用了两个耗时方法:这样当我启动应用时,Tprofile 就会在我配置的目录记录它所收集的方法信息。我访问接口 http://127.0.0.1:5688/cicada-example/demoAction?name=test&id=10 几次后它就会把每个方法的明细响应写入 tprofile.log。由左到右每列分别代表为:线程ID、方法栈深度、方法编号、耗时(毫秒)。但 tmethod.log 还是空的;这时我们只需要执行这个命令即可把最新的方法采样信息刷到 tmethod.log 文件中。java -cp /TProfiler/tprofiler.jar com.taobao.profile.client.TProfilerClient 127.0.0.1 50000 flushmethodflushmethod success其实就是访问了 Tprofile 暴露出的一个服务,他会读取、解析 tprofile.log 同时写入 tmethod.log.其中的端口就是配置文件中的 port。再打开 tmethod.log :其中会记录方法的信息。第一行数字为方法的编号。可以通过这个编号去 tprofile.log(明细)中查询每次的耗时情况。行末的数字则是这个方法在源码中最后一行的行号。其实大部分的性能分析都是统计某个方法的平均耗时。所以还需要执行下面的命令,通过 tmethod.log tprofile.log 来生成每个方法的平均耗时。java -cp /TProfiler/tprofiler.jar com.taobao.profile.analysis.ProfilerLogAnalysis tprofiler.log tmethod.log topmethod.log topobject.logprint result success打开 topmethod.log 就是所有方法的平均耗时。4 为请求次数。205 为平均耗时。818 则为总耗时。和实际情况是相符的。方法的明细耗时这是可能还会有其他需求;比如说我想查询某个方法所有的明细耗时怎么办呢?官方没有提供,但也是可以的,只是要麻烦一点。比如我想查看 selectDB() 的耗时明细:首先得知道这个方法的编号,在 tmethod.log 中可以看查到。2 top/crossoverjie/cicada/example/action/DemoAction:selectDB:84编号为 2.之前我们就知道 tprofile.log 记录的是明细,所以通过下面的命令即可查看。grep 2 tprofiler.log通过第三列方法编号为 2 的来查看每次执行的明细。但这样的方式显然不够友好,需要人为来过滤干扰,步骤也多;所以我也准备加上这样一个功能。只需要传入一个方法名称即可查询采集到的所有方法耗时明细。总结回到之前的问题;线上通过这个工具分析我们得到了如下结果。有些方法确实执行时快时慢,但都是和数据库相关的。由于目前数据库压力较大,准备在接下来进行冷热数据分离,以及分库分表。在第一步操作还没实施之前将部分写数据库的操作改为异步,减小响应时间。考虑接入 pinpoint 这样的 APM工具。类似于 Tprofile 的工具确实挺多的,找到适合自己的就好。在还没有使用类似于 pinpoint 这样的分布式跟踪工具之前应该会大量依赖于这个工具,所以后续说不定也会做一些定制,比如增加一些可视化界面等,可以提高排查效率。你的点赞与分享是对我最大的支持 ...

November 12, 2018 · 1 min · jiezi