Apache Spark
在大數據處理與分析領域,Apache Spark無疑佔據着重要地位。它的特點是基於內存計算,支持各類資源管理平臺,其中以YARN最爲常見,同時又與Hadoop平臺集成,在集羣節點以HDFS作爲分佈式文件存儲系統。
我們可以先看一下搭建一個常見的Apache Spark大數據平臺需要哪些步驟:
1.安裝Hadoop集羣
2.配置HDFS
3.配置YARN
4.安裝Spark
5.配置Spark與YARN集成
事實上如果參閱官方文檔,還有更多細節檢查與配置,有過大數據相關領域從業經驗的人都知道,要搭建一套可用的大數據環境並不容易,再加上後期維護,就更吃力了,而一套穩定的大數據平臺正是進行大數據應用開發的基礎。根據筆者瞭解,有不少公司正是因爲大數據平臺搭建及配置的複雜性等原因,不得不在多個測試環境中,共用一套大數據平臺,這種方式長期看維護成本較高,也可能存在安全隱患。
大數據領域需要一些變化,而Kubernetes的出現則提供了契機。
Kubernete(以下簡稱k8s)是容器集羣管理系統,是一個開源的平臺,可以實現容器集羣的自動化部署、自動擴縮容、維護等功能。通過Kubernetes你可以:
· 快速部署應用
· 快速擴展應用
· 無縫對接新的應用功能
· 節省資源,優化硬件資源的使用
大數據社區
隨着K8s社區的發展壯大,微服務及容器化被越來越多的公司應用到生產環境。與此同時,K8s也成爲容器編排的首選平臺。大數據社區在容器化進程中當然也是不甘落後的。
Spark自2.3開始官方支持K8sFlink自1.9開始官方支持K8sHue官方Helm chart包Hive以MR3爲執行引擎支持K8sAirflow自1.10開始支持K8sPresto支持K8s……
可以看到整個大數據社區也在積極支持容器化,但大數據的容器化並不是生硬地將各個組件搬到K8s上,以Spark on YARN爲例,核心組件YARN作爲資源調度器,其結構如下圖所示
下圖講述了Apache Spark on YARN的工作方式:
YARN ResourceManager的功能爲:
負責集羣中所有資源的統一管理和分配,它接收來自各個節點(NodeManager)的資源彙報信息,並把這些信息按照一定的策略分配給各個應用程序
瞭解K8s的同學可以看出YARN的功能其實與K8s Scheduler的功能非常類似
Kubernetes 調度器是一個策略豐富、拓撲感知、工作負載特定的功能,調度器顯著影響可用性、性能和容量。調度器需要考慮個人和集體的資源要求、服務質量要求、硬件/軟件/政策約束、親和力和反親和力規範、數據局部性、負載間干擾、完成期限等。
所以與其將YARN生搬到K8s中(早期確實是這樣做的),何不用K8s調度器替換掉YARN,使得Spark適應K8s呢? 事實上社區確實是在這個方向努力嘗試,並且自Spark 2.3開始,實驗性支持使用K8s原生Scheduler替代YARN。
spark on k8s:
在該方案中
1.客戶端通過spark-submit
將任務提交到K8s集羣中,並在集羣中啓動一個Spark Driver Pod;
2.Spark Driver啓動相應的Executor Pod, 組成一個Spark Application集羣並執行作業任務;
3.任務執行完成後,Executor Pod會被銷燬, 而Driver Pod會持久化相關日誌,並保持在’completed’狀態,直到用戶手清理或被K8s集羣的垃圾回收機制回收.
Spark原生支持K8s的好處也是很明顯的:可以更好的利用K8s的集羣資源,通過K8s賦能,更好的進行資源的隔離。這個方案不太友好的地方在於:spark-submit
在K8s集羣之外,使用非聲明式的提交接口,實際使用起來不夠友好。
將Spark應用遷移到K8s環境中
Spark Operator是Google基於Operator模式開發的一款的工具, 用於通過聲明式的方式向K8s集羣提交Spark作業,並且負責管理Spark任務在K8s中的整個生命週期,其工作模式如下
我們可通過Hem安裝 spark-operator
$ helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator
$ helm install incubator/sparkoperator --namespace spark-operator
創建服務用戶及綁定權限
$ kubectl create serviceaccount spark
$ kubectl create clusterrolebinding spark-role --clusterrole=edit --serviceaccount=default:spark --namespace=default
一個典型的Spark應用在K8s中的資源描述文件 spark-pi.yaml 如下所示
apiVersion: "sparkoperator.k8s.io/v1beta2"
kind: SparkApplication
metadata:
name: spark-pi
namespace: default
spec:
type: Scala
mode: cluster
image: "gcr.io/spark-operator/spark:v2.4.4"
imagePullPolicy: Always
mainClass: org.apache.spark.examples.SparkPi
mainApplicationFile: "local:///opt/spark/examples/jars/spark-examples_2.11-2.4.4.jar"
sparkVersion: "2.4.4"
restartPolicy:
type: Never
volumes:
- name: "test-volume"
hostPath:
path: "/tmp"
type: Directory
driver:
cores: 1
coreLimit: "1200m"
memory: "512m"
labels:
version: 2.4.4
serviceAccount: spark
volumeMounts:
- name: "test-volume"
mountPath: "/tmp"
executor:
cores: 1
instances: 1
memory: "512m"
labels:
version: 2.4.4
volumeMounts:
- name: "test-volume"
mountPath: "/tmp"
部署運行
$ kubectl apply -f spark-pi.yaml
計算與存儲分離
1.計算與存儲耦合存在的問題:當存儲或計算其中一方資源不足時,只能同時對兩者進行擴容,導致擴容的經濟效率比較低(另一種擴容的資源被浪費了);
2.在雲計算場景下,不能實現真正的彈性計算,因爲計算集羣中也有數據,關閉閒置的計算集羣會丟失數據。
因爲耦合導致的以上這些問題,導致很多公司不得不考慮這種耦合的必要性。而Hadoop的架構設計正是計算與存儲耦合,這種設計並不適合雲原生架構。而作爲大數據存儲的基石-HDFS,目前並無官方的K8s解決方案,不過在K8s社區本身就有許多優秀的存儲解決方案-MINIO
MinIO 是一個基於Apache License v2.0開源協議的對象存儲服務。它兼容亞馬遜S3雲存儲服務接口,非常適合於存儲大容量非結構化的數據,例如圖片、視頻、日誌文件、備份數據和容器/虛擬機鏡像等,而一個對象文件可以是任意大小,從幾kb到最大5T不等。而且實驗數據表明,其性能絲毫不遜色於HDFS
安裝MINIO也非常容易
$ helm install stable/minio
我們以WordCount,數據讀寫使用minio存儲系統(兼容亞馬遜S3雲存儲服務接口)
JavaRDD<String> textFile = sc.textFile("s3a://...");
JavaPairRDD<String, Integer> counts = textFile
.flatMap(s -> Arrays.asList(s.split(" ")).iterator())
.mapToPair(word -> new Tuple2<>(word, 1))
.reduceByKey((a, b) -> a + b);
counts.saveAsTextFile("s3a://...");
由於兼容亞馬遜S3雲存儲服務接口這一優勢,minio也同樣可以作爲Hive數據倉庫的可選存儲系統。
<property>
<name>fs.s3a.path.style.access</name>
<value>true</value>
<description>Enable S3 path style access.</description>
</property>
<property>
<name>hive.metastore.warehouse.dir</name>
<value>s3a://hive/warehouse</value>
</property>
總結
通過以上論述,在K8s集羣上搭建Spark大數據平臺,相比傳統YARN調度方式而言更爲簡潔,MINIO可作爲大數據的存儲系統,在保證數據的持久性的同時,也實現了大數據計算系統與存儲系統的解耦。