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.2.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包是调优的三大有效原则,调优没有“银弹”。结合系统现状和多尝试不同的调优策略是找到合适调优方法的唯一途径。
分享到:
相关推荐
Oracle DBA性能调优学习笔记
linux性能调优学习笔记
阿里巴巴Java性能调优华山版是一套系统性能调优教程,!通过这份笔记的学习,你将会有一个系统的调优头脑和策略!快了何止100%?需要的朋友可下载试试! 众所周知性能调优可以使系统稳定,用户体验更佳,甚至在...
学习笔记——JVM性能调优之 jstat(csdn)————程序
Oracle 12c-优化 Hint详解.pdf Oracle 12c-优化 Oracle 索引技术.pdf Oracle 12c 执行计划.pdf Oracle 12c锁.pdf Oracle 12c查询优化器.pdf Oracle 12c 使用绑定变量 VS 不使用绑定变量.pdf Oracle 12c 自动工作负载...
Go语言学习(五) 高质量编程与性能调优实战_青训营笔记
在介绍Oracle系统管理的知识以后,将介绍与开发相关的内容(如PL/SQL基础知识、存储过程、函数、包等),并介绍数据库性能调整,《成功之路:Oracle 11g学习笔记》重点介绍SQL语句调优。SQL语句调优是《成功之路:Oracle...
学习MySQL作的笔记,很详细,如何人都看得懂!!!直接原样输入即可!!
java 性能调优,jvm 工具定位 深入解析
高级java笔试题 StudySpark spark的一个小项目以及笔记 目录 项目内容 用户访问session分析模块 用户访问session分析业务,session...性能调优方案:普通调优、jvm调优、shuffle调优、算子调优 troubleshooting经验 数
Java 虚拟机学习笔记: Java 内存区域, 垃圾收集, 内存分配与回收策略, JVM 调优, 文件结构, 类加载机制, Java 程序 Java是一种面向对象的编程语言,由Sun Microsystems于1995年推出。它是一种跨平台的语言,...
成功之路 Oracle 11g 中文学习笔记 专为开发人员编写,先引导开发新手熟悉Oracle环境,然后进入数据库开发,并要掌握项目开发的一些技巧。开发技巧展示是本书一大特色(这一点很值得资深的开发人员借鉴)! 本书共24...
RHCA学习笔记 一个用于保存学习笔记和其他有关RHCA考试的有用信息的资料库。 RHCA之路 主题完成 EX436-HA群集 EX405-木偶 EX407-Ansible EX403-卫星部署和系统管理 ...EX442-性能调优 EX210-OpenStack 关于该项目
Spark-Core文档是本人经三年总结笔记汇总而来,对于自我学习Spark核心基础知识非常方便,资料中例举完善,内容丰富。具体目录如下: 目录 第一章 Spark简介与计算模型 3 1 What is Spark 3 2 Spark简介 3 3 Spark...
学习笔记较长,如果想查看文章的目录,chrome浏览器可以配合简悦插件使用,或者下载到本地使用Typora打开。 :hot_beverage: Java基础 Java容器 Java并发 数据结构和算法 数据结构 树 图 算法 分治 动态规划 回溯 ...
2012.9.Oracle三思笔记合集,供大家下载...[三思笔记]学习动态性能表.pdf [三思笔记]学用ORACLE AWR和ASH特性.pdf [三思笔记]一步一步学DataGuard.pdf [三思笔记]一步一步学RMAN.pdf [三思笔记]一步一步学Streams.pdf
适合对mysql有一定基础的同学,涉及mysql调优、集群等操作,包含详细的操作步骤和示例代码。 1、性能优化 1.1、Mysql索引底层数据结构与算法 1.2、Explain工具 1.3、索引下推 1.4、Trace工具 1.5、索引优化最佳实践 ...
JVM性能调优监控工具 设计模式 消息中间件 RocketMQ 概念 RocketMQ 特性 RocketMQ 集群 RocketMQ 事务 RocketMQ 常见问题 数据库 Redis 基本数据结构 进阶使用 持久化 集群 分布式锁 Client API 常见问题 ZooKeeper ...
Android 学习笔记之 SQLite基础用法 如何充分利用 Windows Phone 高清屏幕 【cocos2d-x 手游研发----博彩大转盘】 后端架构 回顾2013:HBase的提升与挑战 memcached(十七)协议命令格式 nginx大流量负载调优 12306...
三:下篇——性能监控与调优篇 一: 上篇——内存与垃圾回收器 架构: jvm依赖的架构: 栈架构/寄存器架构 栈架构 JVM的生命周期: 1.启动 通过引导类加载器(Bootstrap class loader)创建一个初始类(Initial Class)来...