全部產品
Search
文件中心

MaxCompute:合并小檔案

更新時間:Jun 19, 2024

Distributed File System按塊(Block)存放資料,檔案大小比塊大小(64MB)小的檔案稱為小檔案。分布式系統不可避免會產生小檔案,比如SQL或其他分布式引擎的計算結果、Tunnel資料擷取。合并小檔案可以達到最佳化系統效能的目的。本文為您介紹如何在MaxCompute中合并小檔案。

背景資訊

小檔案過多,會帶來以下問題:

  • MaxCompute處理單個大檔案比處理多個小檔案更有效率,小檔案過多會影響整體的執行效能。

  • 小檔案過多會給Pangu檔案系統帶來一定的壓力,影響儲存空間的有效利用。

因此從儲存和效能兩方面考慮,都需要將計算過程中產生的小檔案合并。MaxCompute在小檔案處理方面的功能日趨完善,主要體現在以下方面:

  • 預設情況下,當作業完成之後,如果滿足一定的條件,系統會自動分配一個Fuxi Task進行小檔案合并,即使用過程中經常看到的MergeTask。

  • 預設情況下,一個Fuxi Instance不再只能處理一個小檔案,而是最多可以處理100個小檔案,同時可以通過odps.sql.mapper.merge.limit.size參數來控制讀取檔案總大小。

  • MaxCompute後台會定期掃描中繼資料庫,對小檔案較多的表或分區進行小檔案合并,這個合并過程對您透明。

但是通過中繼資料發現仍然存在大量的小檔案未被合并掉,例如有的表一直在寫入,無法自動執行合併作業,需要您先將寫入作業停止,然後再手工進行小檔案合併作業。

注意事項

  • 使用合并小檔案功能需要用到計算資源,如果您購買的執行個體是隨用隨付,會產生相關費用,具體計費規則與SQL隨用隨付保持一致,詳情請參見計算費用

  • 合并小檔案命令不支援Transactional表,如果需要對Transactional表進行小檔案合并,請參見COMPACTION

查看錶的檔案數

  • 命令文法

    您可以通過如下命令查看錶的檔案數:

    desc extended <table_name> [partition (<pt_spec>)];
  • 參數說明

    • table_name:必填。待查看錶的名稱。

    • pt_spec:可選。待查看分區表的指定分區。格式為(partition_col1 = partition_col_value1, partition_col2 = partition_col_value2, ...)

  • 結果樣本

    如下圖所示,odl_bpm_wfc_task_log表的樣本分區有3607個檔案, 分區大小274MB (287869658Byte),平均檔案大小約為0.07MB,需要進行小檔案合并。

    結果樣本

解決方案

通過中繼資料檢測,分區中含有100個以上的檔案且平均檔案大小小於64MB的都可以進行小檔案合并,合并的方案有如下兩種。

  • 即時合并

    使用如下命令進行小檔案即時合并。

    ALTER TABLE <table_name> [partition (<pt_spec>)] MERGE SMALLFILES;

    odl_bpm_wfc_task_log表執行即時合併作業,完成後如下所示檔案數減少為19個,儲存大小也減少到37MB,在合并小檔案的同時,儲存效率也有了明顯提升。即時合并

    一般情況下,使用預設參數可以達到合并小檔案的效果。但MaxCompute同時提供一些參數完成定製需求,常用的一些參數如下:

    • set odps.merge.cross.paths=true|false

      設定是否跨路徑合并,對於表下面有多個分區的情況,合并過程會將多個分區產生獨立的MergeAction進行合并,所以對於odps.merge.cross.paths設定為true,並不會改變路徑個數,只是分別去合并每個路徑下的小檔案。

    • set odps.merge.smallfile.filesize.threshold = 64

      設定合并檔案的小檔案大小閾值,檔案大小超過該閾值,則不進行合并,單位為MB。此參數可以不進行設定,不設定時,則使用全域變數odps_g_merge_filesize_threshold,該參數值預設為32MB,設定時必須大於32MB。

    • set odps.merge.maxmerged.filesize.threshold = 500

      設定合并輸出檔案量的大小,輸出檔案大於該閾值,則建立新的輸出檔案,單位為MB。此參數可以不進行設定,不設定時,則使用全域變odps_g_max_merged_filesize_threshold,該參數值預設為500MB,設定時必須大於500MB。

  • PyODPS指令碼合并

    通過PyODPS非同步提交任務,合并前一天任務產出的小檔案,指令碼樣本如下:

    import os
    from odps import ODPS
    
    # 確保 ALIBABA_CLOUD_ACCESS_KEY_ID 環境變數設定為使用者 Access Key ID,
    # ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境變數設定為使用者 Access Key Secret,
    # 不建議直接使用 Access Key ID / Access Key Secret 字串
    o = ODPS(
        os.getenv('ALIBABA_CLOUD_ACCESS_KEY_ID'),
        os.getenv('ALIBABA_CLOUD_ACCESS_KEY_SECRET'),
        project='your-default-project',
        endpoint='your-end-point',
    )
    
    #注意需要替換$table_name為所需的表名
    table_name = $table_name
    t = odps.get_table(table_name)
    
    #設定merge選項
    hints = {'odps.merge.maxmerged.filesize.threshold': 256}
    
    #examples for multi partition
    insts = []
    #iterate_partitions list列舉ds=$datetime下所有分區,分區格式也可能是其他格式
    for partition in t.iterate_partitions(spec="ds=%s" % $datetime):
        instance=odps.run_merge_files(table_name, str(partition), hints=hints)
    		#從這個logview的Waiting Queue點進去,才可以找到真正執行的logview
        print(instance.get_logview_address())
        insts.append(instance)
    
    #等待分區結果
    for inst in insts:
        inst.wait_for_completion()

    運行上述指令碼需要提前安裝PyODPS,安裝方法請參見PyODPS

使用案例

tbcdm.dwd_tb_log_pv_di是資料穩定性體系識別出來的需要合并小檔案的物理表,通過中繼資料tbcdm.dws_rmd_merge_task_1d提供的資訊,如下圖所示,可以看出此表相關分區的檔案個數大部分都在1000以上,多的甚至達到7000以上,但平均檔案大小有些還不到1MB。使用樣本使用如下命令採用即時合并方案對其進行小檔案合并。

set odps.merge.cross.paths=true;
set odps.merge.smallfile.filesize.threshold=128;
set odps.merge.max.filenumber.per.instance = 2000;
alter table tbcdm.dwd_tb_log_pv_di partition (ds='20151116') merge smallfiles;

合并小檔案後結果如下圖所示:最佳化結果