理解压力停顿信息 (PSI) 指标

详细解释了压力暂停信息 (PSI) 指标以及如何使用它们来识别 Kubernetes 中的资源压力。
特性状态: Kubernetes v1.34 [beta]

作为一项 Beta 功能,Kubernetes 允许您配置 kubelet 以收集 CPU、内存和 I/O 使用情况的 Linux 内核 压力暂停信息 (PSI)。这些信息在节点、Pod 和容器级别进行收集。此功能默认通过设置 KubeletPSI 功能门 来启用。

PSI 指标通过两种不同的来源暴露

  • kubelet 的 Summary API,它在节点、Pod 和容器级别提供 PSI 数据。
  • kubelet 上的 /metrics/cadvisor 端点,它以 Prometheus 格式公开 PSI 指标。

要求

压力暂停信息在您的 Linux 节点上需要以下条件

  • Linux 内核必须是 4.20 或更高版本
  • 内核必须使用 CONFIG_PSI=y 选项编译。大多数现代发行版默认启用此选项。您可以通过运行 zgrep CONFIG_PSI /proc/config.gz 来检查您的内核配置。
  • 某些 Linux 发行版可能将 PSI 编译到内核中,但默认禁用它。如果是这种情况,您需要在启动时通过将 psi=1 参数添加到内核命令行来启用它。
  • 节点必须使用 cgroup v2

了解 PSI 指标

压力暂停信息 (PSI) 指标针对三种资源提供:CPU、内存和 I/O。它们被分为两种主要类型的压力:“some”和“full”。

  • some:此值表示一个或多个任务在某个资源上被暂停。例如,如果某些任务正在等待 I/O,此指标将增加。这可以是资源争用的早期迹象。
  • full:此值表示所有非空闲任务同时在某个资源上被暂停。这表示更严重的资源短缺,整个系统无法取得进展。

每种压力类型提供四种指标:“avg10”、“avg60”、“avg300”和“total”。avg 值表示任务在 10 秒、60 秒和 3 分钟的移动平均值中被暂停的实际挂钟时间的百分比。total 值是一个以微秒为单位的累积计数器,显示任务被暂停的总时间。

示例场景

您可以使用一个简单的 Pod 和一个压力测试工具来生成资源压力并观察 PSI 指标。以下示例使用 agnhost 容器镜像,其中包含 stress 工具。

生成 CPU 压力

创建一个使用 stress 实用程序生成 CPU 压力的 Pod。此工作负载将对一个 CPU 核心施加重载。

创建一个名为 cpu-pressure-pod.yaml 的文件

apiVersion: v1
kind: Pod
metadata:
  name: cpu-pressure-pod
spec:
  restartPolicy: Never
  containers:
  - name: cpu-stress
    image: registry.k8s.io/e2e-test-images/agnhost:2.47
    args:
    - "stress"
    - "--cpus"
    - "1"
    resources:
      limits:
        cpu: "500m"
      requests:
        cpu: "500m"

将其应用于您的集群:kubectl apply -f cpu-pressure-pod.yaml

观察 CPU 压力

Pod 运行后,您可以通过 Summary API 或 Prometheus 指标端点来观察 CPU 压力。

使用 Summary API

观察您节点的摘要统计信息。在另一个终端中,运行

# Replace <node-name> with the name of a node in your cluster
kubectl get --raw "/api/v1/nodes/<node-name>/proxy/stats/summary" | jq '.pods[] | select(.podRef.name | contains("cpu-pressure-pod"))'

您将在 Summary API 输出中看到 CPU 的 some PSI 指标增加。some 压力值的 avg10 应该上升到零以上,表明任务在 CPU 上花费了暂停时间。

使用 Prometheus 指标端点

查询 /metrics/cadvisor 端点以查看 container_pressure_cpu_waiting_seconds_total 指标。

