本文主要介绍了
环境搭建和示例服务启动 首先,使用的 Linux 版本为:
使用的 JDK 版本为:
为了让大家了解使用命令的真实环境,我们在 Linux 系统中搭建了原创发号器服务 Vesta,在介绍下面的每个命令的同时,都会以监控和维护原创发号器服务为例来说明。 为了搭建 Vesta 发号器服务,我们需要从 Github 地址 https://github.com/robertleepeak/vesta-id-generator.git 下载源代码: 下载后工作目录为:
进入 Vesta 发号器项目根目录并列出目录结构:
然后,直接运行发布脚本 make-release.sh 进行打包发布:
最后,启动发号器 REST 服务:
然后,使用 curl 语句测试发号器服务是否正常运行:
看见发号器正确产生 ID=2382742310220727293,并能反解成 JSON 字符串:
这说明发号器服务启动正常,然后使用 Linux 命令查看服务进程,确保服务进程运行正常: 接下来的章节我们围绕这个服务来介绍后续的每个脚本和命令。 神奇的脚本解决不可思议的问题
本章介绍那些“神奇的”脚本。
2.1 show-busiest-java-threads 此命令通过结合 Linux 操作系统的 ps 命令和 jvm 自带的 jstack 命令,查找 Java 进程内 CPU 利用率最高的线程,一般适用于服务器负载较高的场景,并需要快速定位导致负载高的原因。(本脚本来自一个叫候鸟树的网友,原作者不详) 命令格式:
使用示例:
示例输出:
脚本源码:
2.2 find-in-jar 此脚本在 Jar 包中的包名和类名中查找某一关键字,并高亮显示匹配的 Jar 包名称和路径,多用于定位 java.lang.NoClassDefFoundError 和 java.lang.ClassNotFoundException 的问题,以及类版本重复或者冲突的问题等。(此脚本是笔者的原创) 命令格式:
使用示例:
示例输出:
脚本源码:
2.3 grep-in-jar 此脚本在 Jar 包中进行二进制内容查找,通常会解决一些线上出现的“不可思议”的问题,例如:某些功能上线没有生效、某些日志没有打印等,通常是上线工具或者上线过程出现了问题,把线上的二进制包拉下来并查找特定的关键字来定位问题。(此脚本最初来自于微博同事Axb) 命令格式:
使用示例:
示例输出:
脚本源码:
2.4 jar-conflict-detect 此脚本用于识别冲突的 Jar 包,可以在一个根目录下找到所有包含相同类的 Jar 包,并且根据相同类的多少来判断 Jar 包的相似度,常常用于某些功能上线不可用或者没有按照预期起到作用,使用此脚本分析是否存在两个版本的类,而老版本的类被 Java 虚拟机加载,其实,JVM 规范并没有规定类路径下相同类的加载顺序,实现 JVM 规范的虚拟机的实现机制也各不相同,因此无法判断相同的类中哪个版本的类会被先加载,因此 Jar 包冲突是个非常讨厌的问题。(此脚本最初来自于作者hongjiang) 命令格式:
使用示例:
示例输出:
脚本源码:
2.5 http-spy 此脚本利用 Linux 命令 nc 检查 HTTP 请求参数、请求头和请求体等信息,常常用于调试基于 HTTP 协议的服务调用,如果一次 HTTP 调用没有的达到预期的效果,首先检查传递的参数是否正确,这包括请求参数、请求头、请求体等信息,这种场景正式此脚本的用武之地。 命令格式:
使用示例:
示例输出:
脚本源码:
2.6 show-mysql-qps 此脚本可以用于快速查看 Mysql 实例的负载情况,包括 QPS、TPS、提交数、回滚数、并发线程、执行线程等。 命令格式:
使用示例:
示例输出:
脚本源码:
Java虚拟机相关的命令 本节介绍 Java 世界里那些有用的虚拟机命令,但并不会介绍所有的 JDK 自带的工具命令,而是结合实践给读者介绍那些最常用最重要的 Java 虚拟机相关的命令,以及一些开源的 Java 虚拟机工具,目的是帮助大家在现实中解决问题。
3.1 jad jad 反编译工具可以将字节码的二进制类反编译回 Java 源代码,常常用于遇到问题但是无法在源代码中定位的场景,通过反编译字节码可以分析程序事实上执行的流程,从而定位深层次的问题。 由于历史原因或者其他原因,有些时候项目依赖了没有源代码的 jar 包,如果出现问题需要定位,那么 jad 命令可是个小倚天剑。 如果不习惯使用命令行,可以下载界面版本 jd-gui,可以一次反编译一个 JAR 包,并在类之间有简单的导航操作。 如果开发者对字节码进行了混淆,反编译的源代码将很难读懂,混淆的代码只能通过混淆后给出的摘要文件进行分析,这种场景下使用反编译工具作用不大。 使用示例: 示例输出:
3.2 btrace java 应用服务在生产环境中可能会出现各种各样的问题,有些问题在找到根源原因之前看似很“不可思议”,有些时候并没有产生异常或者错误消息,这时我们无法根据已有的日志来定位问题,那么我们需要更多的信息,例如:参数、返回值、程序逻辑判断、循环次数等信息,来追踪问题。 如果临时增加日志,需要重新上线,成本较高,使用远程调试又会影响线上流量甚至导致客户程序超时,这个时候 btrace 应运而生,btrace 可以动态地跟踪 java 运行时程序,将定制化的跟踪字节码切面注入到运行类中,对运行代码无侵入,根据官方信息判断对性能上的影响也可以忽略不计。 下面介绍 btrace 的使用方法: 命令格式: 参数解析:
在运行命令之前,我们需要编写 btrace 的跟踪脚本: 这个跟踪脚本对业务代码的方法进行拦截,并打印方法执行时间:
使用示例:
当 AdminController 类的 sayHello 被调用的时候,控制台就会打印方法执行时间,这对定位线上的棘手问题有非常大的帮助。
3.3 jmap 生产中 java 应用服务发生 OutOfMemoryError 那是家常便饭,发生了 OutOfMemoryError 或者发现内存不足报警,我们经常需要找到是什么原因造成的,要找到内存都去哪儿了,jmap 在这个场景是用来定位问题的主要工具,它主要用来查看 Java 进程内存的使用情况。 jmap 是 JDK 自带的监控工具,在 JDK 的根目录里可以找到。 使用示例1: 按照占用空间大小打印程序中类的列表,从这个列表中可以分析哪些类占用了比较多的内存,再结合代码找到问题的所在。
示例输出:
使用示例2: 按照占用空间大小打印程序中加载的动态链接库的列表。其实,Java 进程在操作系统中会加载多个动态链接库,Java 进程本身和动态链接库都会在其占用的虚拟地址空间上分配内存,Java 堆和栈等内存空间分配在 Java 进程本身,Java 直接内存会分配在 Java 进程堆内存外或者依赖的动态链接库上。 因此,此命令帮助大家定位是 Java 进程本身占用内存较大,还是哪个动态链接库占用内存较多,在定位直接内导致的内存泄露的场景有很大的作用。
示例输出:
使用示例3: java 堆的内存结构很复杂,包括新生代、老年代、持久代、直接内存等,jmap 命令可以查看堆的概要信息。
示例输出:
使用示例4: 有些 Java 内存问题不是显而易见的,从类、动态链接库、堆的概要信息的角度上,无法定位具体产生的原因,我们需要对 Java 堆的内部结构进行剖析才能进一步分析问题的根源原因,这通常通过 jmap 命令导出 Java 堆的快照,然后通过其他工具或者甚至可视化内存分析工具(例如:JHAT、JMAT、JProfiler、Jconsole、JVisualVM)等进行详细分析。
示例输出:
3.4 jstat jstat 利用了 JVM 内建的指令对 Java 应用程序的资源和性能进行实时的命令行的监控,包括了对堆大小和垃圾回收状况的监控等等,与 jmap 对比,jstat 更倾向于输出积累的信息与打印 GC 等的统计信息等。 jstat 是 JDK 自带的监控工具,在 JDK 的根目录里可以找到。 使用示例:
示例输出:
3.5 jstack jstack 命令用于打印出给定的 java 进程 ID 的线程堆栈快照信息,从而可以看到 Java 进程内线程的执行状态、这个你在执行的任务等等,可以据此分析线程等待、死锁等问题。 jstack 也是 JDK 自带的命令,在 JDK 的根目录里可以找到。本文第二章“神奇的”脚本中的 show-busiest-java-threads 脚本也是基于此命令实现的。 使用示例:
示例输出:
3.6 jinfo jinfo 可以输出并修改运行时的 java 进程的环境变量和虚拟机参数。 使用示例:
示例输出:
3.7 其他命令 除了上面介绍的常用 Java 虚拟机相关命令以外,我们还有两类工具。 基本命令:
Java 虚拟机图形界面分析工具:
一次OOM定位与修复过程中与监控同事现场编写的脚本 本节提供一个笔者在实践过程中解决 OOM 问题的一个简单脚本,这个脚本是为了解决 OOM(unable to create native thread)的问题而在问题机器上临时编写,并临时使用的,脚本并没有写的很专业,只是为了抓取需要的信息并解决问题,但是在线上问题十分火急的情况下,这个脚本会有大用处。
这里给读者介绍这个看似简陋而又信息满满的Java服务的监控脚本,如果读者在线上已经遇到了 OOM 的问题,可以顺着这个脚本的思路,利用本文提供的各种脚本和命令来深挖问题的根本原因。 场景与命令汇总表 最后,我把所有的命令和脚本收集在一个表格中,称为“场景与命令汇总表”,便于大家随时参考和使用。
作者简介: 李艳鹏,知名支付平台架构师,专注线上和线下支付平台的应用架构和技术架构的规划与落地,负责交易、支付、渠道、账务、计费、风控、对账等系统的设计与实现,在移动支付、聚合支付、合规账户、扫码支付、标记化支付等业务场景上有产品应用架构规划的经验。
|
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|