做者 | 車漾 Fluid 社區 Commiter 謝遠東 Fluid 社區 Commiter 來源 | 阿里巴巴雲原生公衆號node
**導讀:**彈性伸縮做爲 Kubernetes 的核心能力之一,但它一直是圍繞這無狀態的應用負載展開。而 Fluid 提供了分佈式緩存的彈性伸縮能力,能夠靈活擴充和收縮數據緩存。 它基於 Runtime 提供了緩存空間、現有緩存比例等性能指標, 結合自身對於 Runtime 資源的擴縮容能力,提供數據緩存按需伸縮能力。git
背景
隨着愈來愈多的大數據和 AI 等數據密集應用開始部署和運行在 Kubernetes 環境下,數據密集型應用計算框架的設計理念和雲原生靈活的應用編排的分歧,致使了數據訪問和計算瓶頸。雲原生數據編排引擎 Fluid 經過數據集的抽象,利用分佈式緩存技術,結合調度器,爲應用提供了數據訪問加速的能力。github
彈性伸縮做爲 Kubernetes 的核心能力之一,但它一直是圍繞這無狀態的應用負載展開。而 Fluid 提供了分佈式緩存的彈性伸縮能力,能夠靈活擴充和收縮數據緩存。它基於 Runtime 提供了緩存空間、現有緩存比例等性能指標, 結合自身對於 Runtime 資源的擴縮容能力,提供數據緩存按需伸縮能力。web
這個能力對於互聯網場景下大數據應用很是重要,因爲多數的大數據應用都是經過端到端流水線來實現的。而這個流水線包含如下幾個步驟:數據庫
- 數據提取:利用 Spark,MapReduce 等大數據技術對於原始數據進行預處理。
- 模型訓練:利用第一階段生成特徵數據進行機器學習模型訓練,而且生成相應的模型。
- 模型評估:經過測試集或者驗證集對於第二階段生成模型進行評估和測試。
- 模型推理:第三階段驗證後的模型最終推送到線上爲業務提供推理服務。
能夠看到端到端的流水線會包含多種不一樣類型的計算任務,針對每個計算任務,實踐中會有合適的專業系統來處理(TensorFlow,PyTorch,Spark, Presto);可是這些系統彼此獨立,一般要藉助外部文件系統來實現把數據從一個階段傳遞到下一個階段。可是頻繁的使用文件系統實現數據交換,會帶來大量的 I/O 開銷,常常會成爲整個工做流的瓶頸。apache
而 Fluid 對於這個場景很是適合,用戶能夠建立一個 Dataset 對象,這個對象有能力將數據分散緩存到 Kubernetes 計算節點中,做爲數據交換的介質,這樣避免了數據的遠程寫入和讀取,提高了數據使用的效率。可是這裏的問題是臨時數據緩存的資源預估和預留。因爲在數據生產消費以前,精確的數據量預估是比較難知足,太高的預估會致使資源預留浪費,太低的預估會致使數據寫入失敗可能性增高。仍是按需擴縮容對於使用者更加友好。咱們但願可以達成相似 page cache 的使用效果,對於最終用戶來講這一層是透明的可是它帶來的緩存加速效果是實實在在的。json
咱們經過自定義 HPA 機制,經過 Fluid 引入了緩存彈性伸縮能力。彈性伸縮的條件是當已有緩存數據量達到必定比例時,就會觸發彈性擴容,擴容緩存空間。例如將觸發條件設置爲緩存空間佔比超過 75%,此時總的緩存空間爲 10G,當數據已經佔滿到 8G 緩存空間的時候,就會觸發擴容機制。centos
下面咱們經過一個例子幫助您體驗 Fluid 的自動擴縮容能力。api
前提條件
推薦使用 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.git cd fluid/charts kubectl create ns fluid-system helm 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-svc NAME ENDPOINTS AGE prometheus-svc 10.76.0.2:9090 6m49s $ kubectl get svc -n kube-system prometheus-svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE prometheus-svc NodePort 172.16.135.24 <none> 9090:32114/TCP 2m7s
若是但願可視化監控指標,您能夠安裝 Grafana 驗證監控數據,具體操做能夠參考文檔。
5. 部署 metrics server。
檢查該集羣是否包括 metrics-server,執行kubectl top node有正確輸出能夠顯示內存和 CPU,則該集羣 metrics server 配置正確。
kubectl top node NAME 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: v1 kind: ConfigMap metadata: name: adapter-config namespace: monitoring data: 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.yaml kubectl 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。
$ cat<<EOF >dataset.yaml apiVersion: data.fluid.io/v1alpha1 kind: Dataset metadata: name: spark spec: mounts: - mountPoint: https://mirrors.bit.edu.cn/apache/spark/ name: spark --- apiVersion: data.fluid.io/v1alpha1 kind: AlluxioRuntime metadata: name: spark spec: replicas: 1 tieredstore: levels: - mediumtype: MEM path: /dev/shm quota: 1Gi high: "0.99" low: "0.7" properties: alluxio.user.streaming.data.timeout: 300sec EOF $ kubectl create -f dataset.yaml dataset.data.fluid.io/spark created alluxioruntime.data.fluid.io/spark created
8. 查看這個 Dataset 是否處於可用狀態。
能夠看到該數據集的數據總量爲 2.71GiB, 目前 Fluid 提供的緩存節點數爲 1,能夠提供的最大緩存能力爲 1GiB。此時數據量是沒法知足全量數據緩存的需求。
$ kubectl get dataset NAME UFS TOTAL SIZE CACHED CACHE CAPACITY CACHED PERCENTAGE PHASE AGE spark 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 任務。
$ cat<<EOF > hpa.yaml apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: spark spec: 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: Disabled EOF
首先,咱們解讀一下從樣例配置,這裏主要有兩部分一個是擴縮容的規則,另外一個是擴縮容的靈敏度:
- 規則:觸發擴容行爲的條件爲 Dataset 對象的緩存數據量佔總緩存能力的 90%;擴容對象爲AlluxioRuntime,最小副本數爲 1,最大副本數爲 4;而 Dataset 和 AlluxioRuntime 的對象須要在同一個 namespace。
- 策略:能夠 K8s 1.18 以上的版本,能夠分別針對擴容和縮容場景設置穩定時間和一次擴縮容步長比例。好比在本例子, 一次擴容週期爲 10 分鐘(periodSeconds),擴容時新增 2 個副本數,固然這也不能夠超過 maxReplicas 的限制;而完成一次擴容後,冷卻時間(stabilizationWindowSeconds)爲 20 分鐘;而縮容策略能夠選擇直接關閉。
11. 查看 HPA 配置, 當前緩存空間的數據佔比爲 0。遠遠低於觸發擴容的條件。
$ kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE spark AlluxioRuntime/spark 0/90 1 4 1 33s $ kubectl describe hpa Name: spark Namespace: default Labels: <none> Annotations: <none> CreationTimestamp: Wed, 07 Apr 2021 17:36:39 +0800 Reference: AlluxioRuntime/spark Metrics: ( current / target ) "capacity_used_rate" on Dataset/spark (target value): 0 / 90 Min replicas: 1 Max replicas: 4 Behavior: 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 seconds AlluxioRuntime pods: 1 current / 1 desired Conditions: 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 range Events: <none>
12. 建立數據預熱任務。
$ cat<<EOF > dataload.yaml apiVersion: data.fluid.io/v1alpha1 kind: DataLoad metadata: name: spark spec: dataset: name: spark namespace: default EOF $ kubectl create -f dataload.yaml $ kubectl get dataload NAME DATASET PHASE AGE DURATION spark spark Executing 15s Unfinished
13. 此時能夠發現緩存的數據量接近了 Fluid 能夠提供的緩存能力(1GiB)同時觸發了彈性伸縮的條件。
$ kubectl get dataset NAME UFS TOTAL SIZE CACHED CACHE CAPACITY CACHED PERCENTAGE PHASE AGE spark 2.71GiB 1020.92MiB 1.00GiB 36.8% Bound 5m15s
從 HPA 的監控,能夠看到 Alluxio Runtime 的擴容已經開始, 能夠發現擴容的步長爲 2。
$ kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE spark AlluxioRuntime/spark 100/90 1 4 2 4m20s $ kubectl describe hpa Name: spark Namespace: default Labels: <none> Annotations: <none> CreationTimestamp: Wed, 07 Apr 2021 17:56:31 +0800 Reference: AlluxioRuntime/spark Metrics: ( current / target ) "capacity_used_rate" on Dataset/spark (target value): 100 / 90 Min replicas: 1 Max replicas: 4 Behavior: 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 seconds AlluxioRuntime pods: 2 current / 3 desired Conditions: 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 range Events: 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 dataset NAME UFS TOTAL SIZE CACHED CACHE CAPACITY CACHED PERCENTAGE PHASE AGE spark 2.71GiB 2.59GiB 3.00GiB 95.6% Bound 12m
同時觀察 HPA 的狀態,能夠發現此時 Dataset 對應的 runtime 的 replicas 數量爲 3, 已經使用的緩存空間比例 capacity_used_rate 爲 85%,已經不會觸發緩存擴容。
$ kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE spark AlluxioRuntime/spark 85/90 1 4 3 11m
15. 清理環境。
kubectl delete hpa spark kubectl delete dataset spark
總結
Fluid 提供告終合 Prometheous,Kubernetes HPA 和 Custom Metrics 能力,根據佔用緩存空間的比例觸發自動彈性伸縮的能力,實現緩存能力的按需使用。這樣可以幫助用戶更加靈活的使用經過分佈式緩存提高數據訪問加速能力,後續咱們會提供定時擴縮的能力,爲擴縮容提供更強的肯定性。
Fluid 的代碼倉庫:https://github.com/fluid-cloudnative/fluid.git, 歡迎你們關注、貢獻代碼和 star。