`

解决JAVA服务器性能问题

阅读更多

解决JAVA服务器性能问题

 

通过负载测试和分析来改善JAVA服务器应用的性能

 

作者:Ivan Small

 

译者:xMatrix






版权声明:任何获得Matrix授权的网站,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
作者:Ivan Small;xMatrix
原文地址:http://www.javaworld.com/javaworld/jw-02-2005/jw-0207-server-p3.html
中文地址:http://www.matrix.org.cn/resource/article/43/43998_server_capacity.html
关键词: server capacity

摘要

改善JAVA服务器的性能需要模拟负载下的服务器。创建一个模拟环境、搜集数据并且分析结果可能是对许多开发人员的挑战。这篇文章中的示例介绍了JAVA服务器性能分析的概念和工具。作者使用这个示例来研究超额请求次数下内存使用和同步竟争的影响。
作者Ivan Small

项目团队已经很熟悉如何组织一些具体的任务并完成他们。简单的性能问题很容易由一个开发人员分离并解决。然而大的性能问题,通常在系统处于高负载情况下发生,就不是这么简单能处理的了。这些问题需要一个独立的测试环境、一个模拟的负载,并且需要仔细地分析和跟踪。

在这篇文章中,我使用比较通用的工具和设备创建了一个测试环境。我会专注于两个性能问题,内存和同步,他们很难用简单的分析得到。通过一个具体的例子,我希望比较容易地解决复杂的性能问题而且可以提供处理问题过程中的细节。

改善服务器的性能

服务器的性能改善是依赖于数据的。没有可靠的数据基础而更改应用或环境会导致更差的结果。分析器提供有用的JAVA服务器应用信息,但由于从单用户负载下的数据与多用户负载下得到的数据是完全不同的,这导致分析器的数据并不精确。在开发阶段使用分析器来优化应用的性能是一个好的方式,但在高负载下的应用分析可以取到更好的效果。


在负载下分析服务器应用的性能需要一些基本的元素:
        1、可控的进行应用负载测试的环境。
        2、可控的人造负载使得应用满负荷运行。
        3、来自监视器、应用和负载测试工具自身的数据搜集。
        4、性能改变的跟踪。

不要低估最后一个需求(性能跟踪)的重要性因为如果不能跟踪性能你就不能实际的管理项目。性能上10-20%的改善对单用户环境来说并没有什么不同,但对支持人员来说就不一样了。20%的改善是非常大的,而且通过跟踪性能的改善,你可以提供重要的反馈和持续跟踪。
虽然性能跟踪很重要,但有时为了使后续的测试更加精确而不得不抛弃先前的测试结果。在性能测试中,改善负载测试的精确性可能需要修改模拟环境,而这些变化是必须的,通过变化前后的负载测试你可以观察到其中的转变。


可控的环境        
可控的环境最少也需要两台独立的机器和第三台控制的机器。其中一台用来生成负载,另一台作为控制机与前一台建立测试应用并接受反馈,第三台机器运行应用。此外,负载和应用机器间的网络应该与局域网分开。控制机接受运行应用机器的反馈如操作系统、硬件使用率、应用(特别是VM)的状态。

负载模拟
最精确的模拟通常用实际的用户数据和WEB服务器端的访问日志。如果你还没有实际布署或者缺少实际的用户数据,你可以通过构造类似的场景或询问销售和产品管理团队或做一些有依据的猜想。协调负载测试和实际用户体验是一个持续的过程。

在模拟中一些用户场景是必须的。如在一个通用地址薄应用中,你应该区分更新和查询操作。在我的测试应用中GrinderServlet类只有一个场景。单用户连接10次访问这个servlet(在每一次访问间有一段暂停)。虽然这个应用很小,我认为这可以重复一些常见的东西。用户通常不会连接给服务器请求而没有间断。如果没有间断,我们可能不能得到更精确的实际用户上限。

串行10个请求的另一个原因是实际应用中不会只有一个HTTP请求。单一而又分离的请求可以影响环境中的许多因素。对Tomcat来说,会为每一个请求创建一个会话,并且HTTP协议允许不同的请求重用连接。我会修改一下负载测试来避免混洧。

GrinderServlet类不会执行任何排序操作,但这个需求在大部分应用中都很普通。在这些应用中,你需要创建模拟的数据集并且用他们来构造相关用例的负载测试。

例如,如果用例涉及到用户登录一个WEB应用,从可能的用户列表中选取随机的用户会只使用一个用户更精确。否则,你可能不经意地使用了系统缓存或其他的优化或一些微妙的东西,而这会使得结果不正确。

负载测试软件
负载测试软件可以构造测试场景并且对服务进行负载测试。我会在下面的示例中使用OpenSTA测试软件。这软件简单易学,结果也很容易导出,并且支持参数化脚本,还可以监视信息的变化,他的主要缺点是基于Windows,但在这儿不是个问题。当然还有很多可选项如Apache的JMeter和Mercury的LoadRunner。

The GrinderServlet

列表1中显示了GrinderServlet类,列表2中显示了Grinder类
Listing 1

package pub.capart;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class GrindServlet extends HttpServlet {
   protected void doGet(HttpServletRequest req, HttpServletResponse res)
         throws ServletException, IOException {
      Grinderv1 grinder = Grinderv1.getGrinder();
      long t1 = System.currentTimeMillis();
      grinder.grindCPU(13);
      long t2 = System.currentTimeMillis();

      PrintWriter pw = res.getWriter();
      pw.print("<html>\n< body> \n");
      pw.print("Grind Time = "+(t2-t1));
      pw.print("< body> \n< /html> \n");
   }
}



Listing 2

package pub.capart;

/**
* This is a simple class designed to simulate an application consuming
* CPU, memory, and contending for a synchronization lock.
*/
public class Grinderv1 {
   private static Grinderv1 singleton = new Grinderv1();
   private static final String randstr =
      "this is just a random string that I'm going to add up many many times";

   public static Grinderv1 getGrinder() {
      return singleton;
   }
   public synchronized void grindCPU(int level) {
      StringBuffer sb = new StringBuffer();
      String s = randstr;
      for (int i=0;i<level;++i) {
         sb.append(s);
         s = getReverse(sb.toString());
      }
   }
   public String getReverse(String s) {
      StringBuffer sb = new StringBuffer(s);
      sb = sb.reverse();
      return sb.toString();
   }
} 



类很简单,但他们会产生两个很常见的问题。咋一看瓶颈可能由grindCPU()方法的同步修饰符引起,但实际上内存消耗才是真正的问题所在。如图1,我的第一个负载测试显示了常见的负载变化。在这里负载变化很重要因为你正在模拟一个高的负载。这种热身的方式也更精确因为避免了JSP编译引起的问题。我通常习惯于在进行负载测试前先进行单用户模拟。



 
Figure 1        

我在这篇文章中会使用相同的容量小结图。在执行负载测试时还有更多的可用信息,但这里只用了有用的部分。最上面的面板包含每秒完成的请求数和请求时间信息。第二个面板包含活动用户数和失败率,我将超时、不正确的服务器应答和长于5秒的请求认为是失败的。第三个面板包含JVM内存统计和CPU使用率。CPU值是所有处理器的用户时间的平均值,这里所有的测试机器都是双CPU的。内存统计图包含垃圾回收表和每秒垃圾回收数。

图1中两个最明显的数据是50%的CPU使用率和大量内存使用和释放。从列表2中可以看出这个原因。同步修饰符导致所有进程串行处理,就好像只用了一个CPU,而算法导致大量内存消耗在局部变量上。

通过CPU是个受限的资源,如果在这个测试中我可以完全利用到两个CPU的话就可以提高一倍的性能。垃圾回收器运行得如此频繁以致于不能忽略。在测试中每秒释放的内存达到100M,很显然这是个限制因素。失败数这么大明显这个应用是不可用的。

监视

在生成合理的用户负载后,监视工具需要收集进程的运行状况。在我的测试环境中可以收集到各种有用的信息:

1、        所有计算机、网络设备
2、        等等的使用率
3、        JVM的统计数据。
4、        个别JAVA方法所花费的时间。
5、        数据库性能信息,6、        包括SQL查询的统计。
7、        其他应用相关的信息

当然这些监视也会影响负载测试,但如果影响比较小也可以忽略。基本上如果我们想获取所有上面的信息,肯定会影响测试的性能。但如果不是一次获取所有信息还是有可能保证负载测试的有效性。仅对特定的方法设置定时器,仅获取低负载的硬件信息和低频率地获取样例数据。当然不加载监视器来做测试是最好的,然后和加载监视器的测试来做比较。虽然有时候侵入式监视是个好主意,但就不可能有监视结果了。


获取所有监视数据到一个中央控制器来做分析是最好的,但使用动态运行时工具也可以提供有用的信息。例如,命令行工具如PS、TOP、VMSTAT可以提供UNIX机器的信息;性能监视器工具可以提供WINDOWS机器的信息;而TeamQuest, BMC Patrol, SGI's Performance Co-Pilot, and ISM's PerfMan这样的工具会在所有的测试环境中的机器安装代理并且将需要的信息传回中央控制机,这样就可以提供文本或可视化的信息。在本文中,我使用开源的Performance Co-Pilot作为测试统计的工具。我发现他对测试环境的影响最小,并且以相对直接的方式来提供数据。

JAVA分析器提供很多信息,但通常对负载测试来说影响太大而没有太多的用处。工具甚至可以让你在负载服务器上做一些分析,但这也很容易便测试无效。在这些测试中,我激活了详细的垃圾收集器来收集内存信息。我也使用jconsole 和jstack工具(包含在J2SE 1.5中)来检查高负载下的VM。我没有保留这些测试用例中负载测试的结果因为我认为这些数据不是很正确。


同步瓶颈

在诊断服务器问题时线程的信息是非常有用的,特别是对同步之类的问题。jstack工具可以连接到运行的进程并且保存每一个线程的堆栈信息。在UNIX系统可以用信号量3来保存线程的堆栈信息,在WINDOWS系统的控制台中可以用Ctrl-Break。在第一项测试中,jstack指出许多线程在grindCPU()方法中被阻塞。

你可以已经注意到列表2中grindCPU()方法的同步修饰符实际上并不必须。我在后一项测试中删除了他,如图2显示



 
Figure 2        

在图2中,你会注意到性能下降了。虽然我使用了更多的CPU,但吞吐量和失败数都更差了。虽然垃圾回收周期变了,但每秒依然需要回收100M。显然我们还没有找到主要的瓶颈。
非竟争的同步相对于简单的函数调用还是很费时的。竟争性的同步就更费时了,因为除了内存需要同步外,VM还需要维护等待的线程。在这种状况下,这些代价实际上要小于内存瓶颈。实际上,通过消除了同步瓶颈,VM内存系统承担了更多的压力最后导致更差的吞吐量,即使我使用了更多的CPU。显然最好的方式是从最大的瓶颈开始,但有时这也不是很容易确定的。当然,确保VM的内存处理足够正常也是一个好的开始方向。

内存瓶颈

现在我会首先也定位内存问题。列表3是GrinderServlet的重构版本,使用了StringBuffer实例。图3显示了测试结果。

Listing 3

package pub.capart;

/**
* This is a simple class designed to simulate an application consuming
* CPU, memory, and contending for a synchronization lock.
*/
public class Grinderv2 {
   private static Grinderv2 singleton = new Grinderv2();
   private static final String randstr =
      "this is just a random string that I'm going to add up many many times";
   private StringBuffer sbuf = new StringBuffer();
   private StringBuffer sbufrev = new StringBuffer();

   public static Grinderv2 getGrinder() {
      return singleton;
   }
   public synchronized void grindCPU(int level) {
      sbufrev.setLength(0);
      sbufrev.append(randstr);
      sbuf.setLength(0);
      for (int i=0;i<level;++i) {
         sbuf.append(sbufrev);
         reverse();
      }
      return sbuf.toString();
   }

   public String getReverse(String s) {
      StringBuffer sb = new StringBuffer(s);
      sb = sb.reverse();
      return sb.toString();
   }
} 





 
Figure 3        

通常重用StringBuffer并不是一个好主意,但这里我只是为了重现一些常见的问题,而不量提供解决方案。内存数据已经从图上消失了因为测试中没有垃圾回收器运行。吞吐量戏剧性的增加而CPU使用率又回到了50%。列表3不只是优化了内存,但我认为主要了改善了过度的内存消耗。

检视同步瓶颈

列表4另一个GrinderServlet类的重构版本,实现了一个小的资源池。图4显示了测试结果。
Listing 4

package pub.capart;

/**

* This is just a dummy class designed to simulate a process consuming
* CPU, memory, and contending for a synchronization lock.
*/
public class Grinderv3 {
   private static Grinderv3 grinders[];
   private static int grinderRoundRobin = 0;
   private static final String randstr =
      "this is just a random string that I'm going to add up many many times";
   private StringBuffer sbuf = new StringBuffer();
   private StringBuffer sbufrev = new StringBuffer();

   static {
      grinders = new Grinderv3[10];
      for (int i=0;i<grinders.length;++i) {
         grinders[i] = new Grinderv3();
      }
   }
   public synchronized static Grinderv3 getGrinder() {
      Grinderv3 g = grinders[grinderRoundRobin];
      grinderRoundRobin = (grinderRoundRobin +1) % grinders.length;
      return g;
   }
   public synchronized void grindCPU(int level) {
      sbufrev.setLength(0);
      sbufrev.append(randstr);
      sbuf.setLength(0);
      for (int i=0;i<level;++i) {
         sbuf.append(sbufrev);
         reverse();
      }
      return sbuf.toString();
   }
   public String getReverse(String s) {
      StringBuffer sb = new StringBuffer(s);
      sb = sb.reverse();
      return sb.toString();
   }
} 
  





 
Figure 4        


吞吐量有一定的增加,而且使用更少的CPU资源。竟争和非竟争性同步都是费时的,但通常最大的同步消耗是减少了系统的可伸缩性。我的负载测试不再满足系统的需求了,因此我增加了虚拟的用户数,如图5 所示。



 
Figure 5        


在图5 中吞吐量在负载达到饱和时下降了一些然后在负载减少时又提高了。此外注意到测试使得CPU使用率达到100%,这意味着测试超过了系统的最佳吞吐量。负载测试的一个产出是性能计划,当应用的负载超过他的容量时会产生更低的吞吐量。


水平可伸缩性

水平伸缩允许更大的性能,但并不一定是费用相关的。运行在多个服务器上的应用通常比较运行在单个VM上的应用复杂。但水平伸缩支持在性能上的最大增加。

图6是我的最后一项测试的结果。我已经在三台基本一致的机器上使用了负载平衡,只是在内存和CPU速度上稍有不同。总的吞吐量要高于三倍的单机结果,而且CPU从来没有完全利用。在图6中我只显示了一台机器上的CPU结果,其他的是一样的。



 
Figure 6        


小结

我曾经花了9个月来布署一个复杂的JAVA应用,但却没有时间来做性能计划。但差劲的性能使得用户合约几乎中止。开发人员使用分析器花了很长时间找到几个小问题但没有解决根本的瓶颈,而且被后续的问题完全迷惑了。最后通过负载测试找到解决方法,但你可以想到其中的处境。

又一次我碰得更难的问题,应用只能达到所预期性能的1/100。但通过前期检测到的问题和认识到负载测试的必要性,这个问题很快被解决了。负载测试相对于整个软件开发的花费并不多,但其所归避的风险就高多了。

关于作者
Ivan Small拥有14年的软件开发经验。他在LBNL从开发Supernovae Cosmology Project开始他的职业生涯。这个项目是导致反重力和无限扩展宇宙理论被发现的两个项目之一。他从此工作于数据挖掘和企业级JAVA应用。现在他是nnovative Interfaces公司的首席软件工程师。

资源
·javaworld.com:javaworld.com
·Matrix-Java开发者社区:http://www.matrix.org.cn/
·JAVA性能调优第二版:http://www.amazon.com/exec/obidos/ASIN/0596003773/javaworld
·并发编程技术:JAVA并发编程第二版:http://www.amazon.com/exec/obidos/ASIN/0201310090/javaworld
·JAVA网站分析:JAVA网站的性能分析:http://www.amazon.com/exec/obidos/ASIN/0201844540/javaworld
·JAVA性能:高性能JAVA平台计算:http://www.amazon.com/exec/obidos/ASIN/0130161640/javaworld
·JAVA2性能和术语指南:http://www.amazon.com/exec/obidos/ASIN/0130142603/javaworld
·BEA WebLogic服务器性能调优,包含有用的一般信息:BEA WebLogic服务器上J2EE应用性能测试:http://www.amazon.com/exec/obidos/ASIN/1904284000/javaworld
·JAVA性能调优:http://www.javaperformancetuning.com
·过度的JAVA同步:“轻量级线程”:http://www-106.ibm.com/developerworks/java/library/j-threads1.html
·负载和性能测试工具:http://www.softwareqatest.com/qatweb1.html#LOAD

  • 大小: 39.6 KB
  • 大小: 32.4 KB
  • 大小: 25.7 KB
  • 大小: 24.5 KB
  • 大小: 27.6 KB
  • 大小: 25.3 KB
  • 大小: 93.1 KB
  • 大小: 213.2 KB
分享到:
评论
2 楼 dolphin_ygj 2009-04-13  
JVM监控工具介绍jstack, jconsole, jinfo, jmap, jdb, jsta
http://dolphin-ygj.iteye.com/admin/blogs/366216
1 楼 dolphin_ygj 2009-04-13  
jstack例子
SUN中国软件技术中心 罗浩/Benny Luo
简介:
JDK 5.0, 代号老虎,在以往的Java传统上加入了许多新的设计,给Java语言带来了一些较大的变化,比如泛型,元数据,可变个数参数,静态导入类,新线程架构,自动装箱/拆箱等等新的以往没有的新特性。同时,在调试程序和解决性能各种问题方面,JDK5.0同样加入了多个分析工具来让开发者更加方便地调试他们自己的程序,它们包括了命令行调试工具,图形界面调试工具等等.

JDK5.0包括的调试工具:
我们在这里对JDK5.0的调试工具做大致的概念性的介绍,然后希望通过介绍我自己在实际工作中使用这些工具解决问题的实例来让大家对这些工具有更深入的了解。

JDK5.0里面加入了jstack, jconsole, jinfo, jmap, jdb, jstat, jps, 下面对这些工具做简单介绍:
jstack -- 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。目前只有在Solaris和Linux的JDK版本里面才有。
jconsole – jconsole是基于Java Management Extensions (JMX)的实时图形化监测工具,这个工具利用了内建到JVM里面的JMX指令来提供实时的性能和资源的监控,包括了Java程序的内存使用,Heap size, 线程的状态,类的分配状态和空间使用等等。
jinfo – jinfo可以从core文件里面知道崩溃的Java应用程序的配置信息,目前只有在Solaris和Linux的JDK版本里面才有。
jmap – jmap 可以从core文件或进程中获得内存的具体匹配情况,包括Heap size, Perm size等等,目前只有在Solaris和Linux的JDK版本里面才有。< /li>
jdb – jdb 用来对core文件和正在运行的Java进程进行实时地调试,里面包含了丰富的命令帮助您进行调试,它的功能和Sun studio里面所带的dbx非常相似,但 jdb是专门用来针对Java应用程序的。
jstat – jstat利用了JVM内建的指令对Java应用程序的资源和性能进行实时的命令行的监控,包括了对Heap size和垃圾回收状况的监控等等。
jps – jps是用来查看JVM里面所有进程的具体状态, 包括进程ID,进程启动的路径等等。
另外,还有些其他附带的工具在这里没有列出,比如Heap Analysis Tool, kill -3 方法等等,这些在JDK5.0之前就有,同样也是非常有用的性能调优工具,大家可以参照相应的文档资料来学习,在文章后面也会推荐一些相应的文档给大家作为参考。

好,说了这么多,让我们来看看JDK5.0自带的这些工具在现实工作能给我们带来什么帮助,下面是我和ISV一起共同工作的实际例子,在这里把它们简单阐述出来,希望对大家有所帮助。

jconsole和jstack使用实例:
在做过的项目中,曾经有几个是使用jstack和jconsole来解决问题的。在下面的例子中,由于部分代码涉及到公司名字,我使用了xxx来代替。

1. 其中的一个是Web2.0的客户,由于目前Sun Microsystem公司推出的Niagara服务器系列非常适合网络方面的多线程应用,并且已经在业界非常出名,所以他们决定使用T2000服务器来测试一下如果应用到他们自己的应用是否能够获得出众的性能。
整个应用的架构如下:
Apache 2.0.59 + Resin EE 2.1.17 + Jdk 1.5.0.07 + Oracle 9
运行的操作系统:
Solaris 10 Update 3 (11/06), EIS patches包.
测试工具:
Apache benchmark tool.
在客户的测试环境中,我们分别做了Apache, Resin, Solaris的相应调整,其中包括了Apache使用Prefork模式,并且调整了httpd.conf文件里面相应的ServerLimit, ListenBacklog,Maxclient等等值,Resin服务器调整Jvm heap size, 并行回收new generation和old generation, 最大线程数,oracle连接数等等参数,Solaris操作系统做了网络和系统的相应调整,最终把整套系统搬进了生产环境,一切顺利进行,但当进入其中的一个论坛系统时却发现系统响应时间非常缓慢,用Apache Benchmark Tool加少量压力得到结果如下,由于是在生产环境下所以不敢使用大的压力:
这个命令的意思是启动 ab ,向 www.google.com 发送10个请求(-n 10) ,并每次发送10个请求(-c 10)——也就是说一次都发过去了。跟着下面的是 ab 输出的测试报告,红色部分是我添加的注释。
C:\Program Files\Apache Software Foundation\Apache2.2\bin>ab -n 100 -c 10 free.xxx.com

This is ApacheBench, Version 2.0.41-dev <$Revision: 1.121.2.12 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking free.xxx.com (be patient).....done
Server Software: Resin/2.1.17 (服务器名称)
Server Hostname: free.xxx.com (域名)
Server Port: 8080
Document Path: /forum/bbsMessageList.act?bbsThreadId=1580107
Document Length: 27012 bytes #请求文档大小
Concurrency Level: 10   #并发数 

Time taken for tests: 92.148883 seconds   /*整个测试持续的时间  #全部请求完成耗时
Complete requests: 100   /*完成的请求数量*/   #全部请求数
Failed requests: 0  /*失败的请求数量*/
Write errors: 0
Keep-Alive requests: 0
Total transferred: 2722500 bytes =2.7M /*整个场景中的网络传输量*/ #总传输大小
HTML transferred: 2701200 bytes =2.7M /*整个场景中的HTML内容传输量*/
Requests per second: 1.09 [#/sec] (mean)  #每秒请求数(平均)
Time per request: 9214.888 [ms] (mean)   #每次并发请求时间(所有并发)
Time per request: 921.489 [ms] (mean, across all concurrent requests)  #每一请求时间(并发平均)
/* #传输速率 平均每秒网络上的流量,可以帮助排除是否存在网络流量过大导致响应时间延长的问题*/
Transfer rate: 28.84 [Kbytes/sec] received 2722500 / (28.84*1024)=2722500/29532.16=92.1876(s)
/*网络上消耗的时间的分解,各项数据的具体算法还不是很清楚*/
Connection Times (ms) 
min mean[+/-sd] median max
Connect: 0 0 0.0 0 0
Processing: 9089 9187 139.4 9140 9789
Waiting: 3067 3163 138.3 3117 3766
Total: 9089 9187 139.4 9140 9789
/*下面的内容为整个场景中所有请求的响应情况。在场景中每个请求都有一个响应时间,其中 50% 的用户响应时间小于 9140 毫秒,60 % 的用户响应时间小于 9178 毫秒,最大的响应时间小于 9789 毫秒*/
Percentage of the requests served within a certain time (ms)
50% 9140
66% 9178
75% 9189
80% 9201
90% 9281
95% 9560
98% 9739
99% 9789
100% 9789 (longest request)
每一个请求的响应时间大概去到8-9秒时间,这个是客户所不能接受的。 在实验的初段,Tomcat, Oracle 10g服务器都是架设在T2000上,我们在对T2000服务器的OS,网络,应用服务器做了必要的调整后,发现其表现还是不尽如人意。



我们使用Loadrunner做测试,用户上到了100个同时并发10个迭代时已经出现问题,有许多的请求都被阻塞住,不能正常地进行。


 这时我们决定使用jconsole和jstack来看看系统出现了什么问题。
A. 首先我们需要在Tomcat的启动脚本catalina.sh里面加入JVM选项:
     Dcom.sun.management.jmxremote
     把tomcat服务器java进程置于JDK5.0的性能监控范围之内。

B. 然后我们用jconsole连接到tomcat服务器的java进程,发现基本上Heap size, 垃圾回收都比较正常,但发现tomcat服务器的大部分线程有问题,都处于被Block的状态。
     观察每条线程的stack trace, 发现它们基本上都被堵塞在uk.org.primrose.pool.core.Pool.put和uk.org.primrose.pool.core.Pool.get()的SyncHack同步机制上,我们尝试了改大数据连接池的大小,发现结果是一样的。










C.这个结论在jstack的结果中同样得到了验证,使用jstack连接到tomcat服务器java进程,并观察结果。






D. 最后我们决定用tomcat服务器的连接池配置来代替Primrose数据库连接池,更改以后,发现结果比较理想。

E. 后来,我们把Oracle数据库建立在另外的一台服务器X4200上,而Tomcat应用服务器依然放在T2000上,使用千兆网络交换机,同样地,使用Tomcat服务器自己的连接池配置表现较为理想。
以上两个是我对JDK5.0工具的一些实际操作的例子,在这里和大家分享一下,希望对大家有所帮助。而Sun Microsystem公司也在不断地完善JDK,在新的JDK版本里面加入越来越多的实用的方便开发者开发和调试的新特性,比如在最新的JDK6.0里面就内嵌了Dtrace里面许多关于Java程序中内存,方法,线程等等新的探针,通过这些探针和Dtrace,我们可以更加方便地调试Java程序。
文档资料:
http://java.sun.com/j2se/1.5/pdf/jdk50_ts_guide.pdf
http://developers.sun.com.cn/home/export/sites/default/home/ISVs/docs/docs/thead.html
http://java.sun.com/j2se/1.5.0/docs/guide/management/jconsole.html
http://java.sun.com/docs/hotspot/gc5.0/ergo5.html#0.0.Behavior%20based%20tuning%7Coutline
http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html
http://java.sun.com/
http://www.java.net/

相关推荐

    解决JAVA服务器性能问题研究分析.doc

    解决JAVA服务器性能问题研究分析 改善JAVA服务器的性能需要模拟负载下的服务器。创建一个模拟环境、搜集数据并且分析结果可能是对许多开发人员的挑战。这篇文章中的示例介绍了JAVA服务器性能分析的概念和工具。作者...

    JAVA负载均衡 JAVA性能

    解决JAVA服务器性能问题研究分析,文件类型 DOC

    JProfiler解决Java服务器的性能跟踪.doc

    JProfiler解决Java服务器的性能跟踪

    JProfiler 解决 Java 服务器的性能跟踪.doc

    JProfiler 解决 Java 服务器的性能跟踪.doc

    大话JAVA性能优化.pdf

    大话Java性能优化》主要提供Java性能调优...总的来说,性能调优在很大程度上是一门艺术,解决的Java性能问题越多,技艺才会越精湛。我们不仅要关心JVM的持续演进,也要积极地去了解底层的硬件平台和操作系统的进步。

    论文研究-JavaServlet模式的WebGIS性能优化研究.pdf

    因此对WebGIS服务器端性能问题进行了深入研究,提出了JVM(Java虚拟机)性能调优、建立并改进缓存服务器、使用tmpfs(一种基于内存的文件系统)存储缓存图片等从根本上解决服务器端性能问题的一系列方案,同时设计了...

    大话JAVA性能优化 周明耀 PDF

    《大话Java性能优化》主要提供Java性能调优...总的来说,性能调优在很大程度上是一门艺术,解决的Java性能问题越多,技艺才会越精湛。我们不仅要关心JVM的持续演进,也要积极地去了解底层的硬件平台和操作系统的进步。

    Java性能优化亿级流量秒杀解决方案及电商项目秒杀实现(7.25G)

    Day4:分布式服务器部署.rar Day5:缓存方案及接入实操.rar Day6:静态化及cdn部署.rar'q#Y:a9K%d)W0-0M'p!f Day7:缓存与数据库锁方案.rar Day8:库存问题及数据一致性.rar Day9:token及队列的应用.rar Day10:验证码及...

    java性能分析神器 jprofiler_windows-x64_10_0_4

    JProfiler直觉式的GUI让你可以找到性能瓶颈、抓出内存漏失(memory leaks)、并解决执行绪的问题。它让你得以对heap walker作资源回收器的root analysis,可以轻易找出内存漏失;heap快照(snapshot)模式让未被参照...

    Java应用性能调优实践

    Java应用性能优化是一个老生常谈的话题,典型的性能问题如页面响应慢、接口超时,服务器负载高、并发数低,数据库频繁死锁等。尤其是在”糙快猛”的互联网开发模式大行其道的今天,随着系统访问量的日益增加和代码的...

    一款分布式的java游戏服务器框架,具备高性能、可伸缩、分布式、多线程等特点,java 8 +gradle 4.0

    一款高性能、实时通信、多进程的游戏解决方案 适用于手游、h5游戏等各类高性能游戏服务器的开发 功能特点 基于Disruptor消息队列设计的无锁并发模式 分布式(多进程)架构,几行代码实现一个功能服务器的搭建 多线程...

    决战Nginx 技术卷:高性能Web服务器部署与运维.part3

    《决战Nginx技术卷:高性能Web服务器部署与运维(基于php、Java、ASP.NET等)》详细讲述了Nginx服务器与动态语言应用的结合,动态语言包括PHP、Python、Perl、Java、Ruby及ASP.NET架构。对于PHP部分,我们使用了...

    JAVA高并发高性能高可用高扩展架构视频教程

    企业高并发基石(Tomcat服务器性能优化) spring事务处理 课程文档 高并发之基础数据MySql调优 mongodb 三级联动课程资料 应用架构之灵魂设计模式 应用架构之魂设计模式实战演练应用架构之魂设计模式实战演练 揭开...

    HTTPS 代理-SNI Proxy-WebSocket-Java

    干脆用java自己写了个小程序,性能当然和squid、nginx之类的没法比,还好我们的系统负荷不是很重,运行了一个星期基本没问题。 附件是该 java 程序包。 使用方法: 1。 安装java 2。在命令行输入: java -jar ...

    JAVA上百实例源码以及开源项目

     基于JAVA的UDP服务器模型源代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 ...

    JAVA上百实例源码以及开源项目源代码

     基于JAVA的UDP服务器模型源代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 ...

    决战Nginx 技术卷:高性能Web服务器部署与运维.part2.rar

    《决战Nginx技术卷:高性能Web服务器部署与运维(基于php、Java、ASP.NET等)》详细讲述了Nginx服务器与动态语言应用的结合,动态语言包括PHP、Python、Perl、Java、Ruby及ASP.NET架构。对于PHP部分,我们使用了...

    决战Nginx 技术卷:高性能Web服务器部署与运维.part1

    《决战Nginx技术卷:高性能Web服务器部署与运维(基于php、Java、ASP.NET等)》详细讲述了Nginx服务器与动态语言应用的结合,动态语言包括PHP、Python、Perl、Java、Ruby及ASP.NET架构。对于PHP部分,我们使用了...

    java开源包11

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

    java开源包6

    JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM 是一个可在浏览器上直接运行 Java 项目的系统,无需任何插件支持。目前它包含一...

Global site tag (gtag.js) - Google Analytics