`
hegan_2009
  • 浏览: 12208 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
最近访客 更多访客>>
社区版块
存档分类
最新评论

应用性能分析与优化

阅读更多

1、性能调优的步骤
    1.1、衡量系统现状
        包括请求次数、响应时间、资源消耗等;如:A系统目前95%的请求响应为1s。

    1.2、设定调优目标
        根据用户所能接受的响应速度、系统现有的机器、所支撑的用户量制定出来的,因此通常会设定调优目标:95%的      请求在500ms内返回。

    1.3、寻找性能瓶颈
        在【2、寻找性能瓶颈】会专门介绍。通常性能瓶颈的表像是:
        1.3.1、资源消耗过多(CPU、文件IO、网络IO、内存)
        1.3.2、外部系统处理不足(所调用的其他系统提供的功能——多数情况也是资源消耗过多、数据的操作响应速度               不够——根据数据库SQL执行速度、数据库机器的IOPS、数据库的Active Sessions等分析出来的)
        1.3.3、程序代码运行效率不够高,未充分使用资源或程序结构不合理。

    1.4、性能调优
        在后面的【3、性能调优】会专门介绍

    1.5、衡量是否达到目标值
        优化部署后,达到目标则结束,如果没有则重复1.3、1.4步骤

2、寻找性能瓶颈

    2.1、CPU消耗分析(top、pidstat等方式查看cpu消耗状况;vmstat查看cpu的上下文切换、运行队列、利用率)
        在Linux中,CPU消耗主要用于中断、内核以及用户进程的任务处理。优先级为:中断>内核>用户进程。cpu消耗
    严重时,主要体现在:
        ①us—用户进程所占的%
            过高的原因:1、线程一直处于可运行(Runnable)状态,通常线程在执行无阻塞、循环、正则或纯粹的计算
                                等动作引起的。
                             2、频繁的GC操作引起。如:每次请求需要分配较多内存,当访问量高的时,就不断的进行GC,
                                系统响应速度下降。进而造成堆积的请求更多,消耗内存更严重,最严重的时候可能导致系统                                   不断的进行FULL GC。可通过JVM内存的消耗分析来查找原因。
            可通过kill -3 [javapid]、jstack [pid] | grep 'nid=0X....'的方式dump出应用的java线程信息。通过转换
        出的十六进制的值就可以找到对应的nid值的线程。该线程即为消耗CPU的线程。在采样时多执行几次上诉过程,
        以确保找到真实的消耗CPU的线程。也可以通过intel vtune这样的商业软件进行分析

        ②sy—内核线程所占的%
            过高的原因:Linux花费更多的时间在进行线程切换。Java应用造成这个原因是:因为启动了的线程比较多,且
        这些线程多数都处于不断的阻塞(锁等待、IO等待状态)和执行状态的变化过程,导致了操作系统需要不断的切换
        执行的线程。从而产生大量的上下文切换。
           
            可通过kill -3 [javapid]、jstack -1 [javapid]的方式dump出Java应用线程信息,查看线程的状态、锁信息,
        找出等待状态或锁竞争过多的线程。结合vvmstat查看CPU消耗状况。如cs(上下文切换)、sy等。

        ③ni—被nice命令改变优先级的任务所占的%
        ④id—CPU空闲时间所占的%
        ⑤wa—执行过程中等待io所占的%
        ⑥hi—硬件中断所占的%
        ⑦si—软件中断所占的%

    2.2、文件IO消耗分析(通过pidstat、iostat命令分析)
        Java应用造成io消耗严重主要是:
            ① 多个线程需要大量内容写入(如频繁的log写入)动作;
            ② 磁盘设备本身的处理速度慢
            ③ 文件系统慢
            ④ 操作的文件本身已经很大

    2.3、网络IO消耗分析(通过sar命令,如需跟着TCP/IP通信过程的信息,则可通过tcpdump来进行)
            对于分布式Java应用而言,网络IO的消耗非常值得关注,尤其要注意网络中断是不是均衡地分配到各CPU的
    (通过cat/proc/interrupts命令查看)。对于网卡只分配到一个CPU的现象采用修改kernle方法(Google使用)、       采用支持MSI-X的网卡进行修复。
        由于没办法分析具体每个线程所消耗的网络IO,因此当网络IO消耗高时,对于Java应用而言只能对线程进dump。
    查找产生大量网络IO操作的线程,这些线程的特征是读取或写入网络流,在Java网络通信时,通常要对对象进行序列
    化为字节流,进行发送,或者读取。并反序列化为对象。这个过程要消耗JVM堆内存,JVM对内存通常是有限的。因此
    Java应用一般不会造成网络IO消耗严重。

    2.4、内存消耗分析(vmstat、sar、pidstat、top)
        目前Java应用只有在创建线程和使用Direct ByteBuffer时才会操作JVM堆意外的内存。对于JVM堆以外的内存方
    面消耗,最为值得关注的是swpd的消耗以及物理内存的消耗(可通过vmstat、sar、top、pidstat等方式查看swap
    和物理内存的消耗状况)。

    2.5、消耗资源不多,在访问量不大的情况。但程序执行慢的原因,主要有3方面
        ① 锁竞争激烈(如:数据库连接池数,但是请求数多于连接池数)
        ② 未充分使用硬件资源(如:多核CPU,但程序却采用单线程串行操作。)
        ③ 数据量增长(如:数据量的海量增长。可对数据库的表拆分、库拆分)


3、性能调优
    3.1JVM调优

        3.1.1、代大小调优
            ① 避免新生代大小设置过小
            1、避免频繁进行minor GC;2、可能导致minor GC对象直接进入旧生代,占据旧生代空间,触发FULL GC。
            ② 避免新生代设置过大
            1、导致旧生代变小,可能导致FULL GC频繁执行;2、导致minor GC的耗时大幅度增加。
            ③ 避免survivor space过小或者过大           
            ④ 根据具体代码合理设置新生代的存活周期。

        3.1.1、GC策略调优
                串行GC性能太差,因此实际应用时主要是应用并行和并发GC,
                大部分Web应用在处理请求时设置了一个最大可同时处理的请求数,当超出此请求数时,会将之后的请求放             入等待队列中,而这个等待队列也限制了大小。当等待队列满了后,仍然有请求进入,那么这些请求将丢弃,所
            有的请求又都是有超时限制度。
                在这种情况下如果触发了FULL GC造成应用暂停时间较长的FULL GC,则有可能等这次FULL GC之后,应
            用中很多请求就超时或者被丢弃了。
                从上面可以看出,Web应用非常需要一个对应用造成暂停时间较短的GC,再加上大部分Web应用的瓶颈都
            不在CPU上。因此对于Web应用而言,在G1还不够成熟的情况下,CMS GC是不错的选择。
   
    3.2、程序调优
        3.2.1、CPU us高的解决方法
            ① 执行线程无任何挂起动作,且一直运行,导致CPU没有机会去调度执行其他的线程,造成线程饿死的现象。
                解决:对这种线程的动作增加Thread.sleep(int),以释放CPU的执行权,降低CPU的消耗。
                原理:以损失单次执行性能为代价,但由于降低了CPU消耗,在多线程的情况下,反而提高了平均性能。

            ② 状态扫描。如:某线程要等其他线程改变了值才可以继续执行。
                解决:改为采用wait/notify机制。

            ③ 循环次数过多、正则、计算等造成CPU us过高的情况。结合业务需求进行调优。code review是王道。

            ④ 频繁GC造成us高的情况,通过JVM调优或程序调优,降低GC的执行次数。
       
        3.2.2、CPU sy高的解决方法
            ① 线程运行状态经常切换
                解决:减少线程数,且使用线程池
           
            ② 线程之间锁竞争激烈
                解决:尽可能降低锁的竞争。
                    1、使用并发包中的类(java.util.concurrent.*)
                    2、使用Treiber算法
                    3、使用Michael-Scott非阻塞队列算法(ConcurrentLinkedQueue就是典型的该算法的非阻塞队列)
                    4、通常没必要对整个方法加锁,只对需要控制资源的地方做加锁操作。
                    5、拆分锁,把独占锁拆分为多把锁,如:ConcurrentHashMap。很大程度上可以提高读写速度。
                    6、去除读写操作的互斥锁

            ③ 较多网络IO操作或者确实需要一些锁竞争机制(如数据库连接池),但为了能够支持高的并发量,在Java
            应用中又只能借助更多的线程来支撑。
                解决:采用协程(Coroutine)来支持更高的并发量,避免并发量上涨之后造成CPU sy消耗严重、系统load
            迅速上涨和系统性能下降。
                Java中目前主要可用于实现协程的框架为Kilim,早使用Kilim执行一项任务,并不创建Thread,而是采用
            Task。

    3.3、文件IO消耗严重的解决方法
            从程序角度看,造成文件IO消耗严重的原因主要是多个线程在写大量的数据到同一文件。导致文件很快变大。
        从而写入速度越来越慢,并造成各线程激烈争抢文件锁,对于这种情况解决方法:
            1、异步写入文件;2、批量读写;3、限流;4、限制文件大小;5、尽可能采用缓冲区等方式来读取文件内容
   
    3.4、网络IO消耗严重的解决方法
            从程序角度而言,造成网络IO消耗严重的主要原因是同时需要发送或接受的包太多。可采用限流。限流通常是
        限制发送packet的频率,从而在网络IO消耗可接受的情况下来发送packet。

    3.5、内存消耗严重的情况
            1、对JVM调优;2、代码调优;
            代码调优的方式:
            ① 释放不必要的引用。如使用ThreadLocal,由于线程复用,ThreadLocal中存放的对象如未主动释放的话,
        不会被GC。应该在执行完毕执行ThreadLocal.set把对象清除,避免此有不必要的对象引用。

            ② 使用对象缓存池(享元模式)

            ③ 采用合理的缓存失效算法(FIFO、LRU、LFU等)
               当缓存池达到最大容量后,如果再加入新对象时采用FIFO、LRU、LFU等失效算法。
            ④ 对于占据内存但又不是必须存在的对象使用SoftReference、WeakReference的方式进行缓存。
                SoftReference在内存不够用的情况进行回收;WeakReference在FULL GC的情况下进行回收。

    3.6、对于资源消耗不多,但程序执行慢的情况
        3.6.1、锁竞争激烈—见3.2.2②
       
        3.6.2、未充分利用硬件资源。
            ① 未充分利用CPU
                启动多线程,但是单线程演变为多线程要加锁,如:单线程计算,拆分为多线程分别计算,最后合并结果                 如:JDK7的fork-join框架。

            ② 未充分使用内存
                数据库缓存、耗时资源缓存(数据库连接的创建、网络连接的创建等)、页面片段的缓存等。

    结束语:从纯粹的软件角度调优来讲,充分而不过分的使用硬件资源,合理调整JVM以及合理使用JDK包是调优的三大有效原则,调优没有“银弹”。结合系统现状和多尝试不同的调优策略是找到合适调优方法的唯一途径。

 

以上参考淘宝网 架构师 林昊 著作《分布式JAVA应用 基础与实践》 一书

分享到:
评论

相关推荐

    性能测试诊断分析与优化

    性能测试诊断分析与优化 出版年: 2012-6 页数: 358 《性能测试诊断分析与优化》结合主流性能测试工具LoadRunner,讲解性能测试过程、方法和技术;结合笔者丰富的性能诊断调优经验,讲解如何有效分析和诊断性能问题、...

    面向异构融合处理器的性能分析、优化及应用综述.pdf

    《面向异构融合处理器的性能分析、优化及应用综述》这篇文章主要探讨了在现代计算机领域中,异构融合处理器的性能分析、优化及其广泛应用。随着异构计算技术的不断进步,CPU和GPU等不同类型的处理器集成在一起,形成...

    系统性能的分析和优化

    【系统性能分析与优化】是IT领域中一个关键的话题,主要关注如何提升系统效率,解决性能瓶颈,确保系统稳定运行。对于Unix系统,尤其是大型系统,性能分析和优化显得尤为重要,因为这涉及到内存管理、磁盘I/O等多个...

    Android应用性能优化

    本书《Android应用性能优化》着眼于Android平台下的应用性能提升,覆盖了Java性能优化、NDK入门、NDK进阶、内存管理、多线程与同步技术、性能评测与剖析以及电池续航优化等多个方面。下面将对这些关键知识点逐一展开...

    性能测试诊断分析与优化2012

    本文将深入探讨2012年时性能测试诊断分析与优化的相关知识点,以帮助读者理解如何有效地进行性能测试,识别并解决系统性能瓶颈。 一、性能测试的定义与目的 性能测试是通过对软件系统施加不同的工作负载,来评估其...

    Python性能分析与优化1

    【Python性能分析与优化1】这本书主要探讨了在Python编程中如何进行性能分析和优化,以提高代码执行效率。在项目开发过程中,性能分析是非常重要的一环,它可以帮助开发者识别程序中的瓶颈,从而有针对性地进行优化...

    系统性能分析与优化以及介绍常见的分析及监控系统

    总结,系统性能分析与优化是一门涵盖硬件、操作系统、应用程序等多个层面的综合学科。它需要系统管理员、架构师和开发人员共同参与,通过持续监控、深入理解应用特点、熟练运用分析工具,以及遵循优化原则,才能有效...

    《Android应用性能优化》

    《Android应用性能优化》这本书是Android开发者不可或缺的参考资料,它深入浅出地讲解了如何提升Android应用程序的性能和用户体验。虽然出版时间可能较早,但其中的许多优化原则和技术仍然是当前Android开发中的核心...

    C++应用程序性能优化.rar

    1. **性能分析**:优化的第一步是了解程序的性能瓶颈。这通常通过性能分析工具来完成,例如gprof或Visual Studio的性能分析器,它们可以提供函数级别的执行时间信息。 2. **内存管理**:文件`c++应用程序性能优化ch...

    《Android应用性能优化》.(埃尔韦)

    根据提供的标题“《Android应用性能优化》.(埃尔韦)”及描述“《Android应用性能优化》.(埃尔韦)”,我们可以推断这本书主要讲述了Android应用程序的性能优化技术与实践。接下来,我们将详细探讨Android应用性能优化...

    深入理解 Nsight System 与 Nsight Compute 性能分析优化工具

    深入理解 Nsight System 与 Nsight Compute 性能分析优化工具 Nsight System 和 Nsight Compute 是 NVIDIA 为开发者提供的性能分析优化工具,旨在帮助开发者优化其 CUDA 应用程序的性能。本文将对 Nsight System 和...

    Android性能优化.pdf

    **ANR问题解析**是Android应用性能优化的核心部分。ANR(Application Not Responding)是指应用程序无响应,当用户界面无法及时响应用户的输入事件或者系统服务请求时,Android系统将提示ANR错误。主要分为四类:...

    Web应用前端性能优化浅析

    对于不断发展的Web应用,性能优化如同逆水行舟,不进则退。一般可以从前端和后端的优化来改善Web站点性能。本文侧重通过对前端性能的分析,为Web站点前端性能优化提供了理论依据和一般的优化策略,并讲述了一些用于B/S...

    oracle数据库系统性能和应用性能优化

    Oracle数据库系统性能和应用性能优化是数据库管理员和开发人员关注的重要领域,它涉及到多个层面的调整和优化,以确保系统的高效运行。Oracle数据库是全球广泛使用的数据库管理系统,其性能直接影响到业务应用程序的...

    android应用性能优化最佳实践

    本文将深入探讨一些Android应用性能优化的最佳实践,主要基于Java编程语言。 1. **内存管理** - **避免内存泄漏**:内存泄漏是导致应用性能下降的主要原因之一。开发者应确保及时释放不再使用的资源,防止内存持续...

    让Oracle跑得更快.Oracle.10g性能分析与优化思路].(谭怀远).扫描版.pdf

    根据给定的文件信息,文件标题为“让Oracle跑得更快.Oracle.10g性能分析与优化思路”,同时附有作者“谭怀远”的名字和一个表示扫描版电子书的文件类型“.pdf”。文件描述与标题一致,强调了主题为Oracle 10g数据库...

Global site tag (gtag.js) - Google Analytics