WebSphere Application Server诊断和调优 二

四、用IBM的HeapAnalyzer和GarbageCollector检测

找到这两个工具,已经是够费劲了,因为以前找的IBM HeapRoot工具,让我对这类工具很失望。而且,这两个工具,只有在IBM的Techinical Support网站能够搜索到,但很不容易,因为那两个工具,并不是象IBM的Websphere产品那样宣传,它只在IBM Techinical Support文章的某些角落里出现。要知道,Techinical Support是IBM很重要的收入来源,这类文档,他们并不会让你很轻易就拿到,比起BEA WLS的支持网站dev2dev差远了。
具体诊断细节我就不详述了。我认为,IBM的WAS或JVM出了性能和OOM问题,这两个工具是最有效的,而且是离线分析工具,比起那些实时Profiler工具,某些场合有绝对的优势:譬如我们目前的产品环境,你只能分析宕机后的日志,实时分析前面已经验证是不可行的。
从日志分析,我们最终得出结论,我们购买的CMS系统有严重的碎片(大对象)问题,而该问题是OOM的罪魁祸首,而且IBM工程师也得出了同一结论。不过,在起先我们得出这一结论一周后,我还始终不相信heap碎片会导致OOM,直到IBM工程师总是向我强调。

我想很多人也是不太相信,因为大多数人用的都是Sun的JVM,譬如Windows、Solaris上的hotspot。而且,Sun JVM出问题,如果是配置的问题,一般通过配置heap最大最小值,以及maxPermSize都可以解决。Heap碎片导致的OOM,只有BEA的JRockit和IBM JVM上发生,不过JRockit有专门文档说明,而且很容易找到(就在jdk的文档里面)。

配置heap最小最大值,我想大多数人都有经验。对于Sun的JVM来说,一般可以设置heap最大最小值一致,也是推荐的做法。因为它的GC策略默认是复制、分代算法。也就是说,它会将heap分成不同的几个区,譬如Solaris JVM中最上面有两个大小相等的区。GC时刻,将一个区的存活对象复制到另外一个对等区,垃圾对象就算遗弃了。这样在heap里面,就不存在碎片问题。另外,根据Java对象的存活期不同,将之转移到不同的区(Tenured区),存活最长的在最底部(火车算法),这也就是分代模型。具体请参考官方文档:http://java.sun.com/docs/hotspot/gc1.4.2/

对于maxPermSize(Permanent Generation),主要和那些加载到JVM里面的Java Class对象相关,它的空间不是在Java Heap里面分配。如果你当前的heap有1000M,permSize是200M,那么JVM至少占用1200M。
在这个空间内的对象的生存期和JVM是一样的,譬如JDK的核心类库,它们被System Classloader加载到JVM的Method Area(方法区)后,就不会被GC掉的,这些对象一般是Class对象,而不是普通的实例对象,也就是JVM的元数据。我们在用反射时经常用到它们。所以,对于现在象Spring、Hibernate这些框架经常通过反射创建实例,可能对maxPermSize要求就大了,缺省的64M很多时候是不够的,特别是对于应用服务器里的应用,象JSP就会产生和加载很多classes。不过,如果是它导致的OOM,一般会有类似 perm size提示。

但是,对于IBM的JVM,情况就完全不一样。它的默认GC策略并没有采取复制、分代。这个可以从GC日志分析出来。它不像Sun的JVM那样,有个单独的方法区,它的方法区就放在Java Heap里面。JVM规范里面并没有要求方法区的必须存放的位置,因为它只是一个JVM实现问题。

在IBM的JVM里面,这些对象一般分配在称为k-cluster和p-cluster里(cluster又是属于Heap),而后者一般是临时在heap里面申请。并且,这些cluster是不能GC,或是被移动重排的(Compact过程)。这就导致Java Heap里面就如同马蜂窝,但不同的蜂孔又不能合并,于是,当我们程序里面产生一个大对象,譬如2M的数组(数组必须分配在连续的内存区)时,就没有可分配空间了,于是就报告OOM。这些不能被移动的cluster就称为所谓的碎片。此时,JVM的Heap利用率可能不到50%。
当然,通过一定时期的GC日志,可以计算出cluster的合理大小(专门在Java Heap的底部),另外,还可以为这些大对象专门分配大对象区的(超过64k的对象)。

