Arthas排查Kubernetes中应用频繁挂掉重启异常

目录
  • 前言
  • Kubernetes容器的特殊性
  • 使用到的工具Arthas
  • Arthas的使用
    • 异常解析:
    • 异常解析:
  • 最后的救命稻草
    • 但是为什么堆内存会这么小呢?
  • 解决问题
  • 最后尝试下jmap
  • 结语

前言

其实最终定位到的问题还是蛮好解决的,但是因为应用在Kubernetes容器中的特殊性,导致在使用Arthas过程中出现了各种问题,所以单独成文和大家分享下。照例先讲下问题发生的背景,一个很老的web系统部署在tomcat容器里。近期打成了镜像丢到了Kubernetes环境中运行,总是各种挂,在Kubernetes层面定位了很久没找到具体问题,但是初步定位到是因为系统中的报表导出接口导致的问题,最后使用Arthas找到问题并解决。

Kubernetes容器的特殊性

首先说下,我们的Kubernetes容器中运行的应用都是基于自己构建的基础镜像打包的,如JDK,和tomcat基础镜像,为了减小打包后应用的体积,我们对JDK进行了大量的删减,只保留了最小的jre运行时环境。这样导致的后果是在应用出现问题需要使用jdk工具时,如jinfo、jmap、jstack等都没了,没了这些工具就相当于一个战士没了武器,束手无策了,但是最后忽然想到了Arthas,java线上排错利器。

使用到的工具Arthas

Arthas是阿里巴巴开源的一款在线诊断java应用程序的工具,是greys工具的升级版本,深受开发者喜爱。当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:

  • 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
  • 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
  • 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
  • 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
  • 是否有一个全局视角来查看系统的运行状况?
  • 有什么办法可以监控到JVM的实时运行状态?
  • Arthas采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。

项目地址:https://github.com/alibaba/arthas

Arthas的使用

第一步:下载arthas-boot.jar

wget https://alibaba.github.io/arthas/arthas-boot.jar

第二步:运行

java -jar arthas-boot.jar

运行后,并没有出现熟悉的java进程选择界面,而是一闪而过,如下:

/opt/kl # java -jar arthas-boot.jar
[INFO] arthas-boot version: 3.1.0
[INFO] Can not find java process. Try to pass <pid> in command line.
Please select an available pid.

按官方的说明文档描述,假如出现了找不到pid的情况,在当前目录下应该会输出相关的log,但是我看了并没有日志,那只能尝试是否可以手动指定pid来使用Arthas了。在官网没找到类似说明,只能试试java -jar arthas-boot.jar -help看下,输出如下

/opt/kl # java -jar arthas-boot.jar -help
[INFO] arthas-boot version: 3.1.0
Usage: arthas-boot [-h] [--target-ip <value>] [--telnet-port <value>]
       [--http-port <value>] [--session-timeout <value>] [--arthas-home <value>]
       [--use-version <value>] [--repo-mirror <value>] [--versions] [--use-http]
       [--attach-only] [-c <value>] [-f <value>] [--height <value>] [--width
       <value>] [-v] [pid]

Bootstrap Arthas

EXAMPLES:
  java -jar arthas-boot.jar <pid>
  java -jar arthas-boot.jar --target-ip 0.0.0.0
  java -jar arthas-boot.jar --telnet-port 9999 --http-port -1
  java -jar arthas-boot.jar -c 'sysprop; thread' <pid>
  java -jar arthas-boot.jar -f batch.as <pid>
  java -jar arthas-boot.jar --use-version 3.0.5
  java -jar arthas-boot.jar --versions
  java -jar arthas-boot.jar --session-timeout 3600
  java -jar arthas-boot.jar --attach-only
  java -jar arthas-boot.jar --repo-mirror aliyun --use-http

EXAMPLES的第一条显示出来了,直接在jar后面加上pid即可,执行后,还是不行,输出如下:

