云原生 Profiling:零侵入、随用随取的动态采集实战

    背景

    应用在运行过程中,开启性能分析(Profiling)通常是诊断性能瓶颈、内存泄漏和线程问题的关键手段。然而,持续开启 Profiling 会带来显著的性能开销(可能达 5%-20%),并可能生成大量数据,影响生产环境稳定性。动态开启 Profiling 允许开发或运维人员按需、实时地启动/停止数据收集,实现以下目标:

    1. 降低持续开销:仅在需要时启用,避免长期性能损耗;
    2. 精准问题定位:针对特定时段(如流量高峰或故障期间)进行分析;
    3. 在线诊断:无需重启应用即可获取生产环境实时性能快照;
    4. 灵活控制:可结合监控指标(如 CPU 飙升)自动触发,或在安全审计时手动开启。

    通过动态控制,实现了观测能力与系统负载的平衡,保障了关键业务场景的效率和稳定性。

    Flameshot

    Flameshot 是一个基于 Sidecar 模式运行的轻量级自动性能剖析(Profiling)工具。它通过监控目标进程的资源使用情况(CPU/内存),在达到预设阈值时自动触发底层 Profiler(如 async-profiler ),从而实现无侵入的现场快照采集。

    Flameshot 采用 Sidecar 容器 模式部署。它必须与业务主容器(Main Container)运行在同一个 Pod 中,并开启 PID 命名空间共享。

    1. 监控 (Monitor):Flameshot 持续轮询主容器内目标进程的资源水位。
    2. 触发 (Trigger):当满足阈值(如 CPU > 80%)或收到 HTTP API 请求时,触发采集任务。
    3. 执行 (Execute):根据配置的语言类型(目前支持 Java),调用对应的 Profiler 工具 attach 到目标进程。
    4. 收集 (Collect):生成的 Profile 文件(如 .jfr )存储于共享卷中,随后上传至数据观测中心。

    观测云 datakit-operator1.7.0 版本开始支持工具 flameshots,实现动态开启应用 Profiling。

    实践

    当前在 K8S 环境上部署 JAVA 应用,当 CPU、内存使用率达到 20%(演示方便)则触发 Profiling 数据采集。

    前提条件

    • 观测云帐号
    • K8S 环境

    DataKit

    DataKit 主要是用来采集数据并上报观测云。

    1. 下载 & 安装

    wget https://static.guance.com/datakit/datakit.yaml
    

    2. 配置 datakit.yaml

    配置 DataWay 数据网关地址

    name: ENV_DATAWAY
    value: https://openway.guance.com?token=tkn_xxxxx
    

    DataKit 会默认开启主机相关采集器,这里需要追加 pyroscope

    name: ENV_DEFAULT_ENABLED_INPUTS
    value: cpu,disk,diskio,mem,swap,system,hostobject,net,host_processes,container,pyroscope
    

    3. 启动

    调整完配置后,启动 DataKit

    root@root:~$ kubectl apply -f datakit.yaml
    root@root:~$ kubectl get pods -n datakit
    NAME                                READY   STATUS    RESTARTS   AGE
    datakit-4zg7q                       1/1     Running   0          14h
    datakit-wdtdq                       1/1     Running   0          14h
    

    DataKit Operator

    1. 下载

    下载最新的 datakit-operator.yaml

    wget https://static.guance.com/datakit-operator/datakit-operator.yaml
    

    2. 配置 datakit-operator.yaml

    主要调整 jsonconfig 下的 flameshots 内容,参考如下:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: datakit-operator-config
      namespace: datakit
    data:
      jsonconfig: |-
        {
            "server_listen": "0.0.0.0:9543",
            "log_level":     "info",
            "admission_inject_v2": {
                ...
                "flameshots": [
                    {
                        "namespace_selectors": ["default"],
                        "label_selectors":     [],
                        "image": "pubrepo.jiagouyun.com/datakit/flameshot:0.1.1",
                        "envs": {
                            "FLAMESHOT_DATAKIT_ADDR":     "http://datakit-service.datakit.svc:9529/profiling/v1/input",
                            "FLAMESHOT_MONITOR_INTERVAL": "1s",
                            "FLAMESHOT_PROFILING_PATH":   "/flameshot-data",
                            "FLAMESHOT_HTTP_LOCAL_IP":    "{fieldRef:status.podIP}",
                            "FLAMESHOT_HTTP_LOCAL_PORT":  "8089",
                            "FLAMESHOT_SERVICE":          "{fieldRef:metadata.labels['app']}",
                            "POD_NAME":                "{fieldRef:metadata.name}",
                            "POD_NAMESPACE":           "{fieldRef:metadata.namespace}",
                            "NODE_NAME":               "{fieldRef:spec.nodeName}",
                            "FLAMESHOT_TAGS":          "pod_name:$(POD_NAME),pod_namespace:$(POD_NAMESPACE),host:$(NODE_NAME)"
                            
                        },
                        "resources": {
                            "requests": {
                                "cpu":    "100m",
                                "memory": "128Mi"
                            },
                            "limits": {
                               "cpu":    "200m",
                               "memory": "256Mi"
                            }
                        },
                        "processes": "[{\"command\":\"java\",\"duration\":\"60s\",\"events\":\"--all\",\"language\":\"java\",\"jdk_version\":\"-\",\"tags\":[\"env:testing\",\"version:1.0.0\"],\"cpu_usage_percent\":20,\"mem_usage_percent\":20,\"mem_usage_mb\":1024}]"
                    }
                ]
            },
            ...
        }
    

    参数说明:

    • namespace_selectors: 空间选择,即哪些空间需要开启 flameshots
    • env: 配置环境变量信息
    • processes: 执行命令,如果为空,则 flameshots 不生效

    processes 通用字段说明:

    • service (String): 选填,上报到观测中心的服务名称。
    • language (String): 目标进程语言。目前支持 java。
    • command (String): 匹配进程命令行的正则表达式。
    • duration (String): 单次采集时长(例如 30s1m)。注意:受限于执行超时,建议不超过 5 分钟。
    • tags (List): 自定义标签列表,建议包含 envversion 等元信息。
    • cpu_usage_percent (Int): CPU 触发阈值 (0-N)。多核环境下数值可能超过 100。
    • mem_usage_percent (Int): 内存使用率触发阈值 (0-100)。
    • mem_usage_mb (Int): 内存使用量绝对值触发阈值 (MB)。

    当前配置 processes 可以实现所有 JAVA 服务,为了实践方便,当 cpu 使用率达到 20% 或内存使用率达到 20% 或内存使用值达到 1024m,则会触发执行 Profiling 操作。

    "processes": "[{\"command\":\"java\",\"duration\":\"60s\",\"events\":\"--all\",\"language\":\"java\",\"jdk_version\":\"-\",\"tags\":[\"env:testing\",\"version:1.0.0\"],\"cpu_usage_percent\":20,\"mem_usage_percent\":20,\"mem_usage_mb\":1024}]"
    

    3. 启动

    root@root:~$ kubectl apply -f datakit-operator.yaml
    root@root:~$ kubectl get pods -n datakit
    NAME                                READY   STATUS    RESTARTS   AGE
    datakit-4zg7q                       1/1     Running   0          15h
    datakit-operator-849f868b78-zbcd9   1/1     Running   0          58s
    datakit-wdtdq                       1/1     Running   0          15h
    

    JAVA 应用

    1. Yaml 配置

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: springboot-server
    spec:
      selector:
        matchLabels:
          app: springboot-server
      replicas: 1
      template:
        metadata:
          labels:
            app: springboot-server
        spec:
          containers:
            - image: registry.cn-shenzhen.aliyuncs.com/lr_715377484/springboot-server:flameshots
              name: springboot-server
              imagePullPolicy: IfNotPresent
              ports:
                - containerPort:  8080
                  protocol: TCP
    
              securityContext:
                seccompProfile:
                  type: Unconfined
    

    2. 启动应用

    root@root:~$  kubectl apply -f springboot-server.yaml
    root@root:~$ kubectl get pods
    NAME                                READY   STATUS    RESTARTS   AGE
    springboot-server-d55fc79dd-48c95   2/2     Running   0          3s
    

    3. 查看 flameshot 执行日志

    需要指定 containerName 为 -c datakit-flameshot

    root@root:~$ kubectl logs -f springboot-server-d55fc79dd-48c95 -c datakit-flameshot
    2026-01-15T03:55:58.090Z        ERROR        flameshot        flameshot/config.go:243        read config file failed, err:open /flameshot/flameshot.conf: no such file or directory
    2026-01-15T03:55:58.092Z        INFO        flameshot        flameshot/monitor.go:78        start monitor, interval: 1s
    2026-01-15T03:55:58.092Z        INFO        flameshot        flameshot/http.go:77        start http server on 10.187.217.101:8089
    2026-01-15T03:55:58.092Z        INFO        flameshot        flameshot/http.go:78        profile start at /v1/profile
    2026-01-15T03:55:58.092Z        INFO        flameshot        flameshot/http.go:79        prom http start at /metrics
    2026-01-15T03:56:58.093Z        INFO        flameshot        flameshot/monitor.go:102        match: PID=7, name=java or cmd=java -jar app.jar
    

    从启动日志上分析,已经找到了 java 服务,且 PID 为 7,等待触发事件

    4. 触发阈值

    访问应用

    root@root:~$ kubectl exec -it springboot-server-d55fc79dd-48c95  -- /bin/bash 
    Defaulted container "springboot-server" out of: springboot-server, datakit-flameshot
    springboot-server-d55fc79dd-48c95:/home/app#
    springboot-server-d55fc79dd-48c95:/home/app# curl http://localhost:8080/profiling/generator
    write success!springboot-server-d55fc79dd-48c95:/home/app# 
    

    再来看看 flameshot 执行日志,已触发了阈值 cpu_avg:36.60 且正常上报数据。

    之后恢复了正常,正常之后则不会再产生 Profiling 数据,除非再次触发了阈值。

    观测云平台

    登录观测云平台,访问「应用性能检测」-「Profling」可以查看到刚刚上报的 Profling 信息

    点击列表可以查看 Profling 详细信息,如 CPU 耗时、内存分配情况等,可以更深度的剖析应用代码性能损耗。

    联系我们

    加入社区

    微信扫码
    加入官方交流群

    立即体验

    在线开通,按量计费,真正的云服务!

    立即开始

    选择观测云版本

    代码托管平台