W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
FEATURE STATE: Kubernetes v1.22 [beta]
Kubernetes 內(nèi)存管理器(Memory Manager)為 ?Guaranteed
?QoS 類 的 Pods 提供可保證的內(nèi)存(及大頁面)分配能力。
內(nèi)存管理器使用提示生成協(xié)議來為 Pod 生成最合適的 NUMA 親和性配置。 內(nèi)存管理器將這類親和性提示輸入給中央管理器(即 Topology Manager)。 基于所給的提示和 Topology Manager(拓?fù)涔芾砥鳎┑牟呗栽O(shè)置,Pod 或者會(huì)被某節(jié)點(diǎn)接受,或者被該節(jié)點(diǎn)拒絕。
此外,內(nèi)存管理器還確保 Pod 所請(qǐng)求的內(nèi)存是從盡量少的 NUMA 節(jié)點(diǎn)分配而來。
內(nèi)存管理器僅能用于 Linux 主機(jī)。
你必須擁有一個(gè) Kubernetes 的集群,同時(shí)你的 Kubernetes 集群必須帶有 kubectl 命令行工具。 建議在至少有兩個(gè)節(jié)點(diǎn)的集群上運(yùn)行本教程,且這些節(jié)點(diǎn)不作為控制平面主機(jī)。 如果你還沒有集群,你可以通過 Minikube 構(gòu)建一個(gè)你自己的集群,或者你可以使用下面任意一個(gè) Kubernetes 工具構(gòu)建:
您的 Kubernetes 服務(wù)器必須是 v1.21 或更高版本。 要檢查版本,請(qǐng)輸入 ?kubectl version
?。
為了使得內(nèi)存資源與 Pod 規(guī)約中所請(qǐng)求的其他資源對(duì)齊:
從 v1.22 開始,內(nèi)存管理器通過 特性門控 ?MemoryManager
?默認(rèn)啟用。
在 v1.22 之前,?kubelet
?必須在啟動(dòng)時(shí)設(shè)置如下標(biāo)志:
?--feature-gates=MemoryManager=true
?
這樣內(nèi)存管理器特性才會(huì)被啟用。
內(nèi)存管理器目前為 Guaranteed QoS 類中的 Pod 提供可保證的內(nèi)存(和大頁面)分配能力。 若要立即將內(nèi)存管理器啟用,可參照本節(jié)的指南, 之后按本節(jié)中所展示的,準(zhǔn)備并部署一個(gè) ?Guaranteed
? Pod。
內(nèi)存管理器是一個(gè)提示驅(qū)動(dòng)組件(Hint Provider),負(fù)責(zé)為拓?fù)涔芾砥魈峁┩負(fù)涮崾荆?nbsp;后者根據(jù)這些拓?fù)涮崾緦?duì)所請(qǐng)求的資源執(zhí)行對(duì)齊操作。 內(nèi)存管理器也會(huì)為 Pods 應(yīng)用 ?cgroups
?設(shè)置(即 ?cpuset.mems
?)。 與 Pod 準(zhǔn)入和部署流程相關(guān)的完整流程圖在Memory Manager KEP: Design Overview 和下面。
在這個(gè)過程中,內(nèi)存管理器會(huì)更新其內(nèi)部存儲(chǔ)于節(jié)點(diǎn)映射和內(nèi)存映射中的計(jì)數(shù)器, 從而管理有保障的內(nèi)存分配。
內(nèi)存管理器在啟動(dòng)和運(yùn)行期間按下述邏輯更新節(jié)點(diǎn)映射(Node Map)。
當(dāng)節(jié)點(diǎn)管理員應(yīng)用 ?--reserved-memory
? 預(yù)留內(nèi)存標(biāo)志時(shí)執(zhí)行此邏輯。 這時(shí),節(jié)點(diǎn)映射會(huì)被更新以反映內(nèi)存的預(yù)留,如 Memory Manager KEP: Memory Maps at start-up (with examples) 所說明。
當(dāng)配置了 ?Static
?策略時(shí),管理員必須提供 ?--reserved-memory
? 標(biāo)志設(shè)置。
參考文獻(xiàn) Memory Manager KEP: Memory Maps at runtime (with examples) 中說明了成功的 Pod 部署是如何影響節(jié)點(diǎn)映射的,該文檔也解釋了可能發(fā)生的內(nèi)存不足 (Out-of-memory,OOM)情況是如何進(jìn)一步被 Kubernetes 或操作系統(tǒng)處理的。
在內(nèi)存管理器運(yùn)作的語境中,一個(gè)重要的話題是對(duì) NUMA 分組的管理。 每當(dāng) Pod 的內(nèi)存請(qǐng)求超出單個(gè) NUMA 節(jié)點(diǎn)容量時(shí),內(nèi)存管理器會(huì)嘗試創(chuàng)建一個(gè)包含多個(gè) NUMA 節(jié)點(diǎn)的分組,從而擴(kuò)展內(nèi)存容量。解決這個(gè)問題的詳細(xì)描述在文檔 Memory Manager KEP: How to enable the guaranteed memory allocation over many NUMA nodes? 中。同時(shí),關(guān)于 NUMA 分組是如何管理的,你還可以參考文檔 Memory Manager KEP: Simulation - how the Memory Manager works? (by examples)。
其他管理器也要預(yù)先配置。接下來,內(nèi)存管理器特性需要被啟用, 并且采用 ?Static
?策略(靜態(tài)策略)運(yùn)行。 作為可選操作,可以預(yù)留一定數(shù)量的內(nèi)存給系統(tǒng)或者 kubelet 進(jìn)程以增強(qiáng)節(jié)點(diǎn)的 穩(wěn)定性(預(yù)留內(nèi)存標(biāo)志)。
內(nèi)存管理器支持兩種策略。你可以通過 ?kubelet
?標(biāo)志 ?--memory-manager-policy
? 來 選擇一種策略:
None
?(默認(rèn))Static
?這是默認(rèn)的策略,并且不會(huì)以任何方式影響內(nèi)存分配。該策略的行為好像內(nèi)存管理器不存在一樣。
?None
?策略返回默認(rèn)的拓?fù)涮崾拘畔?。這種特殊的提示會(huì)表明拓?fù)潋?qū)動(dòng)組件(Hint Provider) (在這里是內(nèi)存管理器)對(duì)任何資源都沒有與 NUMA 親和性關(guān)聯(lián)的偏好。
對(duì) ?Guaranteed
?Pod 而言,?Static
?內(nèi)存管理器策略會(huì)返回拓?fù)涮崾拘畔?,該信?nbsp;與內(nèi)存分配有保障的 NUMA 節(jié)點(diǎn)集合有關(guān),并且內(nèi)存管理器還通過更新內(nèi)部的 節(jié)點(diǎn)映射 對(duì)象來完成內(nèi)存預(yù)留。
對(duì) ?BestEffort
?或 ?Burstable
?Pod 而言,因?yàn)椴淮嬖趯?duì)有保障的內(nèi)存資源的請(qǐng)求, ?Static
?內(nèi)存管理器策略會(huì)返回默認(rèn)的拓?fù)涮崾?,并且不?huì)通過內(nèi)部的節(jié)點(diǎn)映射對(duì)象 來預(yù)留內(nèi)存。
節(jié)點(diǎn)可分配機(jī)制通常 被節(jié)點(diǎn)管理員用來為 kubelet 或操作系統(tǒng)進(jìn)程預(yù)留 K8S 節(jié)點(diǎn)上的系統(tǒng)資源,目的是提高節(jié)點(diǎn)穩(wěn)定性。 有一組專用的標(biāo)志可用于這個(gè)目的,為節(jié)點(diǎn)設(shè)置總的預(yù)留內(nèi)存量。 此預(yù)配置的值接下來會(huì)被用來計(jì)算節(jié)點(diǎn)上對(duì) Pods “可分配的”內(nèi)存。
Kubernetes 調(diào)度器在優(yōu)化 Pod 調(diào)度過程時(shí),會(huì)考慮“可分配的”內(nèi)存。 前面提到的標(biāo)志包括 ?--kube-reserved
?、?--system-reserved
? 和 ?--eviction-threshold
?。 這些標(biāo)志值的綜合計(jì)作預(yù)留內(nèi)存的總量。
為內(nèi)存管理器而新增加的 ?--reserved-memory
? 標(biāo)志可以(讓節(jié)點(diǎn)管理員)將總的預(yù)留內(nèi)存進(jìn)行劃分, 并完成跨 NUMA 節(jié)點(diǎn)的預(yù)留操作。
標(biāo)志設(shè)置的值是一個(gè)按 NUMA 節(jié)點(diǎn)的不同內(nèi)存類型所給的內(nèi)存預(yù)留的值的列表,用逗號(hào)分開。 可以使用分號(hào)作為分隔符來指定跨多個(gè) NUMA 節(jié)點(diǎn)的內(nèi)存預(yù)留。 只有在內(nèi)存管理器特性被啟用的語境下,這個(gè)參數(shù)才有意義。 內(nèi)存管理器不會(huì)使用這些預(yù)留的內(nèi)存來為容器負(fù)載分配內(nèi)存。
例如,如果你有一個(gè)可用內(nèi)存為 10Gi 的 NUMA 節(jié)點(diǎn) "NUMA0",而參數(shù) ?--reserved-memory
? 被設(shè)置成要在 "NUMA0" 上預(yù)留 1Gi 的內(nèi)存,那么內(nèi)存管理器會(huì)假定節(jié)點(diǎn)上只有 9Gi 內(nèi)存可用于容器負(fù)載。
你也可以忽略此參數(shù),不過這樣做時(shí),你要清楚,所有 NUMA 節(jié)點(diǎn)上預(yù)留內(nèi)存的數(shù)量要等于 節(jié)點(diǎn)可分配特性 所設(shè)定的內(nèi)存量。如果至少有一個(gè)節(jié)點(diǎn)可分配參數(shù)值為非零,你就需要至少為一個(gè) NUMA 節(jié)點(diǎn)設(shè)置 ?--reserved-memory
?。實(shí)際上,?eviction-hard
? 閾值默認(rèn)為 100Mi, 所以當(dāng)使用 ?Static
?策略時(shí),?--reserved-memory
? 是必須設(shè)置的。
此外,應(yīng)盡量避免如下配置:
memory
?或 ?hugepages-<size>
? 的內(nèi)存類型名稱 (特定的 ?<size>
? 的大頁面也必須存在)。語法:
?--reserved-memory N:memory-type1=value1,memory-type2=value2,...
?
N
?(整數(shù))- NUMA 節(jié)點(diǎn)索引,例如,?0
?memory-type
?(字符串)- 代表內(nèi)存類型:memory
?- 常規(guī)內(nèi)存;hugepages-2Mi
? 或 ?hugepages-1Gi
? - 大頁面value
?(字符串) - 預(yù)留內(nèi)存的量,例如 ?1Gi
?用法示例:
?--reserved-memory 0:memory=1Gi,hugepages-1Gi=2Gi
?
或者
?--reserved-memory 0:memory=1Gi --reserved-memory 1:memory=2Gi
?
當(dāng)你為 ?--reserved-memory
? 標(biāo)志指定取值時(shí),必須要遵從之前通過節(jié)點(diǎn)可分配特性標(biāo)志所設(shè)置的值。 換言之,對(duì)每種內(nèi)存類型而言都要遵從下面的規(guī)則:
?sum(reserved-memory(i)) = kube-reserved + system-reserved + eviction-threshold
?
其中,?i
? 是 NUMA 節(jié)點(diǎn)的索引。
如果你不遵守上面的公示,內(nèi)存管理器會(huì)在啟動(dòng)時(shí)輸出錯(cuò)誤信息。
換言之,上面的例子我們一共要預(yù)留 ?3Gi
? 的常規(guī)內(nèi)存(?type=memory
?),即:
?sum(reserved-memory(i)) = reserved-memory(0) + reserved-memory(1) = 1Gi + 2Gi = 3Gi
?
下面的例子中給出與節(jié)點(diǎn)可分配配置相關(guān)的 kubelet 命令行參數(shù):
--kube-reserved=cpu=500m,memory=50Mi
?--system-reserved=cpu=123m,memory=333Mi
?--eviction-hard=memory.available<500Mi
?Note:
默認(rèn)的硬性驅(qū)逐閾值是 100MiB,不是零。 請(qǐng)記得在使用 ?--reserved-memory
? 設(shè)置要預(yù)留的內(nèi)存量時(shí),加上這個(gè)硬性驅(qū)逐閾值。 否則 kubelet 不會(huì)啟動(dòng)內(nèi)存管理器,而會(huì)輸出一個(gè)錯(cuò)誤信息。
下面是一個(gè)正確配置的示例:
--feature-gates=MemoryManager=true
--kube-reserved=cpu=4,memory=4Gi
--system-reserved=cpu=1,memory=1Gi
--memory-manager-policy=Static
--reserved-memory '0:memory=3Gi;1:memory=2148Mi'
我們對(duì)上面的配置做一個(gè)檢查:
kube-reserved + system-reserved + eviction-hard(default) = reserved-memory(0) + reserved-memory(1)
?4GiB + 1GiB + 100MiB = 3GiB + 2148MiB
?5120MiB + 100MiB = 3072MiB + 2148MiB
?5220MiB = 5220MiB
? (這是對(duì)的)若所選擇的策略不是 ?None
?,則內(nèi)存管理器會(huì)辨識(shí)處于 ?Guaranteed
?QoS 類中的 Pod。 內(nèi)存管理器為每個(gè) ?Guaranteed
?Pod 向拓?fù)涔芾砥魈峁┩負(fù)涮崾拘畔ⅰ?nbsp;對(duì)于不在 ?Guaranteed
?QoS 類中的其他 Pod,內(nèi)存管理器向拓?fù)涔芾砥魈峁┠J(rèn)的 拓?fù)涮崾拘畔ⅰ?
下面的來自 Pod 清單的片段將 Pod 加入到 ?Guaranteed
?QoS 類中。
當(dāng) Pod 的 CPU ?requests
?等于 ?limits
?且為整數(shù)值時(shí),Pod 將運(yùn)行在 ?Guaranteed
?QoS 類中。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "2"
example.com/device: "1"
requests:
memory: "200Mi"
cpu: "2"
example.com/device: "1"
此外,共享 CPU 的 Pods 在 ?requests
?等于 ?limits
?值時(shí)也運(yùn)行在 ?Guaranteed
?QoS 類中。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "300m"
example.com/device: "1"
requests:
memory: "200Mi"
cpu: "300m"
example.com/device: "1"
要注意的是,只有 CPU 和內(nèi)存請(qǐng)求都被設(shè)置時(shí),Pod 才會(huì)進(jìn)入 Guaranteed QoS 類。
下面的方法可用來排查為什么 Pod 無法被調(diào)度或者被節(jié)點(diǎn)拒絕:
這類錯(cuò)誤通常在以下情形出現(xiàn):
錯(cuò)誤信息會(huì)出現(xiàn)在 Pod 的狀態(tài)中:
kubectl get pods
NAME READY STATUS RESTARTS AGE
guaranteed 0/1 TopologyAffinityError 0 113s
使用 ?kubectl describe pod <id>
? 或 ?kubectl get events
? 可以獲得詳細(xì)的錯(cuò)誤信息。
Warning TopologyAffinityError 10m kubelet, dell8 Resources cannot be allocated with Topology locality
針對(duì)特定的 Pod 搜索系統(tǒng)日志。
內(nèi)存管理器為 Pod 所生成的提示信息可以在日志中找到。 此外,日志中應(yīng)該也存在 CPU 管理器所生成的提示信息。
拓?fù)涔芾砥鲗⑦@些提示信息進(jìn)行合并,計(jì)算得到唯一的最合適的提示數(shù)據(jù)。 此最佳提示數(shù)據(jù)也應(yīng)該出現(xiàn)在日志中。
最佳提示表明要在哪里分配所有的資源。拓?fù)涔芾砥鲿?huì)用當(dāng)前的策略來測(cè)試此數(shù)據(jù), 并基于得出的結(jié)論或者接納 Pod 到節(jié)點(diǎn),或者將其拒絕。
此外,你可以搜索日志查找與內(nèi)存管理器相關(guān)的其他條目,例如 ?cgroups
? 和 ?cpuset.mems
? 的更新信息等。
我們首先部署一個(gè) ?Guaranteed
?Pod 示例,其規(guī)約如下所示:
apiVersion: v1
kind: Pod
metadata:
name: guaranteed
spec:
containers:
- name: guaranteed
image: consumer
imagePullPolicy: Never
resources:
limits:
cpu: "2"
memory: 150Gi
requests:
cpu: "2"
memory: 150Gi
command: ["sleep","infinity"]
接下來,我們登錄到 Pod 運(yùn)行所在的節(jié)點(diǎn),檢查位于 ?/var/lib/kubelet/memory_manager_state
? 的狀態(tài)文件:
{
"policyName":"Static",
"machineState":{
"0":{
"numberOfAssignments":1,
"memoryMap":{
"hugepages-1Gi":{
"total":0,
"systemReserved":0,
"allocatable":0,
"reserved":0,
"free":0
},
"memory":{
"total":134987354112,
"systemReserved":3221225472,
"allocatable":131766128640,
"reserved":131766128640,
"free":0
}
},
"nodes":[
0,
1
]
},
"1":{
"numberOfAssignments":1,
"memoryMap":{
"hugepages-1Gi":{
"total":0,
"systemReserved":0,
"allocatable":0,
"reserved":0,
"free":0
},
"memory":{
"total":135286722560,
"systemReserved":2252341248,
"allocatable":133034381312,
"reserved":29295144960,
"free":103739236352
}
},
"nodes":[
0,
1
]
}
},
"entries":{
"fa9bdd38-6df9-4cf9-aa67-8c4814da37a8":{
"guaranteed":[
{
"numaAffinity":[
0,
1
],
"type":"memory",
"size":161061273600
}
]
}
},
"checksum":4142013182
}
從這個(gè)狀態(tài)文件,可以推斷 Pod 被同時(shí)綁定到兩個(gè) NUMA 節(jié)點(diǎn),即:
"numaAffinity":[
0,
1
],
術(shù)語綁定(pinned)意味著 Pod 的內(nèi)存使用被(通過 ?cgroups
?配置)限制到 這些 NUMA 節(jié)點(diǎn)。
這也直接意味著內(nèi)存管理器已經(jīng)創(chuàng)建了一個(gè) NUMA 分組,由這兩個(gè) NUMA 節(jié)點(diǎn)組成, 即索引值分別為 ?0
? 和 ?1
? 的 NUMA 節(jié)點(diǎn)。
注意 NUMA 分組的管理是有一個(gè)相對(duì)復(fù)雜的管理器處理的,相關(guān)邏輯的進(jìn)一步細(xì)節(jié)可在內(nèi)存管理器的 KEP 中示例1和跨 NUMA 節(jié)點(diǎn)節(jié)找到。
為了分析 NUMA 組中可用的內(nèi)存資源,必須對(duì)分組內(nèi) NUMA 節(jié)點(diǎn)對(duì)應(yīng)的條目進(jìn)行匯總。
例如,NUMA 分組中空閑的“常規(guī)”內(nèi)存的總量可以通過將分組內(nèi)所有 NUMA 節(jié)點(diǎn)上空閑內(nèi)存加和來計(jì)算,即將 NUMA 節(jié)點(diǎn) ?0
? 和 NUMA 節(jié)點(diǎn) ?1
? 的 ?"memory"
? 節(jié) (分別是 ?"free":0
? 和 ?"free": 103739236352
?)相加,得到此分組中空閑的“常規(guī)” 內(nèi)存總量為 ?0 + 103739236352
? 字節(jié)。
?"systemReserved": 3221225472
? 這一行表明節(jié)點(diǎn)的管理員使用 ?--reserved-memory
? 為 NUMA 節(jié)點(diǎn) ?0
? 上運(yùn)行的 kubelet 和系統(tǒng)進(jìn)程預(yù)留了 ?3221225472
?字節(jié) (即 ?3Gi
?)。
通過使用此 API, 可以獲得每個(gè)容器的預(yù)留內(nèi)存信息,該信息位于 protobuf 協(xié)議的 ?ContainerMemory
?消息中。 只能針對(duì) Guaranteed QoS 類中的 Pod 來檢索此信息。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: