性能优化

1、响应时间

响应时间指的是从客户端发起一个请求开始,到客户端接收到从服务器端返回的响应结束,这个过程所耗费的时间。响应时间通常用时间单位来衡量(一般为秒)。

 


图形中的拐点,表示响应时间突然增加,意味着一种或者多种系统资源的利用达到了极限



响应时间 = N1+A1+N2+A2+N3+A3+N4

网络传输时间:N1 + N2 + N3 + N4

应用服务器处理时间:A1 + A3

数据库服务器处理时间:A2

 

2、并发用户数

系统用户数:系统额定的用户数量,如一个OA系统,可能使用该系统的用户总数是2000个,那么这个数量,就是系统用户数

同时在线用户数:在一定的时间范围内,最大的同时在线用户数量

平均并发用户数的计算:

C=nL /T

 

其中C是平均的并发用户数,n是平均每天访问用户数,L是一天内用户从登录到退出的平均时间(操作平均时间),T是考察时间长度(一天内多长时间有用户使用系统)


3、吞吐量

吞吐量指的是单位时间内处理的客户端请求数量。

从业务角度看,吞吐量可以用:请求数/秒、页面数/秒、人数/天或处理业务数/小时等单位来衡量

从网络角度看,吞吐量可以用:字节/秒来衡量


 

对于交互式应用来说,吞吐量指标反映的是服务器承受的压力,他能够说明系统的负载能力

以不同方式表达的吞吐量可以说明不同层次的问题,例如,以字节数/秒方式可以表示数要受网络基础设施、服务器架构、应用服务器制约等方面的瓶颈;已请求数/秒的方式表示主要是受应用服务器和应用代码的制约体现出的瓶颈。


当没有遇到性能瓶颈的时候,吞吐量与虚拟用户数之间存在一定的联系,可以采用以下公式计算:F=VU * R / T


其中F为吞吐量,VU表示虚拟用户个数,R表示每个虚拟用户发出的请求数,T表示性能测试所用的时间


4、资源利用率

资源利用率指的是对不同系统资源的使用程度,例如服务器的CPU(s),内存,网络带宽等。

资源利用率通常以占用最大值的百分比n %来衡量。


当某个资源利用率随着负载的增加最终在100%居高不下时,就可能意味着这个资源变成了系统的性能瓶颈所在,提高这个资源的量,将会提高系统的吞吐量,同时降低交易的响应时间,即改进了系统的性能。

1. 优化思路

(1)、升级服务器的硬件,换成更快、更大的机器。

(2)、增加服务器的数量。

(3)、对系统和应用程序进行仔细的调优,以提高响应时间、吞吐量和资源利用率的性能指标。


2. 优化方法

(1)、每次改变一个系统参数或者一个应用逻辑。

(2)、使用固定的负载(比如保持相同的并发用户数)。

(3)、测试另一个设置之前收集本次性能测试的数据。

(4)、重复测试过程,直到应用程序的性能达到了期望的状态。


3. 优化对象

(1)、服务器硬件(CPU、内存、磁盘IO)

(2)、网络(网速、网卡)

(3)、操作系统

(4)、J2EE容器(比如WebLogic)

(5)、应用程序(包括前台和后台)

(6)、数据库

(7)、JVM


4. 优化步骤

(1)、获取系统性能测试的性能参数数据,根据系统现有的性能情况做分析。

(2)、先排除外部因素,然后再对应用程序的性能进行调优。

(3)、对系统的各个环节进行针对性监控,包括操作系统资源、处理线程堆栈、数据库连接池、数据库和JVM等。

(4)、结合监控的结果和性能测试的数据起来做分析,优先处理通道问题(比如连接池连接不够、操作系统最大Socket数不够、内存设置太小等等),然后再到应用程序内部,看看是否出现线程等待是否严重,或者JVM中哪些对象或者方法使用过多、数据库那条SQL语句执行时间太长了、或者哪条SQL语句使用太频繁了、哪个JSP或者Servlet处理的时间太长了等等。

