使用 Grafana Alloy 或 Agent 对 Java 进行性能分析
Grafana Alloy 和 Grafana Agent 在 流模式 下支持 Java 性能分析。
收集器配置文件由用于收集、转换和发送数据的组件组成。Alloy 配置文件使用 Alloy 配置语法。Agent Flow 文件使用 River 语言。
注意
Grafana Alloy 是我们 OTel 收集器发行版的最新名称。Grafana Agent 已被弃用,并将在 2025 年 10 月 31 日之前提供长期支持 (LTS)。Grafana Agent 将于 2025 年 11 月 1 日达到生命周期结束 (EOL)。详细了解我们为何建议迁移到 Grafana Alloy。
配置组件
pyroscope.java
组件用于使用 async-profiler 持续分析在本地 Linux OS 上运行的 Java 进程。
pyroscope.java "java" {
profiling_config {
interval = "15s"
alloc = "512k"
cpu = true
lock = "10ms"
sample_rate = 100
}
forward_to = [pyroscope.write.endpoint.receiver]
targets = discovery.relabel.java.output
}
使用 targets
参数,您可以指定要分析机器上的哪些进程和容器。targets
可以来自 discovery.process
组件。您可以使用 discovery.process
join 参数将进程目标与其他发现(例如 dicovery.kubernetes
、discovery.docker
和 discovery.dockerswarm
)连接起来。您可以使用 discovery.relabel
组件重新标记发现的目标并设置您自己的标签。有关更多信息,请参阅 组件。
forward_to
参数应指向 pyroscope.write
组件,以将收集的配置文件发送到您的 Pyroscope 服务器或 Grafana Cloud。
名称 | 类型 | 描述 | 默认值 | 必需 |
---|---|---|---|---|
targets | list(map(string)) | 要分析的 Java 进程目标列表。 | 是 | |
forward_to | list(ProfilesReceiver) | 要将收集的配置文件发送到的接收器列表。 | 是 | |
tmp_dir | string | 用于存储 async-profiler 的临时目录。 | /tmp | 否 |
特殊标签 __process_pid__
必须始终 存在于 targets
的每个目标中,并且对应于要分析的进程的 PID
。
特殊标签 service_name
是必需的,并且必须始终存在。如果没有指定 service_name
,pyroscope.java
会尝试从发现元标签中推断出来。如果没有指定 service_name
,并且无法推断,则将其设置为 unspecified
。
profiling_config
块描述了如何调用 async-profiler。
它支持以下参数
名称 | 类型 | 描述 | 默认值 | 必需 |
---|---|---|---|---|
间隔 | 持续时间 | 从目标收集配置文件的频率。 | “60s” | 否 |
cpu | bool | 一个启用 CPU 分析的标志,使用 itimer 异步分析器事件。 | true | 否 |
采样率 | int | CPU 分析采样率。它从 Hz 转换为间隔,并作为 -i 参数传递给异步分析器。 | 100 | 否 |
alloc | string | 分配分析采样配置。它作为 --alloc 参数传递给异步分析器。 | “512k” | 否 |
lock | string | 锁分析采样配置。它作为 --lock 参数传递给异步分析器。 | “10ms” | 否 |
有关异步分析器配置的更多信息,请参阅 profiler-options。
为收集器设置权限
您必须以 root 用户身份运行收集器(推荐使用 Grafana Alloy 或使用传统的 Agent),并在主机 pid
命名空间内运行,才能使 pyroscope.java
和 discover.process
组件正常工作。
启动收集器
要启动 Grafana Alloy v1.2:将 configuration.alloy
替换为您配置的文件名
alloy run configuration.alloy
要启动 Grafana Alloy v1.0/1.1:将 configuration.alloy
替换为您配置的文件名
alloy run --stability.level=public-preview configuration.alloy
stability.level
选项对于使用 Alloy v1.0 或 v1.1 的 pyroscope.scrape
是必需的。有关 stability.level
的更多信息,请参阅 The run command 文档。
要启动 Grafana Agent,请将 configuration.river
替换为您配置的文件名:grafana-agent-flow run configuration.river
将数据发送到 Grafana Cloud Profiles
当发送到 Grafana Cloud Profiles 时,您可以使用以下 pyroscope.write
组件配置,该配置使用环境变量。
确保您已正确配置 GC_URL
、GC_USER
和 GC_PASSWORD
环境变量。
pyroscope.write "endpoint" {
endpoint {
basic_auth {
password = env("GC_PASSWORD")
username = env("GC_USER")
}
url = env("GC_URL")
}
}
示例
分析本地进程
discovery.process "all" {
}
discovery.relabel "java" {
targets = discovery.process.all.targets
// Filter only java processes
rule {
source_labels = ["__meta_process_exe"]
action = "keep"
regex = ".*/java$"
}
// Filter processes. For example: only processes with command line containing "FastSlow"
rule {
source_labels = ["__meta_process_commandline"]
regex = "java FastSlow"
action = "keep"
}
// Provide a service name for the process, otherwise it will be unspecified.
rule {
action = "replace"
target_label = "service_name"
replacement = "java-fast-slow"
}
}
pyroscope.java "java" {
forward_to = [pyroscope.write.example.receiver]
targets = discovery.relabel.java.output
}
pyroscope.write "example" {
endpoint {
url = "http://pyroscope:4040"
}
}
分析 Docker 容器
discovery.docker "local_containers" {
host = "unix:///var/run/docker.sock"
}
discovery.process "all" {
join = discovery.docker.local_containers.targets
}
discovery.relabel "java" {
targets = discovery.process.all.targets
// Filter only java processes
rule {
source_labels = ["__meta_process_exe"]
action = "keep"
regex = ".*/java$"
}
// Filter only needed containers
rule {
source_labels = ["__meta_docker_container_name"]
regex = ".*suspicious_pascal"
action = "keep"
}
// Provide a service name for the process, otherwise it will default to the value of __meta_docker_container_name label.
rule {
action = "replace"
target_label = "service_name"
replacement = "java-fast-slow"
}
}
pyroscope.java "java" {
forward_to = [pyroscope.write.example.receiver]
targets = discovery.relabel.java.output
}
pyroscope.write "example" {
endpoint {
url = "http://pyroscope:4040"
}
}
分析 Kubernetes Pod
discovery.kubernetes "local_pods" {
selectors {
field = "spec.nodeName=" + env("HOSTNAME")
role = "pod"
}
role = "pod"
}
discovery.process "all" {
join = discovery.kubernetes.local_pods.targets
}
discovery.relabel "java_pods" {
targets = discovery.process.all.targets
// Filter only java processes
rule {
source_labels = ["__meta_process_exe"]
action = "keep"
regex = ".*/java$"
}
rule {
action = "drop"
regex = "Succeeded|Failed|Completed"
source_labels = ["__meta_kubernetes_pod_phase"]
}
rule {
action = "replace"
source_labels = ["__meta_kubernetes_namespace"]
target_label = "namespace"
}
rule {
action = "replace"
source_labels = ["__meta_kubernetes_pod_name"]
target_label = "pod"
}
rule {
action = "replace"
source_labels = ["__meta_kubernetes_pod_node_name"]
target_label = "node"
}
rule {
action = "replace"
source_labels = ["__meta_kubernetes_pod_container_name"]
target_label = "container"
}
// Provide arbitrary service_name label, otherwise it will be inferred from discovery labels automatically
rule {
action = "replace"
regex = "(.*)@(.*)"
replacement = "java/${1}/${2}"
separator = "@"
source_labels = ["__meta_kubernetes_namespace", "__meta_kubernetes_pod_container_name"]
target_label = "service_name"
}
// Filter only needed services
rule {
action = "keep"
regex = "(java/ns1/.*)|(java/ns2/container-.*0)"
source_labels = ["service_name"]
}
}
pyroscope.java "java" {
forward_to = [pyroscope.write.example.receiver]
targets = discovery.relabel.java.output
}
pyroscope.write "example" {
endpoint {
url = "http://pyroscope:4040"
}
}
参考
有关更多信息