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,需要進行小檔案合并。odps@ admin_task_project>desc extended jxbwarehouse.odl_bpm_wfc_task_log partition(new_dts_sync_modifytime_year='2022',new_dts_sync_modifytime_month='11',new_dts_sync_modifytime_day='27'); +--------------------------------------------------------------------------------------------+ | PartitionSize: 287869658 | +--------------------------------------------------------------------------------------------+ | CreateTime: 2022-11-27 00:00:46 | | LastDDLTime: 2022-11-27 00:00:46 | | LastModifiedTime: 2022-11-27 23:59:47 | +--------------------------------------------------------------------------------------------+ | IsExstore: false | | IsArchived: false | | PhysicalSize: 863608974 | | FileNum: 3607 | +--------------------------------------------------------------------------------------------+
解決方案
通過中繼資料檢測,分區中含有100個以上的檔案且平均檔案大小小於64MB的都可以進行小檔案合并,合并的方案有如下兩種。
即時合并
使用如下命令進行小檔案即時合并。
ALTER TABLE <table_name> [partition (<pt_spec>)] MERGE SMALLFILES;對
odl_bpm_wfc_task_log表執行即時合併作業,完成後如下所示檔案數減少為19個,儲存大小也減少到37MB,在合并小檔案的同時,儲存效率也有了明顯提升。odps@ adxxx>alter table jxbwarehouse.odl_bpm_wfc_task_log partition(new_dts_sync_modifytime_year='2022',new_dts_sync_modifytime_month='11',new_dts_sync_modifytime_day='27') merge smallfiles; ID = xxx Log view: http: E2NzA aW9uIjoiMSJ9 Job Queueing.. STAGES STATUS TOTAL COMPLETED RUNNING PENDING BACKUP MergeFinalizeTask_0_admin.. TERMINATED 1 1 0 0 0 MergeTask_0_admin_task_pr.. TERMINATED 19 19 0 0 0 STAGES: 02/02 [==============================>>] 100% ELAPSED TIME: 75.88 s Summary: project name: , xxx schema name: jxbwarehouse table name: odl_bpm_wfc_task_log /new_dts_sync_modifytime_year=2022/new_dts_sync_modifytime_month=11/new_dts_sync_modifytime_day=27 instance count: 20 before merge, file count: 3607 file size: 281122K file physical size: 843368K after merge, file count: 19 file size: 37495K file physical size: 112486K一般情況下,使用預設參數可以達到合并小檔案的效果。但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。
查詢表 dwd_tb_log_pv_di 在分區 ds=20151114 下各子分區(按 visitor_type 和 url_type 組合)的檔案統計資訊,結果顯示 pangu_file_num(檔案數量)普遍較高(如 7384、7018、6818、5384 等),而 avg_pangu_file_size(平均檔案大小)較小,存在明顯的小檔案問題。
使用如下命令採用即時合并方案對其進行小檔案合并。
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;執行合并命令後,各分區的合并結果如下,file count 從數千個大幅減少到與 instance count 一致的數十個。
Summary:
table name: dwd_tb_log_pv_di /ds=20151116/visitor_type=uid/url_type=other/company=c instance count: 442 run time: 182
before merge, file count: 8285 file size: 226272202K file physical size: 678816607K
after merge, file count: 442 file size: 226193505K file physical size: 678580517K
table name: dwd_tb_log_pv_di /ds=20151116/visitor_type=mid/url_type=other/company=c instance count: 50 run time: 136
before merge, file count: 8285 file size: 25174441K file physical size: 75523325K
after merge, file count: 50 file size: 24979902K file physical size: 74939708K
table name: dwd_tb_log_pv_di /ds=20151116/visitor_type=mid/url_type=ipv/company=c instance count: 48 run time: 183
before merge, file count: 7888 file size: 24452025K file physical size: 73356075K
after merge, file count: 48 file size: 24328967K file physical size: 72986902K
table name: dwd_tb_log_pv_di /ds=20151116/visitor_type=uid/url_type=ipv/company=c instance count: 131 run time: 125
before merge, file count: 7620 file size: 66788449K file physical size: 200365347K
after merge, file count: 131 file size: 66660873K file physical size: 199982619K
table name: dwd_tb_log_pv_di /ds=20151116/visitor_type=uid/url_type=search/company=c instance count: 45 run time: 115
before merge, file count: 6285 file size: 22863879K file physical size: 68591639K
after merge, file count: 45 file size: 22732543K file physical size: 68197630K
table name: dwd_tb_log_pv_di /ds=20151116/visitor_type=uid/url_type=shop/company=c instance count: 50 run time: 104
before merge, file count: 6285 file size: 25156741K file physical size: 75470224K
after merge, file count: 50 file size: 25029475K file physical size: 75088426K
table name: dwd_tb_log_pv_di /ds=20151116/visitor_type=mid/url_type=search/company=c instance count: 15 run time: 130
before merge, file count: 6285 file size: 7265051K file physical size: 21795153K
after merge, file count: 15 file size: 7148859K file physical size: 21446577K
table name: dwd_tb_log_pv_di /ds=20151116/visitor_type=mid/url_type=shop/company=c instance count: 12 run time: 140
before merge, file count: 6285 file size: 5861160K file physical size: 17583481K
after merge, file count: 12 file size: 5734710K file physical size: 17204132K