(5)、如果发现了性能瓶颈的原因,则每次只修改一个地方,并且做性能测试,对两次的性能测试参数进行对比。

(6)、如果没有找到原因,那么我们只能做试探性的修改,并且在改后重新做性能测试,并进行对比。

调优思路

1、 操作系统最大Socket数设置

2、操作系统Socket关闭等待时间设置

调优思路:

1、网络带宽(路由器是采用百兆还是千兆速率)

2、是否采用磁盘阵列(特别是数据库很容易出现瓶颈)

3、机器的网卡是采用百兆网卡还是千兆网卡

4、应用服务器的发送和接收是否采用两个独立的网卡

5、JVM的内存大小是否设置准确

6、监控应用服务器和数据库服务器的CPU利用率、内存利用率和IO读写情况,找出瓶颈

7、监控应用服务器到数据库服务器之间的网络流速,看是否网速太小

Tomcat性能调优 

1. 调整虚拟内存 

Linux: 
在/usr/local/tomcat_home/bin目录下的catalina.sh 
添加:JAVA_OPTS='-Xms1024m -Xmx2048m' 
要加“m”说明是MB,否则就是KB了,在启动tomcat时会报内存不足。 
-Xms:初始值 
-Xmx:最大值 
-Xmn:最小值 

Windows: 
在catalina.bat最前面加入 
set JAVA_OPTS=-Xms1024m -Xmx2048m 
如果用startup.bat启动tomcat,OK设置生效.够成功的分配200M内存. 
但是如果不是执行startup.bat启动tomcat而是利用windows的系统服务启动tomcat服务,上面的设置就不生效了,就是说set JAVA_OPTS=-Xms1024m -Xmx2048m没起作用. 
windows服务执行的是bin\tomcat.exe.他读取注册表中的值,而不是catalina.bat的设置. 
解决办法: 
修改注册表HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Tomcat Service Manager\Tomcat5\Parameters\JavaOptions 
原值为 
-Dcatalina.home="C:\ApacheGroup\Tomcat 5.0" 
-Djava.endorsed.dirs="C:\ApacheGroup\Tomcat 5.0\common\endorsed" 
-Xrs 
加入 -Xms1024m -Xmx2048m 
重起tomcat服务,设置生效 

2. HTTP通道调优 

将tomcat_home/conf/server.xml中的HTTP通道默认配置屏蔽,添加下面这段配置:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <Connector port="8080" redirectPort="8443"    
  2.    maxHttpHeaderSize="8192" useBodyEncodingForURI="true"    
  3.    minProcessors="100" maxProcessors="5000"    
  4.    maxThreads="5000" minSpareThreads="1000" maxSpareThreads="4000"    
  5.    enableLookups="false" acceptCount="3500"    
  6.    compression="on" compressionMinSize="2048"    
  7.    compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain"    
  8.    connectionTimeout="60000" disableUploadTimeout="true" debug="0" URIEncoding="UTF-8"/>  


3. 禁用DNS查询 

当web应用程序向要记录客户端的信息时,它也会记录客户端的IP地址或者通过域名服务器查找机器名转换为IP地址。DNS查询需要占用网络,并且包括可能从很多很远的服务器或者不起作用的服务器上去获取对应的IP的过程,这样会消耗一定的时间。为了消除DNS查询对性能的影响我们可以关闭 DNS查询,方式是修改server.xml文件中的enableLookups参数值: 

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <Connector port="80" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false"   
  2. redirectPort="8443" acceptCount="100" debug="0" connectionTimeout="20000" disableUploadTimeout="true"/>     

1. 调优思路:

(1). 数据库连接最大数设置

(2). 回滚段大小设置

(3). 共享SGA大小设置

(4). 数据切分(水平分库、垂直分库、分区表)

