作者 观测云 高级技术专家 深圳办公室 黄小龙
简介
Profile 通过收集和分析应用程序运行过程中 CPU、内存和 I/O 相关的数据,可以识别应用程序的性能瓶颈和错误,帮助我们更好地了解程序的运行情况。Profile 是一种非常有价值的技术,通过 Profile 可以实现:
- 识别性能瓶颈: Profiling 可以帮助发现程序的性能瓶颈,即程序中最耗费时间的部分。通过识别性能瓶颈,以便我们采取措施来优化这部分性能。
- 优化程序性能: 通过 Profiling 收集的数据,我们可以知道程序的哪些部分需要进行优化。通过优化这些部分,可以提高程序的性能,减少资源的消耗。
- 排查程序错误: 在应用程序中,有时会出现各种错误。通过 Profiling 分析程序的运行情况,我们可以找到错误的原因,并及时进行修复。
利用**观测云**可以快速收集应用程序 Profile 数据,利用 Profile 火焰图查看器分析 Java 、Python 、 Go 不同语言环境下应用程序运行过程中的动态性能数据,直观 地 查看每一个方法、类和线程的调用关系和执行效率。通过关联链路,获取链路相关 Span 的关联代码执行片段,实现方法级代码性能追踪,帮助开发人员发现代码优化方向。
收集应用程序 Profile 数据,会对应用程序本身性能造成一定的影响,所以一般情况下不建议在生产环境实时启动 Profile 数据收集,在 Kubernetes 部署的应用程序可以通过动态开关打开 Profile 数据采集,从而实现对应用程序的关键问题定位。
前置条件
安装 DataKit
登录观测云控制台,选择「集成」-「DataKit」-「Kubernetes」,按照所提示的安装步骤下载 datakit.yaml
,并配置 DataWay 数据网关地址。
打开 Profile 采集器
修改 datakit.yaml
文件,ConfigMap 加入 Profile 采集配置:
apiVersion: v1
kind: ConfigMap
metadata:
name: datakit-conf
namespace: datakit
data:
profile.conf: |-
[[inputs.profile]]
## profile Agent endpoints register by version respectively.
## Endpoints can be skipped listen by remove them from the list.
## Default value set as below. DO NOT MODIFY THESE ENDPOINTS if not necessary.
endpoints = ["/profiling/v1/input"]
## set true to enable election, pull mode only
election = true
## go pprof config
## collect profiling data in pull mode
#[[inputs.profile.go]]
## pprof url
#url = "http://localhost:6060"
## pull interval, should be greater or equal than 10s
#interval = "10s"
## service name
#service = "go-demo"
## app env
#env = "dev"
## app version
#version = "0.0.0"
## types to pull
## values: cpu, goroutine, heap, mutex, block
#enabled_types = ["cpu","goroutine","heap","mutex","block"]
#[inputs.profile.go.tags]
# tag1 = "val1"
## pyroscope config
#[[inputs.profile.pyroscope]]
## listen url
#url = "0.0.0.0:4040"
## service name
#service = "pyroscope-demo"
## app env
#env = "dev"
## app version
#version = "0.0.0"
#[inputs.profile.pyroscope.tags]
#tag1 = "val1"
DaemonSet 添加相应的挂载配置:
volumeMounts:
- mountPath: /usr/local/datakit/conf.d/profile/profile.conf
name: datakit-conf
subPath: profile.conf
修改完成之后,安装 datakit.yaml
配置:
kubectl apply -f datakit.yaml
应用配置
本文以 Java 应用程序为例,介绍如何动态开关打开 Profile 数据采集。
安装 Datakit Operator
Datakit-Operator 通过 K8s 的 Admission Controller(准入控制器)功能,会向指定的 Pod 注入应用程序启动所需要的 dd-lib
探针文件,这样就不需要应用程序打包镜像时加入对应的探针文件,减少配置从而提高效率。
下载 datakit-operator.yaml
文件并执行安装:
wget https://static.guance.com/datakit-operator/datakit-operator.yaml
kubectl apply -f datakit-operator.yaml
通过以下命令验证所有配置是否安装完成,正常会有 datakit 和 datakit-operator 两种类型的 Pod:
kubectl get pod -n datakit
修改 Dockerfile
修改应用 Dockerfile,暴露启动参数:
注意: java版本要求:java8版本需要高于8u262+,或者使用java11及以上版本。
FROM openjdk:8u292
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
ENV jar my-service.jar
ENV workdir /data/app/
RUN mkdir -p ${workdir}
COPY ${jar} ${workdir}
WORKDIR ${workdir}
ENTRYPOINT ["sh", "-ec", "exec java ${JAVA_OPTS} -jar ${jar} ${PARAMS} 2>&1 > /dev/null"]
应用部署 yaml
添加以下环境变量,通过 ENV_PROFILE
环境变量来动态控制 Profile 数据采集:
env:
- name: DD_AGENT_HOST
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.hostIP
- name: ENABLE_PROFILE
value: "true"
- name: JAVA_OPTS
value: |-
-javaagent:/datadog-lib/dd-java-agent.jar -Ddd.service=my-service -Ddd.profiling.enabled=$(ENABLE_PROFILE) -Ddd.profiling.allocation.enabled=$(ENABLE_PROFILE) -Ddd.env=env -Ddd.agent.port=9529
添加 annotation,位置 spec.template.metadata
下:
annotations:
admission.datakit/java-lib.version: ""
生产环境部署时,ENV_PROFILE
环境变量可以设置为 false
,需要排查性能问题时,再打开 Profile 开关收集数据,从而实现动态采集 Profile 数据的功能。
完整 yaml 参考:
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: profile
labels:
app: my-service
spec:
selector:
app: my-service
ports:
- protocol: TCP
port: 9299
nodePort: 30001
targetPort: 9299
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-service
namespace: profile
labels:
app: my-service
spec:
replicas: 1
selector:
matchLabels:
app: my-service
template:
metadata:
labels:
app: my-service
annotations:
admission.datakit/java-lib.version: ""
spec:
containers:
- name: my-container
env:
- name: DD_AGENT_HOST
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.hostIP
- name: ENABLE_PROFILE
value: "true"
- name: JAVA_OPTS
value: |-
-javaagent:/datadog-lib/dd-java-agent.jar -Ddd.service=my-service -Ddd.profiling.enabled=$(ENABLE_PROFILE) -Ddd.profiling.allocation.enabled=$(ENABLE_PROFILE) -Ddd.env=env -Ddd.agent.port=9529
image: my-service:v1.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9299
protocol: TCP
restartPolicy: Always