分析单个 Web 会话

Profiling single Web session

在 Java-web-app 中搜索性能问题时,我想分析(通过采样)单个网络会话。 Web 应用程序部署在 Java EE 应用程序服务器上(JBoss 或 WLS,因此不可能有特定于 OpenJDK 的内容)

使用像 JVisualVM 或 YourKit 这样的传统采样器只允许我一次分析所有 运行 线程,因此不会揭示 CPU- 所述网络会话与基础分离的用法-load,它已经在服务器上了。部分问题是,(显然)网络会话和单个线程之间没有技术联系,即每个请求都可能从应用程序服务器的线程池中获得不同的线程。

我的想法是实现一个采样器,并在每次从服务器收到新请求时注册与观察到的网络会话相关联的线程(一旦请求完成就注销线程)。

第一个问题:您必须手动执行此操作还是已有工具可以为您执行此操作?

第二个问题(正如我发现 none 并假设这是一个相当具体的问题):最好的方法是什么?

显然,人们会尽量减少分析对应用程序性能的影响。同样显然,因为我需要将(技术)线程信息连接到特定于应用程序的数据(websession-ID),这似乎没什么,可以通过 JVMTI 完成。

保留编写应用程序内分析器的选项,其中线程通过 Thread.stackTrace 或 ThreadMXBean.getThreadInfo 进行采样。哪个更好?还有其他更好的选择吗?

看看:

http://messadmin.sourceforge.net/

这应该对您要分析的内容有所帮助。

此外,http://www.appdynamics.com/ and http://newrelic.com/ 是用于分析 Web 应用程序的非常好的工具。

JProfiler 可以为不同的 URL 或查询参数拆分调用树。

如果您可以为此目的修改 URL 或查询参数,那么您将能够将会话与后台加载分开。例如,您可以添加一个查询参数 profile=true,您只为应该分析的请求传递该参数。

免责声明:我公司开发了 JProfiler。

如果您没有 JProfiler,“编写应用内分析器”当然是一个选择。简单地在单个方法调用期间以特定时间间隔打印堆栈跟踪已经提供了一个很好的快照视图来了解正在发生的事情。

这是一个帮助程序 class 执行此操作的示例:

import java.io.Closeable;
import java.io.IOException;
import java.lang.management.ManagementFactory;

public class StackDumper extends Thread implements Closeable {
    static final String pid = ManagementFactory.getRuntimeMXBean().getName().replaceFirst("@.*", "");
    final Thread t;
    final int step;

    public StackDumper(int timeStepMs) {
        setName("Profiler");
        this.t = Thread.currentThread();
        this.step = timeStepMs;
        start();
    }

    @Override
    public void run() {
        StringBuilder buf = new StringBuilder(4096);
        for (int i = 0;; i += step) {
            try {
                Thread.sleep(step);
            } catch (InterruptedException e) {
                break;
            }
            buf.setLength(0);
            for (StackTraceElement e : t.getStackTrace()) {
                buf.append("  ").append(e).append('\n');
            }
            System.out.print(pid + " @" + i + "ms: [" + t.getName() + "]:\n" + buf);
        }
    }

    @Override
    public void close() throws IOException {
        interrupt();
    }

}

用作:

    try (StackDumper p = new StackDumper(100)) { // prints stack every 100 ms ...
        methodUnderTest();
    }