所在的位置: Web开发 >> HTTP >> 云上JavaSystemProfilin

云上JavaSystemProfilin

摘要:在Java20岁生日这年,我们用这篇文章记录蚂蚁金服内部,在金融云环境下Java系统的Profiling和Debugging经验与实践,与大家分享交流,有非常特别的意义。希望读者能够从中借鉴到一些解决问题的思路。

从年Java1.0beta发布到现在,整整过去了20年。Java的发明源于嵌入式领域,不过后来Java的发展,出乎意料地在企业级应用领域占据了几乎统治的地位。阿里巴巴以及支付宝(就是后来的蚂蚁金服),绝大部分的业务代码都是Java编写的。在Java20岁生日这年,我们用这篇文章记录蚂蚁金服内部,在金融云环境下Java系统的Profiling和Debugging经验与实践,与大家分享交流,有非常特别的意义。希望读者能够从中借鉴到一些解决问题的思路。

线上Profiling/Debugging难点

在集中式架构的时代,应用按照大的业务功能划分为不同的模块或者系统,无论在系统类型、数量还是依赖上,均相对可控,一旦出现线上问题也容易在线下模拟分析。但建立在分布式架构体系上的应用具有数量多、规模大、环境复杂的特点。这些特点带来了很多问题,不是单一的工具和系统能解决的。这里仅着重讲述给Profiling和Debugging工作带来的挑战。

因安全问题增加的权限控制。在SOA架构下,系统间通过服务进行通信,但不是所有服务都可以公开暴露,不是所有客户端都是可信的。于是系统中增加各种管控和权限设置。这些安全措施给Profiling和Debugging工作带来很大的麻烦。比如网络隔离,导致无法直接使用有简便图形界面的Eclipse去远程调试线上服务器。即使登录到服务器上使用命令行工具,也面临着登录账户权限、sudo权限以及源码查看权限等一系列权限申请问题,极大地降低了问题定位效率。

类库依赖复杂,版本碎片化。类库的复用是系统设计的经典法则,但随着系统规模增加到百甚至千级规模时,每个系统对类库的依赖就会形成多种排列组合,而且类库的版本分布也呈碎片化。Profiling和Debugging时需要针对具体的系统查找相关类库的版本号,然后再找对应的代码,比较繁琐。

架构规范易制定难保持:架构规范在单体数量众多且相对不可控的情况下显得尤为重要,但又因为系统分散,规模庞大,架构规范的保持将会十分困难,每次引入系统变更的同时就会引入新复杂度和破坏架构规范的风险,代码也会随之产生一些“badsmell”。因此在分布式环境下,问题的长尾效应非常明显。一个系统发现的Bug或者性能问题,可能在后续比较长的一段时间会在不同的系统中重复出现。反过来,一些通常认为出现概率很低的问题,在机器数量大的情况下,出现的机会还是很大的。

请求调用链路跟踪困难。模块和系统拆解得越细,服务就越多,系统间的依赖关系就越复杂,在SOA架构下,随着系统规模的增加,服务的上下游依赖将错综复杂,系统间的依赖和平台之间的依赖复杂度也将急剧增加。一个分布式下的请求从用户点击到收到响应,途中往往会经过N个系统,或者说N台运行着不同系统的服务器,每台服务器同一时刻都并发处理着很多请求。这需要Profiling和Debugging系统简洁明了地展示分析结果,让开发人员能够快速判断出其中某个节点是否有问题,以及问题的严重程度,将更多的精力放在调用链路在各集群中的走向等更上层信息的分析上。毕竟在大规模分布式系统中,保证系统的可用率是第一位的,而不应该在一个细节的问题上纠缠很久。

线上问题难以重现:线上问题有时与环境有关,线下难以复现,有时又是偶发性出现,难以捕捉。随着系统复杂度的增加,线上问题的快速定位和实时分析将是一项巨大挑战,一般只能靠人来解决,但人的问题排查能力的提升需要一次次的故障来换取,需要长期的经验积累,而且经验还很难传承,一旦关键人员流失,整个团队的问题解决能力就下降了,这个代价也让人难以接受。需要有一个方便的沉淀经验的地方,更好的做法是将这种宝贵的经验沉淀到Profiling和Debugging工具中。

与Profiling和Debugging相关的,蚂蚁金服内部开发使用有两款产品:ZProflier与ZDebugger。顾名思义,ZProfiler主要用于Profling,而ZDebugger主要用于Debugging。蚂蚁金服也有自己基于OpenJDK定制,ZProflier和ZDebugger的大多数功能是可以直接在标准的JDK上运行的,只是一些高级特性需要配合我们定制的JDK使用,这个我们后面也会谈到。针对前面提到的挑战,我们的产品有如下特点。

作为蚂蚁金服金融云的一部分,与服务器一起运行在隔离的网络中,解决网络隔离问题。

部分功能作为JVMTi扩展,直接集成在金融云生产环境使用的JDK里,不需要繁琐的权限申请。

让Profiling和Debugging支持LateAttach,这意味着用户不需要重启应用,随时可以对任何一台服务器进行问题定位和分析。

整合各种常用和不常用的Profiling/Debugging功能,并尽量打通功能之间的联系,提供一站式的服务,不需要开发人员在不同的工具间切换。

