Fluid給資料彈性一雙隱形的翅膀(1)- 自定義彈性伸縮

背景

隨著越來越多的大資料和AI等資料密集應用開始部署和執行在Kubernetes環境下,資料密集型應用計算框架的設計理念和雲原生靈活的應用編排的分歧,導致了資料訪問和計算瓶頸。雲原生資料編排引擎Fluid透過資料集的抽象,利用分散式快取技術,結合排程器,為應用提供了資料訪問加速的能力。

彈性伸縮作為Kubernetes的核心能力之一,但它一直是圍繞這無狀態的應用負載展開。而Fluid提供了分散式快取的彈性伸縮能力,可以靈活擴充和收縮資料快取。 它基於Runtime提供了快取空間、現有快取比例等效能指標, 結合自身對於Runtime資源的擴縮容能力,提供資料快取按需伸縮能力。

這個能力對於網際網路場景下大資料應用非常重要,由於多數的大資料應用都是透過端到端流水線來實現的。而這個流水線包含以下幾個步驟:

資料提取,利用Spark,MapReduce等大資料技術對於原始資料進行預處理

模型訓練,利用第一階段生成特徵資料進行機器學習模型訓練,並且生成相應的模型

模型評估,透過測試集或者驗證集對於第二階段生成模型進行評估和測試

模型推理,第三階段驗證後的模型最終推送到線上為業務提供推理服務

可以看到端到端的流水線會包含多種不同型別的計算任務,針對每一個計算任務,實踐中會有合適的專業系統來處理(TensorFlow,PyTorch,Spark, Presto);但是這些系統彼此獨立,通常要藉助外部檔案系統來實現把資料從一個階段傳遞到下一個階段。但是頻繁的使用檔案系統實現資料交換,會帶來大量的 I/O 開銷,經常會成為整個工作流的瓶頸。

而Fluid對於這個場景非常適合,使用者可以建立一個Dataset物件,這個物件有能力將資料分散快取到Kubernetes計算節點中,作為資料交換的介質,這樣避免了資料的遠端寫入和讀取,提升了資料使用的效率。但是這裡的問題是臨時資料快取的資源預估和預留。由於在資料生產消費之前,精確的資料量預估是比較難滿足,過高的預估會導致資源預留浪費,過低的預估會導致資料寫入失敗可能性增高。還是按需擴縮容對於使用者更加友好。我們希望能夠達成類似page cache的使用效果,對於終端使用者來說這一層是透明的但是它帶來的快取加速效果是實實在在的。

我們透過自定義HPA機制,透過Fluid引入了快取彈性伸縮能力。彈性伸縮的條件是當已有快取資料量達到一定比例時,就會觸發彈性擴容,擴容快取空間。例如將觸發條件設定為快取空間佔比超過75%,此時總的快取空間為10G,當資料已經佔滿到8G快取空間的時候,就會觸發擴容機制。

下面我們透過一個例子幫助您體驗Fluid的自動擴縮容能力。

前提條件

推薦使用Kubernetes 1。18以上,因為在1。18之前,HPA是無法自定義擴縮容策略的,都是透過硬編碼實現的。而在1。18後,使用者可以自定義擴縮容策略的,比如可以定義一次擴容後的冷卻時間。

具體步驟

1。安裝jq工具方便解析json,在本例子中我們使用作業系統是centos,可以透過yum安裝jq

yum install -y jq

2。下載、安裝Fluid最新版

git clone https://github。com/fluid-cloudnative/fluid。gitcd fluid/chartskubectl create ns fluid-systemhelm install fluid fluid

3。部署或配置 Prometheus

這裡透過Prometheus對於AlluxioRuntime的快取引擎暴露的 Metrics 進行收集,如果叢集內無 prometheus:

$ cd fluid$ kubectl apply -f integration/prometheus/prometheus。yaml

如叢集內有 prometheus,可將以下配置寫到 prometheus 配置檔案中:

scrape_configs: - job_name: ‘alluxio runtime’ metrics_path: /metrics/prometheus kubernetes_sd_configs: - role: endpoints relabel_configs: - source_labels: [__meta_kubernetes_service_label_monitor] regex: alluxio_runtime_metrics action: keep - source_labels: [__meta_kubernetes_endpoint_port_name] regex: web action: keep - source_labels: [__meta_kubernetes_namespace] target_label: namespace replacement: $1 action: replace - source_labels: [__meta_kubernetes_service_label_release] target_label: fluid_runtime replacement: $1 action: replace - source_labels: [__meta_kubernetes_endpoint_address_target_name] target_label: pod replacement: $1 action: replace

4。驗證 Prometheus 安裝成功

$ kubectl get ep -n kube-system prometheus-svcNAME ENDPOINTS AGEprometheus-svc 10。76。0。2:9090 6m49s$ kubectl get svc -n kube-system prometheus-svcNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEprometheus-svc NodePort 172。16。135。24none9090:32114/TCP 2m7s

如果希望視覺化監控指標,您可以安裝Grafana驗證監控資料,具體操作可以參考文件

5。部署 metrics server

檢查該叢集是否包括metrics-server, 執行kubectl top node有正確輸出可以顯示記憶體和CPU,則該叢集metrics server配置正確

kubectl top nodeNAME CPU(cores) CPU% MEMORY(bytes) MEMORY%192。168。1。204 93m 2% 1455Mi 10%192。168。1。205 125m 3% 1925Mi 13%192。168。1。206 96m 2% 1689Mi 11%

否則手動執行以下命令

kubectl create -f integration/metrics-server

6。部署 custom-metrics-api 元件

為了基於自定義指標進行擴充套件,你需要擁有兩個元件。第一個元件是從應用程式收集指標並將其儲存到Prometheus時間序列資料庫。第二個元件使用收集的度量指標來擴充套件Kubernetes自定義metrics API,即 k8s-prometheus-adapter。第一個元件在第三步部署完成,下面部署第二個元件:

如果已經配置了custom-metrics-api,在adapter的configmap配置中增加與dataset相關的配置

apiVersion: v1kind: ConfigMapmetadata: name: adapter-config namespace: monitoringdata: config。yaml: | rules: - seriesQuery: ‘{__name__=~“Cluster_(CapacityTotal|CapacityUsed)”,fluid_runtime!=“”,instance!=“”,job=“alluxio runtime”,namespace!=“”,pod!=“”}’ seriesFilters: - is: ^Cluster_(CapacityTotal|CapacityUsed)$ resources: overrides: namespace: resource: namespace pod: resource: pods fluid_runtime: resource: datasets name: matches: “^(。*)” as: “capacity_used_rate” metricsQuery: ceil(Cluster_CapacityUsed{。LabelMatchers}*100/(Cluster_CapacityTotal{。LabelMatchers}))

否則手動執行以下命令

kubectl create -f integration/custom-metrics-api/namespace。yamlkubectl create -f integration/custom-metrics-api

注意:因為custom-metrics-api對接叢集中的Prometheous的訪問地址,請替換prometheous url為你真正使用的Prometheous地址。

檢查自定義指標

$ kubectl get ——raw “/apis/custom。metrics。k8s。io/v1beta1” | jq{ “kind”: “APIResourceList”, “apiVersion”: “v1”, “groupVersion”: “custom。metrics。k8s。io/v1beta1”, “resources”: [ { “name”: “pods/capacity_used_rate”, “singularName”: “”, “namespaced”: true, “kind”: “MetricValueList”, “verbs”: [ “get” ] }, { “name”: “datasets。data。fluid。io/capacity_used_rate”, “singularName”: “”, “namespaced”: true, “kind”: “MetricValueList”, “verbs”: [ “get” ] }, { “name”: “namespaces/capacity_used_rate”, “singularName”: “”, “namespaced”: false, “kind”: “MetricValueList”, “verbs”: [ “get” ] } ]}

7。提交測試使用的Dataset

$ catEOFdataset。yamlapiVersion: data。fluid。io/v1alpha1kind: Datasetmetadata: name: sparkspec: mounts: - mountPoint: https://mirrors。bit。edu。cn/apache/spark/ name: spark——-apiVersion: data。fluid。io/v1alpha1kind: AlluxioRuntimemetadata: name: sparkspec: replicas: 1 tieredstore: levels: - mediumtype: MEM path: /dev/shm quota: 1Gi high: “0。99” low: “0。7” properties: alluxio。user。streaming。data。timeout: 300secEOF$ kubectl create -f dataset。yamldataset。data。fluid。io/spark createdalluxioruntime。data。fluid。io/spark created

8。檢視這個Dataset是否處於可用狀態, 可以看到該資料集的資料總量為2。71GiB, 目前Fluid提供的快取節點數為1,可以提供的最大快取能力為1GiB。此時資料量是無法滿足全量資料快取的需求。

$ kubectl get datasetNAME UFS TOTAL SIZE CACHED CACHE CAPACITY CACHED PERCENTAGE PHASE AGEspark 2。71GiB 0。00B 1。00GiB 0。0% Bound 7m38s

9。當該Dataset處於可用狀態後,檢視是否已經可以從custom-metrics-api獲得監控指標

kubectl get ——raw “/apis/custom。metrics。k8s。io/v1beta1/namespaces/default/datasets。data。fluid。io/*/capacity_used_rate” | jq{ “kind”: “MetricValueList”, “apiVersion”: “custom。metrics。k8s。io/v1beta1”, “metadata”: { “selfLink”: “/apis/custom。metrics。k8s。io/v1beta1/namespaces/default/datasets。data。fluid。io/%2A/capacity_used_rate” }, “items”: [ { “describedObject”: { “kind”: “Dataset”, “namespace”: “default”, “name”: “spark”, “apiVersion”: “data。fluid。io/v1alpha1” }, “metricName”: “capacity_used_rate”, “timestamp”: “2021-04-04T07:24:52Z”, “value”: “0” } ]}

10。建立 HPA任務

$ catEOFhpa。yamlapiVersion: autoscaling/v2beta2kind: HorizontalPodAutoscalermetadata: name: sparkspec: scaleTargetRef: apiVersion: data。fluid。io/v1alpha1 kind: AlluxioRuntime name: spark minReplicas: 1 maxReplicas: 4 metrics: - type: Object object: metric: name: capacity_used_rate describedObject: apiVersion: data。fluid。io/v1alpha1 kind: Dataset name: spark target: type: Value value: “90” behavior: scaleUp: policies: - type: Pods value: 2 periodSeconds: 600 scaleDown: selectPolicy: DisabledEOF

首先,我們解讀一下從樣例配置,這裡主要有兩部分一個是擴縮容的規則,另一個是擴縮容的靈敏度:

規則:觸發擴容行為的條件為Dataset物件的快取資料量佔總快取能力的90%; 擴容物件為AlluxioRuntime, 最小副本數為1,最大副本數為4; 而Dataset和AlluxioRuntime的物件需要在同一個namespace

策略: 可以K8s 1。18以上的版本,可以分別針對擴容和縮容場景設定穩定時間和一次擴縮容步長比例。比如在本例子, 一次擴容週期為10分鐘(periodSeconds),擴容時新增2個副本數,當然這也不可以超過 maxReplicas 的限制;而完成一次擴容後, 冷卻時間(stabilizationWindowSeconds)為20分鐘; 而縮容策略可以選擇直接關閉。

11。檢視HPA配置, 當前快取空間的資料佔比為0。遠遠低於觸發擴容的條件

$ kubectl get hpaNAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGEspark AlluxioRuntime/spark 0/90 1 4 1 33s$ kubectl describe hpaName: sparkNamespace: defaultLabels:noneAnnotations:noneCreationTimestamp: Wed, 07 Apr 2021 17:36:39 +0800Reference: AlluxioRuntime/sparkMetrics: ( current / target ) “capacity_used_rate” on Dataset/spark (target value): 0 / 90Min replicas: 1Max replicas: 4Behavior: Scale Up: Stabilization Window: 0 seconds Select Policy: Max Policies: - Type: Pods Value: 2 Period: 600 seconds Scale Down: Select Policy: Disabled Policies: - Type: Percent Value: 100 Period: 15 secondsAlluxioRuntime pods: 1 current / 1 desiredConditions: Type Status Reason Message —— ———— ———— ————- AbleToScale True ScaleDownStabilized recent recommendations were higher than current one, applying the highest recent recommendation ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from Dataset metric capacity_used_rate ScalingLimited False DesiredWithinRange the desired count is within the acceptable rangeEvents:none

12。建立資料預熱任務

$ catEOFdataload。yamlapiVersion: data。fluid。io/v1alpha1kind: DataLoadmetadata: name: sparkspec: dataset: name: spark namespace: defaultEOF$ kubectl create -f dataload。yaml$ kubectl get dataloadNAME DATASET PHASE AGE DURATIONspark spark Executing 15s Unfinished

13。此時可以發現快取的資料量接近了Fluid可以提供的快取能力(1GiB)同時觸發了彈性伸縮的條件

$ kubectl get datasetNAME UFS TOTAL SIZE CACHED CACHE CAPACITY CACHED PERCENTAGE PHASE AGEspark 2。71GiB 1020。92MiB 1。00GiB 36。8% Bound 5m15s

從HPA的監控,可以看到Alluxio Runtime的擴容已經開始, 可以發現擴容的步長為2

$ kubectl get hpaNAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGEspark AlluxioRuntime/spark 100/90 1 4 2 4m20s$ kubectl describe hpaName: sparkNamespace: defaultLabels:noneAnnotations:noneCreationTimestamp: Wed, 07 Apr 2021 17:56:31 +0800Reference: AlluxioRuntime/sparkMetrics: ( current / target ) “capacity_used_rate” on Dataset/spark (target value): 100 / 90Min replicas: 1Max replicas: 4Behavior: Scale Up: Stabilization Window: 0 seconds Select Policy: Max Policies: - Type: Pods Value: 2 Period: 600 seconds Scale Down: Select Policy: Disabled Policies: - Type: Percent Value: 100 Period: 15 secondsAlluxioRuntime pods: 2 current / 3 desiredConditions: Type Status Reason Message —— ———— ———— ————- AbleToScale True SucceededRescale the HPA controller was able to update the target scale to 3 ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from Dataset metric capacity_used_rate ScalingLimited False DesiredWithinRange the desired count is within the acceptable rangeEvents: Type Reason Age From Message —— ———— —— —— ————- Normal SuccessfulRescale 21s horizontal-pod-autoscaler New size: 2; reason: Dataset metric capacity_used_rate above target Normal SuccessfulRescale 6s horizontal-pod-autoscaler New size: 3; reason: Dataset metric capacity_used_rate above target

14。在等待一段時間之後發現數據集的快取空間由1GiB提升到了3GiB,資料快取已經接近完成

$ kubectl get datasetNAME UFS TOTAL SIZE CACHED CACHE CAPACITY CACHED PERCENTAGE PHASE AGEspark 2。71GiB 2。59GiB 3。00GiB 95。6% Bound 12m

同時觀察HPA的狀態,可以發現此時Dataset對應的runtime的replicas數量為3, 已經使用的快取空間比例capacity_used_rate為85%,已經不會觸發快取擴容。

$ kubectl get hpaNAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGEspark AlluxioRuntime/spark 85/90 1 4 3 11m

16。清理環境

kubectl delete hpa sparkkubectl delete dataset spark

總結

Fluid提供了結合Prometheous,Kubernetes HPA和Custom Metrics能力,根據佔用快取空間的比例觸發自動彈性伸縮的能力,實現快取能力的按需使用。這樣能夠幫助使用者更加靈活的使用透過分散式快取提升資料訪問加速能力,後續我們會提供定時擴縮的能力,為擴縮容提供更強的確定性。

作者 | 車漾 Fluid社群Commiter

作者 | 謝遠東 Fluid社群Commiter

相關文章