(5). 找出执行时间长的SQL语句并优化SQL的执行计划

(6)查看数据库是否有死锁

(7)数据库集群

 

2. 优化措施

(1). 查看和设置数据库最大连接数

当数据库最大连接数不够时,会出现客户端连接间歇性失败,报ORA-12519错,我们可以通过以下的SQL语句来查看当前连接数和数据库允许的最大连接数,对比一下,看是否达到了最大值。

[sql]  view plain copy
  1. --查看当前连接数  
  2. select count(*) from v$process;  
  3.   
  4. --查看数据库允许的最大连接数  
  5. select value from v$parameter where name = 'processes';   


(2). 修改数据库允许的最大连接数:

a. 使用sqlplus登陆数据库
sqlplus "sys/oracle as sysdba"


b. 设置数据库允许的最大连接数

alter system set processes = 300 scope = spfile;


c. 重启数据库

shutdown immediate;
startup;


d. 查看数据库允许的最大连接数

select value from v$parameter where name = 'processes';


(3). 查看数据库是否有被锁的表

[sql]  view plain copy
  1. SELECT A.OWNER 方案名,  
  2.        A.OBJECT_NAME 表名,  
  3.        B.XIDUSN 回滚段号,  
  4.        B.XIDSLOT 槽号,  
  5.        B.XIDSQN 序列号,  
  6.        B.SESSION_ID 锁表SESSION_ID,  
  7.        B.ORACLE_USERNAME 锁表用户名,  
  8.        decode(D.type,  
  9.               'XR',  
  10.               'NULL',  
  11.               'RS',  
  12.               'SS(Row-S)',  
  13.               'CF',  
  14.               'SS(Row-S)',  
  15.               'TM',  
  16.               'TABLE LOCK',  
  17.               'PW',  
  18.               'TABLE LOCK',  
  19.               'TO',  
  20.               'TABLE LOCK',  
  21.               'TS',  
  22.               'TABLE LOCK',  
  23.               'RT',  
  24.               'ROW LOCK',  
  25.               'TX',  
  26.               'ROW LOCK',  
  27.               'MR',  
  28.               'S(Share)',  
  29.               NULL) 锁定方式,  
  30.         
  31.        C.MACHINE 用户组,  
  32.        C.TERMINAL 机器名,  
  33.        B.OS_USER_NAME 系统用户名,  
  34.        B.PROCESS 系统进程id,  
  35.        DECODE(C.STATUS, 'INACTIVE''不活动''ACTIVE''活动') 活动情况,  
  36.        C.SERVER,  
  37.        C.SID,  
  38.        C.SERIAL#,  
  39.        C.PROGRAM 连接方式,  
  40.        C.LOGON_TIME  
  41.   FROM ALL_OBJECTS A, V$LOCKED_OBJECT B, SYS.GV_$SESSION C, v$lock d  
  42.  WHERE (A.OBJECT_ID = B.OBJECT_ID)  
  43.    AND (B.PROCESS = C.PROCESS)  
  44.    and C.sid = d.sid  
  45.    and B.LOCKED_MODE = D.LMODE  

一. 优化原则:

1、减少数据库访问次数

(1) 使用数据缓存的存取方式

(2) 使用批量处理的方式

 

2、减少SQL语句的执行时间

(1) 使用占位符的访问方式

(2) 优化SQL的执行计划(比如使用数据库索引或者调整SQL)


3、 减少程序执行的时间

(1) 使用异步调用代替同步调用

(2) 使用本地API方式代替远程调用(比如WebSerivce)

(3) 减少同步块或者同步方法的使用

(4) 减少IO读写

 

4、减少请求压力

(1) 使用应用集群部署方式分担掉服务器的压力

(2) 将静态文件和动态文件分离部署,减少J2EE容器的压力


二. 高效Java:

1、尽量避免不必要的方法调用

