合并小文件

更新时间:
复制 MD 格式

分布式文件系统按块(Block)存放数据,文件大小比块大小(64MB)小的文件称为小文件。分布式系统不可避免会产生小文件,比如SQL或其他分布式引擎的计算结果、Tunnel数据采集。合并小文件可以达到优化系统性能的目的。本文为您介绍如何在MaxCompute中合并小文件。

背景信息

小文件过多,会带来以下问题:

  • MaxCompute处理单个大文件比处理多个小文件更有效率,小文件过多会影响整体的执行性能。

  • 小文件过多会给Pangu文件系统带来一定的压力,影响存储空间的有效利用。

因此从存储和性能两方面考虑,都需要将计算过程中产生的小文件合并。MaxCompute在小文件处理方面的功能日趋完善,主要体现在以下方面:

  • 默认情况下,当作业完成之后,如果满足一定的条件,系统会自动分配一个Fuxi Task进行小文件合并,即使用过程中经常看到的MergeTask。

  • 默认情况下,一个Fuxi Instance不再只能处理一个小文件,而是最多可以处理100个小文件,同时可以通过odps.sql.mapper.merge.limit.size参数来控制读取文件总大小。

  • MaxCompute后台会定期扫描元数据库,对小文件较多的表或分区进行小文件合并,这个合并过程对您透明。

但是通过元数据发现仍然存在大量的小文件未被合并掉,例如有的表一直在写入,无法自动执行合并操作,需要您先将写入作业停止,然后再手工进行小文件合并操作。

注意事项

  • 使用合并小文件功能需要用到计算资源,如果您购买的实例是按量计费,会产生相关费用,具体计费规则与SQL按量计费保持一致,详情请参见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)
    		#从这个logviewWaiting 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_typeurl_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