分类

网游分类软件分类

TSF微服务中java应用系统缓慢异常处理解析?linux伊甸园开源社区排障思路

时间:2022-06-20 09:48作者:佚名

  当出现系统变慢的时候,我们需要定位清楚这个变慢的表现:跟家方便用户就连手机多可以操作使用,在里面包含包涵各方方面面专业技术定位分析,更能展示客户需求,拥有很强创新突破点,更加快速找到问题处在那个问题上,所以这篇文章可以帮助大家分析出问题原因。有兴趣赶紧来看看吧!

问题背景

  应用系统出现运行缓慢

  目前采用微服务架构已经逐渐成为企业架构的标准范式,而大多微服务是基于Spring Cloud框架来进行应用的构建的,所以在开发实践中,甚至生产环境中,会遇到java相关问题,例如系统运行变慢、内存OOM,堆栈异常等问题,这里结合我之前的一些实践提供一些相关工具,和大家一起分享我们的诊断思路和解决技巧。

  1、服务是突然变慢还是长时间运行后观察到变慢?类似问题是否重复出现?

  2、“慢”的定义是什么,是系统对其他方面的请求的反应延时变长吗?

  3、理清问题的症状,这更便于我们接下来定位具体的原因。

  定位分析思路

  1、问题可能来自于 Java 服务自身,也可能仅仅是受系统里其他服务的影响。初始判断可以先确认是否出现了意外的程序错误,例如检查应用本身的错误日志。对于分布式系统,很多公司都会实现更加系统的日志、性能等监控系统。一些 Java 诊断工具也可以用于这个诊断,例如通过 JFR(Java Flight Recorder),监控应用是否大量出现了某种类型的异常。如果有,那么异常可能就是个突破点。如果没有,可以先检查系统级别的资源等情况,监控 CPU、内存等资源是否被其他进程大量占用,并且这种占用是否不符合系统正常运行状况。

  2、监控 Java 服务自身,例如 GC 日志里面是否观察到 Full GC 等恶劣情况出现,或者是否 Minor GC 在变长等;利用 jstat 等工具,获取内存使用的统计信息也是个常用手段;利用 jstack 等工具检查是否出现死锁等。

  3、如果还不能确定具体问题,对应用进行 Profiling 也是个办法,但因为它会对系统产生侵入性,如果不是非常必要,大多数情况下并不建议在生产系统进行。

  4、定位了程序错误或者 JVM 配置的问题后,就可以采取相应补救措施,然后验证是否解决,否则还需要重复上面部分过程

  整个具体定位排障过程分为:

  1、服务端系统性能分析。

  2、JVM层面的性能分析。

  java服务端运行系统性能分析

  系统性能分析中,CPU、内存和 IO 是主要关注项。

  对于 CPU,如果是常见的 Linux,可以先用 top 命令查看负载状况。如下图所示:

  top命令

  可以看到,其平均负载(load average)的三个值(分别是 1 分钟、5 分钟、15 分钟)非常低,并且暂时看并没有升高迹象。如果这些数值非常高(例如,超过 50%、60%),并且短期平均值高于长期平均值,则表明负载很重;如果还有升高的趋势,那么就要非常警惕了。

  如果我们定位到CPU持续增高,怎么找到最耗费 CPU 的 Java 线程,下面我们简要介绍步骤:

  1、输入命令:top –H,利用 top 命令获取相应 pid,“-H”代表 thread 模式,你可以配合 grep 命令更精准定位。

  2、top –H然后转换成为 16 进制。输入命令为:printf "%x" your_pid

  3、最后利用 jstack 获取的线程栈,对比相应的 ID 即可。

  当然,还有更加通用的诊断方向,利用 vmstat 之类,查看上下文切换的数量,比如下面就是指定时间间隔为 1,收集 10 次。

  输入命令如下:vmstat -1 -10,结果如下图所示:

  vmstat 命令结果

  如果每秒上下文(cs,context switch)切换很高,并且比系统中断高很多(in,system interrupt),就表明很有可能是因为不合理的多线程调度所导致。当然还需要利用pidstat等手段,进行更加具体的定位。。

  除了 CPU,内存和 IO 是重要的注意事项,比如:利用 free 之类查看内存使用。或者,进一步判断 swap 使用情况,top 命令输出中 Virt 作为虚拟内存使用量,就是物理内存(Res)和 swap 求和,所以可以反推 swap 使用。显然,JVM 是不希望发生大量的 swap 使用的。

  对于 IO 问题,既可能发生在磁盘 IO,也可能是网络 IO。例如,利用 iostat 等命令有助于判断磁盘的健康状况。也会遇到过一些服务器本身IO性能问题,拖累了整体性能,解决办法就是申请替换了机器。

  JVM 层面的性能分析

  Java 是基于 JVM 上运行的,大部分内存都是在 JVM 的用户内存中创建的,所以除了通过以上 Linux 命令来监控整个服务器内存的使用情况之外,我们更需要知道 JVM 中的内存使用情况。JDK 中就自带了很多命令工具可以监测到 JVM 的内存分配以及使用情况。

  对于 JVM 层面的性能分析,我们可以利用 JMC、JConsole 等工具进行运行时监控。利用各种工具,在运行时进行堆转储分析,或者获取各种角度的统计数据(如jstat -gcutil 分析 GC、内存分带等)。GC 日志等手段,诊断 Full GC、Minor GC,或者引用堆积等。

  在这里我将分别展示使用 JDK 自带的工具来排查 JVM 参数配置问题、使用 Wireshark 来分析网络问题、通过 MAT 来分析内存问题,以及使用 Arthas 来分析 CPU 使用高的问题。

  使用 JDK 自带工具查看 JVM 情况

  JDK 自带了很多命令行甚至是图形界面工具,帮助我们查看 JVM 的一些信息。比如,在Linux机器上运行 ls 命令,可以看到 JDK 8 提供了非常多的工具或程序:

  JDK自带的工具

  JDK自带工具的基本作用如下:

  JDK自带命令行工具作用

  下面就分别介绍几个典型的JVM自带的工具:

  JDK 工具之 jstat 命令

  jstat 可以监测 Java 应用程序的实时运行情况,包括堆内存信息以及垃圾回收信息。我们可以运行 jstat -help 查看一些关键参数信息:

  jstat

  再通过 jstat -option 查看 jstat 有哪些操作:

  jstat操作

  JDK 工具之 jstack 命令

  jstack是一种线程堆栈分析工具,最常用的功能就是使用 jstack pid 命令查看线程的堆栈信息,通常会结合 top -Hp pid 或 pidstat -p pid -t 一起查看具体线程的状态,也经常用来排查一些死锁的异常。

  每个线程堆栈的信息中,都可以查看到线程 ID、线程的状态(wait、sleep、running 等状态)以及是否持有锁等。

  jstack命令

  JDK 工具之 jmap 命令

  jmap 查看堆内存初始化配置信息以及堆内存的使用情况。那么除了这个功能,我们其实还可以使用 jmap 输出堆内存中的对象信息,包括产生了哪些对象,对象数量多少等。我们可以用 jmap 来查看堆内存初始化配置信息以及堆内存的使用情况:

  jmap命令

  我们可以使用 jmap -histo[:live] pid 查看堆内存中的对象数目、大小统计直方图,如果带上 live 则只统计活对象:

  jmap命令

  我们可以通过 jmap 命令把堆内存的使用情况 dump 到文件中:

  jmap dump文件

  我们可以将文件下载下来,使用 MAT 工具打开文件进行分析:

  MAT工具分析

  我们平时遇到的内存溢出问题一般分为两种,一种是由于大峰值下没有限流,瞬间创建大量对象而导致的内存溢出;另一种则是由于内存泄漏而导致的内存溢出。使用限流,我们一般就可以解决第一种内存溢出问题,但其实很多时候,内存溢出往往是内存泄漏导致的,这种问题就是程序的 BUG,我们需要及时找到问题代码。

  1.应用复杂度增加,更新、维护困难

  一个简单的应用会随着时间的推移而逐渐变大。一旦应用变的庞大而又复杂,那么开发团队将会面临很多问题,其中最主要问题就是这个应用太复杂,以至于任何单个开发者都很难进行二次开发或维护。

  2.易造成系统资源浪费

  虽然使用负载均衡的方式可以对项目中的服务容量进行水平扩展,但由于传统单体架构的代码中只有一个包含所有功能的WA R包,所以在对服务容量扩容时,只能选择重复的部署这个WA R包来扩展服务能力,而不仅仅是扩展了所需的服务。这样导致其他不需要扩展的服务也进行了相应的扩展,但这种扩展是不需要的,因此这种方式会极大的浪费资源。

  3.影响开发效率

  当一个应用越大时,启动时间就会越长。开发和调试的过程中,如果有很大一部分时间都要在等待中渡过,那么必然会对开发效率有极大的影响。

  4.应用可靠性低

  传统单体应用架构在运行时的可靠性比较低,当所有模块都运行在一个进程中时,如果任何一个模块中出现了一个Bug,可能会导致整个进程崩溃,从而影响到整个应用。

  5.不利于技术的更新

  传统单体应用架构一旦选定使用某些技术,则后期的开发和扩展将在这些技术的基础上实现。如果需要更改某种技术,则可能需要将整个应用全部重新开发,这种成本是非常大的。当然,传统单体应用架构的问题还不只这些,但出现这些问题的根本原因可以说就是由于传统单体架构中一个WA R包内包含了系统的所有服务功能所导致的。随着业务变的越来越多,问题也就越来越多。