原则:在Java中,一切都是对象,如果有方法(Method)调用,处理器先要检查该方法是属于哪个对象,该对象是否有效,对象属于什么类型,然后选择合适的方法并调用。尽可能在外层确定是否一定要执行该方法。

优化前:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public void CallMethod(int i ){    
  2.  if( i ==0 ){    
  3.   return;    
  4.  }    
  5.  ... // 其他处理    
  6. }    
  7.     
  8. int i = 0;    
  9. ...    
  10. CallMethod(i);  

优化后:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int i = 0;    
  2. ...    
  3.     
  4. if( i ==0 ){    
  5.  CallMethod(i);    
  6. }    

2、尽量避免不必要的对象创建

原则:当一个对象是用new进行初始化时,其构造函数链的所有构造函数都被调用到,所以new操作符是很消耗系统资源的,new一个对象耗时往往是局部变量赋值耗时的上千倍。同时,当生成对象后,系统还要花时间进行垃圾回收和处理。尽量少用new来初始化一个类的实例, 当new创建对象不可避免时,注意避免多次的使用new初始化一个对象,尽量在使用时再创建该对象。

优化前:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. NewObject object = new NewObject();  
  2. int value;  
  3. if(i>0 )  
  4. {  
  5.  value =object.getValue();  
  6. }  

优化后:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int value;  
  2. if(i>0 )  
  3. {  
  4.  NewObject object = new NewObject();  
  5.  Value =object.getValue();  
  6. }  

3、尽量减少对变量的重复计算体
原则:循环是比较重复运行的地方,如果循环次数很大,循环体内不好的代码对效率的影响就会被放大而变的突出。当有较大的循环时,应该检查循环内是否有效率不高的地方,寻找更优的方案加以改进。
优化前:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Vector vect = new Vector(1000);  
  2. ...  
  3. forint i=0; i<vect.size(); i++){  
  4.  ...  
  5. }  
优化后:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int size = vect.size();  
  2. forint i=0; i>size; i++){  
  3.  ...  
  4. }  

4、生成对象时,分配合理的空间和大小
原则:Java中的很多类都有它的默认的空间分配大小,对于一些有大小的对象的初始化,应该预计对象的大小,然后使用进行初始化。
StringBuilder builder = new StringBuilder(100);


5、使用StringBuilder代替String
原则:String是用来存储字符串常量的,如果要执行“+”的操作,系统会生成一些临时的对象,并对这些对象进行管理,造成不必要的开销。如果字符串有连接的操作,替代的做法是用StringBuilder的append方法,StringBuffer是有同步机制的,效率上没有StringBuilder快。

6、控制查询返回的结果条数
原则:当查询返回的数据量过大时,通过截取前面100条的数据返回,不然将严重影响系统的响应时间。

7、多线程不能使用HashMap
原则:HashMap没有同步机制,用于多线程的频繁读写会产生线程死锁的情况。推荐使用ConcurrentHashMap来代替HashMap,在初时化时尽量传入大小容量。

8、不要在循环中使用try…catch
原则:在循环中使用try…catch的话会造成多次异常判断逻辑,尽量做到一个方法最多只有一个try…catch块。

9、使用高效的HashMap的遍历
效率的遍历方式:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Map map = new HashMap();   
  2. Iterator iter = map.keySet().iterator();   
  3. while (iter.hasNext()) {   
  4.   Object key = iter.next();   
  5.   Object val = map.get(key);   
  6. }  

高效率的遍历方式:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Map map = new HashMap();   
  2. Iterator iter = map.entrySet().iterator();   
  3. while (iter.hasNext()) {   
  4.   Map.Entry entry = (Map.Entry) iter.next();   
  5.   Object key = entry.getKey();   
  6.   Object val = entry.getValue();   
  7. }  


第一种对于keySet其实是遍历了2次,一次是转为iterator,一次就从hashmap中取出key所对于的value。
第二种entryset只是遍历了第一次,他把key和value都放到了entry中,所以会比第一种快。

