大資料實踐解析(下):Spark的讀寫流程分析
導讀:
眾所周知,在大資料/資料庫領域,資料的儲存格式直接影響著系統的讀寫效能。spark是一種基於記憶體的快速、通用、可擴充套件的大資料計算引擎,適用於新時代的資料處理場景。在“”中,我們分析了spark的多種檔案儲存格式,以及分割槽和分桶的設計。接下來,本文透過簡單的例子來分析在Spark中的讀寫流程,主要聚焦於Spark中的高效並行讀寫以及在寫過程中如何保證事務性。
1、檔案讀
如何在Spark中做到高效的查詢處理呢?這裡主要有兩個最佳化手段:
1)減少不必要的資料處理。資料處理涉及檔案的IO以及計算,它們分別需要耗費大量的IO頻寬和CPU計算。在實際的生產環境中,這兩類資源都是有限的,同時這些操作十分耗時,很容易成為瓶頸,所以減少不必要的資料處理能有效提高查詢的效率;
以下面的查詢為例:
spark.read.parquet("/data/events") .where("year = 2019") .where("city = 'Amsterdam'") .select("timestamp")
由於在events表中按照year欄位做了分割槽,那麼首先透過 year 欄位我們就可以過濾掉所有year欄位不為 2019 的分割槽:
因為檔案是parquet的檔案格式,透過謂詞下推可以幫助我們過濾掉 city 欄位不是 "Amsterdam" 的 row groups;同時,由於我們的查詢最終需要輸出的投影欄位只有 "timestamp" ,所以我們可以進行列裁剪最佳化,不用讀取其他不需要的欄位,所以最終整個查詢所讀的資料只有剩下的少部分,過濾掉了大部分的資料,提升了整體的查詢效率:
2)並行處理,這裡主流的思想分為兩類:任務並行和資料並行。任務並行指充分利用多核處理器的優勢,將大的任務分為一個個小的任務交給多個處理器執行並行處理;資料並行指現如今越來越豐富的SIMD指令,一次動作中處理多個資料,比如AVX-512可以一次處理16個32bit的整型數,這種也稱為向量化執行。當然,隨著其他新硬體的發展,並行也經常和GPU聯絡在一起。本文主要分析Spark讀流程中的任務並行。
下面是Spark中一個讀任務的過程,它主要分為三個步驟:
(1)將資料按照某個欄位進行hash,將資料儘可能均勻地分為多個大小一致的Partition;
(2)發起多個任務,每個任務對應到圖中的一個Executor;
(3)任務之間並行地進行各自負責的Partition資料讀操作,提升讀檔案效率。
2、檔案寫
Spark寫過程的目標主要是兩個:並行和事務性。其中並行的思想和讀流程一樣,將任務分配給不同的Executor進行寫操作,每個任務寫各自負責的資料,互不干擾。
為了保證寫過程的事務性,Spark在寫過程中,任何未完成的寫都是在臨時資料夾中進行寫檔案操作。如下圖所示:寫過程中,results資料夾下只存在一個臨時的資料夾_temporary;不同的job擁有各自job id的檔案目錄,相互隔離;同時在各目錄未完成的寫操作都是存在臨時資料夾下,task的每次執行都視為一個taskAttempt,並會分配一個task attempt id,該目錄下的檔案是未commit之前的寫檔案。
當task完成自己的寫任務時,會進行commit操作,commit成功後,該任務目錄下的臨時資料夾會移動,寫檔案移到對應的位置,表示該任務已經寫完成。
當寫任務失敗時,首先需要刪除之前寫任務的臨時資料夾和未完成的檔案,之後重新發起該寫任務(relaunch),直到寫任務commit提交完成。
整個任務的描述可用下圖表示,如果commit成功,將寫完成檔案移動到最終的資料夾;如果未commit成功,寫失敗,刪除對應的檔案,重新發起寫任務。當寫未完成時,所有寫資料都存在對應的臨時檔案中,其他任務不可見,直到整個寫commit成功,保證了寫操作的事務性。
當所有任務完成時,所有的臨時資料夾都移動,留下最終的資料檔案,它是最終commitJob之後的結果。
本文介紹的演算法是 FileOutputCommitter v1的實現,它的commitJob階段由Driver負責依次移動資料到最終的目錄。但是在當前廣泛應用的雲環境下,通常採取存算分離的架構,這時資料一般存放在物件儲存中(如AWS S3,華為雲OBS),Spark FileOutputCommitter中的資料移動並不像HDFS檔案系統移動那麼高效,v1的commitJob過程耗時可能會非常長。為了提升FileOutputCommitter 的效能,業界提出了FileOutputCommitter v2的實現,它們可以透過 spark.hadoop.mapreduce.fileoutputcommitter.algorithm.version = 1或2 配置項來設定,它和v1的不同點在於,每個Task在commitTask時就將檔案移動到最終的目錄,而在commitJob時,Driver只需要負責將Task留下來的空目錄刪除,這樣相比 v1 帶來好處是效能提升, 但是由於commit task時直接寫最終目錄,在執行未完成時,部分資料就對外可見。同時,如果job失敗了,成功的那部分task產生的資料也會殘留下來。這些情況導致spark寫作業的事務性和一致性無法得到保障。
其實v1也不完全一定能保證資料一致性,檔案移動過程中完成的資料對外是可見的,這部分資料外部已經可以讀取,但是正在移動和還未移動的資料對外是不可見的,而在雲環境下,這個移動耗時會進一步加長,加重資料不一致的情況。
那麼有沒有能夠使得Spark 分析在雲環境下也可以保證資料的事務性和一致性的解決方案呢?改進了v1和v2這兩種演算法,使得Spark 分析在雲環境下也可以保證資料的事務性和一致性,同時做到高效能,並且完全相容Apache Spark和Apache Flink生態, 是實現批流一體的Serverless大資料計算分析服務,歡迎點選體驗。
參考
【1】Databricks. 2020. Apache Spark's Built-In File Sources In Depth - Databricks. [online] Available at: <>.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4606/viewspace-2796534/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 基於 Spark 的資料分析實踐Spark
- 資料讀寫流程
- HBase資料的讀寫流程
- HBase 讀流程解析與優化的最佳實踐優化
- 《Hadoop+Spark大資料分析實戰》簡介HadoopSpark大資料
- JuiceFS 資料讀寫流程詳解UI
- Yelp 的 Spark 資料血緣建設實踐!Spark
- 資料讀寫壓力大,讀寫分離
- 基於雲原生的大資料實時分析方案實踐大資料
- spark讀取hbase的資料Spark
- Spark RDD中Runtime流程解析Spark
- 寶付大資料分析解析大資料
- spark寫入hive資料SparkHive
- 最佳實踐 | 資料庫遷雲解決方案選型 & 流程全解析資料庫
- 大資料分享Spark任務和叢集啟動流程大資料Spark
- Spark讀取MySQL資料SparkMySql
- 基於python的大資料分析-pandas資料讀取(程式碼實戰)Python大資料
- 大資料系列2:Hdfs的讀寫操作大資料
- HDFS的讀寫流程
- MobX流程分析與最佳實踐
- 遊戲資料分析的三大實戰案例深度解讀遊戲
- 開源大資料生態下的 Flink 應用實踐大資料
- Flink 實踐教程-入門(6):讀取 PG 資料寫入 ClickHouse
- 騰訊雲EMR大資料實時OLAP分析案例解析大資料
- 愛奇藝大資料實時分析平臺的建設與實踐大資料
- Spark讀取elasticsearch資料指南SparkElasticsearch
- 每週一書《Spark與Hadoop大資料分析》分享!SparkHadoop大資料
- mysql讀寫分離的最佳實踐MySql
- Spark原始碼解析-Yarn部署流程(ApplicationMaster)Spark原始碼YarnAPPAST
- Flume 在有贊大資料的實踐大資料
- 大資料分析之資料下鑽上卷大資料
- Flink 實踐教程 - 入門(4):讀取 MySQL 資料寫入到 ESMySql
- 大資料場景下Volcano高效排程能力實踐大資料
- 從 ClickHouse 到 ByteHouse:實時資料分析場景下的最佳化實踐
- 圖資料庫 NebulaGraph 的 Java 資料解析實踐與指導資料庫Java
- 開源實踐 | OceanBase 在紅象雲騰大資料場景下的實踐與思考大資料
- Spark on Yarn 實踐SparkYarn
- 在 Spark 資料匯入中的一些實踐細節Spark