天天看點

Spark on Kubernetes 的現狀與挑戰1. Standalone 模式2. Kubernetes Native 模式3. Spark Operator4. 挑戰5. 結語6. 參考:

作者:

陶克路,花名敵琺,阿裡巴巴技術專家。Apache Pulsar 等開源軟體 Contributor。技術領域包括大資料和雲原生技術棧,目前緻力于建構大資料領域業界領先的 APM 産品。

雲原生時代,Kubernetes 的重要性日益凸顯,這篇文章以 Spark 為例來看一下大資料生态 on Kubernetes 生态的現狀與挑戰。

1. Standalone 模式

Spark 運作在 Kubernetes 叢集上的第一種可行方式是将 Spark 以 Standalone 模式運作,但是很快社群就提出使用 Kubernetes 原生 Scheduler 的運作模式,也就是 Native 的模式。關于 Standalone 模式這裡就沒有繼續讨論的必要了。

2. Kubernetes Native 模式

Native 模式簡而言之就是将 Driver 和 Executor Pod 化,使用者将之前向 YARN 送出 Spark 作業的方式送出給 Kubernetes 的 apiserver,送出指令如下:

--master k8s://https://<k8s-apiserver-host>:<k8s-apiserver-port> \
    --deploy-mode cluster \
    --name spark-pi \
    --class org.apache.spark.examples.SparkPi \
    --conf spark.executor.instances=5 \
    --conf spark.kubernetes.container.image=<spark-image> \
    local:///path/to/examples.jar           

其中 master 就是 kubernetes 的 apiserver 位址。送出之後整個作業的運作方式如下,先将 Driver 通過 Pod 啟動起來,然後 Driver 會啟動 Executor 的 Pod。這些方式很多人應該都了解了,就不贅述了,詳細資訊可以參考:

https://spark.apache.org/docs/latest/running-on-kubernetes.html

Spark on Kubernetes 的現狀與挑戰1. Standalone 模式2. Kubernetes Native 模式3. Spark Operator4. 挑戰5. 結語6. 參考:

3. Spark Operator

除了這種直接想 Kubernetes Scheduler 送出作業的方式,還可以通過 Spark Operator 的方式來送出。Operator 在 Kubernetes 中是一個非常重要的裡程碑。在 Kubernetes 剛面世的時候,關于有狀态的應用如何部署在 Kubernetes 上一直都是官方不願意談論的話題,直到 StatefulSet 出現。StatefulSet 為有狀态應用的部署實作了一種抽象,簡單來說就是保證網絡拓撲和存儲拓撲。但是狀态應用千差萬别,并不是所有應用都能抽象成 StatefulSet,強行适配反正加重了開發者的心智負擔。

然後 Operator 出現了。我們知道 Kubernetes 給開發者提供了非常開放的一種生态,你可以自定義 CRD,Controller 甚至 Scheduler。而 Operator 就是 CRD + Controller 的組合形式。開發者可以定義自己的 CRD,比如我定義一種 CRD 叫 EtcdCluster 如下:

kind: "EtcdCluster"
metadata:
  name: "example-etcd-cluster"
spec:
  size: 3
  version: "3.1.10"
  repository: "quay.io/coreos/etcd"           

送出到 Kubernetes 之後 Etcd 的 Operator 就針對這個 yaml 中的各個字段進行處理,最後部署出來一個節點規模為 3 個節點的 etcd 叢集。你可以在 github 的這個 repo:

https://github.com/operator-framework/awesome-operators

中檢視目前實作了 Operator 部署的分布式應用。

Google 雲平台,也就是 GCP 在 github 上面開源了 Spark 的 Operator,repo 位址:。Operator 部署起來也是非常的友善,使用 Helm Chart 方式部署如下,你可以簡單認為就是部署一個 Kubernetes 的 API Object (Deployment)。

$ helm install incubator/sparkoperator --namespace spark-operator           

這個 Operator 涉及到的 CRD 如下:

|__ ScheduledSparkApplicationSpec
    |__ SparkApplication
|__ ScheduledSparkApplicationStatus

|__ SparkApplication
|__ SparkApplicationSpec
    |__ DriverSpec
        |__ SparkPodSpec
    |__ ExecutorSpec
        |__ SparkPodSpec
    |__ Dependencies
    |__ MonitoringSpec
        |__ PrometheusSpec
|__ SparkApplicationStatus
    |__ DriverInfo               

如果我要送出一個作業,那麼我就可以定義如下一個 SparkApplication 的 yaml,關于 yaml 裡面的字段含義,可以參考上面的 CRD 文檔。

kind: SparkApplication
metadata:
  ...
spec:
  deps: {}
  driver:
    coreLimit: 200m
    cores: 0.1
    labels:
      version: 2.3.0
    memory: 512m
    serviceAccount: spark
  executor:
    cores: 1
    instances: 1
    labels:
      version: 2.3.0
    memory: 512m
  image: gcr.io/ynli-k8s/spark:v2.4.0
  mainApplicationFile: local:///opt/spark/examples/jars/spark-examples_2.11-2.3.0.jar
  mainClass: org.apache.spark.examples.SparkPi
  mode: cluster
  restartPolicy:
      type: OnFailure
      onFailureRetries: 3
      onFailureRetryInterval: 10
      onSubmissionFailureRetries: 5
      onSubmissionFailureRetryInterval: 20
  type: Scala