# Replace <node-name> with the name of the node where the pod is running
kubectl get --raw "/api/v1/nodes/<node-name>/proxy/metrics/cadvisor" | \
    grep 'container_pressure_cpu_waiting_seconds_total{container="cpu-stress"'

输出应显示一个不断增长的值,表明容器花费了时间等待 CPU 资源。

清理

完成后清理 Pod

kubectl delete pod cpu-pressure-pod

生成内存压力

此示例创建一个不断向容器可写层中的文件写入内容的 Pod,导致内核的页面缓存增长并强制进行内存回收,从而产生压力。

创建一个名为 memory-pressure-pod.yaml 的文件

apiVersion: v1
kind: Pod
metadata:
  name: memory-pressure-pod
spec:
  restartPolicy: Never
  containers:
  - name: memory-stress
    image: registry.k8s.io/e2e-test-images/agnhost:2.47
    command: ["/bin/sh", "-c"]
    args:
    - "i=0; while true; do dd if=/dev/zero of=testfile.$i bs=1M count=50 &>/dev/null; i=$(((i+1)%5)); sleep 0.1; done"
    resources:
      limits:
        memory: "200M"
      requests:
        memory: "200M"

将其应用于您的集群:kubectl apply -f memory-pressure-pod.yaml

观察内存压力

使用 Summary API

在摘要输出中,您将观察到内存的 full PSI 指标增加,这表明系统正承受着巨大的内存压力。

# Replace <node-name> with the name of a node in your cluster
kubectl get --raw "/api/v1/nodes/<node-name>/proxy/stats/summary" | jq '.pods[] | select(.podRef.name | contains("memory-pressure-pod"))'

使用 Prometheus 指标端点

查询 /metrics/cadvisor 端点以查看 container_pressure_memory_waiting_seconds_total 指标。

# Replace <node-name> with the name of the node where the pod is running
kubectl get --raw "/api/v1/nodes/<node-name>/proxy/metrics/cadvisor" | \
    grep 'container_pressure_memory_waiting_seconds_total{container="memory-stress"'

在输出中,您将观察到该指标的值不断增长,这表明系统正承受着巨大的内存压力。

清理

完成后清理 Pod

kubectl delete pod memory-pressure-pod

生成 I/O 压力

此 Pod 通过反复将文件写入磁盘并使用 sync 将数据从内存中刷新来生成 I/O 压力,这会产生 I/O 暂停。

创建一个名为 io-pressure-pod.yaml 的文件

apiVersion: v1
kind: Pod
metadata:
  name: io-pressure-pod
spec:
  restartPolicy: Never
  containers:
  - name: io-stress
    image: registry.k8s.io/e2e-test-images/agnhost:2.47
    command: ["/bin/sh", "-c"]
    args:
      - "while true; do dd if=/dev/zero of=testfile bs=1M count=128 &>/dev/null; sync; rm testfile &>/dev/null; done"

将其应用于您的集群:kubectl apply -f io-pressure-pod.yaml

观察 I/O 压力

使用 Summary API

随着 Pod 不断写入磁盘,您将看到 I/O 的 some PSI 指标增加。

# Replace <node-name> with the name of a node in your cluster
kubectl get --raw "/api/v1/nodes/<node-name>/proxy/stats/summary" | jq '.pods[] | select(.podRef.name | contains("io-pressure-pod"))'

使用 Prometheus 指标端点

查询 /metrics/cadvisor 端点以查看 container_pressure_io_waiting_seconds_total 指标。

# Replace <node-name> with the name of the node where the pod is running
kubectl get --raw "/api/v1/nodes/<node-name>/proxy/metrics/cadvisor" | \
    grep 'container_pressure_io_waiting_seconds_total{container="io-stress"'

随着 Pod 不断写入磁盘,您将看到该指标的值增加。

清理

完成后清理 Pod

kubectl delete pod io-pressure-pod

下一步

有关 集群故障排除的任务页面讨论了如何使用依赖于这些数据的指标管道。