spark 小文件合并優(yōu)化實(shí)踐

對(duì) spark 任務(wù)數(shù)據(jù)落地(HDFS) 碎片文件過(guò)多的問(wèn)題的優(yōu)化實(shí)踐及思考。

背景

此文是關(guān)于公司在 Delta Lake 上線之前對(duì)Spark任務(wù)寫(xiě)入數(shù)據(jù)產(chǎn)生碎片文件優(yōu)化的一些實(shí)踐。

  • 形成原因
    數(shù)據(jù)在流轉(zhuǎn)過(guò)程中經(jīng)歷 filter/shuffle 等過(guò)程后,開(kāi)發(fā)人員難以評(píng)估作業(yè)寫(xiě)出的數(shù)據(jù)量。即使使用了 Spark 提供的AE功能,目前也只能控制 shuffle read 階段的數(shù)據(jù)量,寫(xiě)出數(shù)據(jù)的大小實(shí)際還會(huì)受壓縮算法及格式的影響,因此在任務(wù)運(yùn)行時(shí),對(duì)分區(qū)的數(shù)據(jù)評(píng)估非常困難。

    • shuffle 分區(qū)過(guò)多過(guò)碎,寫(xiě)入性能會(huì)較差且生成的小文件會(huì)非常多。
    • shuffle 分區(qū)過(guò)少過(guò)大,則寫(xiě)入并發(fā)度可能會(huì)不夠,影響任務(wù)運(yùn)行時(shí)間。
  • 不利影響
    在產(chǎn)生大量碎片文件后,任務(wù)數(shù)據(jù)讀取的速度會(huì)變慢(需要尋找讀入大量的文件,如果是機(jī)械盤(pán)更是需要大量的尋址操作),同時(shí)會(huì)對(duì) hdfs namenode 內(nèi)存造成很大的壓力。

在這種情況下,只能讓業(yè)務(wù)/開(kāi)發(fā)人員主動(dòng)的合并下數(shù)據(jù)或者控制分區(qū)數(shù)量,提高了用戶的學(xué)習(xí)及使用成本,往往效果還非常不理想。
既然在運(yùn)行過(guò)程中對(duì)最終落地?cái)?shù)據(jù)的評(píng)估如此困難,是否能將該操作放在數(shù)據(jù)落地后進(jìn)行?對(duì)此我們進(jìn)行了一些嘗試,希望能自動(dòng)化的解決/緩解此類問(wèn)題。

一些嘗試

大致做了這么一些工作:

  1. 修改 Spark FileFormatWriter 源碼,數(shù)據(jù)落盤(pán)時(shí),記錄相關(guān)的 metrics,主要是一些分區(qū)/表的記錄數(shù)量和文件數(shù)量信息。
  2. 在發(fā)生落盤(pán)操作后,會(huì)自動(dòng)觸發(fā)碎片文件檢測(cè),判斷是否需要追加合并數(shù)據(jù)任務(wù)。
  3. ?實(shí)現(xiàn)一個(gè) MergeTable 語(yǔ)法用于合并表/分區(qū)碎片文件,通過(guò)系統(tǒng)或者用戶直接調(diào)用。

第1和第2點(diǎn)主要是平臺(tái)化的一些工作,包括監(jiān)測(cè)數(shù)據(jù)落盤(pán),根據(jù)采集的 metrics 信息再判斷是否需要進(jìn)行 MergeTable 操作,下文是關(guān)于 MergeTable 的一些細(xì)節(jié)實(shí)現(xiàn)。

MergeTable

功能:

  1. 能夠指定表或者分區(qū)進(jìn)行合并
  2. 合并分區(qū)表但不指定分區(qū),則會(huì)遞歸對(duì)所有分區(qū)進(jìn)行檢測(cè)合并
  3. ?指定了生成的文件數(shù)量,就會(huì)跳過(guò)規(guī)則校驗(yàn),直接按該數(shù)量進(jìn)行合并

語(yǔ)法:

merge table [表名] [options (fileCount=合并后文件數(shù)量)]  --非分區(qū)表
merge table [表名] PARTITION (分區(qū)信息) [options (fileCount=合并后文件數(shù)量)] --分區(qū)表

碎片文件校驗(yàn)及合并流程圖?:

在這里插入圖片描述

性能優(yōu)化

