提升資源利用率
1.1資源浪費場景
資源預留普遍存在 50% 以上的浪費Kubernetes中的請求字段用于管理容器的CPU和內存資源預留的機制,并確保容器至少可以達到資源量,不能被其他容器搶占。詳情請見(https://kubernetes . io/docs/concepts/configuration/manage-resources-containers/)。當請求設置過小時,服務的資源量無法保證,當服務的負載變高時,無法承載。因此,用戶通常習慣于將要求設置得很高,以保證服務的可靠性。
但實際上,大部分時間段的業務負荷都不會很高。以CPU為例,下圖是一個容器在實際業務場景下的資源預留(Request)和實際使用(CPU_Usage)的關系:資源預留遠大于實際使用,兩者的差額所對應的資源無法被其他負載使用,因此Request的過度設置必然會造成資源的極大浪費。
img如何解決這樣的問題?目前用戶需要根據實際負載情況設置一個更合理的請求,限制服務對資源的無限制請求,防止資源被某些服務過度占用。稍后您可以在此處參考請求配額和限制范圍的設置。
2. 業務資源波峰波谷現象普遍,通常波谷時間大于波峰時間,資源浪費明顯的大多數企業都有高峰和低谷。例如,公共交通系統的負荷通常在白天增加,在晚上減少。生意通常在周五晚上開始達到高峰,周日晚上開始達到高峰。
如下圖所示,同一個服務在不同的時間段對資源有不同的請求。如果用戶設置了固定的請求,那么在負載較低時,服務利用率很低。
此時,img可以動態調整副本數量,以承載資源利用率高的業務的峰谷??梢詤⒖糼8s提供的HPA 。。
3.不同類型的業務,導致資源利用率有較大差異的在線業務通常在白天負載很高,需要很高的時延,因此必須先進行調度并運行。而離線計算服務通常需要相對較低的運行時間和時延,理論上可以運行在在線服務的峰值。另外,有些業務是計算密集型的,消耗更多的CPU資源,有些業務是內存密集型的,消耗更多的內存。
如上圖所示,img可以在離線mix中動態調度離線服務和在線服務,讓不同類型的服務在不同時間段運行,提高資源利用率。對于計算密集型業務和內存密集型業務,可以使用親和調度為業務分配更合適的節點,對于特定的業務場景,可以通過污點/容忍策略隔離部分節點,有效提高資源利用率。
1.2提高資源利用率的方法
主要從兩個方面:一是利用原生的Kubernetes能力,手動劃分和限制資源;二是結合業務特點的自動化方案。簡要介紹了利用k8s原生能力對資源的劃分和限制。
1.2.1 如何資源劃分和限制
假設你是一個集群管理員,現在有四個業務部門在使用同一個集群。你的責任是保證業務穩定,讓業務真正做到按需使用資源。為了有效地提高集群的整體資源利用率,需要限制每個業務使用的資源上限。
,以及通過一些默認值防止業務過量使用。理想情況下,業務應該根據實際情況,設置合理的 Request 和 Limit。(Request 用于對資源的占位,表示容器至少可以獲得的資源;Limit 用于對資源的限制,表示容器至多可以獲得的資源。)這樣更利于容器的健康運行、資源的充分使用。但實際上用戶經常忘記設置容器對資源的 Request 和 Limit。此外,對于共享使用一個集群的團隊/項目來說,他們通常都將自己容器的 Request 和 Limit 設置得很高以保證自己服務的穩定性。
Request | Limit | |
---|---|---|
CPU(核) | 0.25 | 0.5 |
Memory(MiB) | 256 | 1024 |
為了更細粒度的劃分和管理資源,可以設置命名空間級別的 Resource Quota 以及 Limit Ranges。
1.2.2 使用 Resource Quota 劃分資源
如果你管理的某個集群有4個業務,為了實現業務間的隔離和資源的限制,你可以使用命名空間和 Resource Quota
Resource Quota 用于設置命名空間資源的使用配額,命名空間是 Kubernetes 集群里面的一個隔離分區,一個集群里面通常包含多個命名空間,例如 Kubernetes 用戶通常會將不同的業務放在不同的命名空間里,你可以為不同的命名空間設置不同的 Resource Quota,以限制一個命名空間對集群整體資源的使用量,達到預分配和限制的效果。Resource Quota 主要作用于如下方面,具體可查看(https://kubernetes.io/docs/concepts/policy/resource-quotas/)。
計算資源:所有容器對 CPU 和 內存的 Request 以及 Limit 的總和
存儲資源:所有 PVC 的存儲資源請求總和
對象數量:PVC/Service/Configmap/Deployment等資源對象數量的總和
Resource Quota 使用場景
- 給不同的項目/團隊/業務分配不同的命名空間,通過設置每個命名空間資源的 Resource Quota 以達到資源分配的目的
- 設置一個命名空間的資源使用數量的上限以提高集群的穩定性,防止一個命名空間對資源的過度侵占和消耗
這里提供一個腳本,來為集群各命名空間設置初始的Resource Quota
「說明」:該腳本借助kubectl-view-allocations 插件獲取集群各個命名空間當前所有pod所設置的request和limit總和,然后在此基礎之上上浮30%用于設置命名空間的request和limit Resource Quota。
后續可通過集群具體情況,調整對應配置。
使用說明:
wget https://my-repo-1255440668.cos.ap-chengdu.myqcloud.com/ops/ResourceQuota-install.tar.gz
tar -xvf ResourceQuota-install.tar.gz
cd ResourceQuota-install && bash install.sh
執行完之后,會在當前目錄生成一個resourceQuota目錄和limitrange目錄,里面包含各個命名空間的ResourceQuota.yaml文件,便于后續根據集群實際情況,進行對應調整,調整之后再根據需要進行apply

【注意】:如果命名空間request和limit總和超過了所設置的resourceQuota,那么將無法新建pod,而且設置了resourceQuota后,pod必須配置“limits.cpu,limits.memory,requests.cpu,requests.memory”,否則也無法正常部署,查看event會提示如下報錯:

同時可通過監控查看該ns的的資源使用情況是否合理,調整原有各pod的request和limit,以及根據情況調整所設置的resourceQuota。
CI配置reques和limit的方式如下:
- yaml渲染配置如下(其中resources字段):
【推薦配置】:
java服務:request和limit配置同樣的值
golang/python服務:request和limit配置為1:2
#推薦配置:
#java服務:request和limit配置同樣的值
#golang/python服務:request和limit配置為1:2
resources:
cpu: 500/1000m
memory: 500/1000Mi
1.2.3 使用 Limit Ranges 限制資源
用戶經常忘記設置資源的 Request 和 Limit,或者將值設置得很大怎么辦?作為管理員,如果可以為不同的業務設置不同資源使用默認值以及范圍,可以有效減少業務創建時的工作量同時,限制業務對資源的過度侵占。
與 Resource Quota 對命名空間整體的資源限制不同,Limit Ranges 適用于一個命名空間下的單個容器??梢苑乐褂脩粼诿臻g內創建對資源申請過小或過大容器,防止用戶忘記設置容器的 Request 和 Limit。Limit Ranges 主要作用于如下方面,具體可查看(https://kubernetes.io/zh/docs/concepts/policy/resource-quotas/)。
計算資源:對所有容器設置 CPU 和內存使用量的范圍
存儲資源:對所有 PVC 能申請的存儲空間的范圍
比例設置:控制一種資源 Request 和 Limit 之間比例
默認值:對所有容器設置默認的 Request/Limit,如果容器未指定自己的內存請求和限制,將為它指定默認的內存請求和限制
Limit Ranges 使用場景
設置資源使用默認值,以防用戶遺忘,也可以避免 QoS 驅逐重要的 Pod
不同的業務通常運行在不同的命名空間里,不同的業務通常資源使用情況不同,為不同的命名空間設置不同的 Request/Limit 可以提升資源利用率
限制容器對資源使用的上下限,保證容器正常運行的情況下,限制其請求過多資源
1.2.4 調度策略
Kubernetes 調度機制是 Kubernetes 原生提供的一種高效優雅的資源分配機制,它的核心功能是為每個 Pod 找到最適合它的節點,通過合理利用 Kubernetes 提供的調度能力,根據業務特性配置合理的調度策略,也能有效提高集群中的資源利用率。
1.2.4.1 節點親和性
- 說明
倘若你的某個業務是 CPU 密集型,不小心被 Kubernetes 的調度器調度到內存密集型的節點上,導致內存密集型的 CPU 被占滿,但內存幾乎沒怎么用,會造成較大的資源浪費。如果你能為節點設置一個標記,表明這是一個 CPU 密集型的節點,然后在創建業務負載時也設置一個標記,表明這個負載是一個 CPU 密集型的負載,Kubernetes 的調度器會將這個負載調度到 CPU 密集型的節點上,這種尋找最合適的節點的方式,將有效提升資源利用率。
創建 Pod 時,可以設置節點親和性,即指定 Pod 想要調度到哪些節點上(這些節點是通過 K8s Label)來指定的。
2. 節點親和性使用場景節點親和性非常適合在一個集群中有不同資源需求的工作負載同時運行的場景。比如說,k8s集群節點有 CPU 密集型的機器,也有內存密集型的機器。如果某些業務對 CPU 的需求遠大于內存,此時使用普通的 節點 機器,勢必會對內存造成較大浪費。此時可以在集群里添加一批 CPU 密集型的 節點,并且把這些對 CPU 有較高需求的 Pod 調度到這些 節點上,這樣可以提升 節點 資源的整體利用率。同理,還可以在集群中管理異構節點(比如 GPU 機器),在需要 GPU 資源的工作負載中指定需要GPU資源的量,調度機制則會幫助你尋找合適的節點去運行這些工作負載。
1.2.4.2 Taints和Tolerations(污點和容忍)
- 說明
我們說到的的NodeAffinity節點親和性,是在pod上定義的一種屬性,使得Pod能夠被調度到某些node上運行。Taint剛好相反,它讓Node拒絕Pod的運行。
Taint需要與Toleration配合使用,讓pod避開那些不合適的node。在node上設置一個或多個Taint后,除非pod明確聲明能夠容忍這些“污點”,否則無法在這些node上運行。Toleration是pod的屬性,讓pod能夠(注意,只是能夠,而非必須)運行在標注了Taint的node上。
創建 Pod 時,可以通過設置Taints和Tolerations,來讓某些node只允許某些特定的pod
- Taints和Tolerations場景
- 節點獨占。
如果想要拿出一部分節點,專門給特定的應用使用,則可以為節點添加這樣的Taint:
kubectl taint nodes nodename dedicated=groupName:NoSchedule
然后給這些應用的pod加入相應的toleration,則帶有合適toleration的pod就會被允許同使用其他節點 一樣使用有taint的節點。然后再將這些node打上指定的標簽,再通過nodeSelector或者親和性調度的方式,要求這些pod必須運行在指定標簽的節點上。
- 具有特殊硬件設備的節點
在集群里,可能有一小部分節點安裝了特殊的硬件設備,比如GPU芯片。用戶自然會希望把不需要占用這類硬件的pod排除在外。以確保對這類硬件有需求的pod能夠順利調度到這些節點上??梢允褂孟旅娴拿顬楣濣c設置taint:
kubectl taint nodes nodename special=true:NoSchedule
kubectl taint nodes nodename special=true:PreferNoSchedule
然后在pod中利用對應的toleration來保障特定的pod能夠使用特定的硬件。然后同樣的,我們也可以使用標簽或者其他的一些特征來判斷這些pod,將其調度到這些特定硬件的服務器上
- 應對節點故障
在節點故障時,可以通過TaintBasedEvictions功能自動將節點設置Taint,然后將pod驅逐。但是在一些場景下,比如說網絡故障造成的master與node失聯,而這個node上運行了很多本地狀態的應用即使網絡故障,也仍然希望能夠持續在該節點上運行,期望網絡能夠快速恢復,從而避免從這個node上被驅逐。Pod的Toleration可以這樣定義:
tolerations:
- key: "node.alpha.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 6000
K8s集群穩定性提升手段,有很多,提升資源利用率只是某一種,后續還會繼續輸出其他手段的應用,還請持續關注,未完待續。。。