集成源码管理功能,自动下载目标系统对应的源代码到ZDebugger服务器,不占用开发人员的硬盘和时间。

集成权限管理,用户只要在登录ZProflier与ZDebugger系统时进行一次认证,后续各项操作(比如拷贝heapdump文件)的权限问题由系统代为处理。

集成问题对比、关键词查找、案例分享等功能,方便重复问题查找和经验传承。

常见问题解决思路

下面介绍一下处理一些常见的问题时,使用ZProflier和ZDebugger系统与使用传统工具在流程和思路上的一些区别。一个新上线的系统如果处理能力达不到我们的预期,或者一个老的系统处理速度突然下降了,抑或频繁抛出异常,这些都促使我们去思考系统存在性能问题该优化了,那我们通常会碰到的性能问题有OOM、CPU占用率高、Load高、频繁GC等。OOM的现象为Java进程直接退出,出错日志里可以看到OutOfMemoryError的异常。如果发现频繁的做MajorGC甚至是FullGC,一般也是OOM的前兆。解决此类问题的主要手段是分析heapdump。

JDK自带jmap工具,使用命令jmap-dump:live,format=b,file=heap.bin即可将Java进程的heap内存按照HPROFBinaryFormat的格式dump

图1ZProfiler

到名字为heap.bin的文件里。命令中的live参数,意味在dump之前会做一次FullGC,保证dump出来的对象都尽量是活的对象,减少heap.bin的大小,降低工具的分析时间。是否要设置这个参数要视具体问题,比如想知道old区到底为什么会增长这么快,都增加了些什么对象呢?这个时候你可能没必要去加live参数了,只要连续做两次heapdump,然后做一次内存对比,就知道这段时间内增加了哪些对象。但如果你想找出一些长时间不释放的对象,分析其根引用树是怎样的,这时加上live参数来dump就比较合理。

常用的heapdump分析工具是EclipseMemoryAnalyzerTool,简称MAT。这款工具功能很强大,但正由于它过于强大,因此给初学者带来的学习成本也比较高。其次它是一个客户端程序,需要安装在本地,因此它也受限于本地的机器性能,比如本机内存就4GB,而heap文件大小为8GB,这时MAT就无法完成分析工作了。因为MAT本身也是Java程序,它在分析大heap时会出现不断做GC,甚至fullgc等异常情况,导致分析没有结果。针对这些问题,我们的性能分析产品ZProfiler精减了部分不常用的功能,保证绝大部分用户使用上的简便性。另外ZProfiler是个Web系统,运行在一台服务器上,分析能力不再受限于开发人员的机器性能,而WebUI操作的方式也大大减轻了开发人员的工作量。

CPU高的问题需要分层来考虑,首先检查操作系统层面的一些原因,比如频繁的memorypaging,可能导致Java应用在内核态花费的时间较多。也可以使用perftop检查JVM内部比如JIT,GC线程的CPU使用情况。如果JIT线程使用的CPU较高,就需要看看codecache或者其他JIT相关参数是否设置合理;如果是gc线程,就需要进一步分析gclog,然后调整GC相关的参数等。

排除以上原因之后,基本可以确认是Java代码的问题,可以使用ZProfiler提供了HotMethodProfiling功能查看热点方法,这个后面有详细描述。

Load高意味着运行的线程或者运行队列里的线程比较多,此时可以通过线程dump进行排查。线程dump,可以使用JDK自带的工具jstack,执行命令jstack即可,会将进程的所有Java线程给dump出来。如果还想跟踪native的堆栈,需要增加-m参数。当拿到线程dump之后,按照线程状态进行归类。对于同一个系统,Load高的机器RUNNABLE态的线程数目一定比Load低的机器多。我们可以通过threaddump来分析这些多出的线程都在干嘛,从而找到Load高的原因。

针对线程分析,ZProfiler不仅仅从状态粒度提供了分析,还从锁粒度以及热点栈粒度做了统计分析,ZProfiler可以帮助用户看到一把锁影响到了哪些线程,哪个线程持有这把锁,那些线程正在等待这把锁,对于线程数因为同步锁的问题突然大增基本可以通过ZProifiler的分析结果看出问题在哪里。同样的,对于某个方法在哪些线程里或者运行态的线程里正在栈上执行,ZProfiler也提供了统计,方便用户排查Load高等问题。

图2ZDebugger

GC频繁是Java程序最常见的问题之一,大多数情况下都是由于相关参数配置不合理导致的。HotSpotGC相关的设置参数比较多,要找到比较合理的参数设置,首先要对应用的内存情况有一个总体的了解:比如应用运行稳定后,LiveDataSize大概是多少,这个会影响到-Xmx/-Xms/-Xmn的设置大小;运行过程中创建的对象temp对象和longlived对象的大概比率,这个会影响到heap老区新区的设置比例。

查看GC情况通常有两种方式,一种是打开gclog相关的参数,事后分析gclog;另外一种是实时获取GC信息,可以打开JMX接口通过相关的MXbean获取,或者通过jstat命令。

gclog分析是个苦差,因为gclog输出的信息非常多,但是很多时候我们需要







































白斑医院哪家好
云南白癜风医院



转载请注明:http://www.guyukameng.com/http/8310.html

  • 上一篇文章:
  •   
  • 下一篇文章: 没有了