caifengguo 2011-11-11
转载分布式Java应用(二)性能调优
2010年08月17日星期二19:50
From:http://hi.baidu.com/ygdu/blog/item/6817728dd318c11fb31bbaf6.html
性能调优
性能调优的第一步是寻找性能瓶颈,寻找瓶颈的方法是首先分析资源消耗,然后结合一些工具查找程序中资源消耗过多的代码。
CPU消耗分析
cpu的三个概念:上下文切换(不要过于频繁)、运行队列(每个核1-3个最好)、利用率
cpu状况的查看方式:
Top
pidstat,需安装sysstat
Jstack-l/[pid]|gerp'nid=0x4249',可根据pid列出子线程信息
vtune,商业软件,可查看整个线程内部执行的动作
文件IO消耗分析
Pidstat-d-t-p[pid],可查看线程的io消耗状况,kb_rd/s表示每秒读取kb数,kb_wr/s就是写了
Iostat,首先关注cpu中的iowait%,如果这是主要问题,再通过iostat-x查看具体情况
网络IO消耗分析
sar-nFULL12输出网络IO消耗信息
内存消耗分析
Jmap,jstat,mat,visualvm
Vmstat
Sar-r
Top
Pidstat-r-p[pid][interval][times]
程序执行慢的原因分析
如果资源消耗不多,程序仍然慢,一般原因分为三种:
锁竞争激烈
未充分使用硬件资源
数据量增长
调优
调优通常可从硬件、操作系统、JVM和程序四个方面入手
JVM调优
主要表现在降低GC所导致的应用暂停时间。不过如果不是有确切的理由证明是GC问题,不需要倾注太多的心思在GC调优上,JVM做得已经够好了。
程序调优
Cpuus高:一般是因为有线程不停地执行,cpu无机会调用其他线程,造成线程饿死,可在线程中增加Thread.sleep(1),如果这个线程需要等待其他线程改变了值后才能继续,则使用wait/notify。
Cpusy高:主要是因为线程运行状态经常要切换,最简单的优化办法是减少线程数。如果应用要支撑大量的并发,在减少线程数的情况下最好是增加一个缓冲队列,避免因为线程数的减少而造成的出错率上升。还有另外一种利用较少线程支撑较高并发量的方式:协程(coroutine)。目前Java有Kilim框架、JDK7、Scala的Actor可以支持协程。
文件IO消耗严重:主要是多个线程将大量数据写到同一文件,线程之间争夺文件锁,会造成系统写入速度很慢,有几种解决办法:
异步写文件,如Log4j提供的AsyncAppender
批量读写
限流
限制文件大小
网络IO消耗严重:限流——限制发送packet的频率
内存消耗严重:
找到内存消耗严重的代码,对代码本身进行优化
释放不必要的引用
使用对象缓存池
采用合理的缓存失效算法
合理使用WeakReference和SoftReference
资源消耗不多,但是程序执行慢:
锁竞争激烈:
使用并发包里的类
使用Treiber算法,实现无阻塞的Stack
用Michael-Scott、MCAS、WSTM等非阻塞队列算法
尽可能少用锁,将锁最小化
拆分锁,可以提高读写速度,但是全局性质的操作会变得比较麻烦,如ConcurrentHashMap
去掉读写操作的互斥锁
未充分使用硬件资源:
未充分使用cpu:
单线程的计算可改为多线程,最后再合并结果,jdk7中的fork-join可提供支持
未充分使用内存:
使用数据的缓存、耗时资源的缓存、页面片段的缓存等
构建高可用的系统
避免系统中出现单点
负载均衡技术:
分类:硬件/软件的负载均衡、去中心化负载均衡(谣言传播的方式)
均衡策略:随机选、Hash选、Round-Robin选、按权重选、按负载选、按连接选
响应返回方式:通过负载均衡机返回(基于NAT实现),
构建可伸缩的系统
垂直伸缩:增加单台机器的性能
水平伸缩:增加机器数量来提升总体性能
支撑大数据量:
分表,按主键ID,按时间等,根据业务而定,分表通常会带来开发的复杂,可以借助DAL解决,另外会带来分页查询、跨表查询的难题
缓存状态的水平伸缩方法:
广播同步,基于Multicast实现,JGroups提供支持,jetty,tomcat的session信息同步都用了它。广播不会给机器带来过多负担,不过可能会有一定延时
分布式缓存
文件的水平伸缩方法:
直连式存储
网络存储(Fabric-AttachedStorage),有NAS(通过网络协议),SAN(通过mount)两种方式
分布式文件系统,GFS,HDFS(基于GFS实现)
应用的水平伸缩方法:
按照业务领域拆分应用
水平伸缩带来的数据库问题解决方案:
缓存,页面静态化,页面片段缓存,数据缓存(适用于变化不大的数据)
分库,按业务领域拆分到不同的数据库服务器
异步数据库访问,减少连接数占用
DAL,开源的有Amoeba框架,可以透明化分库、分表对业务服务器的影响
支撑大数据量:
读写分离(master-slave库)
多master
提升计算能力
MapReduce,MPI,将任务拆解到多台机器执行