為什么 Top node、Free、Grafana 的數(shù)據(jù)對不上,你知道嗎?
1. top 節(jié)點資源使用率超過 100%
kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
master-1 995m 16% 13760Mi 118%
master-2 827m 13% 10672Mi 92%
master-3 889m 14% 10244Mi 88%
這是由于在計算使用率時,默認(rèn)使用的是可分配的資源,排除了 Kubelet 保留的部分。在 kubectl 源碼中可以看到:
for _, n := range nodes {
if !o.ShowCapacity {
availableResources[n.Name] = n.Status.Allocatable
} else {
availableResources[n.Name] = n.Status.Capacity
}
}
如果需要查看節(jié)點總的資源使用情況,可添加 --show-capacity 參數(shù):
kubectl top node --show-capacity
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
master-1 1161m 14% 13822Mi 87%
master-2 998m 12% 10640Mi 67%
master-3 877m 10% 10298Mi 65%
實際上 Allocatable 和 Capacity 在節(jié)點對象上可以直接看到:
kubectl get node master-1 -oyaml
...
status:
allocatable:
cpu: "6"
ephemeral-storage: "284333649859"
hugepages-1Gi: "0"
hugepages-2Mi: "0"
memory: 11877928Ki
pods: "110"
capacity:
cpu: "8"
ephemeral-storage: 308521756Ki
hugepages-1Gi: "0"
hugepages-2Mi: "0"
memory: 16174632Ki
pods: "110"
在 Kubelet 的配置文件 /var/lib/kubelet/config.yaml 或者啟動命令參數(shù) --system-reserved=cpu=1,memory=2Gi --kube-reserved=cpu=1,memory=2Gi 可以查看具體的資源預(yù)留額度。詳情可以參考 https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/reserve-compute-resources/ 。
Allocatable = Capacity - Reserved - Evicted Threshold(驅(qū)逐容忍度),其中 Evicted Threshold 根據(jù)不同資源,通常為一個很小的數(shù)值或比例。
2. top node 與 Grafana 數(shù)據(jù)不一致
2.1 free 與 node_memory_Mem 同源
使用 free 查看節(jié)點資源使用情況如下:
free -h
total used free shared buff/cache available
Mem: 503Gi 62Gi 243Gi 12Gi 198Gi 426Gi
Swap: 0B 0B 0B
Grafana 節(jié)點資源使用情況如下:
圖片
使用的 PromQL 為:
- 總內(nèi)存, node_memory_MemTotal_bytes{instance=~\"$node\"}
- 已用, node_memory_MemTotal_bytes{instance=~\"$node\"} - node_memory_MemAvailable_bytes{instance=~\"$node\"}
從數(shù)值上看,free 與 Grafana 數(shù)據(jù)基本一致。
因為 Grafana 使用的 Node Exporter 采集的 node_memory_Mem 這些指標(biāo)來自主機的 /proc/meminfo 與 free -h 的數(shù)據(jù)同源。
2.2 top 使用的是 metrics-server 采集的指標(biāo)
top 查看節(jié)點資源使用情況
kubectl top node my-node-name
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
my-node-name 4809m 8% 132883Mi 25%
模擬 top 命令向 metrics-server 請求數(shù)據(jù):
kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes/my-node-name
{
"kind": "NodeMetrics",
"window": "10.292s",
"usage": {
"cpu": "5094380203n",
"memory": "136278224Ki"
}
}
這里的內(nèi)存使用量約 130 Gi,130 / 503 = 25.8% 與 kubectl top node 基本一致。
2.3 metrics-server 的數(shù)據(jù)來自 Kubelet
從 metrics-server 的源碼可以看到,其在請求 Kubelet 的數(shù)據(jù)。
func (kc *kubeletClient) GetMetrics(ctx context.Context, node *corev1.Node) (*storage.MetricsBatch, error) {
port := kc.defaultPort
path := "/metrics/resource"
nodeStatusPort := int(node.Status.DaemonEndpoints.KubeletEndpoint.Port)
if kc.useNodeStatusPort && nodeStatusPort != 0 {
port = nodeStatusPort
}
if metricsPath := node.Annotations[AnnotationResourceMetricsPath]; metricsPath != "" {
path = metricsPath
}
addr, err := kc.addrResolver.NodeAddress(node)
if err != nil {
return nil, err
}
url := url.URL{
Scheme: kc.scheme,
Host: net.JoinHostPort(addr, strconv.Itoa(port)),
Path: path,
}
return kc.getMetrics(ctx, url.String(), node.Name)
}
模擬 metrics-server 向 Kubelet 請求數(shù)據(jù)
kubectl get --raw /api/v1/nodes/my-node-name/proxy/metrics/resource |grep node_
# HELP node_cpu_usage_seconds_total [ALPHA] Cumulative cpu time consumed by the node in core-seconds
# TYPE node_cpu_usage_seconds_total counter
node_cpu_usage_seconds_total 1.2683530100816046e+08 1721957059813
# HELP node_memory_working_set_bytes [ALPHA] Current working set of the node in bytes
# TYPE node_memory_working_set_bytes gauge
node_memory_working_set_bytes 1.39524251648e+11 1721957059813
符合預(yù)期,請求 metrics-server 與 Kubelet API 提供的監(jiān)控數(shù)據(jù)相同。
2.4 node_memory_working_set_bytes 指標(biāo)有什么不同
- top 使用的是 node_memory_working_set_bytes,是 Kubelet 提供的指標(biāo)
包括當(dāng)前正在使用的內(nèi)存,活躍的緩存,不包括可以被立即回收的緩存、緩沖區(qū),主要是非活躍的文件緩存,其數(shù)據(jù)來源于 /sys/fs/cgroup。
- Grafana 使用的是 node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes,是 Node Exporter 提供的指標(biāo)
包括當(dāng)前正在使用的內(nèi)存,但不包括緩存,其數(shù)據(jù)來源于 /proc/meminfo。
前面可以看到 top 看到的內(nèi)存使用量大約為 130 Gi,而 Grafana 看到的內(nèi)存使用量大約是 77 Gi,相差 53 Gi 內(nèi)存存儲的就是一些不能立即被回收的緩存。但由于這兩種方式的數(shù)據(jù)源不同,無法對 53 Gi 進(jìn)行更詳細(xì)的分析。
2.5 Kubelet limit 使用的是 container_memory_working_set_bytes
對于 Pod 來說,通過 top 和 Grafana 看到的內(nèi)存使用量可能是相同的,因為,大部分 Grafana 面板繪制 Pod 內(nèi)存使用量用的是 container_memory_working_set_bytes,這與 top 的計算方式是一致的。
這里需要重點關(guān)注的是 Kubelet 會以哪個指標(biāo)驅(qū)逐 Pod? 答案是,container_memory_working_set_bytes 。
container_memory_working_set_bytes 更能代表容器的真實內(nèi)存使用量。
下面這張圖體現(xiàn)的是 container_memory_working_set_bytes (大約 18GiB) 與 container_memory_usage_bytes (大約 33GiB) 的區(qū)別。
圖片
3. 總結(jié)
本文采集數(shù)據(jù)的主機內(nèi)核版本為 5.4.0-48-generic,主要內(nèi)容如下:
- 因為 Kubelet 預(yù)留資源,top node 資源使用率可能超過 100%,使用 --show-capacity 可以看到總的資源使用情況
- 常用的節(jié)點資源使用率(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)/ node_memory_MemTotal_bytes ,因為忽略了活躍的緩存資源,所以使用率會比 top node 看到的低一些。上面例子大約是 Grafana 15% 使用率,top node 28% 的區(qū)別
- Kubelet 對 Pod 驅(qū)逐使用的是 container_memory_working_set_bytes,與 top pod 看到的內(nèi)存使用量相同