本JVM系列均来源于《深入理解Java虚拟机》一书中,版权归该书作者所有。

环境:一个15万PV/天左右的在线文档类型网站最近更换了硬件系统,新系统硬件为4个CPU、16GB物理内存、OS为64位CentOS5.4、Resin作为Web服务器。

说明:整个服务暂时没有部署别的应用,所有硬件资源都可以提供给访问量并不算太大的网站使用。管理员为了尽量利用硬件资源选用了64位的JDK1.5,并通过-Xmx和-Xms参数将java堆固定在12GB。

问题:使用一段时间后发现使用效果并不理想,网站经常不定期出现长时间没有响应的现象。

排查:监控服务器运行状况后发现网站没有响应是由于GC停顿导致的,虚拟机运行在Server模式,默认使用吞吐量优先收集器,回收12GB的堆,一次Full GC的停顿时间高达14s。并且由于程序设计的关系,访问文档时要把文档从磁盘提取到内存中,

导致内存中出现很多由文档序列化产生的大对象,这些大对象很多都进入了老年代,没有在Minor GC中清理掉。这种情况下即使有12GB的堆,内存也很块被消耗殆尽,由此导致每隔十几分钟出现十几秒的停顿。

分析:先不延伸讨论程序代码问题,程序部署上主要问题显然是过大的堆内存进行回收时带来的长时间停顿。硬件升级前使用32位系统1.5GB的堆,用户只感到访问网站比较缓慢,但不会发生十分明显的停顿,因此才考虑升级硬件来提升程序效能,如果重新

缩小给java堆分配的内存,那么硬件上的投资就浪费了。

在高性能硬件上部署程序,目前主要有两种方式:1.通过64为JDK来使用大内存 2.使用若干个32位虚拟机建立逻辑集群来利用硬件资源

此案例中管理员采用了第一种部署方式。对于用户交互性强、对停顿时间敏感的系统,可以给Java虚拟机分配超大堆的前提是有把握把应用程序的Full GC频率控制得足够低,至少要低到不会影响用户使用,譬如十几个小事乃至一天才出现一次Full GC,这样可以通过在深夜执行定时任务的方式触发Full GC甚至自动重启服务器来将内存可用空间保持在一个稳定的水平。

控制Full GC频率的关键是看应用中绝大多数对象能否符合“招生夕灭”的原则,即大多数对象的生存时间不应太长,尤其是不能产生批量的、长生存时间的大对象,这样才能保证老年代空间的稳定。

在大多数网站形式的应用里,主要对象的生存周期都应该是请求级或页面级的,回话级和全局级的长生命对象相对减少。只要代码写得合理,应当都能实现在超大堆中正常使用而没有Full GC,这样的话,使用超大堆内存时,网站响应的速度才比较有保证。除此之外,如果读者计划使用64位JDK来管理大内存,还需要考虑下面可能面临的问题:

1.内存回收导致的长时间停顿

2.现阶段,64位JDK的性能测试结果普遍低于32位JDK。

3.需要保证程序足够稳定,因为这种应用要是产生堆溢出几乎无法产生堆转储快照(因为要产生十几GB乃至更大的dump文件),哪怕产生了快照也几乎无法进行分析。

4.相同的程序在64位JDK中消耗的内存一般比32位JDK大,这是由于指针膨胀及数据型对齐补白等因素导致的。

上面的问题听起来有点吓人,所以现价段不少管理员还是选择了第二种方式:使用若干个32位虚拟建立逻辑集群来利用硬件资源。具体做法是在一台物理机器上启动多个应用服务器进程,给每个服务器进行分配不同的端口,然后在前端搭建一个负载均衡器,以反向代理的方式来分配访问请求。读者不需要太在意均衡器转发所消耗的性能,即使使用64位JDK,许多应用也不止有一台服务器,因此许多应用中前段的均衡器总是要存在的。

考虑到一台物理机器上建立逻辑集群的目的仅仅是尽可能地利用硬件资源,并不需要关心状态保留、热转移之类的高可用性需求,也不需要保证每个虚拟机进程有绝对准确的均衡负载,因此使用无Session复制的亲合式集群是一个相当不错的选择。我们仅仅需呀保障集群具备亲和性,也就是均衡器按一定的规则算法(一般根据SessionID分配)将一个固定的用户请求永远分配到固定的一个集群节点进行处理即可,这样程序开发阶段就基本不用为集群环境做什么特别的考虑。

当然,很少有没有缺点的方案,如果读者计划使用逻辑集群的方式来部署程序,可能会遇到下面的一些问题。

1.尽量避免节点竞争全局资源,最典型的就是磁盘竞争,各个节点如果同时访问某个磁盘文件的话(尤其是并发写操作容易出现问题),很容易导致IO异常。

2.很难最高效率地利用某些资源池,如连接池,一般都是在各个节点建立自己独立的连接池,这样有可能导致一些节点池满了而另外一些节点仍有较多空余。尽管可以使用集中式的JNDI,但这有一定的复杂性且可能带来额外的性能代价。

3.各个节点仍然不可避免地受到32位的内存限制,在32位Windows平台中每个进程只能使用2GB的内存,考虑到堆以外的内存开销,堆一般最多只能开到1.5GB。在某些Linux,Unix系统(如Solaris)中,可以提升到3GB乃至接近4GB的内存,但32位

中仍然受最高4GB(2^32)内存的限制。

4.大量使用本地缓存(如大量使用HashMap所谓K/V缓存)的应用,在逻辑集群中会造成较大的内存浪费,因为每个逻辑节点上都有一份缓存,这时可以考虑把本地缓存改成集中式缓存

