分享一种 Spring 应用启动过程采样的方法

2023-08-08 09:18:23 +08:00
 linyimin520812

spring-startup-analyzer采集 Spring 应用启动过程数据,生成交互式分析报告(HTML),用于分析 Spring 应用启动卡点,支持 Spring Bean 异步初始化,减少优化 Spring 应用启动时间。

其中 Wall Clock 采样火焰图是基于async-profiler的,async-profiler 只支持 linux 和 mac ,问题在于 windows 没有 POSIX 信号的概念,也没有类似 Linux 中 perf_event_open 的 API 。为了在 windows 下也能生成火焰图,使用了一种简单的方法,采样结果与 async-profiler 相比虽然会存在一些偏差Safepoint bias problem,但是基本上也能用。

思路很简单:

1.首先获取线程名为 main 的线程(主线程)

List<Thread> sampledThreads = new ArrayList<>(ThreadUtils.findThreads(thread -> StringUtils.equals("main", thread.getName())));

2.起一个周期调度任务进行采样,采样结果放到一个LinkedBlockingQueue

LinkedBlockingQueue<StackTraceElement[]> STACK_TRACE_QUEUE = new LinkedBlockingQueue<>();

ScheduledExecutorService SAMPLE_SCHEDULER = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());

SAMPLE_SCHEDULER.scheduleAtFixedRate(() -> {

    sampledThreads = getTargetThreads();

    for (Thread thread : sampledThreads) {
        STACK_TRACE_QUEUE.add(thread.getStackTrace());
    }
}, 0, 5, TimeUnit.MILLISECONDS);

3.起一个处理线程将队列中的采样结果放到 Map 中

while (true) {

    try {
    	StackTraceElement[] traces = STACK_TRACE_QUEUE.poll(5, TimeUnit.SECONDS);
        if (traces == null || traces.length == 0) {
        	continue;
        }
        List<StackTraceElement> elements = Arrays.asList(traces);
        Collections.reverse(elements);
        String trace = elements.stream().map(element -> element.getClassName() + "." + element.getMethodName()).collect(Collectors.joining(";"));
        TRACE_MAP.put(trace, TRACE_MAP.getOrDefault(trace, 0) + 1);
    } catch (InterruptedException ignored) {
    }

    if (stop && STACK_TRACE_QUEUE.isEmpty()) {
    	break;
    }
}

将采样和处理两个逻辑通过阻塞队列分开可以在一定程度上保证采样周期的稳定性。

将采样到的调用栈样本集进行整合后,需输出如下所示的文本格式。每一行代表一“类“调用栈,空格左边是调用栈的方法名排列,以分号分割,左栈底右栈顶,空格右边是该样本出现的次数。这样就可以进行可视化输出 svg 了,可视化的逻辑参考了 async-profiler 的实现,这里就不在具体描述了。

base_func;func1;func2;func3 10
base_func;funca;funcb 15

最后再推荐一下项目,如果感兴趣欢迎 star, 提 PR

2173 次点击
所在节点    程序员
5 条回复
lyxeno
2023-08-08 10:14:07 +08:00
用了一下,蛮不错的,已 star
xubeiyou
2023-08-08 10:51:03 +08:00
这个感觉不错的样子! STAR 了 破坏了队形 本来是 666 的 变成 667 了
chengyiqun
2023-08-08 14:09:57 +08:00
感觉不错, mark 了
banzhe0421
2023-08-08 18:49:43 +08:00
简单跑了一下,感觉不错,后续有时间看一下代码
258
2023-08-09 09:07:03 +08:00
感觉不错,

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/963251

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX