优化Kubernetes横向扩缩HPA
Pod水平自動擴縮(Horizontal Pod Autoscaler, 簡稱HPA)可以基于 CPU/MEM 利用率自動擴縮Deployment、StatefulSet 中的 Pod 數量,同時也可以基于其他應程序提供的自定義度量指標來執行自動擴縮。默認HPA可以滿足一些簡單場景,對于生產環境并不一定適合,本文主要分析HPA的不足與優化方式。
HPA Resource類型不足
默認HPA提供了Resource類型,通過CPU/MEM使用率指標(由metrics-server提供原始指標)來擴縮應用。
使用率計算方式
在Resource類型中,使用率計算是通過request而不是limit,源碼如下:
// 獲取Pod resource request func calculatePodRequests(pods []*v1.Pod, resource v1.ResourceName) (map[string]int64, error) {requests := make(map[string]int64, len(pods))for _, pod := range pods {podSum := int64(0)for _, container := range pod.Spec.Containers {if containerRequest, ok := container.Resources.Requests[resource]; ok {podSum += containerRequest.MilliValue()} else {return nil, fmt.Errorf("missing request for %s", resource)}}requests[pod.Name] = podSum}return requests, nil } // 計算使用率 func GetResourceUtilizationRatio(metrics PodMetricsInfo, requests map[string]int64, targetUtilization int32) (utilizationRatio float64, currentUtilization int32, rawAverageValue int64, err error) {metricsTotal := int64(0)requestsTotal := int64(0)numEntries := 0for podName, metric := range metrics {request, hasRequest := requests[podName]if !hasRequest {// we check for missing requests elsewhere, so assuming missing requests == extraneous metricscontinue}metricsTotal += metric.ValuerequestsTotal += requestnumEntries++}currentUtilization = int32((metricsTotal * 100) / requestsTotal)return float64(currentUtilization) / float64(targetUtilization), currentUtilization, metricsTotal / int64(numEntries), nil }通常在Paas平臺中會對資源進行超配,limit即用戶請求資源,request即實際分配資源,如果按照request來計算使用率(會超過100%)是不符合預期的。相關issue見72811,目前還存在爭論。可以修改源碼,或者使用自定義指標來代替。
多容器Pod使用率問題
默認提供的Resource類型的HPA,通過上述方式計算資源使用率,核心方式如下:
metricsTotal = sum(pod.container.metricValue) requestsTotal = sum(pod.container.Request) currentUtilization = int32((metricsTotal * 100) / requestsTotal)計算出所有container的資源使用量再比總的申請量,對于單容器Pod這沒影響。但對于多容器Pod,比如Pod包含多個容器con1、con2(request都為1cpu),con1使用率10%,con2使用率100%,HPA目標使用率60%,按照目前方式得到使用率為55%不會進行擴容,但實際con2已經達到資源瓶頸,勢必會影響服務質量。當前系統中,多容器Pod通常都是1個主容器與多個sidecar,依賴主容器的指標更合適點。
好在1.20版本中已經支持了ContainerResource可以配置基于某個容器的資源使用率來進行擴縮,如果是之前的版本建議使用自定義指標替換。
性能問題
單線程架構
默認的hpa-controller是單個Goroutine執行的,隨著集群規模的增多,勢必會成為性能瓶頸,目前默認hpa資源同步周期會15s,假設每個metric請求延時為100ms,當前架構只能支持150個HPA資源(保證在15s內同步一次)
func (a *HorizontalController) Run(stopCh <-chan struct{}) {// ...// start a single worker (we may wish to start more in the future)go wait.Until(a.worker, time.Second, stopCh)<-stopCh }可以通過調整worker數量來橫向擴展,已提交PR。
調用鏈路
在hpa controller中一次hpa資源同步,需要調用多次apiserver接口,主要鏈路如下
尤其在獲取metrics value時,需要先調用apiserver,apiserver調用metrics-server/custom-metrics-server,當集群內存在大量hpa時可能會對apiserver性能產生一定影響。
其他
對于自定義指標用戶需要實現custom.metrics.k8s.io或external.metrics.k8s.io,目前已經有部分開源實現見custom-metrics-api。
另外,hpa核心的擴縮算法根據當前指標和期望指標來計算擴縮比例,并不適合所有場景,只使用線性增長的指標。
期望副本數 = ceil[當前副本數 * (當前指標 / 期望指標)]watermarkpodautoscaler提供了更靈活的擴縮算法,比如平均值、水位線等,可以作為參考。
總結
Kubernetes提供原生的HPA只能滿足一部分場景,如果要上生產環境,必須對其做一些優化,本文總結了當前HPA存在的不足,例如在性能、使用率計算方面,并提供了解決思路。
總結
以上是生活随笔為你收集整理的优化Kubernetes横向扩缩HPA的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Arduino实验三十五 声音传感器
- 下一篇: python最适合做什么生意好-本周互联