查看数据
创建时间:2024-08-08 最近修改时间:2024-08-23
#1. 获取指定进程的 Profile
#1.1 Grafana Panel
在 app_service
中选择一个进程名之后,Grafana 中的展示效果图如下:
On-CPU - Process
#1.2 API
Profile 查询 API 示例:
# 确认 deepflow-server 的监听 IP 和端口
deepflow_server_node_ip=FIXME # 注意修改
port=$(kubectl get --namespace deepflow -o jsonpath="{.spec.ports[0].nodePort}" services deepflow-server)
# 请求 deepflow-server 的 API
curl -X POST http://${deepflow_server_node_ip}:$port/v1/profile/ProfileTracing \
-H 'Content-Type: application/json' \
-d '{
"app_service": "deepflow-agent",
"profile_language_type": "eBPF",
"profile_event_type": "on-cpu",
"tag_filter": "",
"time_start": 1708479421,
"time_end": 1708480321
}'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
API 请求参数说明:
- app_service:进程名
- profile_language_type:获取 eBPF Profile 数据时使用
eBPF
- profile_event_type:对于 eBPF On-CPU Profile 数据赋值为
on-cpu
即可 - tag_filter:当进程名冲突时,可使用其他 Tag 过滤
- 例如
"tag_filter": "pod_cluster='prod-cluster' AND pod_ns='app'"
- 例如
- time_start、time_end:时间范围
profile.in_process
表支持使用的 tag_filter
字段如下:
Name | DisplayName | Description |
---|---|---|
_id | UID | |
time | 时间 | |
region | 区域 | |
az | 可用区 | |
host | 宿主机 | 承载虚拟机的宿主机。 |
chost | 云服务器 | 包括虚拟机、裸金属服务器。 |
vpc | VPC | |
router | 路由器 | |
dhcpgw | DHCP 网关 | |
lb | 负载均衡器 | |
lb_listener | 负载均衡监听器 | |
natgw | NAT 网关 | |
redis | Redis | |
rds | RDS | |
pod_cluster | K8s 容器集群 | |
pod_ns | K8s 命名空间 | |
pod_node | K8s 容器节点 | |
pod_ingress | K8s Ingress | |
pod_service | K8s 容器服务 | |
pod_group_type | K8s 工作负载类型 | |
pod_group | K8s 工作负载 | 例如 Deployment、StatefulSet、Daemonset 等。 |
pod | K8s 容器 POD | |
service | 服务 | 已废弃,请使用 pod_service |
auto_instance_type | 自动实例类型 | auto_instance 实例对应的类型。 |
auto_instance | 自动实例 | IP 对应的实例,实例为IP时,auto_instance_id显示为子网ID。 |
auto_service_type | 自动服务类型 | auto_service 实例对应的类型。 |
auto_service | 自动服务 | 在auto_instance 基础上,将容器服务的 ClusterIP 与工作负载聚合为服务,实例为IP时,auto_service_id显示为子网ID。 |
gprocess | 进程 | |
host_ip | 宿主机 | 宿主机的管理 IP。 |
host_hostname | 宿主机 | 宿主机的 Hostname。 |
chost_ip | 云服务器 | 云服务器的主 IP。 |
chost_hostname | 云服务器 | 云服务器的 Hostname。 |
pod_node_ip | K8s 容器节点 | 容器节点的主 IP。 |
pod_node_hostname | K8s 容器节点 | 容器节点的 Hostname。 |
k8s.label | K8s Label | |
k8s.annotation | K8s Annotation | |
k8s.env | K8s Env | |
cloud.tag | Cloud Tag | |
ip | IP 地址 | |
is_ipv4 | IPv4 标志 | |
app_service | 应用服务 | |
app_instance | 应用实例 | |
process_id | 进程 ID | |
trace_id | TraceID | |
span_name | Span名称 | |
vtap | 采集器 | 已废弃,请使用 agent。 |
agent | 采集器 | |
profile_value_unit | 单位 | |
profile_event_type | 剖析类型 | |
profile_create_timestamp | 聚合时间 | |
profile_in_timestamp | 写入时间 | |
profile_language_type | 语言类型 | |
profile_id | ProfileID |
generate from csv file: in_process.ch
API 返回结果示例:
{
"OPT_STATUS": "SUCCESS",
"DESCRIPTION": "",
"result": {
"functions": [
"deepflow-agent",
"[t] platform-synchr",
"[k] entry_SYSCALL_64_after_hwframe",
// ...
"[l] __write"
],
"function_types": [
"P",
"T",
"K",
// ...
"K"
],
"function_values": {
"columns": ["self_value", "total_value"],
"values": [
[0, 640352895],
[0, 6292923],
[0, 46848438],
// ...
[0, 1797978]
]
},
"node_values": {
"columns": ["function_id", "parent_node_id", "self_value", "total_value"],
"values": [
[0, -1, 0, 640352895],
[1, 0, 0, 6292923],
[2, 1, 0, 1444443],
// ...
[3, 2, 0, 10101]
]
}
},
"debug": null
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
API 返回结果说明:
- functions:函数名
- function_types: 函数类型
[t] thread_name
:线程,只会出现在火焰图的第二层[k] function_name
:Linux 内核函数、CUDA 动态链接库函数(libcuda (opens new window)、libcublas (opens new window) 等)[l] function_name
:动态链接库中的函数function_name
:表示应用程序的业务函数$app_service
:火焰图最顶层的节点,名字为进程名- 除此之外,当函数名未成功翻译时,可能显示为如下几种形式之一
[/tmp/perf-29887.map]
:方括号中为进程号 29887 的 Java 进程符号文件名,函数地址未能在该文件中找到。Java 进程符号文件会自动周期性生成,此时一般由于该符号文件生成时该函数尚未加载导致。[/lib/ld-musl-x86_64.so.1]
:方括号中为动态链接库的文件路径(带有so
),函数地址属于该文件但未能成功翻译,一般是符号表被裁剪导致。[/usr/local/bin/kube-apiserver]
:方括号中为可执行文件的路径,函数地址属于该文件但未能成功翻译,一般是符号表被裁剪导致。[unknown] 0x0000000003932388
:除上述所有情况以外,当某个地址无法成功翻译为函数名时显示如此。特别地,当火焰图第三层函数地址(一般是线程的入口函数)未能翻译为函数名时,显示为[unknown start_thread?]
。
- function_values: 函数的 CPU 时长,单位是微秒(us)。
- node_values: 函数作为节点的 CPU 时长,单位是微秒(us)。
- function_id:函数唯一标识
- parent_node_id:该函数的父节点在火焰图中的唯一标识
- total_value:该函数的 CPU 时长,单位是微秒(us)。
- On-CPU Profile:此值表示函数花费 CPU 的时长
- Off-CPU Profile:此值表示函数等待 CPU 的时长
- self_value:该函数作为叶子节点(最底层函数)的 CPU
净
时长,单位是微秒(us)。- On-CPU 和 Off-CPU 的差异同上
使用 API 的返回结果,可以绘制指定进程的 CPU 火焰图。
#2. 获取指定主机的 Profile
#2.1 Grafana Panel
在 app_service
中选择 Total
之后,Grafana 中的展示效果图如下(火焰图只有三层):
On-CPU - Host
#2.2 API
提示
当前仅 On-CPU Profile 支持查询主机的整体数据。
当请求参数携带 "app_service": "Total"
时,能够获取到名为 Total
的特殊 On-CPU Profile 数据,它是一台主机上所有进程的、精细到线程粒度的 Profile。可用于当 On-CPU regex
未配置某个进程时,能够快速定位瓶颈进程和线程。此时的返回结果示例:
{
"OPT_STATUS": "SUCCESS",
"DESCRIPTION": "",
"result": {
"functions": [
"Total",
"[p] java",
// ...
"[t] DefaultTimer10-"
],
"function_types": [
"H",
"P",
// ...
"T"
],
"function_values": {
"columns": ["self_value", "total_value"],
"values": [
[0, 4563875153],
[4616160, 325630360],
// ...
[6565660, 6565660]
]
},
"node_values": {
"columns": ["function_id", "parent_node_id", "self_value", "total_value"],
"values": [
[0, -1, 0, 4563875153],
[1, 0, 4616160, 325630360],
// ...
[2, 1, 6565660, 6565660]
]
}
},
"debug": null
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
上述返回结果中 functions 的补充说明如下:
$app_service
:火焰图最顶层的节点,名字固定为 Total[p] name
:一个进程的名称[t] name
:一个线程的名称,它的父节点是一个[p] name
类型的节点,表示这个线程所属的进程
使用 API 的返回结果,可以绘制指定主机的 On-CPU 火焰图。
#3. 关于 Function Type
Function Type | 含义 | Profile Event Type | 特征 |
---|---|---|---|
O | 对象类型 | mem-* | Memory Profile 的叶子节点 |
H | 云主机 | * | 等于 Total 的根节点 |
P | 进程 | * | [p] 开头,以及不等于 Total 的根节点 |
T | 线程 | * | [t] 开头 |
K | 内核函数 | * | [k] 开头 |
C | CUDA 驱动函数 | * | [c] 开头 |
L | 动态链接库函数 | * | [l] 开头 |
? | 未知函数 | * | 其他 [ 开头 |
A | 应用函数 | * | 除以上之外的函数 |