對(duì)合并操作的性能優(yōu)化

  1. 只合并碎片文件
    如果設(shè)置的碎片閾值是128M,那么只會(huì)將該表/分區(qū)內(nèi)小于該閾值的文件進(jìn)行合并,同時(shí)如果碎片文件數(shù)量小于一定閾值,將不會(huì)觸發(fā)合并,這里主要考慮的是合并任務(wù)存在一定性能開(kāi)銷(xiāo),因此允許系統(tǒng)中存在一定量的小文件?。

  2. 分區(qū)數(shù)量及合并方式
    定義了一些規(guī)則用于計(jì)算輸出文件數(shù)量及合并方式的選擇,獲取任務(wù)的最大并發(fā)度 maxConcurrency 用于計(jì)算數(shù)據(jù)的分塊大小,再根據(jù)數(shù)據(jù)碎片文件的總大小選擇合并(coalesce/repartition)方式。

    • 開(kāi)啟 dynamicAllocation
      maxConcurrency = spark.dynamicAllocation.maxExecutors * spark.executor.cores
    • 未開(kāi)啟 dynamicAllocation
      maxConcurrency = spark.executor.instances * spark.executor.cores

    以幾個(gè)場(chǎng)景為例對(duì)比優(yōu)化前后?的性能:
    ? 場(chǎng)景1:最大并發(fā)度100,碎片文件數(shù)據(jù)100,碎片文件總大小100M,如果使用 coalesce(1),將會(huì)只會(huì)有1個(gè)線程去讀/寫(xiě)數(shù)據(jù),改為 repartition(1),則會(huì)有100個(gè)并發(fā)讀,一個(gè)線程順序?qū)憽P阅芟嗖?00X。

    ? 場(chǎng)景2:最大并發(fā)度100,碎片文件數(shù)量10000,碎片文件總大小100G,如果使用 repartition(200),將會(huì)導(dǎo)致100G的數(shù)據(jù)發(fā)生 shuffle,改為 coalesce(200),則能在保持相同并發(fā)的情況下避免 200G數(shù)據(jù)的IO。

    ? 場(chǎng)景3:最大并發(fā)度200,碎片文件數(shù)量10000,碎片文件總大小50G,如果使用 coalesce(100),會(huì)保存出100個(gè)500M文件,但是會(huì)浪費(fèi)一半的計(jì)算性能,改為 coalesce(200),合并耗時(shí)會(huì)下降為原來(lái)的50%。

    上述例子的核心都是在充分計(jì)算資源的同時(shí)避免不必要的IO。

  3. 修復(fù)元數(shù)據(jù)
    因?yàn)?merge 操作會(huì)修改數(shù)據(jù)的創(chuàng)建及訪問(wèn)時(shí)間,所以在目錄替換時(shí)需要將元數(shù)據(jù)信息修改到 merge 前的一個(gè)狀態(tài),該操作還能避免冷數(shù)據(jù)掃描的誤判。最后還要調(diào)用 refresh table 更新表在 spark 中的狀態(tài)緩存。?

  4. commit 前進(jìn)行校驗(yàn)
    在最終提交前對(duì)數(shù)據(jù)進(jìn)行校驗(yàn),判斷合并前后數(shù)據(jù)量是否發(fā)生變化(從數(shù)據(jù)塊元數(shù)據(jù)中直接獲取數(shù)量,避免發(fā)生IO),存在異常則會(huì)進(jìn)行回滾,放棄合并操作。?

數(shù)據(jù)寫(xiě)入后,自動(dòng)合并效果圖:


自動(dòng)合并效果圖

后記

收益
該同步合并的方式已經(jīng)在我們的線上穩(wěn)定運(yùn)行了1年多,成功的將平均文件大小從150M提升到了270M左右,提高了數(shù)據(jù)讀取速度,與此同時(shí) Namenode 的內(nèi)存壓力也得到了極大緩解。

?對(duì) MergeTable 操作做了上述的相關(guān)優(yōu)化后,根據(jù)不同的數(shù)據(jù)場(chǎng)景下,能帶來(lái)數(shù)倍至數(shù)十倍的性能提升。

缺陷
因?yàn)椴捎玫氖峭胶喜⒌姆绞?,由于沒(méi)有事務(wù)控制,所以在合并過(guò)程中數(shù)據(jù)不可用,這也是我們后來(lái)開(kāi)始引入 D?elta Lake 的一個(gè)原因。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。