pyroscope.ebpf
pyroscope.ebpf
为当前主机配置 eBPF 分析任务。收集的性能分析结果将转发到 forward_to
中提供的接收者列表。
注意
要使用pyroscope.ebpf
组件,必须以 root 身份运行 Alloy 并在进程 ID 命名空间内运行。
您可以通过提供不同的标签来指定多个 pyroscope.ebpf
组件,但这不是推荐的,因为它可能会导致额外的内存和 CPU 使用。
支持的语言
此 eBPF 分析器只能收集 CPU 分析结果。通常,支持原生日编译语言如 C/C++、Go 和 Rust。有关其他要求的更多信息,请参阅 未知符号故障排除。
Python 是唯一受支持的高级语言,只要 python_enabled=true
。其他高级语言如 Java、Ruby、PHP 和 JavaScript 需要额外的配置以正确显示这些语言中方法的堆栈跟踪。目前,这些语言的 CPU 使用率报告为属于运行时方法。
用法
pyroscope.ebpf "LABEL" {
targets = TARGET_LIST
forward_to = RECEIVER_LIST
}
参数
该组件会配置并启动一个新 eBPF 分析任务,从当前主机收集性能分析结果。
您可以使用以下参数来配置 pyroscope.ebpf
。只有 forward_to
和 targets
字段是必需的。省略的字段将采用默认值。
名称 | 类型 | 描述 | 默认值 | 必需 |
---|---|---|---|---|
targets | list(map(string)) | 按容器 ID 分组的分析目标列表 | yes | |
forward_to | list(ProfilesReceiver) | 收集到后发送到接收者列表 | yes | |
collect_interval | duration | 收集分析结果的频率 | 15s | no |
sample_rate | int | 每秒收集分析样本的次数 | 97 | no |
pid_cache_size | int | pid -> proc 符号表 LRU 缓存的大小 | 32 | no |
build_id_cache_size | int | elf 文件 build id -> 符号表 LRU 缓存的大小 | 64 | no |
same_file_cache_size | int | elf 文件 -> 符号表 LRU 缓存的大小 | 8 | no |
container_id_cache_size | int | pid -> 容器 ID 表 LRU 缓存的大小 | 1024 | no |
collect_user_profile | bool | 启用/禁用用户空间分析收集的标志 | true | no |
collect_kernel_profile | bool | 启用/禁用内核空间分析收集的标志 | true | no |
demangle | string | C++ 冲突消除模式。可用选项为:`none`,`simplified`,`templates`,`full` | none | no |
python_enabled | bool | 启用/禁用 Python 分析的标志 | true | no |
symbols_map_size | int | eBPF 符号表的大小 | 16384 | no |
pid_map_size | int | eBPF PID 表的大小 | 2048 | no |
导出字段
pyroscope.ebpf
不导出其他组件可以引用的字段。
组件健康
pyroscope.ebpf
只有在给定无效配置时才报告为不健康。
调试信息
targets
当前跟踪的活跃目标。pid_cache
每个进程的 ELF 符号表及其符号计数。elf_cache
每个构建 ID 及相同文件的符号表及其符号计数。
调试指标
pyroscope_fanout_latency
(直方图):向直接和间接组件发送的写入延迟。pyroscope_ebpf_active_targets
(仪表盘):组件跟踪的活跃目标数量。pyroscope_ebpf_profiling_sessions_total
(计数器):完成的概要分析会话数量。pyroscope_ebpf_profiling_sessions_failing_total
(计数器):失败的概要分析会话数量。pyroscope_ebpf_pprofs_total
(计数器):eBPF 组件收集的 pprof 分析数量。
概要收集行为
pyroscope.ebpf
组件收集当前主机上运行的进程关联的堆栈跟踪。您可以使用 sample_rate
参数定义每秒收集的堆栈跟踪数量。默认值为 97。
如果您未定义以下标签,则会自动将其注入收集的概要中。这些标签可以帮助您定位分析目标。
标签 | 描述 |
---|---|
service_name | Pyroscope 服务名称。如果可能,它将自动从发现元标签中选择。否则,默认为 unspecified 。 |
__name__ | pyroscope 指标名称。默认为 process_cpu 。 |
__container_id__ | 从目标派生的容器 ID。 |
目标
targets
的每个目标必须包含以下特殊标签之一 必须,并且标签必须与被分析的容器或进程相对应
__container_id__
:容器 ID。__meta_docker_container_id
:Docker 容器的 ID。__meta_kubernetes_pod_container_id
:Kubernetes pod 容器的 ID。__process_pid__
:进程 ID。
然后,每个进程都与目标列表中的指定目标相关联,该目标通过容器 ID 或进程 PID 确定。
如果进程的容器 ID 与目标的容器 ID 标签相匹配,则根据容器 ID 对堆栈跟踪进行聚合。如果进程的 PID 与目标的进程 PID 标签相匹配,则根据进程 PID 对堆栈跟踪进行聚合。否则,该进程不进行分析。
服务名称
特殊标签 service_name
是必需的,并且始终必须存在。如果没有指定,则尝试从多个来源推断。
__meta_kubernetes_pod_annotation_pyroscope_io_service_name
,它是一个pyroscope.io/service_name
pod 注解。__meta_kubernetes_namespace
和__meta_kubernetes_pod_container_name
__meta_docker_container_name
如果 service_name
未指定且无法推断,则将其设置为 unspecified
。
处理未知符号
符号从各种来源提取,包括
- ELF 文件中的
.symtab
和.dynsym
部分。 - 调试 ELF 文件中的
.symtab
和.dynsym
部分。 - Go 语言 ELF 文件中的
.gopclntab
部分。
调试文件的搜索遵循 gdb 算法。例如,如果分析器希望找到带有 .gnu_debuglink
设置为 libc.so.6.debug
和构建 ID 0123456789abcdef
的 /lib/x86_64-linux-gnu/libc.so.6
的调试文件。将检查以下路径
/usr/lib/debug/.build-id/01/0123456789abcdef.debug
/lib/x86_64-linux-gnu/libc.so.6.debug
/lib/x86_64-linux-gnu/.debug/libc.so.6.debug
/usr/lib/debug/lib/x86_64-linux-gnu/libc.so.6.debug
处理未知符号
您收集的概要中的未知符号表示分析器无法访问与跟踪中的给定地址关联的 ELF 文件。
这可能是以下几种原因造成的
- 进程已终止,导致 ELF 文件不可访问。
- ELF 文件已损坏或未识别为 ELF 文件。
- 在
/proc/pid/maps
中没有与堆栈跟踪中的地址对应的 ELF 文件条目。
解决未解析的符号
如果您只看到模块名称(例如,/lib/x86_64-linux-gnu/libc.so.6
),而没有对应的函数名称,这表明符号无法映射到相应的函数名称。
这可能是以下几种原因造成的
- 二进制文件已经被剥离,ELF 文件中没有 .symtab、.dynsym 或 .gopclntab 部分。
- 调试文件丢失或无法定位。
为了修复您的二进制文件,请确保它们没有被剥离,或者您有可用的单独调试文件。您可以通过运行以下命令实现
objcopy --only-keep-debug elf elf.debug
strip elf -o elf.stripped
objcopy --add-gnu-debuglink=elf.debug elf.stripped elf.debuglink
对于系统库,确保已安装调试符号。以 Ubuntu 为例,您可以通过执行以下命令安装 libc
的调试符号
apt install libc6-dbg
理解平坦的堆栈跟踪
如果您的配置文件显示许多浅层堆栈跟踪,通常是1-2层,这意味着您的二进制可能是在没有帧指针的情况下编译的。
要使用帧指针编译您的代码,请在编译器选项中包含 -fno-omit-frame-pointer
标志。
示例
Kubernetes 发现
在以下示例中,使用 discovery.kubernetes
发现同一节点上的 pod,收集性能配置文件。Pod 选择依赖于 HOSTNAME
环境变量,如果使用 Alloy Helm 图表,则是 pod 名称。设置 service_name
标签为从 Kubernetes 元标签中的 {__meta_kubernetes_namespace}/{__meta_kubernetes_pod_container_name}
。
discovery.kubernetes "all_pods" {
role = "pod"
selectors {
field = "spec.nodeName=" + env("HOSTNAME")
role = "pod"
}
}
discovery.relabel "local_pods" {
targets = discovery.kubernetes.all_pods.targets
rule {
action = "drop"
regex = "Succeeded|Failed"
source_labels = ["__meta_kubernetes_pod_phase"]
}
rule {
action = "replace"
regex = "(.*)@(.*)"
replacement = "ebpf/${1}/${2}"
separator = "@"
source_labels = ["__meta_kubernetes_namespace", "__meta_kubernetes_pod_container_name"]
target_label = "service_name"
}
rule {
action = "labelmap"
regex = "__meta_kubernetes_pod_label_(.+)"
}
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_node_name"]
target_label = "node"
}
rule {
action = "replace"
source_labels = ["__meta_kubernetes_pod_container_name"]
target_label = "container"
}
}
pyroscope.ebpf "local_pods" {
forward_to = [ pyroscope.write.endpoint.receiver ]
targets = discovery.relabel.local_pods.output
}
pyroscope.write "endpoint" {
endpoint {
url = "http://pyroscope:4040"
}
}
Docker 发现
在以下示例中,从 discovery.docker
查找的容器中收集性能配置文件,并忽略来自任何 Docker 容器外部的所有其他配置文件。设置 service_name
标签为 __meta_docker_container_name
标签。
discovery.docker "linux" {
host = "unix:///var/run/docker.sock"
}
discovery.relabel "local_containers" {
targets = discovery.docker.linux.targets
rule {
action = "replace"
source_labels = ["__meta_docker_container_name"]
target_label = "service_name"
}
}
pyroscope.write "staging" {
endpoint {
url = "http://pyroscope:4040"
}
}
pyroscope.ebpf "default" {
forward_to = [ pyroscope.write.staging.receiver ]
targets = discovery.relabel.local_containers.output
}
兼容组件
pyroscope.ebpf
可以接受以下组件的参数
- 导出 目标 的组件
- 导出 Pyroscope
ProfilesReceiver
的组件
注意
某些组件之间的连接可能不合理,或可能需要进一步配置以正确连接。请参阅链接的文档以获取更多详细信息。