通过上面的理论介绍,我想大家一定知道了为什么IBM的JVM里面不推荐heap的最大最小值相同,因为这样碎片问题会非常严重:如果我们每次大对象申请内存时,heap都扩展5%,譬如50M,碎片问题很大程度上可以避开,程序性能也高些(寻找可用空隙和分配耗时,以及每次GC时间拉长)。
以上的具体阐述,请参考我在上文推荐的几个URL,另外再推荐三个宝贵的链接:
http://www-1.ibm.com/support/docview.wss?rs=180&context=SSEQTP&q1=fragmentation&uid=swg21176363&loc=en_US&cs=utf-8&lang=en
http://www-900.ibm.com/cn/support/viewdoc/detail?DocId=2447476A10000(IBM 技术支持告诉我的,太重要了!)
http://www-900.ibm.com/cn/support/viewdoc/detail?DocId=2847476B08000

我想大家应该会问:我怎么能够肯定我的OOM问题是heap碎片造成的呢?下面的方法可以验证。
在OOM发生时,JVM会产生一个heapdump文件。然后用GarbageCollector分析出该OOM发生时刻,JVM去申请的空间,譬如约235k。此时,你再用HeapAnalyzer去分析此时的heap快照里面的gap size大小(空隙大小)和各自的可用数目。你会发现,大于235k的空隙个数为0。这就是碎片导致OOM的证据。

另外,有人会问:我怀疑我的OOM是因为程序内存泄漏造成的,怎么去验证

你可以用HeapAnalyzer分析发生OOM时刻的heap快照,工具会罗列出哪些对象怀疑有内存泄漏,譬如Cache对象都非常大(但你可以确定它不是内存泄漏)。另外,分析这次宕机(从这次虚拟机启动到宕机这段时间)的heap走势,如果曲线明显是向上倾斜,也就是那种典型的内存泄漏图,就有可能是内存泄漏。当然,还必须结合heap快照。
内存持续上升在JVM开始一段时间很正常,因为JVM对第一次访问到的Class 对象,譬如一个典型的Web应用,就有jdk的class、Spring或Hibernate的class对象,它们都会被缓存下来(ClassLoader原理),一般均不会被GC。当大多数class对象缓存差不多(当然还可能有一些Singleton对象,不过不怎么占分量),JVM的Heap就平稳了,呈一水平波浪或锯齿线。
如果可以用JProfiler这类工具实时监控,就更容易确诊了。

经过一番周折,我们终于看到了一线希望了

在一定的准备后,我们决定对WAS进行性能调优了。WAS的调优参数,可以分为两个部分:JVM级别和WAS级别:
JVM:主要是GC和Heap。
WAS:Thread Pool,JDBC DataSource。
当然要调节,你需要明白你的目标是什么,调节依据是什么,怎么计算,绝对不是凭空想象的,譬如heap最小值1024M,日志证明,该参数非常不适合我们的环境。具体细节,留给后文吧。

战战兢兢地,中午12:00,我们给产品环境下的WAS调节参数、重启,同时优化了AIX的IO相关参数。

我试着设置了一下JVM的k-cluster和p-cluster。下午15:00左右,WAS挂了,AIX也挂了。这下麻烦可大了。我们都慌了,马山客户的老总就来电话了,一阵哗哗啦啦。实在无奈,让客户那边工作人员通知机房(服务器托管处)工作人员重启AIX。我也不得不强行更改刚才的参数,立即设为另外一个值。
其实,我把那个两个cluster值确实设置太大了,我把它们设置为推荐值的5倍,譬如p-cluster是65k×110%×5。另外一个愚蠢的设置就是把最小heap设置为2048M(AIX有4G内存)。
后来我恢复到约正常的值,也就是去掉那个cluster的5,另外分配了一个30%的大对象区(如果1000M的heap,就是700M+300M)。

就这样,系统持续正常运行了三天,以前可是一天一down。当在三天后再次宕机时,我们都没有自信了 。不得不通过AIX的cron,继续每天深夜11点的WAS定时重启。
不过,那次宕机,包括以后的几次宕机,再也没有出现OOM错误了,但系统依然不稳定。虽然我可以说OOM问题解决了,但领导和客户需要的并不是这种结果。

