skywalking源码解读–栈快照

首先介绍功能:

官方在线demo地址:http://demo.skywalking.apache.org

我们可以在这里体验skywalking的功能:服务-普通服务-点击服务[songs]进入钻取面板-点击Trace Profiling,查看链路分析. –点击”分析”按钮,采集当前的栈信息

服务面板
Tracing Profiling

当线上发生故障,或者观测在线运行状况时,可以在此面板新建一个Trace Profiling任务,来进行采样,分析

性能分析配置界面

本文我们主要关注栈信息是怎么获取的.

在我们日常排查问题时,会使用jstack查看线程栈详情. 而skywalking是如何获取的呢? 其实skywalking获取线程栈信息的方式与jstack在本质上是一样的. 他们都是native方法 dumpThreads来获取当前栈信息的.

在ProfileThread类中,会轮询profiler任务.当执行profiling任务时,会生成TracingThreadSnapshot 线程快照.

追踪源码可以找到 ThreadProfiler.buildSnapshot()中,通过prifilingThread(一个后台线程)对堆栈信息进行采样

为了了解Thread.getStackTrace的效果,我们可以执行如下代码


public class MainClazz {

    public static void main(String[] args) {
        methodA();
    }

    private static void methodA(){
        System.out.println("方法A执行");
        int a = 0;
        methodB();
    }

    private static void methodB(){
        System.out.println("方法B执行");
        int b = 1;
        StackTraceElement[] stackTraceElement = Thread.currentThread().getStackTrace();
        System.out.println(stackTraceElement.length);
    }
}

通过断点,查看栈帧

栈帧详情

让我们追进Thread.getStackTrace方法,我们能够看到当前线程内的调用链路.相关代码如下:

Thread.getStackTrace
dumpThreads

知道了获取stack的手段, 那么如何在触发指定业务逻辑的时候,打印/记录堆栈信息呢?

结合skywalking中的处理细节,可以在增强类里 织入针对异常/特定业务code(比如后端返回400)的处理. 当出现需要追踪的异常时,获取当前堆栈的快照.


public class MainClazz {

    public static void main(String[] args) {
        try {
            methodA();
        } catch (Exception ex){
            System.out.println("业务异常");
            ProfileUtil.printStack(ex.getStackTrace());
        }
        methodA();
    }

    private static void methodA(){
        System.out.println("方法A执行");
        int a = 0;
        methodB();
    }

    private static void methodB(){
        System.out.println("方法B执行");
        int b = 1;
        int c = b * 0;
        int d = b/c;
    }
}
import java.util.ArrayList;
import java.util.Arrays;

public class ProfileUtil {

    public static void printStack(StackTraceElement[] stackTrace){
        if(stackTrace == null) return;
        //把JVM给的堆栈倒序打印
        for (int i = stackTrace.length -1; i >= 0; i--) {
            System.out.println(buildStackElementCodeSignature(stackTrace[i]));
        }
    }

    private static String buildStackElementCodeSignature(StackTraceElement element) {
        return element.getClassName() + "." + element.getMethodName() + ":" + element.getLineNumber();
    }
}

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注