在上篇文章中,咱們分析了Spark Operator內部的機制,今天咱們會討論一個在大數據領域中最重要的話題 - 存儲。大數據已經無聲無息的融入了每一個人的生活中。大到旅遊買房,小到外賣打車,均可以看到經過大數據提供數據分析、數據推薦、數據決策的使用場景。大數據要想可以更準確地協助決策,須要在數據多維度、數據完備性等方面有較高要求。可預知的在將來,數據的量級會愈來愈大,特別是隨着5G時代的到來,數據的吞吐量級成指數的增加,數據的維度與來源會愈來愈多,數據的種類也會變得愈來愈異質化,對大數據平臺也帶來新的挑戰。成本低、存得多、讀寫快成爲大數據存儲的三大問題,而今天咱們就會針對這三大問題進行探討。git
計算和存儲分離是大數據領域被你們討論過不少次的問題了,一般咱們會經過以下幾個角度來看這個問題:github
這三大問題,隨着容器時代的到來也變得愈發的凸顯。咱們知道在kubernetes中,Pod是運行在底層的資源池上,而Pod所須要的存儲是經過PV或者PVC的方式動態分配與掛載的,從某種意義來說,容器自己的架構就是計算與存儲分離的。那麼使用了存儲與計算分離方式的大數據容器集羣會帶來哪些變化與優點呢?sql
一般在阿里雲上創建一個Spark大數據平臺的時候,首先會選擇D系列的機器,在上面搭建HDFS、Hadoop等一系列的基礎組件,而後再將Spark等做業任務經過Yarn進行調度,跑在這個集羣之上。D系列的內網帶寬範圍是3Gbps-20Gbps,默承認以綁定(4-28塊) 5.5T的本地盤。由於在雲上,雲盤的IO和網絡的IO是共享的,而本地盤的IO是獨立的,所以D系列+本地盤的IO性能會比同規格傳統機型+雲盤的性能更好。數據庫
可是在實際生產中,咱們會發現存儲的數據對着時間變得愈來愈多,而因爲數據具備必定的時效性,形成單位時間的算力與存儲的增加是不相匹配的,這個時候就會帶來了成本的浪費。那麼若是咱們使用計算和存儲分離的思想,使用外部存儲,例如OSS、Nas或者DFS(阿里雲HDFS產品),會有哪些變化呢?apache
首先,咱們屏蔽因爲存儲的IO差別形成的影響,先都使用遠程的DFS做爲文件存儲。而後咱們選擇了ecs.ebmhfg5.2xlarge(8C32G6Gbps)和ecs.d1ne.2xlarge (8C32G6Gbps) 兩款分別面向計算和大數據場景規格配置相同的熱門機型,進行了比對。api
ecs.ebmhfg5.2xlarge(8C32G)的測試結果網絡
ecs.d1ne.2xlarge (8C32G)的測試結果架構
經過Hibench咱們可粗略的估算,在假定IO性能基本一致的場景下,ecs.ebmhfg5.2xlarge會比ecs.d1ne.2xlarge計算性能高30%左右,而成本上ecs.ebmhfg5.2xlarge會比ecs.d1ne.2xlarge低25%左右。app
也就是說若是單單隻看計算的能力,是能夠有更高效、更節省的機型選擇的。當存儲和計算分離後,咱們能夠從存儲和計算兩個維度分開去估算所需的用量,在機型上能夠更多的考慮高主頻計算能力較強ECS,而存儲上可使用OSS或者DFS,存儲成本也相較本地存儲更爲低廉。此外一般D系列的機型都是1:4的CPU內存比,隨着大數據做業的場景愈來愈豐富,1:4的CPU內存比也不徹底是最佳的配比,當存儲與計算分離後,咱們能夠根據業務的類型選擇合適的計算資源,甚至能夠在一個計算資源池中維護多種計算資源,從而提升資源使用率。運維
數據存儲的SLA和計算任務的SLA也是徹底不一樣的,存儲上是沒法忍受宕機或者中斷的,可是對於計算任務而言,自己已經被切割爲子任務了,單個子任務的異常只需重試便可,那麼進一步就可使用相似競價實例這種成本更低的資源來做爲計算任務運行時環境,實現成本的進一步優化。
此外容器最大的特色就是彈性,經過彈性的能力,容器能夠在短期內得到超遠本來自身幾十甚至上百倍的計算資源,而計算任務完成後又自動釋放掉。目前阿里雲容器服務提供autoscaler進行節點級別的彈性伸縮,能夠作到在1分半內伸縮500臺節點。傳統的計算與存儲耦合的場景下,存儲是阻礙彈性的一大障礙,而存儲和計算分離後,就能夠針對近乎無狀態的計算來實現彈性的能力,實現真正的按需使用、按量消費。
使用外部存儲後,咱們不止存儲量級上能夠作到近乎無限,並且能夠有更多的選擇。在本文開頭位置,咱們已經提到了大數據時代的到來,將引入更多維度、更異質化的數據。而這也對數據存儲的方式與類型也帶來了更多的挑戰。單純的HDFS、Hbase、Kafka等數據存儲與鏈路將沒法知足咱們的需求。例如從IoT設備採集的數據更傾向於使用時序存儲進行離線、從應用上下游的產生的數據更傾向於存放在結構化數據庫中,數據的來源與鏈路會愈來愈多,大數據平臺的底層基礎設施與依賴就會越變越多。在雲上,阿里雲提供了多種類型的存儲服務,能夠知足各類大數據處理的場景。除了傳統的HDFS、Hbase、kafka、OSS、Nas、CPFS等存儲,還包包含MNS、TSDB、OAS(冷數據歸檔)等等。使用存儲服務可讓大數據平臺更關注在業務的開發,而不是底層基礎架構的運維。不但可以存的更多,還能夠存的更好、存的更省。
從某種角度來說,讀寫更快是不可能的,由於獨立本地盤能夠經過掛足夠盤並行的方式進行提高的,可是要注意的問題在於,當咱們經過MR進行任務切割後,每一個子任務的瓶頸是否仍是在磁盤IO上,大部分狀況下答案是否認。上面咱們測試的ECS規格內網的帶寬已經能夠到達6Gbps,若是所有網絡帶寬都換算成磁盤的IO的話,這個量級的數據吞吐IO相比8C32G的算力而言是冗餘的,因此此處咱們提到的讀寫更快是指在IO冗餘的前提下提高讀寫速度的方式。OSS是阿里雲上提供的對象存儲,讀取不一樣單個文件的IO是並行的,也就是說若是你的業務場景是大量中小型文件的並行讀取,例如在Spark中讀寫目錄的方式,那麼此時IO的讀寫速度近似是線性加強的。若是依然但願使用HDFS的開發者,阿里雲也提HDFS存儲服務,提供了大量存儲與查詢的優化,和傳統的自建的HDFS相比有50%左右的提高。
阿里雲容器服務在多個維度多個層次知足大數據處理中的需求。開發者能夠根據不一樣的業務場景和IO的新更能指標要求,選擇合適本身的存儲方式。
OSS是面向這個場景的最佳使用方式,在容器中可使用兩種方式操做OSS,一種是將OSS掛載爲一個文件系統,一種是直接在Spark中使用SDK來操做。第一種方案在大數據的場景下是很是不適用的,特別是文件比較多的場景,若是沒有相似SmartFS的優化手段,會帶來很大的時延與不一致性。而使用SDK的方式則很是直接簡單,只需將相應的Jar放在CLASSPATH下便可,能夠參考以下代碼,直接處理OSS中的文件內容。
package com.aliyun.emr.example object OSSSample extends RunLocally { def main(args: Array[String]): Unit = { if (args.length < 2) { System.err.println( """Usage: bin/spark-submit --class OSSSample examples-1.0-SNAPSHOT-shaded.jar <inputPath> <numPartition> | |Arguments: | | inputPath Input OSS object path, like oss://accessKeyId:accessKeySecret@bucket.endpoint/a/b.txt | numPartitions the number of RDD partitions. | """.stripMargin) System.exit(1) } val inputPath = args(0) val numPartitions = args(1).toInt val ossData = sc.textFile(inputPath, numPartitions) println("The top 10 lines are:") ossData.top(10).foreach(println) } override def getAppName: String = "OSS Sample" }
另外針對Spark SQL的場景,阿里雲也提供了https://yq.aliyun.com/articles/593910">oss-select的方式進行支持,能夠經過SparkSQL的方式對單文件檢索和查詢。代碼倉庫地址。特別注意:當使用Spark Operator的方式進行任務執行是,須要在Driver Pod與Exector Pod的CLASSPATH下預置好相應的Jar包。
OSS的方式主要面向單個文件在百兆之下,文件數目比較多的場景優化較好,數據存儲是幾種常見存儲中最便宜的,支持冷熱數據的分離,主要面向讀多寫少或者不寫的場景。
阿里雲上新推出了DFS服務,能夠像在Hadoop分佈式文件系統 (Hadoop Distributed File System) 中管理和訪問數據。無需對現有大數據分析應用作任何修改,便可使用具有無限容量及性能擴展、單一命名空間、多共享、高可靠和高可用等特性的分佈式文件系統。
DFS服務兼容HDFS協議,開發者只需將相應的調用Jar包放置在Driver Pod與Exector Pod的CLASSPATH中便可,調用時能夠以下的方式進行調用。
/* SimpleApp.scala */ import org.apache.spark.sql.SparkSession object SimpleApp { def main(args: Array[String]) { val logFile = "dfs://f-5d68cc61ya36.cn-beijing.dfs.aliyuncs.com:10290/logdata/ab.log" val spark = SparkSession.builder.appName("Simple Application").getOrCreate() val logData = spark.read.textFile(logFile).cache() val numAs = logData.filter(line => line.contains("a")).count() val numBs = logData.filter(line => line.contains("b")).count() println(s"Lines with a: $numAs, Lines with b: $numBs") spark.stop() } }
DFS服務的方式主要是面向高IO讀寫的熱數據場景,價格會高於OSS存儲,但低於Nas以及其餘結構化存儲。對於已經習慣了HDFS的開發者而言,是最佳的的方案。在全部的存儲方案中,目前IO性能最佳,同容量場景,IO優於本地盤。
OSS的方式對於某些場景而言,數據的上傳與傳輸依賴SDK,操做會略顯不便。那麼Nas也是一種備選的方案,Nas的自己的協議是強一致性的,開發者能夠像操做本地文件的方式,讀寫數據。使用方式以下:
apiVersion: "sparkoperator.k8s.io/v1alpha1" kind: SparkApplication metadata: name: spark-pi namespace: default spec: type: Scala mode: cluster image: "gcr.io/spark-operator/spark:v2.4.0" imagePullPolicy: Always mainClass: org.apache.spark.examples.SparkPi mainApplicationFile: "local:///opt/spark/examples/jars/spark-examples_2.11-2.4.0.jar" restartPolicy: type: Never volumes: - name: pvc-nas persistentVolumeClaim: claimName: pvc-nas driver: cores: 0.1 coreLimit: "200m" memory: "512m" labels: version: 2.4.0 serviceAccount: spark volumeMounts: - name: "pvc-nas" mountPath: "/tmp" executor: cores: 1 instances: 1 memory: "512m" labels: version: 2.4.0 volumeMounts: - name: "pvc-nas" mountPath: "/tmp"
固然對於Kubernetes比較熟悉的開發者,一樣可使用動態存儲的方式直接掛載。具體文檔地址以下。
Nas存儲的方式在Spark的場景下用途比較少,主要是由於在IO方面與HDFS有必定差距,在存儲價格方面比OSS也貴了很多。不過對於須要複用一些data workflow的產生結果,且IO要求要求不是特別高的場景,Nas的使用仍是很是簡單的。
在Spark Streaming的場景中,咱們還常用例如mns或者kafka,有的時候也會使用Elasticsearch與Hbase等等。這些在阿里雲上面也都有對應的服務支持,開發者能夠經過這些雲服務的集成與使用,將精力更多的放在數據開發上。
本文主要和你們探討了當容器遇到大數據後,改如何經過存儲與計算分離的方式,下降資源的使用成本,經過不一樣的場景,選擇合適的存儲方式,實現雲原生的大數據容器化計算。在下一篇文章中,咱們會爲你們介紹如何經過彈性的方式,在存儲和計算分離的場景下,實現計算資源池的成本節約。
本文爲雲棲社區原創內容,未經容許不得轉載。