其实,在这个时候,我们已经发现我们系统的四大问题:
1、WAS和JVM参数:OOM问题
2、AIX的IO和Paging Spacing不足:AIX日志后来显示错误
3、AIX的WAS分区空间不够:WAS的日志膨胀一周就把那个opt分区塞满了。
4、应用程序的JDBC连接池:我们20来个应用,一个20 connections,DB2数据库有时被撑死。

也就是说,我们最初在客户那儿部署时,用的默认值根本不行。而且,部署涉及多人,人员之间出现断层。如果我们只是按OOM,无疑是走入死胡同,必须全局考虑!
但是,项目组实力薄弱,公司范围内就没有对AIX精通的。不过项目组原来有一个搞银行系统,在AIX下开发,就他熟悉些。我当时对AIX也比较陌生,你们从Linux转到AIX,你就知道它有多别扭了。命令都自定一套(也许因为是Unix元老吧),那个shell也超级别扭,而且参考书特少。不是自诩,我两年前负责一个高负载的Linux服务器管理一年多,也是玩得很转的。

就这样,他负责AIX的相关问题,我负责WAS相关的。
但是,现实环境,已经不允许我们再试验下去了 。我们必须找到一条绝对可靠的对策!
这就是下文的CMS系统大迁移,服务器再次优化。

文章太长(上万字),我把剩下部分发表在回复贴里面吧。

Job1-1.png
 描述: 
 文件大小: 14 KB
 看过的: 文件被下载或查看 288 次

Job1-1.png
下载
all-GC.png
 描述: 
 文件大小: 78 KB
 看过的: 文件被下载或查看 223 次

all-GC.png
下载
HeapAnaylizer_gap.png
 描述: 
 文件大小: 18 KB
 看过的: 文件被下载或查看 183 次

HeapAnaylizer_gap.png
下载

五、隔离CMS系统,服务器优化
从前面的介绍,大家应该记得,我们开始是固定CMS,分离其它应用,但遭遇失败。现在是反过来,干脆把CMS系统赶出WAS平台

说实话,项目经理做这个决定,我认为已经是鼓出很大勇气了

当时我们想在一个备用AIX机上安装CMS产品测试,但最后还是没有做成:
CMS这类文章发布系统很难安装,也不好测试,又没有liscence,而且还有一堆准备工作。绝对没有著名的openCMS安装那么简单,当然功能远远比它复杂。而且,我们当时也低估了后来的工作,总觉得问题好解决。

在很遥远的06年中期,CMS厂商在客户那边一台AIX的Tomcat上部署了一套CMS产品。但当时客户执意要求将其跑在WAS上,也就是现在的情况。最开始,客户还要求我们必须用WAS的集群(我们买的就是WAS的ND版),无奈该CMS不支持。要是集群,又是死伤一遍。其实,现在想想,我们当时太被动,CMS这种东西,就供公司的几十个编辑用,一个普通Tomcat就完全够用。而且,把它和面向公网的Internet应用混在一起,完全没有必要。也许,被动是因为我的实力造成的。

我们决定背水一战时,已经做过周密的计划:某年某月某日晚上8:00......
CMS产品负责人现场切换
xx(我)负责WAS相关参数调整
yy负责AIX参数。
zz负责应用的测试
…..

总之,该行动涉及到客户方、产品提供商、公司高层、项目组。每个人都密切关注,不下20人。每个人都守在电脑前,随时听候调遣,当天晚上,我们都没有准备回家睡觉,大家齐心协力。

真没想到,整个式切换工作,一个小时就顺利完成 !第二天,客户编辑打开浏览器,她们一定想不到昨晚大家准备经历一场厮杀….

系统持续平稳地运行了一周,然后是漫长的五一,我回湖北黄冈老家休息了八天。回来时,一切依旧。

当天晚上,我们这边主要做了两项工作:
1、JVM的Heap参数,共五个。
2、AIX的IO、Paging Space等共六个。
当然还有其他人的工作,譬如测试、监控。

还有一个非常重要的方面:JDBC连接池。我们原来是在每个Web应用里面独立设置,这样20来个应用就有几百个DB连接,一不小心DB就给撑死。现在统一交由WAS内置DataSource处理,总共连接不到30个。其实,我们项目开始部署时,就是这样做的,但当时WAS内置的DataSource对JTA(XA)支持有bug (这个和IBM技术支持确认过,但他们没有给予很好的解决方案),不过Datasource还是配好的。

