首页/数据/数据工程与 ETL 速查/文件到达触发与完成标记
管道基础52 条

文件到达触发与完成标记

文件类批次的可靠触发依赖“完成标记”:要么源端先写临时文件再重命名,要么用 _SUCCESS/清单文件标记批次结束,避免读到半截文件。

文件批次为什么要有完成标记

文件类数据交换的触发方式很朴素:上游把文件放到约定目录,下游定时扫描目录、发现新文件就启动批次。问题在于「目录里出现了文件」不等于「文件已经写完」——大文件写到一半就会出现在目录里,此时读取只能拿到半截内容。所以可靠的文件触发必须依赖一个完成信号:要么上游先写临时文件再原子重命名到正式目录,要么整批文件写完后放置 _SUCCESS 或清单文件作为批次结束标记。

基本信息

适用平台Linux 服务器、HDFS 与 S3/OSS 对象存储、Windows 共享盘
触发对象落地目录中的新文件或批次标记
完整性判定原子重命名、_SUCCESS 标记、清单文件
实现方式调度轮询 + 已处理清单,或对象存储事件通知

典型使用场景

  • 外部供应商按天投递对账文件:约定凌晨放到指定目录,到达即触发入库
  • Spark/Hive 批量作业产出后交付下游:用 _SUCCESS 表示输出目录已经写完
  • 对象存储文件到达触发:S3 事件通知或 OSS 事件规则直接拉起处理任务
  • 批量 CSV/Excel 手工导入数仓:先校验文件完整再解析,避免半包入库
  • 跨网闸或跨安全域的文件摆渡:必须防半包、防重复消费

轮询扫描与已处理清单

轮询扫描与已处理清单
LAND=/data/landing/orders                  # 正式目录,上游原子重命名后文件才会出现在这里
DONE=/data/landing/.processed.list         # 已处理清单,逐行记录文件名
cd $LAND || exit 1
for f in *.csv; do                          # 只扫描正式目录里的 csv
  grep -qx "$f" $DONE && continue           # 已在清单里就跳过,保证不重复消费
  [ -f "_SUCCESS" ] || { echo "批次未完成,等下一轮"; break; }   # 批次标记不存在则等待
  /opt/etl/load_orders.sh "$f" || exit 1    # 处理失败直接退出,下一轮重试
  echo "$f" >> $DONE                        # 成功后立刻登记,失败不登记
done

完成标记方案对比

方式原理适用风险点
临时目录 + 重命名先写 _tmp 再 rename 到正式目录单文件、同文件系统跨文件系统 rename 不再原子
_SUCCESS 标记整批写完后放置空标记文件Spark/Hive 输出目录标记与数据非同一事务
清单文件批次末尾生成 manifest 列出文件多文件大批次清单写失败会整批漏触发
事件通知对象存储文件创建事件推送云对象存储海量小文件易触发限流
Spark 写文件系统或 Hive 表完成后会在输出目录生成 _SUCCESS 文件,调度可以直接以它是否存在判断批次结束;历史目录里通常也留有 _SUCCESS,重跑前要先清理,否则会立刻被判定为完成。
FTP 与 SMB 共享目录上不能假设 rename 原子:Windows 共享盘与 Linux 之间的跨协议移动可能退化为「复制 + 删除」,此时应改用与数据文件同名的 .done 标记文件来宣告单个文件写完。

易错点

  • 只判断「目录非空」就开跑,多文件批次会漏掉后到的文件,产出数据缺日或缺供应商
  • 跨文件系统、跨协议的 rename 不是原子操作,临时目录必须与正式目录同盘同挂载点
  • 处理完不归档也不登记,轮询会重复消费同一批文件,只能靠目标表主键去重兜底
  • 触发后不做文件数量与大小核对,_SUCCESS 与数据文件可见性不一致时会读到残缺批次

数据来源与参考

  • Apache Spark 官方文档:Saving to Hive/文件系统输出约定
  • 行业通用文件批次落地规范
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