三. 高效SQL

1、尽量不用通配符“%”或者“_”作为查询字符串的第一个字符
当通配符“%”或者“_”作为查询字符串的第一个字符时,索引不会被使用。比如用 T 表中 Column1  LIKE  ‘%5400%’  这个条件会产生全表扫描,如果改成  Column1  ‘X5400%’  OR Column1 LIKE ‘B5400%’  则会利用 Column1 的索引进行两个范围的查询,性能肯定大大提高。

2、尽量EXISTS替换IN 操作符(主要考虑索引是否能用上的问题)
基本上所有的 IN 操作符都可以用 EXISTS 代替,在选择 IN 或 EXIST 操作时,要根据主子表数据量大小来具体考虑。

3、用 UNION ALL 代替 UNION
UNION 是最常用的集操作,使多个记录集联结成为单个集,对返回的数据行有唯一性要求, 所以 oracle 就需要进行 SORT UNIQUE 操作(与使用 distinct 时操作类似),如果结果集又 比较大,则操作会比较慢;
UNION  ALL 操作不排除重复记录行,所以会快很多,如果数据本身重复行存在可能性较
小时,用 union all 会比用 union 效率高很多!

4、SELECT子句中避免使用“*”号
ORACLE在解析的过程中, 会将'*' 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间。

5、尽量用 NOT EXISTS 或者外连接替代 NOT IN 操作符
因为 NOT IN 不能应用表的索引。

6、尽量不用“<>”或者“!=”操作符
不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。比如:a<>0
改为  a>0 or a<0

一. 优化思路

1、减少HTTP请求的次数

(1) 合并Javascript/CSS以减少请求次数

(2) 合并前台请求次数成一次操作

(3) 前台页面缓存


2、 减少网络数据的传输量

(1) 将大JSP页面的JS挪到JS文件

(2) 将JS文件进行压缩传输

(3) 最小化JS文件的大小(去掉空格和替换变量名等)

 

3、减少服务端IO读

(1) 将静态文件和动态文件分开(将静态HTML、图片之类的存放在HttpServer、动态文件JSP/Servlet放在J2EE容器)

1. 尽量避免随意使用静态变量

当某个对象被定义为static的变量引用时,那么GC通常是不会回收这个对象所占用的内存

public class A {

static B b = new B(); // 静态变量b的生命周期与A类同步, 只要A类不被卸载,那么b对象就会常驻内存,直到程序终止

}


2. 处理好包装类型和基本类型的使用场所

虽然包装类型和基本类型在使用过程中是可以相互转换,但它们两者所产生的内存区域是完全不同的,基本类型数据产生和处理在栈中;

包装类型是对象,在堆中产生实例。


3. 慎用synchronized

实现同步是要很大的系统开销为代价,甚至可能造成死锁,所以尽量避免无谓的同步控制。


4. 单线程尽量使用HashMap、ArrayList

HashTable、Vector等使用了同步机制,降低了性能。


5. 尽量减少对变量的重复计算

for(int i = 0; i < list.size(); i++)  // 循环中,循环条件会被反复计算

应该改为 for(int i = 0, len = list.size(); i < len; i++) 


6. 尽量避免不必要的创建

A a = new A();

if(i == 1){ list.add(a); }  

应该改为: if(i == 1){ A a = new A(); list.add(a); }  


7. 尽量确定StringBuilder的容量

StringBuilder的构造器会创建一个默认大小(通常是16)的字符数组,在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再丢弃旧的数组。在大多数情况下,你可以在创建StringBuilder的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。


8. 尽量早释放无用对象的引用

大部分时间,方法局部引用变量所引用的对象会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部引用变量显示地设为null;但是如果对象较大,占用较多内存,不用的时候就应手动置为空了


转载于:https://my.oschina.net/liting/blog/406548

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值