status:
  sparkApplicationId: spark-5f4ba921c85ff3f1cb04bef324f9154c9
  applicationState:
    state: COMPLETED
  completionTime: 2018-02-20T23:33:55Z
  driverInfo:
    podName: spark-pi-83ba921c85ff3f1cb04bef324f9154c9-driver
    webUIAddress: 35.192.234.248:31064
    webUIPort: 31064
    webUIServiceName: spark-pi-2402118027-ui-svc
    webUIIngressName: spark-pi-ui-ingress
    webUIIngressAddress: spark-pi.ingress.cluster.com
  executorState:
    spark-pi-83ba921c85ff3f1cb04bef324f9154c9-exec-1: COMPLETED
  LastSubmissionAttemptTime: 2018-02-20T23:32:27Z           

送出作業。

對比來看 Operator 的作業送出方式似乎顯得更加的冗長複雜,但是這也是一種更 kubernetes 化的 api 部署方式,也就是 Declarative API,聲明式 API。

4. 挑戰

基本上,目前市面的大部門公司都是使用上面兩種方式來做 Spark on Kubernetes 的,但是我們也知道在 Spark Core 裡面對 Kubernetes 的這種 Native 方式支援其實并不是特别成熟,還有很多可以改善的地方:

4.1 scheduler 差異。

資源排程器可以簡單分類成集中式資源排程器和兩級資源排程器。兩級資源排程器有一個中央排程器負責宏觀資源排程,對于某個應用的排程則由下面分區資源排程器來做。兩級資源排程器對于大規模應用的管理排程往往能有一個良好的支援,比如性能方面,缺點也很明顯,實作複雜。其實這種設計思想在很多地方都有應用,比如記憶體管理裡面的 tcmalloc 算法,Go 語言的記憶體管理實作。大資料的資源排程器 Mesos/Yarn,某種程度上都可以歸類為兩級資源排程器。

集中式資源排程器對于所有的資源請求進行響應和決策,這在叢集規模大了之後難免會導緻一個單點瓶頸,毋庸置疑。但是 Kubernetes 的 scheduler 還有一點不同的是,它是一種更新版,一種基于共享狀态的集中式資源排程器。Kubernetes 通過将整個叢集的資源緩存到 scheduler 本地,在進行資源排程的時候在根據緩存的資源狀态來做一個 “樂觀” 配置設定(assume + commit)來實作排程器的高性能。

Kubernetes 的預設排程器在某種程度上并不能很好的 match Spark 的 job 排程需求,對此一種可行的技術方案是再提供一種 custom scheduler,比如 Spark on Kubernetes Native 方式的參與者之一的大資料公司 Palantir 就開源了他們的 custom scheduler,github repo:

https://github.com/palantir/k8s-spark-scheduler

4.2 叢集規模瓶頸。

基本上現在可以确定的是 Kubernetes 會在叢集規模達到五千台的時候出現瓶頸,但是在很早期的時候 Spark 發表論文的時候就聲稱 Spark Standalone 模式可以支援一萬台規模。Kubernetes 的瓶頸主要展現在 master 上,比如用來做中繼資料存儲的基于 raft 一緻性協定的 etcd 和 apiserver 等。對此在剛過去的 2019 上海 KubeCon 大會上,阿裡巴巴做了一個關于提高 master 性能的 session: 了解 Kubernetes Master 的可擴充性和性能,感興趣的可以自行了解。

4.3 Pod 驅逐(Eviction)問題。

在 Kubernetes 中,資源分為可壓縮資源(比如 CPU)和不可壓縮資源(比如記憶體),當不可壓縮資源不足的時候就會将一些 Pod 驅逐出目前 Node 節點。國内某個大廠在使用 Spark on kubernetes 的時候就遇到因為磁盤 IO 不足導緻 Spark 作業失敗,進而間接導緻整個測試集都沒有跑出來結果。如何保證 Spark 的作業 Pod (Driver/Executor) 不被驅逐呢?這就涉及到優先級的問題,1.10 之後開始支援。但是說到優先級,有一個不可避免的問題就是如何設定我們的應用的優先級?正常來說,線上應用或者 long-running 應用優先級要高于 batch job,但是顯然對于 Spark 作業來說這并不是一種好的方式。

4.4 作業日志。

Spark on Yarn 的模式下,我們可以将日志進行 aggregation 然後檢視,但是在 Kubernetes 中暫時還是隻能通過 Pod 的日志檢視,這塊如果要對接 Kubernetes 生态的話可以考慮使用 fluentd 或者 filebeat 将 Driver 和 Executor Pod 的日志彙總到 ELK 中進行檢視。

4.5 Prometheus 生态。

Prometheus 作為 CNCF 畢業的第二個項目,基本是 Kubernetes 監控的标配,目前 Spark 并沒有提供 Prometheus Sink。而且 Prometheus 的資料讀取方式是 pull 的方式,對于 Spark 中 batch job 并不适合使用 pull 的方式,可能需要引入 Prometheus 的 pushgateway。

5. 結語

被稱為雲上 OS 的 Kubernetes 是 Cloud Native 理念的一種技術承載與展現,但是如何通過 Kubernetes 來助力大資料應用還是有很多可以探索的地方。歡迎交流。

6. 參考:

  1. https://medium.com/palantir/spark-scheduling-in-kubernetes-4976333235f3
  2. Kubecon: 了解 Kubernetes Master 的可擴充性和性能
  3. Kubecon: SIG-Scheduling Deep Dive
  4. https://github.com/coreos/etcd-operator
Spark on Kubernetes 的現狀與挑戰1. Standalone 模式2. Kubernetes Native 模式3. Spark Operator4. 挑戰5. 結語6. 參考:

繼續閱讀