/opt/kl # java -jar arthas-boot.jar 1
[INFO] arthas-boot version: 3.1.0
[INFO] Start download arthas from remote server: https://maven.aliyun.com/repository/public/com/taobao/arthas/arthas-packaging/3.1.0/arthas-packaging-3.1.0-bin.zip
[INFO] Download arthas success.
[INFO] arthas home: /root/.arthas/lib/3.1.0/arthas
[INFO] Try to attach process 1
Exception in thread "main" java.lang.IllegalArgumentException: Can not find tools.jar under java home: /usr/java/jdk/jre1.8.0_191, please try to start arthas-boot with full path java. Such as /opt/jdk/bin/java -jar arthas-boot.jar
        at com.taobao.arthas.boot.ProcessUtils.findJavaHome(ProcessUtils.java:195)
        at com.taobao.arthas.boot.ProcessUtils.startArthasCore(ProcessUtils.java:206)
        at com.taobao.arthas.boot.Bootstrap.main(Bootstrap.java:441)

异常解析:

根据异常可以明显看到说找不到tools.jar这个工具包了,还是回归到Kubernetes容器环境中因为精简了jre运行时环境导致jdk很多功能受限了。后面我做了一个非常规的事情,就是在完整的jdk中找到了这个tools.jar,丢到了jre里的lib目录中,继续尝试,但是还有问题,如下:

/opt/kl # java -jar arthas-boot.jar 1
[INFO] arthas-boot version: 3.1.0
[INFO] arthas home: /root/.arthas/lib/3.1.0/arthas
[INFO] Try to attach process 1
[ERROR] Start arthas failed, exception stack trace:
java.lang.UnsatisfiedLinkError: no attach in java.library.path
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
        at java.lang.Runtime.loadLibrary0(Runtime.java:870)
        at java.lang.System.loadLibrary(System.java:1122)
        at sun.tools.attach.LinuxVirtualMachine.<clinit>(LinuxVirtualMachine.java:342)
        at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:78)
        at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:250)
        at com.taobao.arthas.core.Arthas.attachAgent(Arthas.java:73)
        at com.taobao.arthas.core.Arthas.<init>(Arthas.java:26)
        at com.taobao.arthas.core.Arthas.main(Arthas.java:100)
[ERROR] attach fail, targetPid: 1

异常解析:

可以看到在补全了tools.jar之后,出现了新的异常信息java.lang.UnsatisfiedLinkError: no attach in java.library.path,表明可能我们缺的东西不是一点半点,我们知道attach功能是Arthas实现原理的两大原理之一。

attach:jdk1.6新增功能,通过attach机制,可以在jvm运行中,通过pid关联应用

instrument:jdk1.5新增功能,通过instrument俗称javaagent技术,可以修改jvm加载的字节码

然后Arthas和其他诊断工具一样,都是先通过attach链接上目标应用,通过instrument动态修改应用程序的字节码达到不重启应用而监控应用的目的

最后的救命稻草

使用完整的JDK中的java命令。

以上方式都试过不行之后,最后我把完整的JDK给下载到本地了,然后通过jdk的bin目录下的java命令启动arthas-boot.jar终于ok了,出现了熟悉的java进程选择界面:

/opt/kl/jdk1.8.0_191/bin # ./java -jar arthas-boot.jar
[INFO] arthas-boot version: 3.1.0
[INFO] Found existing java process, please choose one and hit RETURN.
* [1]: 1 org.apache.catalina.startup.Bootstrap

最后定位到的问题其实很简单,我记录了Arthas大盘中关于内存部分的图,如下:

上图从标题栏开始往下,分别是heap(堆内存)、eden_space(伊甸园区内存),survivor_space(幸存者区内存)、tenured_gen(老年代内存)。这张图是触发导出操作后的内存分布,堆内存从一开始的200M左右占用、到400M、到600M、一瞬间就飚升到900多兆了。最后从堆内存指标我们看到,总共989M,使用的内存已经飚升到988M了,这个时候其实应用已经挂了,Kubernetes容器已经在重启这个实例了。到这里基本已经到位到应用在容器中频繁挂掉重启问题的本质了。

但是为什么堆内存会这么小呢?

最终查明,有方面的原因:

1、因为我们这边都是spring boot应用,只有一个遗留的tomcat部署的应用,所以在镜像优化方面更偏向jdk基础基础镜像,而tomcat镜像没怎么关注,一开始对堆内存这块并没调优设置。