介绍完这两种部署方式,再重新回到这个案例中,最后的部署方案调整为建立5个32位JDK的逻辑集群,每个进程按2GB内存计算(其中堆固定为1.5GB),占用了10GB的内存。另外建立一个Apache服务作为前端均衡器代理访问门户。考虑到用户对响应较低,因此改为CMS收集器进行垃圾回收。部署方式调整后,服务再没有出现长时间停顿,速度比硬件升级前有较多提升。

 

Java之JVM调优案例分析与实战(1) - 高性能硬件上的程序部署策略的更多相关文章

  1. Java之JVM调优案例分析与实战(4) - 外部命令导致系统缓慢

    环境:这是一个来自网络的案例:一个数字校园应用系统,运行在一台4个CPU的Solaris 10操作系统上,中间件为ClassFish服务器.系统在进行大并发压力测试的时候,发现请求响应时间比较慢,通过 ...

  2. Java之JVM调优案例分析与实战(3) - 堆外内存导致的溢出错误

    环境:基于B\S的点子考试系统,为了发现客户端能实时地从服务端接收考试数据,系统使用了逆向AJAX技术(也称Comet或Server Side Push),选用CometD1.1.1作为服务端推送框架 ...

  3. Java之JVM调优案例分析与实战(5) - 服务器JVM进程奔溃

    环境:一个基于B/S的MIS系统,硬件为2个CPU.8GB内存的HP系统,服务器是WebLogic9.2(就是第二个案例中的那个系统).正常运行一段时间后,最近发现在运行期间频繁出现集群节点的虚拟机进 ...

  4. Java之JVM调优案例分析与实战(2) - 集群间同步导致的内存溢出

    环境:一个基于B/S的MIS系统,硬件为两台2个CPU.8GB内存的HP小型机,服务器是WebLogic 9.2,每台机器启动了3个WebLogic实例,构成一个6个节点的亲合式集群. 说明:由于是亲 ...

  5. 《深入理解Java虚拟机》-----第5章 jvm调优案例分析与实战

    案例分析 高性能硬件上的程序部署策略 例 如 ,一个15万PV/天左右的在线文档类型网站最近更换了硬件系统,新的硬件为4个CPU.16GB物理内存,操作系统为64位CentOS 5.4 , Resin ...

  6. 《深入理解Java虚拟机》调优案例分析与实战

    上节学习回顾 在上一节当中,主要学习了Sun JDK的一些命令行和可视化性能监控工具的具体使用,但性能分析的重点还是在解决问题的思路上面,没有好的思路,再好的工具也无补于事. 本节学习重点 在书本上本 ...

  7. 【JVM.4】调优案例分析与实战

    之前已经介绍过处理Java虚拟机内存问题的知识与工具,在处理实际项目的问题时,除了知识与工具外,经验同样是一个很重要的因素.本章会介绍一些具有代表性的案例. 本章的内容推荐还是原文全篇看完的好,实在不 ...

  8. 记一次Java调优案例分析

    上周,一同学给我发来,他们那里的案例 一看就是新生代产生过多对象,肯定是批量或者循环操作导致的,导致新生代一直在进行回收导致. 如果是老生代出现这样的问题,大部分情况下是列表或者集合导致的. 因此我们 ...

  9. java面试-JVM调优和参数配置,如何查看JVM系统参数默认值

    一.JVM的参数类型: 1.标配参数: java -version java -help 2.X参数: -Xmixed 混合模式(先编译后执行) -Xint  解释执行 -Xcomp 第一次使用就编译 ...

随机推荐

  1. 【BIT套主席树】COGS257-动态排名系统

    题意同BZOJ1901,多组数据,数据范围也不一样.重新写一遍复习一下. #include<iostream> #include<cstdio> #include<cst ...

  2. Jeeplus框架中问题解决

    1,文件上传后图片显示的问题 (1)问题:在这个组件的文档介绍里面写了这个组件是有预览功能的,但是我没有找到,就自己写了这个小功能. 在框架中下图中,这个文件上传组件只能将文件上传,然后将文件名显示出 ...

  3. CodeM资格赛1

    题目描述 美团外卖的品牌代言人袋鼠先生最近正在进行音乐研究.他有两段音频,每段音频是一个表示音高的序列.现在袋鼠先生想要在第二段音频中找出与第一段音频最相近的部分. 具体地说,就是在第二段音频中找到一 ...

  4. C#中&和&&,|和||区别

    当两者都为逻辑运算符时. 其实没什么差别. &&和||当已经确定结果时,不会对第二个操作数求值.也不知道什么情况会用到这个差别.做个笔记好了. http://blog.csdn.net ...

  5. Bayesian Face Revisited A Joint Formulation

    很有意思的一篇人脸识别算法文章,人家写的太好,就不好意思写了,收集了一些资料,包括了原理介绍,流程图,项目网址和作者主页信息等. 参考资料: [1]. http://blog.csdn.net/csy ...

  6. windows2008服务器连接Oracle慢的问题。

    昨天发布程序到2008服务器的IIS,从Sql Server数据库取数没问题,但是从Oracle数据库取数,非常的慢,同样的程序在2003服务器上没问题,本机也没问题.一开始怀疑是这台机器有问题,后来 ...

  7. OC 导入类 #import和@class 区别复习

    objective-c中#import和@class的区别 在Objective-C中,可以使用#import和@class来引用别的类型, 但是你知道两者有什么区别吗? @class叫做forwar ...

  8. Trigger a TTL circuit from ECL levels

    ECL circuits typically have relatively small logic spans of approximately 800 mV. Because of the sma ...

  9. Two PWM outputs from MCU combine to form a monotonic 16-bits DAC

    http://www.edn.com/design/analog/4329365/Combine-two-8-bit-outputs-to-make-one-16-bit-DAC

  10. gdb逆向调试

    http://blog.csdn.net/yiling2012/article/details/35988361