阿里在GitHub上的开源工具javascript
https://github.com/oldmanpushcart/greys-anatomycss
摘要: 线上系统为什么常常出错?数据库为什么屡遭黑手?业务调用为什么频频失败?连环异常堆栈案,到底是那次调用所为? 数百台服务器意外雪崩背后又隐藏着什么?是软件的扭曲仍是硬件的沦丧? 走进科学带你了解Greys, Java线上问题诊断工具。前端
线上系统为什么常常出错?数据库为什么屡遭黑手?业务调用为什么频频失败?连环异常堆栈案,到底是那次调用所为?
数百台服务器意外雪崩背后又隐藏着什么?是软件的扭曲仍是硬件的沦丧?
走进科学带你了解Greys, Java线上问题诊断工具。java
![]() |
很早的时候,咱们使用BTrace排查问题,在感叹BTrace的强大之余,也曾好几回将线上系统折腾挂掉。2012年淘宝的聚石写了HouseMD,将经常使用的几个Btrace脚本整合在一块儿造成一个独立风格的应用,但其核心代码用的是Scala,咱们没这方面的编程维护经验,因此只好艳羡HouseMD的才思敏捷而没法在其上增长功能。linux
因而乎,Greys诞生了! |
PS:目前Greys仅支持Linux/Unix/Mac上的Java6+,Windows暂时没法支持nginx
Greys是一个JVM进程执行过程当中的异常诊断工具。 在不中断程序执行的状况下轻松完成JVM相关问题排查工做。git
和HouseMD同样,Greys-Anatomy取名同名美剧“实习医生格蕾”,目的是向前辈致敬。代码编写的时候参考了BTrace和HouseMD两个前辈的思路。程序员
有时候忽然一个问题反馈上来,须要入参才能完成定位,但偏偏没有任何日志。回去加上从新部署,一杯咖啡时间过去了,是否是很崩溃?github
当你通过反复这样几回折腾以后变得聪明了,在本身的代码的全部入参和出参地方都加上debug
日志,但此次问题彷佛暴露在别人的代码中了...是否是很无奈?web
忽然遇到线上一个性能问题没法肯定究竟是哪一个环节的耗时,只能反复抓jstack
猜,还有没有办法能够好好的过日子啦?
遇到以上问题时,你就是咱们这类工具的目标客户,此类工具能利用Java6的Instrumentation
特性,动态加强你所指定的类,获取你想要到的信息。
ClassLoader隔离
在设计和实现这款程序的时候,花费了很是多的精力在隔离目标类与Greys的ClassLoader隔离上。你能够放心大胆的使用Greys,而不用担忧Greys会干扰到现有业务代码所使用的三方类库。
运行时加载
要求目标JVM在JDK6+的基础上,且当前执行人拥有与目标JVM相同权限。能够作到不中断当前JVM而动态进行加载、问题分析定位。
经常使用问题定位命令化
Greys与BTrace、HouseMD等同类软件最大的不一样在于,她拥有我多年来业务代码疑难杂症定位的经常使用技术手段,并将这些排查思路和技巧命令化,将个人问题定位经验Share给你们。
表达式支持
HouseMD相比BTrace最强大的地方就在于能快速指定拦截的类与方法,但却没法支持对观察到的对象进行展开、条件过滤等操做。BTrace的脚本是本身所编写,能够实现此类功能。但编写学习成本很高,且容易出错。
表达式的引用能综合这两款软件的特长同时弥补他们的不足。目前Greys所采用的是OGNL表达式。
多用户同时访问
远程DEBUG最大的问题就在于,只容许一我的访问DEBUG端口,并且一单断点条件设置不当,颇有可能将其余正常的业务请求拦下,影响其余用户的使用。
Greys采用的思路是作观察者,其所设置的断点不容许阻塞正常业务的流程,但你能够观察到断点所拦截到的全部信息。
高性能
精心用ASM设计了字节码加强,核心的数据结构用数组针对实际场景作裁剪优化。能够放心的用在高负载有求下的JVM环境。
纯Java编写
Greys定位是专业的JVM的业务问题定位工具
,既然是JVM那咱们所面对的大部分就是Java程序员。我但愿能Share本身在编写软件时候的全部技巧与思路,让更多的Java程序员能参与开发或从中受益。
目前已经有很是多的热心网友在给个人代码挑错,很是感谢这些朋友的支持!
Greys并不万能,我也没有计划让她能成为万能的问题定位工具。因此若是你在某些场合能用上更专业的工具,我会很是乐意推荐你使用。
性能环境下的性能损耗定位
性能分析须要有更专业的软件,我本身经常使用的则是JProfiler(固然是付费的了)。Greys虽然性能损耗很小,但其分析的维度太少,因此只适合作简单的性能损耗定位。当你用过专业的性能分析软件以后,就会发现什么叫专业!
开发环境下的远程DEBUG
虽然Greys能取代部分的远程DEBUG行为,但毕竟没不像DEBUG工具那样能够看到局部变量的值,并且可操做性上也没有JVM下Eclipse/IDEA等优秀的IDE自带的DEBUG工具这么人性化操做。
线上环境大规模部署
与BTrace同样,Greys获取到的权限过高,若是线上大规模部署会遭受黑客的攻击,而今天我为了实现简单是没有作过多的鉴权控制。
JDK类库分析
JDK的类库存放在rt.jar
中,启动时加载到BootstrapClassLoader
中(Hotspot-JVM),但因为Greys也是用Java语言所编写,因此自身也用到了这些基础类库,默认状况下关闭了对这些类的加强。
固然,对于Spring、ibatis、Tomcat等三方类库是能够放心大胆使用的。
其它不适合场景
BTrace、HouseMD、Greys、JavOSize此类工具都会对Perm区、CodeCache(影响JIT)产生干扰,若是你的程序对这两块很是敏感,也请不要在这些场合下使用。
让程序解决繁琐的事情
命令行交互
由于不少场景下咱们都是用在远程问题分析中(本地我就直接DEBUG了)。通常Java都会使用在Linux/BSD等类UNIX操做系统下。因此命令行是我最开始不二的选择,也是目前支持最成熟的交互方案。
图形界面交互
在2.x.x.x
版本中将会支持WEB方式访问,HTTP采用websocket与后台服务进行交互,预计过年以后能发布上线。
查看已被JVM所加载的类、方法信息
方法执行监控
调用量,成功失败率,响应时间
方法执行数据操做
入参、返回值、异常信息记录与查看;支持动做回放
性能开销渲染
跟踪指定路径中的方法调用轨迹、耗时
查看方法调用堆栈
monitor
、trace
等tt
命令能以时间维度纪录下监控期内的每一次调用环境多人并行协做
基于C/S架构的任务模式甚至能让多人同时远程到同一进程上执行不一样的指令、脚本,很是适合团队一块儿进行线上问题排查与跟踪。Greys采用纯Java编写并留有良好的扩展,若是你有需求,只要你会Java,就能够为你本身编写想要的功能。 Greys最有利的武器是他的表达式,能让你在感觉到HouseMD集成功能便利的同时,也能发挥出自定义Btrace脚本的灵活。
1. 应用管理员拥有JVM进程权限,由他来首先在目标JVM上启动Greys 2. 技术专家A和B平时没有对应机器的权限,但只要网络能访问,他们能够经过指定ip:port直接访问目标机器的JVM进程,仿佛在本地通常
Greys支持在线安装和本地安装两种安装方案,安装便可用,推荐使用在线安装。
在线安装(推荐)
请复制如下内容,并粘贴到命令行中。
curl -sLk http://ompc.oss.aliyuncs.com/greys/install.sh|sh
命令将会下载的启动脚本文件greys.sh
到当前目录,你能够放在任何地方或加入到$PATH
中
本地安装
在某些状况下,目标服务器没法访问远程阿里云主机,此时你须要自行下载greys的安装文件。
下载最新版本的GREYS
http://ompc.oss.aliyuncs.com/greys/release/greys-VERSION-bin.zip
最新的***VERSION***版本请参考主页信息
解压zip文件后,执行如下命令
cd greys sh ./install-local.sh
即完成本地安装。
下载失败
一般这样的缘由你须要检查你的网络是否畅通,核对是否能正确访问这个网址
http://ompc.oss.aliyuncs.com/greys/greys.sh
downloading... download failed!
没有权限
安装脚本首先会将greys文件从阿里云服务器上下载到当前执行脚本的目录,因此你必需要拥有当前目录的写权限。
permission denied, target directory is not writable.
参数说明
./greys.sh <PID>[@IP:PORT]
启动范例
若是不指定**IP**和**PORT**,默认是**127.0.0.1**和**3658**
./greys.sh 12345
等价于
./greys.sh 12345@127.0.0.1
等价于
./greys.sh 12356@127.0.0.1:3658
sudo支持
成熟的线上管理环境通常都不会直接开放JVM部署用户权限给你,而是经过sudo-list来控制和监控用户的越权操做。因为greys.sh
脚本中会对当前用户的环境变量产生感知,因此须要加上-H
参数
sudo -u admin -H ./greys.sh 12345
TELNET的支持
Greys支持经过telnet来访问服务端,若是当你手头的机器没有安装Greys的客户端,你能够简单的经过telnet命令来进行访问。
telnet 10.232.12.113 3658
固然了,telnet命令和Greys自带的Console在使用友好度上仍是有必定的差距,不过解决应急之需没有问题。
Greys是一个C/S架构的程序,因此当Client访问到Server时,Server会维护一个session(会话),以及session的心跳、超时机制。事务(Tx)机制则是创建在session的基础上,全部的命令交互都会建立一个事务,而且产生对应的队列进行输出缓冲。
事务伴随着命令的生命周期而存在,命令分两种:
当即返回
当即返回的命令定义是:敲下命令后Server端当即返回最终结果,后续无持续反馈信息,释放Client对输入的锁定,从新开放让用户输入信息,好比version
、sc
、sm
等。
等待停止
等待停止的命令则是须要用户主动输入Ctrl+D
完成的命令停止操做。命令执行后没法当即返回最终结果,而是不断的将中间产生的输出源源不断的输出到客户端中,这种命令好比stack
、monitor
等。
当session关闭时,全部挂在session的事务也会当即被关闭。
Greys相对于HouseMD、BTrace而言最灵活的地方就是在用表达式来灵活的支持不一样的问题排查、分析场景。
表达式分两种:条件表达式
与观察表达式
条件表达式
条件表达式用在**使用表达式表达TRUE或FALSE**的场景,从1.6.0.6
版本开始,trace
、stack
、tt
、watch
命令都增长了条件表达式支持。
条件表达式将会使用greys内置的表达式解析引擎,识别OGNL语法。
特别指出的是,若是你书写了一个错误的条件表达式,greys为了兼容错误会解析为FALSE。
如下是一些条件表达式使用的例子和预测结果
条件表达式 | 预测结果 | 解析结果说明 |
---|---|---|
1==1 | TRUE | 条件表达式为真 |
true | TRUE | 条件表达式为真 |
@@@ | FALSE | 非法的条件表达式 |
params==null | FALSE | 条件表达式为假 |
false | FALSE | 条件表达式为假 |
1!=1 | FALSE | 条件表达式为假 |
观察表达式
观察表达式用在**使用表达式表达输出内容**的场景,尤为在watch
和tt
命令中,观察表达式很是相当重要。
条件表达式将会使用greys内置的表达式解析引擎,识别OGNL语法,将表达式转换为待输出的对象。
如下是一些观察表达式使用的例子
字符串拼接
clazz.name+"."+method.name
数字运算
clazz.name.length()+method.name.length()
不管是匹配表达式也好、观察表达式也罢,他们核心判断变量都是围绕着一个greys中的通用通知对象Advice
进行。
它的简略代码结构以下
public class Advice { private final ClassLoader loader; private final Class<?> clazz; private final GaMethod method; private final Object target; private final Object[] params; private final Object returnObj; private final Throwable throwExp; private final boolean isBefore; private final boolean isThrow; private final boolean isReturn; // getter/setter }
这里列一个表格来讲明不一样变量的含义
变量名 | 变量解释 |
---|---|
loader | 本次调用类所在的ClassLoader |
clazz | 本次调用类的Class引用 |
method | 本次调用方法反射引用 |
target | 本次调用类的实例 |
params | 本次调用参数列表,这是一个数组,若是方法是无参方法则为空数组 |
returnObj | 本次调用返回的对象。当且仅当isReturn==true 成立时候有效,代表方法调用是以正常返回的方式结束。若是当前方法无返回值void ,则值为null |
throwExp | 本次调用抛出的异常。当且仅当isThrow==true 成立时有效,代表方法调用是以抛出异常的方式结束。 |
isBefore | 辅助判断标记,当前的通知节点有多是在方法一开始就通知,此时isBefore==true 成立,同时isThrow==false 和isReturn==false ,由于在方法刚开始时,还没法肯定方法调用将会如何结束。 |
isThrow | 辅助判断标记,当前的方法调用以抛异常的形式结束。 |
isReturn | 辅助判断标记,当前的方法调用以正常返回的形式结束。 |
全部变量均可以在表达式中直接使用,若是在表达式中编写了不符合OGNL脚本语法或者引入了不在表格中的变量,
对条件表达式
、检索表达式
而言,则一概当成false
来处理
对观察表达式
而言,则放弃当前方法调用的处理(不输出)
JDK的类默认由BootstrapClassLoader负责加载,因为Greys本身也适用了大量的JDK类,因此我不建议使用Greys直接对JDK相关类进行加强、代理。
默认而言,Greys会拒绝执行关于JDK类的操做命令。你需显式用options
命令打开。
ga?>options unsafe true +--------+--------------+-------------+ | NAME | BEFORE-VALUE | AFTER-VALUE | +--------+--------------+-------------+ | unsafe | false | true | +--------+--------------+-------------+ Affect(row-cnt:1) cost in 4 ms. ga?>
一些命令须要对类、方法进行模式匹配过滤,从1.5.4.6
及其以后的版本以后,Greys默认支持通配符
匹配,目前仅支持*
和?
两个通配符,正则表达式须要显式指定-E
参数激活。
模式匹配举例
原sc
命令的正则表达式匹配
sc com\.apache\.commons\.lang\.StringUtils
在1.5.4.6
及其以后的版本中将会默认使用通配符表达式
sc com.apache.commons.lang.StringUtils sc *lang.StringUtils
若想继续使用正则表达式匹配,须要显式-E
参数激活
sc -E com\.apache\.commons\.lang\.StringUtils sc -E com\..*StringUtils
支持模式匹配的命令
全部须要模式匹配的命令都支持参数-E
,他们分别是:sc
、sm
、stack
、monitor
、watch
、tt
、trace
命令 | 说明 |
---|---|
help | 查看命令的帮助文档,每一个命令和参数都有很详细的说明 |
sc | 查看JVM已加载的类信息 |
sm | 查看已加载的方法信息 |
monitor | 方法执行监控 |
trace | 渲染方法内部调用路径,并输出方法路径上的每一个节点上耗时 |
ptrace | 强化版的trace 命令。经过指定渲染路径,并可记录下路径中全部方法的入参、返值;与tt 命令联动。 |
watch | 方法执行数据观测 |
tt | 方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不一样的时间下调用进行观测 |
stack | 输出当前方法被调用的调用路径 |
version | 输出当前目标Java进程所加载的Greys版本号 |
quit | 退出greys客户端 |
shutdown | 关闭greys服务端 |
reset | 重置加强类,将被greys加强过的类所有还原 |
session | 查看当前会话 |
jvm | 查看当前JVM的信息 |
help
命令会是你第一个在Greys中使用的命令,也会是从此使用最频繁的命令之一,当你在使用的过程当中有任何不熟悉的疑问,请直接help
吧~
查看命令清单
进入Greys的欢迎界面后,全部命令均可以经过help
获取帮助。此时你直接输入一个help,Greys则会返回全部命令的大概用途介绍。
ga?>help +----------+----------------------------------------------------------------------------------+ | sc | Search all the classes loaded by JVM | +----------+----------------------------------------------------------------------------------+ | sm | Search the method of classes loaded by JVM | +----------+----------------------------------------------------------------------------------+ | monitor | Monitor the execution of specified Class and its method | +----------+----------------------------------------------------------------------------------+ | watch | Display the details of specified class and method | +----------+----------------------------------------------------------------------------------+ | tt | Time Tunnel | +----------+----------------------------------------------------------------------------------+ | stack | Display the stack trace of specified class and method | +----------+----------------------------------------------------------------------------------+ | ptrace | Display the detailed thread path stack of specified class and method | +----------+----------------------------------------------------------------------------------+ | trace | Display the detailed thread stack of specified class and method | +----------+----------------------------------------------------------------------------------+ | session | Display current session information | +----------+----------------------------------------------------------------------------------+ | quit | Quit Greys console | +----------+----------------------------------------------------------------------------------+ | version | Display Greys version | +----------+----------------------------------------------------------------------------------+ | jvm | Display the target JVM information | +----------+----------------------------------------------------------------------------------+ | reset | Reset all the enhanced classes | +----------+----------------------------------------------------------------------------------+ | shutdown | Shut down Greys server and exit the console | +----------+----------------------------------------------------------------------------------+ | help | Display Greys Help | +----------+----------------------------------------------------------------------------------+ Affect(row-cnt:1) cost in 9 ms. ga?>
嗯,囋囋,我知道个人英文翻译很烂,就不用吐槽了。指望能有人能帮我从新打理英文的帮助界面和英文xwiki,小生感激涕零!
查看命令详细帮助
help命令同时也支持对其余命令的一个解释说明,好比咱们键入help watch
,greys将会返回watch
命令的全部参数解释、用法介绍等详细信息。
ga?>help watch
+---------+----------------------------------------------------------------------------------+
| USAGE | -[bfesx:En:] class-pattern method-pattern express condition-express | | | Display the details of specified class and method | +---------+----------------------------------------------------------------------------------+ | OPTIONS | [b] | Watch before invocation | | | -----------------+-------------------------------------------------------------- | | | [f] | Watch after invocation | | | -----------------+-------------------------------------------------------------- | | | [e] | Watch after throw exception | | | -----------------+-------------------------------------------------------------- | | | [s] | Watch after successful invocation | | | -----------------+-------------------------------------------------------------- | | | [x:] | Expand level of object (0 by default) | | | -----------------+-------------------------------------------------------------- | | | [E] | Enable regular expression to match (wildcard matching by def | | | | ault) | | | -----------------+-------------------------------------------------------------- | | | [n:] | Threshold of execution times | | | -----------------+-------------------------------------------------------------- | | | class-pattern | Path and classname of Pattern Matching | | | -----------------+-------------------------------------------------------------- | | | method-pattern | Method of Pattern Matching | | | -----------------+-------------------------------------------------------------- | | | express | express, write by OGNL. | | | | | | | | FOR EXAMPLE params[0] | | | | params[0]+params[1] | | | | returnObj | | | | throwExp | | | | target | | | | clazz | | | |