2、后面出现问题后,也确实想到过因为是导出报表导致应用挂掉,很可能是内存问题,设置过tomcat镜像内的堆内存大小,但是因为我们重新打包的镜像没有使用新的版本号,而是直接覆盖之前的版本,又使用Jenkins构建的,Jenkins所在主机拉过之前的镜像,导致镜像更新后,Jenkins打包时并没有去拉最新的调优过基础镜像。

解决问题

1、调优过的镜像加上新的版本号,让应用基于新的版本号构建镜像。或者清理下Jenkins所在主机的镜像,这个会导致第一次构建时速度变慢

2、优化导出报表的实现,我给的方案是,在导出大数据报表时,可以通过id分区,分别作业写入同一个服务器本地的文件中,然后让web容器映射下这个文件所在的目录,等所有分区的任务都结束后,直接组装一个文件下载链接返回给前端,让前端触发一次读文件操作即可。

最后尝试下jmap

除了使用Arthas外,最后还尝试了使用jmap工具,但是因为重新下载的JDK版本和主机jre版本不兼容,所有没用上。最后通过JDK发行的归档页面找到了对应的版本,还是成功的使用jmap -heap pid看到了内存情况,。内存分布也蛮清晰的,如:

/opt/kl/jdk1.8.0_191/bin # ./jmap -heap 1
Attaching to process ID 1, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.191-b12
using thread-local object allocation.
Mark Sweep Compact GC
Heap Configuration:
   MinHeapFreeRatio         = 40
   MaxHeapFreeRatio         = 70
   MaxHeapSize              = 3221225472 (3072.0MB)
   NewSize                  = 1073741824 (1024.0MB)
   MaxNewSize               = 1073741824 (1024.0MB)
   OldSize                  = 2147483648 (2048.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 966393856 (921.625MB)
   used     = 856023096 (816.3672409057617MB)
   free     = 110370760 (105.25775909423828MB)
   88.57911199302988% used
Eden Space:
   capacity = 859045888 (819.25MB)
   used     = 787314712 (750.8418197631836MB)
   free     = 71731176 (68.4081802368164MB)
   91.6499017104893% used
From Space:
   capacity = 107347968 (102.375MB)
   used     = 68708384 (65.52542114257812MB)
   free     = 38639584 (36.849578857421875MB)
   64.00529537736568% used
To Space:
   capacity = 107347968 (102.375MB)
   used     = 0 (0.0MB)
   free     = 107347968 (102.375MB)
   0.0% used
tenured generation:
   capacity = 2147483648 (2048.0MB)
   used     = 1521987528 (1451.4804153442383MB)
   free     = 625496120 (596.5195846557617MB)
   70.87306715548038% used

jdk归档下载页:https://www.oracle.com/technetwork/java/javase/downloads

结语

Arthas是一个非常不错的工具,我们线上多次使用Arthas定位过问题。不过像今天的这种Kubernetes容器环境的话,因为本身运行时环境的缺失,可能使用的时候会存在各种问题,这里主要还是分享个思路。希望能给类似场景的同学提供一个有用的参考。

以上就是Arthas排查Kubernetes中应用频繁挂掉重启异常的详细内容,更多关于Arthas异常排查Kubernetes频繁重启的资料请关注我们其它相关文章!

(0)

相关推荐

  • kubernetes YAML文件的使用

    目录 01 YAML文件介绍 YAML---key-value类型 YAML---list类型 02 K8S中Master.Node和Pod的关系 01 YAML文件介绍 K8S在启动Pod的时候,会使用yaml文件的方式来启动,今天我们来看看YAML文件最常用的格式. YAML的语法和JSON语法很像,都是通过key-value形式来组织的,它可以表示list.dict等常用数据类型,它的后缀一般使用".yml",它有如下几个特点: 1.大小写敏感 2.使用缩进表示递进关系 3.缩进

  • Java开源诊断工具Arthas使用方法详解

    一.前言 1.热更新代码的场景 (1)当线上服务器出现问题时,有些时候现有的手段不足以发现问题所在,可能需要追加打印日志或者增加一些调试代码,如果我们去改代码重新部署,会破坏问题现场,可以通过热部署的手段来增加调试代码 (2)线上出现紧急bug,通过Review代码找到问题,修改好后打包部署的流程可能比较久,可以通过热部署代码及时解决问题 二.使用阿里巴巴开源的Java诊断工具 ---Arthas,他可以附着在我们的Java服务器进程上面,查看服务器状态,jvm状态等各种参数指标,还可以进行热更

  • Java线上问题排查神器Arthas实战原理解析

    概述 背景 是不是在实际开发工作当中经常碰到自己写的代码在开发.测试环境行云流水稳得一笔,可一到线上就经常不是缺这个就是少那个反正就是一顿报错抽风似的,线上调试代码又很麻烦,让人头疼得抓狂:而且debug不一定是最高效的方法,遇到线上问题不能debug了怎么办.原先我们Java中我们常用分析问题一般是使用JDK自带或第三方的分析工具如jstat.jmap.jstack. jconsole.visualvm.Java Mission Control.MAT等.但此刻的你没有看错,还有一款神器Art

  • Kubernetes(k8s)基础介绍

    之前我一直想学习Kubernetes,因为它听起来很有意思(如果你是希腊人,你会觉得这个名字很有问题),但我从来没有机会,因为我没有任何东西需要运行在集群中.而最近,我的工作中开始逐步涉及Kubernetes相关的事情,所以这次我抓住机会,开始查资料,但后来我发现目前所有的资料(包括官方教程)都过于冗长,结构也不合理,这让我一开始有点沮丧. 经过几天的研究,我开始逐步理解Kubernetes的核心理念,并且把他部署到了生产环境中.因为我的简历现在说自己是个"Kubernetes专家",

  • 使用arthas命令redefine实现Java热更新(推荐)

    arthas 是一个 Java 开源诊断神器. 今天分享一个非常重要的命令 redefine ,主要作用是加载外部的 .class 文件,用来替换 JVM 已经加载的类,总结起来就是实现了 Java 的热更新. redefine 在一下几种情况中会失败:1.增加了 field :2.增加了 method :3.替换正在运行的方法. 前两个比较好理解,第三个意思就是这个方法必须结束之后才会被替换,如果有个方法开始运行之后就不会跳出,那么这个方法所在的类是无法被替换的,类似无限循环的方法. 中间提到

  • 云原生技术kubernetes(K8S)简介

    目录 01 kubernetes是什么? 02 kubernetes和Compost+Swarm之间的区别 03 一点总结 今天我们看看kubernetes技术的介绍,最近在极客时间上看张磊老师的深入kubernetes技术,讲的非常好,有兴趣的同学可以去收听一下,对于理解kubernetes技术非常有帮助,这里我会按照自己的进度,分享一下学习的笔记. 今天站的角度比较高,概念性质的东西会多一点. 01 kubernetes是什么? 曾经我认为这个问题很好回答,直到不断的去理解kubernete

  • Arthas排查Kubernetes中应用频繁挂掉重启异常

    目录 前言 Kubernetes容器的特殊性 使用到的工具Arthas Arthas的使用 异常解析: 异常解析: 最后的救命稻草 但是为什么堆内存会这么小呢? 解决问题 最后尝试下jmap 结语 前言 其实最终定位到的问题还是蛮好解决的,但是因为应用在Kubernetes容器中的特殊性,导致在使用Arthas过程中出现了各种问题,所以单独成文和大家分享下.照例先讲下问题发生的背景,一个很老的web系统部署在tomcat容器里.近期打成了镜像丢到了Kubernetes环境中运行,总是各种挂,在K

  • arthas排查jvm中CPU占用过高问题解决

    目录 安装 小试 找出CPU的元凶 查看线程栈的参数 安装 小试 记一次使用arthas排查jvm中CPU占用过高问题.这工具屌爆了 碾压我目前使用的全部JVM工具. curl -O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar --repo-mirror aliyun --use-http jar后面的参数也可以不加 加上只是为了下载速度更快 接下来arthas 控制台中显示了当前机器上jvm进程列表 输

  • Kubernetes中使用临时容器进行故障排查的方法

    目录 前言 什么是临时容器? 临时容器的配置 启动临时容器 使用临时容器 与临时容器共享进程命名空间 结论 前言 容器及其周围的生态系统改变了工程师部署.维护和排查工作负载故障的方式.但是,在 Kubernetes 集群上调试应用程序有时可能会很困难,因为你可能在容器中找不到所需的调试工具.许多工程师使用基于精简.发行版构建无发行版的基础镜像,其中甚至没有包管理器或shell.甚至一些团队使用 scratch 作为基础镜像,并且只添加应用程序运行所需的文件.这种常见做法的一些原因是: 具有较小的

  • 解决node修改后需频繁手动重启的问题

    在开发过程中,每次修改代码保存后,我们都需要手动重启程序,才能查看改动的效果.使用 supervisor 可以解决这个繁琐的问题,全局安装 supervisor: npm install -g supervisor 运行 supervisor --harmony server启动程序,如下所示: supervisor 会监听当前目录下 node 和 js 后缀的文件,当这些文件发生改动时,supervisor 会自动重启程序. 以上这篇解决node修改后需频繁手动重启的问题就是小编分享给大家的全

  • 详解 Linux中的关机和重启命令

    详解 Linux中的关机和重启命令 一 shutdown命令 shutdown [选项] 时间 选项: -c:取消前一次关机命令 -h:关机 -r:重启 二 shutdown实战 [root@localhost tmp]# date Sat Jul 15 09:28:35 CST 2017 [root@localhost tmp]# shutdown -r 05:30 Shutdown scheduled for Sun 2017-07-16 05:30:00 CST, use 'shutdow

  • 如何在kubernetes中创建Pod

    目录 如何创建Pod? kubectl工具 如何创建Pod? 在之前的文章中,我们介绍了容器和Pod的区别和关系.我们知道Pod是k8s调度的最小单位,而一个Pod中可以有多个容器,那么我们如何来定义一个我们自己的Pod呢? 在k8s中,我们通常使用编写配置文件的方式创建一个Pod,配置文件的格式通常采用yaml格式,(yaml格式如何表示list.key-value键值对,这些知识在前一篇文章中说过了),编写好yaml文件之后,通过下面的办法来启动一个Pod: kubectl create -

  • Kubernetes中Nginx配置热加载的全过程

    目录 前言 使用方法 总结 前言 Nginx本身是支持热更新的,通过nginx -s reload指令,实际通过向进程发送HUB信号实现不停服重新加载配置,然而在Docker或者Kubernetes中,每次都需要进容器执行nginx -s reload指令,单docker容器还好说,可以在外面通过exec指定容器执行该指令进行热加载,Kubernetes的话,就比较难受了 今天介绍一下Kubernetes中Nginx热加载配置的处理方法——reloader reloader地址:https://

  • 了解Kubernetes中的Service和Endpoint

    目录 Srevice Service 的创建及现象 Service 定义 Endpoint slices 创建 Endpoint.Service Service 创建应用 创建 Endpoint Srevice Service 是将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法.如果我们使用 Deployment 部署 pod,则可以以 Deployment 为对象创建 Service. 在 K8S 中,每个 Pod 都有其自己唯一的 ip 地址,而 Service 可以为多个 Po

  • Kubernetes中创建命名空间实现方法

    目录 正文 命名空间类型 查看命名空间 创建命名空间 结论 正文 命名空间系统对计算来说并不陌生,我们大多数人可能在几乎所有编程语言中都见过命名空间,无论您在哪里遇到命名空间,其基本目的都是相同的:用于逻辑分组. 同样,在 Linux 内核中,也有命名空间的概念,比如存储和网络命名空间.每个容器也有自己的存储命名空间和网络命名空间,用于资源的隔离和分配. Kubernetes命名空间是指由同一物理集群支持的虚拟集群,此选项专为在多个用户分布在多个工作团队或项目的环境中使用而设计. 本文将介绍如何

  • 一文详解kubernetes 中资源分配的那些事

    目录 概要 一个nginx的配置 我们进入nginx容器所在目录看下 cpu.shares cpu.cpu.cfs_period_us.cpu.cfs_quota_us 资源使用率数据来源 下kubelet相关配置:** 概要 在k8s中,kube-scheduler是Kubernetes中的调度器,用于将Pod调度到可用的节点上.在调度过程中,kube-scheduler需要了解节点和Pod的资源需求和可用性情况,其中CPU和内存是最常见的资源需求.那么这些资源的使用率是怎么来的呢?当Pod调

随机推荐