但是这个工作已经属于WAS性能优化的主题了,而且优化值必须持续观察一段时间,通过专门的分析工具来计算。
优化本身,是一项很考验人的工作,我就简单说一下最实用方法吧,也许是专门针对IBM的产品。
1、清理归零WAS日志。然后启动WAS,生成日志(-verbose:gc默认是开的)
2、让WAS持续运行约两周,让JVM Heap占用曲线平稳一段时间即可(用IBM的Garbage Collector分析观察)。
3、在AIX的shell里,产生heapdump.phd文件,也就是heap快照。命令:kill -3 pid (pid是WAS的PID,通过ps –ef查看),观察heap当时的碎片情况,是否需要单独分大对象区(一般不需要设置),特别是那个方法区Class对象大小(p-cluster参数)。
4、通过GC工具,观察GC平均时间、Heap实际占用情况。Note: GC是一个Stop The World过程,也就是说GC时系统对外不响应,多CPU也不例外。看你的应用实际需求了,GC持续时间和频率是矛盾的,另外还有性能考虑。一般Web应用,我想让GC持续时间(Pause time)调节到合理值就ok了,譬如0.2到0.4s。
5、根据3可以算出k-cluster值,它是工具推荐值的110%。
6、Heap的最小值是程序刚启动不久的占用值,譬如320M。切记:IBM JVM初始值太大非常不好。
7、Heap的最大值是系统平稳后的100/70。也就是说如果最大值是1000M,那么应该平稳时是700M,还有30%的空余。IBM的JVM默认情下的碎片问题,WAS控制台下操作Heap猛增这种bug,你不得不堤防。Heap最大值不设,AIX下的WAS肯定OOM。

当然啦,我没有考虑到大对象区的计算(虽然我们的应用设置了专门的大对象区),包括IBM JVM支持的分代GC、并行GC,Heap每次expand百分比等。那些情况我们一般不常用,譬如,你的AIX平台一般不是16CPU吧?

一口气写到现在,我忽然觉得该收尾了。下面就说说我对这类工作的整体看法吧。
1、尽量在项目测试和试运行的时候就进行压力、性能测试,当正式投入使用后,如果发现类似问题,代价非常大。躲过算你运气好,一般来说,可能你们系统没多少人用,也不是核心业务系统,譬如一般的电子政务。
2、千万不要低估了技术风险,用IBM的系列产品尤其要慎重,出问题一定不要忘了技术支持。而且,查资料时,建议用google English,因为象WebSphere这类问题,很少有中文资料。
3、程序部署环境建立时,就要考虑到日后的正式环境,譬如AIX的Paging Space、IO、分区大小,默认值往往是不行的,而且在产品环境下改这些值,往往非常难。
4、在项目开发初期,就考虑到日志的问题,因为它分散到每个方法内,必须慎重定义好debug、info、warn、error级别,不要随便忽视异常(catch里面不记录),到真正程序出问题时,它就是我们的最重要的依据之一。当然这主要是功能性问题诊断。另外对于高负载网站,日志文件往往非常大,各级别日志千万不要混在一起,否则找问题就很困难了。
5、怎么说呢,别死扣技术,以为什么都可以通过技术解决。你看我们最大的问题就是把CMS给移到Tomcat下。你要是问我,为什么CMS产品会导致系统这么多的问题,我也不知道,到那时候,我确实也不想深入。我只要知道,赶出你这个应用,我的系统就好控制多了。而且,那个CMS系统,在Tomcat下,就是跑得服服帖帖的,非常稳定。难度是可恶的WAS?不过那CMS,据IBM工程师,包括我们二次开发,都觉得够烂了,每个jsp页面都打开、关闭DB connection(7年前的jsp开发模式),还有那么严重的大对象问题。

好了,以上总结的几点可能也不充分、深入,但如果你仔细读我这篇文章,应该有自己的想法。毕竟,只有经过思考的东西,才会属于自己。

 

WAS.PNG
 描述: WAS控制台的部分状态参数
 文件大小: 20 KB
 看过的: 文件被下载或查看 183 次

WAS.PNG
下载
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值