Kubernetes支持以Request和Limit的形式來描述容器內存資源需求,應用的內存性能會受到多種因素影響,例如Page Cache回收、其他容器的過度使用,甚至引發節點資源不足而導致整機OOM,影響服務質量。ack-koordinator提供容器內存QoS功能,支持根據優先級為容器設置服務質量參數,可以在確保內存資源公平性的前提下,優先保障高優先級應用的性能。
為了幫助您更好地理解本文檔并使用本功能,推薦您參見Kubernetes官方文檔了解Pod Qos類、為容器和 Pod 分配內存資源等概念。
功能介紹
為什么需要容器內存QoS
在Kubernetes集群,為了確保工作負載Pod能夠高效、安全地運行,Kubernetes在資源使用層面引入了資源請求Request和資源限制Limit模型,容器內存情況如下圖所示。
內存Request(requests.memory):作用于調度階段,以確保為Pod找到一個具有足夠資源的合適節點。
內存Limit(requests.memory):在單個節點層面進行約束,限制Pod內存使用總量,對應cgroup文件參數memory.limit_in_bytes,表示內存使用上限。
容器在使用內存時,其服務質量會受自身用量以及節點用量兩個方面的影響。
自身內存限制:當Pod自身的內存使用(含Page Cache)接近聲明的Limit值時,會觸發內存子系統(Memcg)級別的直接內存回收,阻塞進程執行。如果此時的內存申請速度超過回收速度,容器會因觸發OOM而被異常終止。
節點內存限制:容器的Limit參數可以高于Request。當多個容器部署在同一節點上時,可能會導致容器內存Limit之和超出節點物理總量。當整機內存用量較高時,同樣會觸發內存資源回收,影響應用性能,甚至在資源不足時,應用會因整機OOM而被異常終止。
功能特性
為了提高應用運行時性能和節點的穩定性,ack-koordinator組件結合不同Alibaba Cloud Linux內核版本提供了容器內存QoS保障的能力,支持依據Pod參數自動配置內存子系統(Memcg),為容器開啟Memcg QoS、Memcg后臺異步回收、Memcg全局最低水位線分級等特性,以保障容器的內存資源QoS和公平性。
容器內存回收及保障策略
容器的內存QoS包括多個cgroup參數配置,具體情況如下圖所示。
memory.limit_in_bytes:內存使用上限。
memory.high:內存限流閾值。
memory.wmark_high:內存后臺回收閾值。
memory.min:內存使用鎖定閾值。
關于參數的詳細介紹及配置說明,請參見下文高級參數配置。
通過啟用容器內存QoS,您可以獲得以下功能特性。
Pod內存使用接近Limit限制時,優先在后臺異步回收一部分內存,緩解直接內存回收帶來的性能影響。
Pod之間實施更公平的內存回收。當整機內存資源不足時,優先從內存超用的Pod中回收內存,避免個別Pod造成整機內存資源質量下降。
整機資源回收時,優先保障延時敏感型LS(Latency-Sensitive)Pod,即Guaranteed、Burstable Pod的內存運行質量。
靈活配置、多環境適配
Kubernetes在社區1.22版本中提供的容器內存QoS(Memory QoS)特性,僅支持cgroup v2接口,您需要在kubelet上手動配置開啟,啟用后會對所有節點上的所有容器生效,無法進行更細粒度的配置。相比之下,ack-koordinator的容器內存QoS功能有以下能力優化。
結合Alibaba Cloud Linux,相比社區額外提供內存后臺回收、最低水位線分級等QoS增強能力,并自適應兼容cgroup v1和cgroup v2接口。更多關于ACK容器內存QoS啟用的內核能力,請參見Alibaba Cloud Linux的內核功能與接口概述。
支持通過Pod Annotation或ConfigMap實現指定Pod維度的、集群全局維度的或者命名空間維度的容器內存QoS配置,更加靈活,使用簡單。
前提條件
已創建ACK集群,且符合以下條件:
已安裝ack-koordinator組件,且版本為0.8.0及以上。具體操作,請參見ack-koordinator(ack-slo-manager)。
費用說明
ack-koordinator組件本身的安裝和使用是免費的,不過需要注意的是,在以下場景中可能產生額外的費用:
ack-koordinator是非托管組件,安裝后將占用Worker節點資源。您可以在安裝組件時配置各模塊的資源申請量。
ack-koordinator默認會將資源畫像、精細化調度等功能的監控指標以Prometheus的格式對外透出。若您配置組件時開啟了ACK-Koordinator開啟Prometheus監控指標選項并使用了阿里云Prometheus服務,這些指標將被視為自定義指標并產生相應費用。具體費用取決于您的集群規模和應用數量等因素。建議您在啟用此功能前,仔細閱讀阿里云Prometheus計費說明,了解自定義指標的免費額度和收費策略。您可以通過賬單和用量查詢,監控和管理您的資源使用情況。
操作步驟
當您為Pod開啟容器內存QoS時,內存cgroup參數將基于系數配置和Pod參數自適應調整。您可以參見下文,在單個Pod維度、集群全局維度或集群下命名空間維度開啟容器內存QoS并配置相關參數。
通過Annotation為指定Pod配置
您可以在Pod YAML中添加以下Annotation,為Pod單獨開啟容器內存QoS功能,僅針對指定Pod生效。
annotations:
# 設置為auto,表示開啟該Pod的容器內存QoS功能。
koordinator.sh/memoryQOS: '{"policy": "auto"}'
# 設置為none,表示關閉該Pod的容器內存QoS功能。
koordinator.sh/memoryQOS: '{"policy": "none"}'
通過ConfigMap在集群維度配置
您可以通過ConfigMap配置,在集群維度開啟容器內存QoS,針對集群全局生效。您可以根據應用特征,使用koordinator.sh/qosClass
來統一管理內存QoS參數,在Pod Labelkoordinator.sh/qosClass
配置Pod的QoS級別為LS
或BE
等級,無需通過Pod Annotation重復配置。
參見以下示例創建ConfigMap,開啟全集群的容器內存QoS功能。
apiVersion: v1 data: resource-qos-config: |- { "clusterStrategy": { "lsClass": { "memoryQOS": { "enable": true } }, "beClass": { "memoryQOS": { "enable": true } } } } kind: ConfigMap metadata: name: ack-slo-config namespace: kube-system
在Pod YAML中指定QoS等級為
LS
或BE
。說明如果Pod中沒有指定
koordinator.sh/qosClass
,ack-koordinator將參考Pod原生的QoSClass來設置參數,其中Guaranteed
為系統內部默認值,Burstable和Besteffort分別使用ConfigMap中LS
和BE
的默認配置。apiVersion: v1 kind: Pod metadata: name: pod-demo labels: koordinator.sh/qosClass: 'LS' # 指定Pod的QoS級別為LS。
查看命名空間
kube-system
下是否存在ConfigMapack-slo-config
。存在:使用PATCH方式進行更新,避免干擾ConfigMap中其他配置項。
kubectl patch cm -n kube-system ack-slo-config --patch "$(cat configmap.yaml)"
不存在:執行以下命令創建ConfigMap。
kubectl apply -f configmap.yaml
(可選)參見下文高級參數配置配置高級參數。
通過ConfigMap在NameSpace維度配置
若您需要開啟或關閉部分命名空間下LS
和BE
Pod的參數設置,可以參見以下流程,為指定Namespace內的Pod開啟或禁用容器內存QoS功能,在命名空間級別生效。
參見以下示例創建ConfigMap,開啟全集群的容器內存QoS功能。
apiVersion: v1 data: resource-qos-config: |- { "clusterStrategy": { "lsClass": { "memoryQOS": { "enable": true } }, "beClass": { "memoryQOS": { "enable": true } } } } kind: ConfigMap metadata: name: ack-slo-config namespace: kube-system
使用以下ConfigMap內容,創建ack-slo-pod-config.yaml文件。
下方代碼以為命名空間kube-system為例,展示如何開啟或禁用kube-system中Pod的容器內存QoS功能。
apiVersion: v1 kind: ConfigMap metadata: name: ack-slo-pod-config namespace: koordinator-system # 首次使用時需要先手動創建該Namespace data: # 單獨開啟或關閉部分Namespace的Pod。 memory-qos: | { "enabledNamespaces": ["allow-ns"], "disabledNamespaces": ["block-ns"] }
執行以下命令,更新ConfigMap。
kubectl patch cm -n kube-system ack-slo-pod-config --patch "$(cat ack-slo-pod-config.yaml)"
(可選)參見下文高級參數配置配置高級參數。
高級參數配置
容器內存QoS支持Pod級別和集群級別的精細化配置,對于同時支持在Pod Annotation和ConfigMap配置的參數,Pod Annotation配置優先級大于ConfigMap配置。如果Pod Annotation中沒有對應配置,ack-koordinator會進一步參考ConfigMap中的配置。
相關參數說明如下。
Annotation和ConfigMap兩列分別代表是否允許通過Pod Annotation或ConfigMap進行配置。其中,代表支持,代表不支持。
參數 | 類型 | 取值范圍 | 說明 | Pod Annotation | ConfigMap |
| Boolean |
|
| ||
| String |
|
| ||
| Int | 0~100 | 單位為百分比,默認值為 表示相較于內存Request,容器內存絕對鎖定、不被全局回收的比例。計算方式為 | ||
| Int | 0~100 | 單位為百分比,默認值為 表示相較于內存Request,容器內存相對鎖定、優先不被回收的比例。計算方式為 | ||
| Int | 0~100 | 單位為百分比,默認值為 表示相較于內存Limit,容器內存使用觸發限流的比例。計算方式為 | ||
| Int | 0~100 | 單位為百分比,默認值為 表示相較于內存Limit和 | ||
| Int | -25~50 | 單位為百分比,默認值依據QoS, 表示相較于(整機)全局內存最低水位線,容器所做出調整的比例。負數值讓容器更晚進入全局內存回收,正數值讓容器更早進入全局內存回收。例如,如果Pod的QoS等級為LS,按默認配置,最低水位線分級系數 |
使用示例
測試步驟
本示例使用以下評測環境進行測試,驗證在內存超賣場景下,關閉或開啟ACK容器內存QoS時,示例應用的時延和吞吐性能表現差異。
使用ACK集群Pro版。
集群內包含兩個節點:壓測節點(規格為8 Core 32 GB)、測試節點(規格為8 Core 32 GB)。
使用以下YAML內容,創建redis-demo.yaml文件。
apiVersion: v1 kind: ConfigMap metadata: name: redis-demo-config data: redis-config: | appendonly yes appendfsync no --- apiVersion: v1 kind: Pod metadata: name: redis-demo labels: koordinator.sh/qosClass: 'LS' # 指定Redis實例的QoS級別為LS。 annotations: koordinator.sh/memoryQOS: '{"policy": "auto"}' # 增加容器內存QoS的配置。 spec: containers: - name: redis image: redis:5.0.4 command: - redis-server - "/redis-master/redis.conf" env: - name: MASTER value: "true" ports: - containerPort: 6379 resources: limits: cpu: "2" memory: "6Gi" requests: cpu: "2" memory: "2Gi" volumeMounts: - mountPath: /redis-master-data name: data - mountPath: /redis-master name: config volumes: - name: data emptyDir: {} - name: config configMap: name: redis-demo-config items: - key: redis-config path: redis.conf nodeName: # nodeName需修改為測試節點的nodeName。 --- apiVersion: v1 kind: Service metadata: name: redis-demo spec: ports: - name: redis-port port: 6379 protocol: TCP targetPort: 6379 selector: name: redis-demo type: ClusterIP
執行以下命令,部署Redis Server作為目標評測應用。
您可通過Service redis-demo進行集群內訪問。
kubectl apply -f redis-demo.yaml
模擬內存超賣場景。
使用Stress工具制造較大的節點內存壓力,觸發系統內存回收,節點上已分配Pod的內存Limit之和已超過整機大小。
使用以下Pod YAML內容,創建stress-demo.yaml文件。
apiVersion: v1 kind: Pod metadata: name: stress-demo labels: koordinator.sh/qosClass: 'BE' # 指定Stress實例的QoS級別為BE。 annotations: koordinator.sh/memoryQOS: '{"policy": "auto"}' # 增加Memory QoS功能的配置。 spec: containers: - args: - '--vm' - '2' - '--vm-bytes' - 11G - '-c' - '2' - '--vm-hang' - '2' command: - stress image: polinux/stress imagePullPolicy: Always name: stress restartPolicy: Always nodeName: # nodeName需修改為測試節點的nodeName,與Redis的節點相同。
使用以下命令,部署stress-demo。
kubectl apply -f stress-demo.yaml
使用以下命令,查看系統的全局最低水位線。
說明由于系統的全局最低水位線較低,對于內存超賣場景可能來不及回收就觸發整機OOM,因此通常配合較高的全局最低水位線使用。以內存32 GiB的測試機為例,設置最低水位線為4000000 KB。
cat /proc/sys/vm/min_free_kbytes
預期輸出:
4000000
在Pod YAML中,使用memtier-benchmark壓測工具發送請求。
apiVersion: v1 kind: Pod metadata: labels: name: memtier-demo name: memtier-demo spec: containers: - command: - memtier_benchmark - '-s' - 'redis-demo' - '--data-size' - '200000' - "--ratio" - "1:4" image: 'redislabs/memtier_benchmark:1.3.0' name: memtier restartPolicy: Never nodeName: # nodeName需修改為壓測節點的nodeName。
使用以下命令,收集memtier-benchmark測試結果。
kubectl logs -f memtier-demo
在Pod YAML中,通過修改Redis實例和Stress實例的Pod Annotation,測試不同配置下的性能結果。
apiVersion: v1 kind: Pod metadata: name: redis-demo labels: koordinator.sh/qosClass: 'LS' annotations: koordinator.sh/memoryQOS: '{"policy": "none"}' # 配置關閉容器內存QoS。 spec: ... --- apiVersion: v1 kind: Pod metadata: name: stress-demo labels: koordinator.sh/qosClass: 'BE' annotations: koordinator.sh/memoryQOS: '{"policy": "none"}' # 配置關閉容器內存QoS。
結果分析
當功能全部關閉或開啟ACK容器內存QoS時,指標的數據結果如下。
全部關閉:不開啟容器內存QoS,Pod配置為
none
。開啟容器內存QoS:Pod配置為
auto
,全部使用自適應配置。
以下結果數據僅為理論值(參考值),實際數據以您的操作環境為準。
指標 | 全部關閉 | 開啟容器內存QoS |
| 51.32 ms | 47.25 ms |
| 149.0 MB/s | 161.9 MB/s |
由對比數據可得,在內存超賣場景下,開啟容器內存QoS后,Redis應用的時延(Latency)下降了7.9%,吞吐(Throughput)上漲了8.7%,時延和吞吐指標都得到一定的改善。
FAQ
當前已經通過ack-slo-manager的舊版本協議使用了容器內存QoS功能,升級為ack-koordinator后是否繼續支持容器內存QoS功能?
舊版本(≤0.8.0)的Pod協議包括兩部分。
在Pod的Annotation中填寫
alibabacloud.com/qosClass
。在Pod的Annotation中填寫
alibabacloud.com/memoryQOS
。
ack-koordinator保持了對以上舊版本協議的兼容,您可以將組件無縫升級至ack-koordinator。ack-koordinator將對以上舊版本協議兼容至2023年7月30日,我們建議您將原協議資源字段及時升級到新版本。
ack-koordinator各版本對內存QoS功能的適配如下。
組件版本 | alibabacloud.com協議 | koordinator.sh協議 |
≥0.3.0且<0.8.0 | 支持 | 不支持 |
≥0.8.0 | 支持 | 支持 |