明升ms88社区

 找回暗码
 注册
明升ms88社区 主页 业界资讯 技能文摘 检查内容

运用神器BTrace追寻线上Spring Boot运用运转时信息

2019-1-18 10:53| 发布者: joejoe0332| 检查: 2094| 谈论: 0|原作者: oschina|来自: oschina

摘要: 出产环境中的服务或许会呈现各种问题,但总不能让服务下线来专门排查过错,这时分最好有一些手法来获取程序运转时信息,比方 接口办法参数/回来值、外部调用状况 以及 函数履行时刻等信息以便定位问题。传统的日志记 ...

概述

出产环境中的服务或许会呈现各种问题,但总不能让服务下线来专门排查过错,这时分最好有一些手法来获取程序运转时信息,比方 接口办法参数/回来值、外部调用状况 以及 函数履行时刻等信息以便定位问题。传统的日志记载办法确实能够,但有时十分费事,乃至或许需求重启服务,因而价值太大,这时能够凭借一个牛批的东西:BTrace

BTrace 可用于动态盯梢正在运转的 Java程序,其原理是经过动态地检测方针运用程序的类并注入盯梢代码 ( “字节码盯梢” ),因而能够直接用于监控和追寻线上问题而无需修正事务代码并重启运用程序。

Profile

BTrace 的运用办法是用户自己编写契合 BTrace运用语法的脚本,并结合btrace指令,来获取运用的全部调用信息,就像下面这样:

<btrace>/bin/btrace <PID> <trace_script>
  • 其间 <PID>为被监控 Java运用的 进程ID
  • <trace_script> 为 根据需求监控的信息 而自行编写的 Java脚本

本文就来实操一波 BTrace东西的运用,试验环境如下:

注: 本文首发于 My Personal Blog:CodeSheep·程序羊,欢迎光临 小站


BTrace 装置布置

这儿我解压到目录:/home/btrace

  • 装备体系环境变量
vim /etc/profile

BTRACE_HOME=/home/btrace
export BTRACE_HOME
export PATH=$PATH:$BTRACE_HOME/bin
  • 验证 BTrace装置状况
btrace --version

编译 BTrace源码

  • 克隆源码
git clone git@github.com:btraceio/btrace.git
  • 编译源码
./gradlew build

编译源码

  • 构建完结的生成物途径坐落build/libs目录下

构建生成物途径

咱们取出构建生成的 jar包供下文运用。


运用btrace追寻 Spring Boot运用例析

首要咱们得结构一个 Spring Boot的模仿事务 用于下文被追寻和剖析,这儿我就运用文章 《Spring Boot运用缓存实践之:Ehcache加持》中的试验工程。

咱们在此工程里再增加一个 scripts包,用于放置 btrace 脚本文件:

项目结构

因为 btrace脚本中需求用到 btrace相关的组件和函数库,因而咱们还需求在工程的 pom.xml中引进 btrace的依靠,所运用的 jar包便是上文编译生成的 btrace-1.3.11.3.jar

        <dependency>
            <groupId>com.sun.btrace</groupId>
            <artifactId>btrace</artifactId>
            <version>1.3.11.3</version>
        </dependency>

Talk is cheap ,Show you the code !接下来就用四五个试验来阐明全部吧:


0x01 监控办法耗时状况

btrace 脚本:

@BTrace
public class BtraceTest2 {

    @OnMethod(clazz = "cn.codesheep.springbt_brace.controller.UserController", method = "getUsersByName", location = @Location(Kind.RETURN))
    public static void getFuncRunTime( @ProbeMethodName String pmn, @Duration long duration) {
        println( "接口 " + pmn + strcat("的履行时刻(ms)为: ", str(duration / 1000000)) ); //单位是纳秒,要转为毫秒
    }
}

接下来开端运转 btrace脚原本阻拦办法的参数,首要咱们用 jps指令取到需求被监控的 Spring Boot运用的进程 Id为 27887,然后履行:

/home/btrace/bin/btrace 27887 BtraceTest2.java

这儿我总共对 /getusersbyname接口宣布了 12次 POST恳求,状况如下:

12次恳求状况

接下来咱们再看看运用btrace脚本监控到的 /getuserbyname接口的履行时刻:

12次恳求所对应的接口调用时刻

这样一比照很明显,从数据库取数据仍是需求 花费十几毫秒的,但从缓存读取数据 几乎没有耗时,这便是为什么要让缓存加持于运用的原因!!!


0x02 阻拦办法的 参数/回来值

btrace 脚本:

    @OnMethod(
            clazz = "cn.codesheep.springbt_brace.controller.UserController",
            method = "getUsersByName",
            location = @Location(Kind.ENTRY)
    )
    public static void getFuncEntry(@ProbeClassName String pcn, @ProbeMethodName String pmn, User user ) {

        println("类名: " + pcn);
        println("办法名: " + pmn);

        // 先打印入参实体全体信息
        BTraceUtils.print("入参实体为: ");
        BTraceUtils.printFields(user);

        // 再打印入参实体每个特点的信息
        Field oneFiled = BTraceUtils.field("cn.codesheep.springbt_brace.entity.User", "userName");
        println("userName字段为: " + BTraceUtils.get(oneFiled, user));

        oneFiled = BTraceUtils.field("cn.codesheep.springbt_brace.entity.User", "userAge");
        println("userAge字段为: " + BTraceUtils.get(oneFiled, user));

    }

接下来开端运转 btrace脚原本阻拦办法的参数,首要咱们用 jps指令取到需求被监控的java运用的进程 Id为 27887,然后履行:

/home/btrace/bin/btrace -cp springbt_brace/target/classes 27887 BtraceTest4.java

此刻正常带参数 {"userName":"codesheep.cn"} 去恳求事务接口:POST /getusersbyname,会得到如下输出:

成功阻拦到了接口入参

很明显恳求参数现已被 btrace给阻拦到了

同理,假如想阻拦办法的回来值,能够运用如下 btrace脚本:

    @OnMethod(
            clazz = "cn.codesheep.springbt_brace.controller.UserController",
            method = "getUsersByName",
            location = @Location(Kind.RETURN)  //函数回来的时分履行,假如不填,则在函数开端的时分履行
    )
    public static void getFuncReturn( @Return List<User> users ) {
        println("回来值为: ");
        println(str(users));
    }

运转 btrace指令后,持续恳求想要被监控的事务接口,则能够得到相似如下的输出:

成功阻拦到了接口回来值


0x03 监控代码是否抵达了某类的某一行

btrace 脚本如下:

@BTrace
public class BtraceTest3 {

    @OnMethod(
            clazz="cn.codesheep.springbt_brace.service.UserService",
            method="getUsersByName",
            location=@Location(value= Kind.LINE, line=28)  // 比方阻拦第28行, 28行是从数据库取数据操作
    )
    public static void lineTest( @ProbeClassName String pcn, @ProbeMethodName String pmn, int line ) {
        BTraceUtils.println("ClassName: " + pcn);
        BTraceUtils.println("MethodName: " + pmn);
        BTraceUtils.println("履行到的line行数: " + line);
    }
}

履行 btrace追寻指令

/home/btrace/bin/btrace 28927 BtraceTest3.java

接着用 POSTMAN东西接连宣布了对 /getuserbyname接口的 十几次POST恳求,因为只要榜首次恳求没有缓存时才会从数据库读,因而也才会履行到 UserService类的第 28行 !


0x04 监控指定函数中所有外部调用的耗时状况

btrace脚本如下:

@BTrace
public class BtraceTest5 {

    @OnMethod (clazz = "cn.codesheep.springbt_brace.service.UserService",method = "getUsersByName",
    [email protected](value= Kind.CALL, clazz="/.*/", method="/.*/", where = Where.AFTER) )
    public static void printMethodRunTime(@Self Object self,@TargetInstance Object instance,@TargetMethodOrField String method, @Duration long duration) {

        if( duration > 5000000 ){  //假如外部调用耗时大于 5ms 则打印出来
            println( "self: " + self );
            println( "instance: " + instance );
            println( method + ",cost:" + duration/1000000 + " ms" );
        }
    }

}

履行监控指令:

/home/btrace/bin/btrace 28927 BtraceTest5.java

然后再对接口 /getuserbyname宣布POST恳求,调查监控成果如下:

发现最耗时的外部调用来源于 MyBatis调用

咱们发现最耗时的外部调用来源于 MyBatis调用。


0x05 其他追寻与监控

除了上面四种典型的追寻场景之外,其他的 btrace追寻与监控场景还比方 检查谁调用了System.gc(),调用栈怎么,则能够运用如下 btrace脚本进行监控

@BTrace
public class BtraceTest {
    @OnMethod(clazz = "java.lang.System", method = "gc")
    public static void onSystemGC() {
        println("entered System.gc()");
        jstack();
    }
}

很明显,因为btrace 内置了一系列比方 jstack等十分有用的监控指令。

当然最终需求阐明的是 btrace内置了许多语法和指令,能够应对许多线上 Java运用监控场景,咱们能够去研究一下官方文档


跋文

因为才能有限,若有过错或许不当之处,还请咱们批评指正,一同学习沟通!



  • 快毕业了,没作业经验,
    找份作业好难啊?
    赶忙去人才芯片公司锻炼吧!!

最新谈论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|明升ms88社区 ( 浙B2-20090187  

回来顶部