如何解决传统应用架构的问题

  针对传统单体架构的问题,大部分企业通过SOA(Service-Oriented Architecture,面向服务的架构)来解决上述问题。SOA的思路是把应用中相近的功能聚合到一起,以服务的形式提供出去,因此基于SOA架构的应用可以理解为一批服务的组合。

  同样以网上商城为例,一个简单的SOA系统如图1-3所示。

  SOA系统

  从上图可以看出,SOA将原来的单体架构按照功能细分为不同的子系统,然后再由各个子系统依赖服务中间件(这里指企业服务总线Enterprise Service Bus,简称ESB)来调用所需服务。

  使用SOA可以将系统切分成多个组件服务,这种通过多个组件服务来完成请求的方式有很多好处,具体如下:

  l把项目拆分成若干个子项目,不同的团队可以负责不同的子项目,从而提高开发效率;

  l把模块拆分,使用接口通信,降低了模块之间的耦合度;

  l为企业的现有资源带来了更好的重用性;l能够在最新的和现有的应用之上创建应用;

  l能够使客户或服务消费者免予服务实现的改变所带来的影响;

  l能够升级单个服务或服务消费者而无需重写整个应用,也无需保留已经不再适用于新需求的现有系统。

  虽然使用SOA解决了单体架构中的问题,但多数情况下,SOA中相互独立的服务仍然会部署在同一个运行环境中(类似于一个Tomcat实例下,运行了很多web应用)。和单体架构类似,随着业务功能的增多,SOA的服务会变得越来越复杂。本质上看,单体架构的问题并没有因为使用SOA而变的更好。

  针对单体架构和SOA的问题,许多公司(如Amazon、eBay和NetFlix)通过采用微处理结构模式解决了系统架构中的问题。其思路不是开发一个巨大的单体式的应用,而是将应用分解为小的、互相连接的微服务。随着微服务的使用,微服务架构的思想也随之产生。

相关文章