Pyroscope Java 持续剖析快速上手:基于 javaagent 的 simple 示例从零跑通
【免费下载链接】pyroscopeContinuous Profiling Platform. Debug performance issues down to a single line of code项目地址: https://gitcode.com/GitHub_Trending/py/pyroscope
导读
本文以仓库 examples/language-sdk-instrumentation/java/simple 示例为主线,完整讲解如何在 Linux 上通过 Docker Compose 一键拉起 Pyroscope 服务端、一个使用-javaagent接入 Pyroscope Java Agent 的 Java 应用以及预置了 Pyroscope 数据源的 Grafana,并在数分钟内于浏览器中看到实时火焰图。读完本文,你将掌握 Pyroscope Java 集成的最小可运行闭环、agent 关键环境变量的含义,以及如何在此基础上扩展标签(Tagging)与多维度对比分析。
示例概览:一个最小可运行的 Java 持续剖析闭环
simple示例是整个 Java SDK 接入系列中结构最精简的一支,它只包含四类文件:
| 文件 | 作用 |
|---|---|
| Main.java | 被剖析的 Java 应用本体:一个死循环中交替执行fastFunction与slowFunction |
| Dockerfile | 构建应用镜像,下载 pyroscope-java agent 并以 javaagent 方式注入 |
| docker-compose.yml | 编排 pyroscope、app、grafana 三个服务 |
| grafana-provisioning/datasources/pyroscope.yml | Grafana 自动预置 Pyroscope 数据源 |
它的价值在于:用极少的代码和配置,就能直观地验证"Java 应用 → Pyroscope 服务端 → Grafana 火焰图"这条完整链路。而同一目录下的 fib(Java 锁竞争剖析)与 rideshare(多区域多标签对比)示例,则是在此基础上的进阶玩法。
运行前提:为什么只能运行在 Linux 上
原文档特别强调:由于权限问题,该 docker-compose 示例只能在 Linux 上运行。
这一限制源于 docker-compose.yml 中app服务声明了privileged: true。特权模式允许容器内访问宿主机更多内核能力,这在 macOS/Windows 的 Docker Desktop 上并不总是可用,因此示例明确将运行环境限定为 Linux。
三步运行示例
原文档给出的运行流程非常简洁,共三条命令:
# 1. 拉取最新的 pyroscope 与 grafana 镜像 docker pull grafana/pyroscope:latest docker pull grafana/grafana:latest # 2. 构建并启动示例项目 docker-compose up --build # 3. 需要时重置数据库 # docker-compose down三条命令的作用分别对应三个阶段:
- 预拉取镜像:确保
grafana/pyroscope:latest与grafana/grafana:latest已就绪,避免up阶段因网络下载耗时过长。 - 构建并启动:
--build会先按 Dockerfile 构建应用镜像,再一并启动三个容器。启动后:- Pyroscope 服务端监听宿主机
4040端口; - Grafana 监听宿主机
3000端口; - Java 应用持续向
http://pyroscope:4040上报剖析数据。
- Pyroscope 服务端监听宿主机
- 重置数据库:
docker-compose down(默认不删除命名卷时)用于停止容器并清理运行状态,方便重新演示。
启动完成后,可以打开http://localhost:3000(Grafana,已匿名开启且预置数据源)或http://localhost:4040(Pyroscope 自带界面)查看实时火焰图。
剖析对象:Main.java 中刻意构造的快慢函数
为了让火焰图"一眼可见",Main.java 故意构造了两档耗时不同的函数:
class Main { public static int work(int n) { int i = 0; for (i = 0; i < n; i++) {} return i; } public static void fastFunction() { work(20000); } public static void slowFunction() { work(80000); } public static void main(String[] args) { int i = 0; while (true) { fastFunction(); slowFunction(); i++; } } }从代码结构可以推断其设计意图:fastFunction每轮循环执行 2 万次空循环,slowFunction执行 8 万次,因此slowFunction的 CPU 占用理论上约为fastFunction的 4 倍。在火焰图中,slowFunction对应矩形的宽度将明显大于fastFunction,从而直观展示"CPU 时间与代码热区"的对应关系。main中的while (true)保证应用持续运行、持续产生剖析数据,便于实时观察。
接入方式:javaagent 与环境变量全解
simple/Dockerfile 是整个接入的核心,它展示了 Pyroscope Java 集成最典型的两种操作:下载 agent 与通过环境变量配置。
FROM eclipse-temurin:11.0.31_11-jdk-jammy WORKDIR /opt/app ADD https://github.com/grafana/pyroscope-java/releases/download/v2.9.1/pyroscope.jar /opt/app/pyroscope.jar COPY Main.java ./Main.java RUN javac Main.java ENV PYROSCOPE_APPLICATION_NAME=simple.java.app ENV PYROSCOPE_PROFILING_INTERVAL=10ms ENV PYROSCOPE_PROFILER_EVENT=cpu ENV PYROSCOPE_PROFILER_LOCK=10ms ENV PYROSCOPE_PROFILER_ALLOC=512k ENV PYROSCOPE_UPLOAD_INTERVAL=15s ENV PYROSCOPE_LOG_LEVEL=debug ENV PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 CMD ["java", "-XX:-Inline", "-javaagent:pyroscope.jar", "Main"]1. agent 获取与注入
- 基础镜像使用
eclipse-temurin:11.0.31_11-jdk-jammy(Java 11 JDK),并直接编译运行Main.java,无需构建工具链; - 通过
ADD从 pyroscope-java 的 v2.9.1 发布包下载pyroscope.jar到/opt/app; - 启动命令以
-javaagent:pyroscope.jar注入 agent,实现零侵入式剖析——应用代码本身不需要任何 Pyroscope 依赖; - 同时使用
-XX:-Inline关闭 JIT 内联,保证fastFunction/slowFunction等函数在火焰图中以独立栈帧呈现,便于观察,这也是本示例刻意为之的演示手段。
2. 核心环境变量含义
| 环境变量 | 示例值 | 作用 |
|---|---|---|
PYROSCOPE_APPLICATION_NAME | simple.java.app | 应用名,在 UI 中用于区分不同被剖析服务,也作为标签维度出现 |
PYROSCOPE_SERVER_ADDRESS | http://pyroscope:4040 | Pyroscope 服务端地址;此处使用 Compose 服务名pyroscope做容器间通信 |
PYROSCOPE_PROFILING_INTERVAL | 10ms | CPU 剖析采样间隔,10ms 即每秒约 100 次采样 |
PYROSCOPE_PROFILER_EVENT | cpu | 剖析事件类型,示例选用 CPU 剖析 |
PYROSCOPE_PROFILER_LOCK | 10ms | 锁(lock)剖析相关阈值/间隔参数 |
PYROSCOPE_PROFILER_ALLOC | 512k | 内存分配剖析相关参数(分配采样阈值) |
PYROSCOPE_UPLOAD_INTERVAL | 15s | 每 15 秒向服务端上传一次剖析数据 |
PYROSCOPE_LOG_LEVEL | debug | agent 日志级别,调试接入问题时非常有帮助 |
需要说明的是,同一目录下 fib/Dockerfile 还额外使用了PYROSCOPE_FORMAT=jfr,说明 agent 底层支持基于 JFR(Java Flight Recorder)的数据格式,可作为扩展配置项参考;而 rideshare 示例 则通过PYROSCOPE_SERVER_ADDRESS环境变量分别指向 Pyroscope 服务端,展示了多实例部署的写法。
部署架构:Compose 三服务如何协同
docker-compose.yml 由模板 examples/_templates/pyroscope/docker-compose.yml 与 Grafana 模板生成,包含三个服务:
| 服务 | 镜像/构建 | 端口 | 职责 |
|---|---|---|---|
pyroscope | grafana/pyroscope:latest | 宿主机4040→ 容器4040 | Pyroscope 服务端,接收剖析数据并提供查询 API |
app | build: .(本地 Dockerfile) | 无对外端口 | 被剖析的 Java 应用,privileged: true提权运行 |
grafana | grafana/grafana:latest | 宿主机3000→ 容器3000 | 可视化前端,预装 pyroscope 插件并自动配置数据源 |
Grafana 服务的环境变量承担了插件与免登录配置:
GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app:启动时自动同步安装 Pyroscope 应用插件;GF_AUTH_ANONYMOUS_ENABLED=true、GF_AUTH_ANONYMOUS_ORG_ROLE=Admin、GF_AUTH_DISABLE_LOGIN_FORM=true:开启匿名访问并授予 Admin 角色,免登录直达仪表盘;GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph:启用 trace 关联 profile 与内嵌火焰图等实验特性。
数据源自动配置:Grafana 免手动接入
pyroscope.yml 通过 Grafana Provisioning 机制在容器启动时自动注册数据源,省去了手动配置步骤:
apiVersion: 1 datasources: - uid: pyroscope type: grafana-pyroscope-datasource name: Pyroscope url: http://pyroscope:4040 jsonData: keepCookies: [pyroscope_git_session]type: grafana-pyroscope-datasource指定插件类型,url指向 Compose 网络内的 Pyroscope 服务;jsonData.keepCookies保留了 Pyroscope 会话 Cookie,便于从 Grafana 内嵌打开 Pyroscope 界面时保持登录态;- 文件中注释给出了对接 Grafana Cloud 的写法(
basicAuth+basicAuthUser+basicAuthPassword),可满足云端场景; - 该文件同样由模板生成,注释明确提示"编辑模板后运行
make examples/sync-templates"再同步,直接修改生成文件会被覆盖。
验证结果:在火焰图中看到"快慢分明"
docker-compose up --build成功后等待约 15 秒(对应PYROSCOPE_UPLOAD_INTERVAL=15s),即可在 Grafana 的 Pyroscope 数据源或http://localhost:4040中选择应用simple.java.app。由于slowFunction的空循环次数是fastFunction的 4 倍,火焰图底部会呈现两条宽度差异明显的栈帧,这正对应 Main.java 中构造的 CPU 热点分布——这也是验证剖析链路是否打通的最快方式。
从 simple 起步:进阶能力与仓库内相关示例
跑通 simple 示例后,可以继续在仓库内探索同一目录下的进阶示例:
- rideshare 多区域对比:模拟
us-east、eu-north、ap-south三个区域的服务,通过Pyroscope.setStaticLabels打静态标签(如REGION),用Pyroscope.LabelsWrapper.run(new LabelsSet("vehicle", vehicle), ...)打动态标签(如vehicle),再借助 FlameQL(如REGION = "eu-north"/REGION != "eu-north")做对比与 diff 火焰图分析。具体实现可参考 OrderService.java。 - fib 锁竞争剖析:两个线程围绕
ReentrantLock竞争,配合PYROSCOPE_PROFILER_LOCK=10ms演示锁等待事件的剖析,应用名在 Compose 中通过PYROSCOPE_APPLICATION_NAME覆盖为fibonacci-java-lock-push。
这些示例与 simple 共享同一套镜像与数据源模板,改动成本极低,适合作为掌握 javaagent 接入后的下一步实验。
结语
simple示例虽然只有不足十行文档与四个小文件,却完整覆盖了"Linux 环境 → javaagent 注入 → 环境变量配置 → Compose 编排 → Grafana 数据源自动预置 → 火焰图验证"的 Pyroscope Java 集成全流程。将其作为起点,配合 rideshare 的标签体系与 fib 的锁剖析,即可系统掌握 Pyroscope 在 Java 服务性能诊断中的实战用法。
【免费下载链接】pyroscopeContinuous Profiling Platform. Debug performance issues down to a single line of code项目地址: https://gitcode.com/GitHub_Trending/py/pyroscope
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考