性能分析的前提是将应用程序内部的运行情况以及应用运行环境的情况以一种可视化的方式更加直接的展示出来,如何来达到这种可视化的展现呢?咱们须要配合使用操做系统中集成的程序监控工具和 Java 中内置的监控分析工具来进行 Java 程序的性能分析。本文为系列文章,共三篇分别介绍这几类工具。在本文中将介绍操做系统中的性能监控工具。html
操做系统中的程序性能监控工具并不是只针对于 Java 程序,适用于全部运行其中的程序。在基于 UNIX 的操做系统中,有许多命令行工具能够用来监控程序的运行情况,例如 sar, vmstat, iostat,prstat 等等。在 Windows 操做系统中,既有图形化用户界面的资源监控器 Perfmon(Performance Monitor),也有如 typeperf 的命令行工具。java
进行性能测试时,咱们须要经过操做系统提供的工具收集操做系统中的各种资源监控数据,包括 CPU、内存和硬盘的使用数据,若是被测试程序使用了网络,还须要收集网络使用数据。只有收集的数据足够完整和充分,性能测试的结果才会更准确,性能分析也会更加容易进行。下面将首先介绍在 UNIX/类 UNIX 系统中各种资源的监控和分析的方法。ios
CPU 使用时间分为两类:用户时间(User Time)和系统时间(System Time),系统时间在 Windows 系统中被称为特权时间(Privileged Time)。用户时间为 CPU 执行应用程序代码的时间,而系统时间则为 CPU 执行操做系统内核代码的时间比例。系统时间与应用程序自己有关,例如当应用程序执行 I/O 操做时,操做系统内核将会执行从硬盘读取文件的代码,或者执行向网络数据缓存中写入数据的代码。应用程序中任何须要使用操做系统底层资源的行为都会致使应用程序占用更多的系统时间。数据库
性能调优的终极目标是在单位时间内最大限度提升 CPU 使用率。CPU 使用率是在一个特定时间间隔内的平均值,这个时间间隔能够是 30 秒,也能够是 1 秒。好比,一个程序须要 10 分钟执行完成,在此期间该程序的 CPU 使用率为 50%。当对程序代码优化以后,CPU 使用率提升为 100%,那么该程序的性能将提高一倍,只须要 5 分钟执行完成。当该程序再次优化代码使用 2 个 CPU,CPU 的使用率依然为 100%,那么该程序将只须要 2.5 分钟执行结束。从这个例子能够看出,CPU 使用率可以反应程序使用 CPU 的效率,CPU 使用率越高程序性能越好,反之亦然。缓存
在 Linux 操做系统中执行 vmstat 5 命令,将会获得如清单 1 中的数据(每 5 秒增长一行)。为了易于理解,此例中的程序只使用单线程运行,在多线程环境中一样适用。从示例数据中第一行数据能够知道,在 5 秒内,CPU 一共被使用了 2.25 秒(5*(37%+8%)),其中 37%的时间用于执行用户代码,8%的时间用户执行系统代码。剩余的 2.75 秒 CPU 处于闲置状态(idle)。安全
procs -----------memory--------------- ----swap---- ---io--- -----system------ ----------CPU-------r b swpd free buff cache si so bi bo in cs us sy id wa st2 0 236456 2259632 200052 730348 0 0 1 6 1 1 37 8 55 0 02 0 236456 2259624 200052 730348 0 0 0 10 179 332 40 7 53 0 02 0 236456 2259624 200052 730348 0 0 0 20 180 356 56 7 37 0 0
如下三点缘由会形成 CPU 闲置:bash
前两种状况比较容易理解,也有对应的调优方式。针对缘由一,若是可以减小锁的竞争,或者调整数据库返回请求资源的性能,那么应用程序会运行的更快;对于缘由二,优化请求响应方,提升响应速度;那么在其余条件不变的状况下,应用程序会运行的更快,CPU 使用率也会提升。服务器
第三种状况当应用程序有事去作时,CPU 将利用 CPU 周期去执行应用程序的代码。这是一条通用的规则。当执行一段无限循环的代码(以下所示)时,它将会再消耗一个 CPU 100%的时间。若是 CPU 的使用率并无达到 100%,意味着操做系统应该执行无限循环,但它并无去作而是处于闲置状态。这种状况对于无限循环并无多少影响,可是若是咱们的程序是用来计算一个表达式的结果,那么这种状况将会致使计算的速度变慢。网络
#!/bin/bashwhile truedo echo“In the loop…”done
当在一台单核机器上运行清单 2 中的代码,绝大多数时间咱们不会注意到它在运行。可是若是启动另外一个程序或者监控另外一个程序的性能时,这种影响就会体现出来。操做系统善于利用时间切片程序来竞争 CPU 周期,可是最新启动的程序只能得到极少的的可用 CPU 周期。有一种解决问题的方案,那就是留出必定比例的闲置 CPU 周期以防有其余程序须要使用 CPU。可是这种方案暴露出来的问题就是操做系统没法知晓下一步操做,操做系统只能去执行当前全部的操做而不会留出闲置的 CPU 周期。多线程
咱们回到 Java 应用程序,周期性的 CPU 闲置意味着什么呢?这取决于应用程序的类型。对于有固定做业量的批处理程序,除非所有做业完成,不然 CPU 不会有闲置时间。提升 CPU 的使用率可使批处理程序更快地完成。若是 CPU 使用率已经达到 100%,咱们能够在保持 CPU 使用率 100%的前提下从其余方面进行优化使程序完成地更快。
对于接收请求的服务器类型的应用程序,在没有请求到来的时候,CPU 会处于闲置状态。举例来讲,当 Web 服务器处理完当前全部 HTTP 请求处于等待下一个请求的状态时,CPU 为闲置状态。从这里能够理解 CPU 使用率为什么为必定时间间隔内的平均数值。上文 vmstat 示例中的数据采集自一个应用服务器的运行过程当中,这个服务器每 5 秒接收到一个请求,花费 2.25 秒处理,这意味着在这 2.25 秒内 CPU 的使用率为 100%,而在剩下的 2.75 内使用率为 0。由此计算得出 CPU 使用率为 45%。
这种状况老是发生在很是短的时间间隔内,所以很难被发现,可是这种相似应用服务器的程序老是按照此方式运行。当咱们下降时间间隔,上述应用服务每 2.5 秒接受一个请求同时花费 1.125 秒处理请求,剩余的 1.375 秒 CPU 处于闲置状态。平均下来,CPU 平均使用率依然为 45%,55%的时间处于闲置状态。
优化应用服务器以后,处理每一个请求只须要 2 秒,CPU 使用率将降至 40%。下降 CPU 使用率是咱们优化程序代码的目标。只有在单位时间内,没有外部资源约束的应用程序负载固定。从另外一方面来说,优化这种应用程序能够适当增长程序负载来提高 CPU 使用率。这样一来,能够看出这种优化策略依然遵循前文的规则,即在尽量短的时间内使 CPU 使用率尽量高。
调优多线程程序的目标依然是尽量的提升每一个 CPU 的使用率,使 CPU 尽量少的被阻塞。在多核多线程环境中,当 CPU 处于闲置状态时须要多考虑的是即便应用程序有做业未完成,CPU 依然会处于闲置状态,由于该应用程序中没有可用的线程来处理做业。最典型的例子为一个拥有固定大小线程池的应用程序运行数量变化的任务。每一个线程每次只能处理一个任务,若是此线程被某些操做阻塞,这个线程不能转而去处理另外一个任务。在这种状况下就会出现没有可用线程来处理未完成的任务。所以会致使 CPU 处于闲置状态。对于此种情形应该考虑如何增长线程池的大小来完成更多的任务。
监控 CPU 使用率只是理解应用程序性能的第一步,这只能肯定代码的 CPU 使用率是否达到开发人员的指望,或者找到代码中存在的同步问题和资源问题。
在 Windows 和 UNIX 系统中均可以监控当前能够执行任务的线程数。UNIX 系统中称为 Run Queue,有不少工具能够查到此数据。例如前文中的 vmstat,每行的第一个数字便是 Run Queue 的长度。Windows 系统中称之为 Processor Queue,能够经过 typeperf 命令查到。
Windows 与 UNIX 的区别是:在 UNIX 中,Run Queue 长度为当前正在运行和能够运行的线程数,因此这个长度最小为 1;而在 Windows 中,Processor Queue 长度并不包括正在运行的线程数,所以 Processor Queue 长度最小值为 0。
当可用线程数大于可用 CPU 数量,性能就会降低。因此在 Windows 中 Processor Queue 长度为 0,在 UNIX 中 Run Queue 长度等于 CPU 数的状况性能达到最好。但这并不绝对,由于系统程序中会周期性运行致使此数值增大,单对应用程序的影响不大。若是 Run Queue 长度长时间远远大于 CPU 数,表示机器负载过大,应该适当减小当前机器的做业量。
监控硬盘使用率有两个重要的目标,一是应用程序自己,若是应用程序进行了很是多的硬盘 I/O 操做,很容易推断出应用程序的性能瓶颈在于 I/O。
须要进行详细的监控才能发现应用程序的性能瓶颈在于 I/O。当应用程序没有高效地使用缓存来进行硬盘写操做时,硬盘 I/O 的数据将会很是低。可是当应用程序进行的 I/O 操做数超出了硬盘可以处理的数量,硬盘 I/O 数据将会很是高。这两种状况都须要进行调优。
在 Linux 系统中执行 iostat -xm 5 命令能够获得清单 3 中的数据:
avg-CPU: %user %nice %system %iowait %steal %idle18.20 0.00 40.20 0.00 0.00 51.60Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s sda 0.00 0.20 0.00 34.60 0.10 0.23avgrq-sz avgqu-sz await svctm %util 8.35 0.00 5.04 0.04 2.02
应用程序在向硬盘 sda 中写入数据,看上去硬盘写入的时间状况还不错,每次写入等待时间(await)为 5.04 毫秒,硬盘使用率也仅为 2.02%。但仔细来看,系统执行内核代码用掉 40.2%的时间,这是意味着应用程序中存在低效的写操做。系统每秒进行 34.60(w/s)次写操做,可是只写入了 0.23MB(wMB/s) 数据。能够判断 I/O 是应用程序的性能瓶颈所在。下一步将分析应用程序如何进行写操做。
再看另外一组数据(清单 4),硬盘使用率(%util)达到 100%,等待硬盘的时间占到了 49.81%(%iowait),应用程序每秒写入 60.45mb 数据,这些数据共同证实 I/O 是应用程序的性能瓶颈所在,必须减小如此大量的 I/O 操做。
avg-CPU: %user %nice %system %iowait %steal %idle40.20 0.00 5.70 49.81 0.00 54.10Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s sda 0.00 0.20 0.00 134.60 0.10 60.45avgrq-sz avgqu-sz await svctm %util 727.24 68.46 798.04 5.67 100
监控硬盘使用率的另外一个做用是得知系统是否在进行交换(swapping),计算机拥有固定数量的物理内存,可是它能够运行使用内存远远大于其物理内存的一些应用程序。应用程序占有的内存每每多于它们真正须要的内存,在这种状况下,操做系统将这些没有被用到内存挪入硬盘,当须要的时候将它们经过换页换进物理内存中。对于大多数应用程序,这种内存管理方式是不错的,可是对于服务器类型的应用程序而言,这种方式就显得尤其糟糕,由于因为 Java 内存堆的存在,服务器类型的应用每每须要用到很是多的物理内存。
因为须要将硬盘中的数据与物理内存中的数据进行交换,会严重影响系统性能。vmstat 命令的结果中 si,so 两列数据表示了换入物理内存和换出物理内存的数据量。经过这些数据能够知道系统是否在进行交换。
若是应用程序运行过程当中使用了网络,在进行性能监控时必须监控系统网络传输使用率。网络传输相似于硬盘传输,低效地使用网络传输会形成网络带宽不足;若是网络传输的数据量超过了其所能负载的上限一样会形成网络传输性能瓶颈。
操做系统内置的网络监控工具只能得到某个网络接口接收和发送的包数和字节数。经过这些信息还不足以肯定网络负载正常仍是负载过大。
在 UNIX 系统中,基本的网络监控工具是 netstat。
固然,还有很是多的第三方网络监控工具,nicstat 就是 UNIX 系统中使用很普遍的一个命令行工具,经过这个工具能够获得指定网络接口的使用率。
执行 nicstat 5 命令,获得清单 5 中的数据,从数据中能够看到,网络接口 e1000g1 为 1000MB 接口,该接口使用率只有 2.98%(%Util),每秒钟经过此接口读入 156.4Kb 数据,写入 256.9Kb 数据,经过这些数据,能够明确得出网络接口的带宽以及使用率。
Time Int rKB/s wKB/s rPk/s wPk/s rAvs wAvs %Util Sat 17:05:17 e1000g1 156.4 256.9 875.0 909.5 215.4 175.3 2.98 0.00
若是只用 netstat 命令,能够得到每秒读写的数据量,可是必须知道网络带宽而且经过额外的脚本才能计算得出网络接口的使用率。在计算过程当中须要注意,带宽单位为位每秒(bps),所以 1000Mb 带宽每秒能够传输 125MB 数据。而在 nicstat 已经帮咱们作了相似的计算。
网络传输没法支撑 100%的使用率,在本地以太网网络,超过 40%的使用率就被认为接口饱和。使用其余媒介进行网络传输的饱和使用率须要咨询网络架构师。Java 程序只是使用操做系统的网络接口进行传输,并不能决定网络使用率的饱和值。
下面将主要介绍 Windows 系统的系统监控工具 Perfmon。Perfmon 是 Windows 系统自带的性能监控工具,能够监控包括上文所述的各种系统资源的使用状况,并提供图形化的用户展现界面。Perfmon 包括性能监视器、计数器日志、跟踪日志和警报四个部分。
1. 性能监视器
在 Windows 系统的命令行中运行 perfmon.msc 命令便可启动 Perfmon 的性能监视器的用户界面。经过性能监视器,能够对 CPU、硬盘、网络的资源进行实时监控。具体的分析方式与 Linux 系统中相似,在此再也不赘述。使用下面将要介绍的计数器日志能够保存这些监控数据
性能监视器的另外一个功能是将计数器日志保存的数据以图形化的形式展示给用户。经过“查看当前活动”或者“查看日志数据”功能来指定监控的资源。
2. 计数器日志
虽然性能监视器能够实时监控系统资源,但并不能保存监控数据,若是须要持续对系统的监控数据采样,必须使用 Perfmon 的计数器日志功能。用户可使用系统监视器或者其余工具对计数器日志保存的数据的进行分析。
3. 跟踪日志
经过跟踪日志功能,用户能够跟踪某些重要的系统事件,能够跟踪指定的应用程序。跟踪日志默认被保存为扩展名为.etl 二进制文件,可使用 tracert 命令对文件进行分析,并生成 CSV 格式的 Dump 文件。
目前必须经过编辑系统注册表的形式配置跟踪的应用程序以及保存日志文件的路径。
4. 警报
当某个计数器的性能监控数据达到预先设定的阀值时,将会触发 Perfmon 的警报,警报是指预先设定的动做,如发送电子邮件、运行指定的命令等动做。也能够将警报动做设置为将警报做为系统事件记录,这样就能够在事件查看器中查看警报的内容。针对不一样的应用能够指定不一样的警报策略。例如当 CPU 的闲置时间低于 80%时触发警报,将发送邮件给系统维护人员;或者当内存使用率高于 90%时出发警报,执行 typeperf 命令收集保存数据。
必须是管理员用户才能使用 Perfmon,Perfmon 有两种部署方式:本地监控模式和远程监控模式。
在本地监控模式中,日志文件被默认保存在 C:\perflogs 目录中,能够在“日志文件”下修改此目录。本地监控生成的日志文件既能够在本机使用性能监视器进行分析,也能够传输到其余分析平台中分析。
在远程监控模式中,在创建监控主机与被监控主机之间信任关系并打开远程访问控制的前提下,能够对局域网内的多台目标监控机器进行集中采样监控。但随之而来的是安全隐患,因此在访问控制比较严格的环境下,远程监控模式难以实施。
在部署过程当中还需考虑日志文件存储问题,设置合适的采样间隔时间,若是设置太小,日志文件会快速递增,若是设置过大,监控数据会出现较大偏差。
Perfmon 有两种管理方式:控制台管理和命令行管理,如前文所述,经过运行 perfmon.msc 能够打开控制台管理器,并根据监控策略管理控制台。经过命令 Logman 能够在命令行中建立、启动、中止日志 Session。主要包括 create, start, stop, delete, query, update 这些参数,具体的使用方法参考 Logman 帮助文档。除了 Logman 命令,Typeperf 命令也是 Windows 中经常使用的系统功能监控命令,经过此命令能够得到 Perfmon 中全部资源当前的性能数据,但不能生成日志和设置警报。咱们将 Typeperf 的输出重定向至文本文件中,使用第三方工具进行分析。Typeperf 能够配合其余性能工具一块儿使用,经过定制计划任务执行此命令能够定时得到系统的性能数据。
本文在性能监测和优化方面给出了多种方法,并结合 CPU 时间特性阐述了其性能影响的因素和缘由。整体上讲,性能监测首先应当从应用程序运行时所消耗的 CPU 时间来入手,剖析其运行状态,以及资源消耗的瓶颈在哪里。其次,以 CPU 使用率的提高为目标来优化代码。
性能监测还能够经过监测硬盘的使用状况来得到,大量硬盘的读写将会产生应用程序的性能问题,这就要求咱们的程序设计人员在设计程序的时候尽可能下降减小磁盘的读写操做,以及读写的数据量,并采用缓存交换的数据的形式提高应用程序性能。
对基于网络的应用程序,监测其网络传输的开销,也是性能监测的一种方法。大量数据在网络层面上的交换也会带来性能上的开销。
最后,本文讲解了 Java 自带的性能分析工具的使用,在使用这些工具的时候请你们铭记一点,
没有一个完美的工具来帮您彻底理解应用程序的总体性能问题,实际工做中咱们可能须要结合多种工具来完成一个应用程序的性能分析。不一样的工具备不一样的方向,全方面的理解和使用才可以更好的完成分析任务。
原做者:李 伟军, 宋 翰瀛, 和 杨 翔宇
原文连接: 操做系统工具
原出处:IBM Developer