3. 数据采集策略

数据采集策略是成本台账清洗与现金流周转率监控的“第一公里”。错误的采集策略会导致数据延迟、重复计算或丢失关键交易记录。本章节围绕全量采集与增量采集两种模式,设计ETL调度频率与容错机制,确保数据管道稳定、高效、可追溯。

3.1 全量采集 vs 增量采集:适用场景与决策矩阵

全量采集适用于数据量小、需要完整快照的场景;增量采集适用于数据量大、仅需捕获变更的场景。成本台账通常采用“首次全量 + 后续增量”的混合策略。

维度 全量采集 增量采集
数据量 适合单表 < 500万行 适合单表 > 500万行
采集频率 每日/每周一次 每小时/每15分钟一次
变更捕获方式 全表覆盖 时间戳、CDC日志、增量标记
对源系统压力 高(全表扫描) 低(仅读取变更)
数据一致性 强(完整快照) 弱(需处理乱序/延迟)
适用阶段 初始化、数据修复、月末关账 日常流水、实时监控
实践建议:成本台账中的“凭证主表”建议首次全量加载后,每日凌晨执行一次全量校验;而“凭证分录明细表”采用增量采集,以“最后修改时间”作为增量字段,每30分钟拉取一次。

3.2 增量采集的三种实现方式

增量采集的核心是可靠地识别“哪些数据发生了变化”。以下是三种主流实现方式及其在成本台账场景下的适用性:

  1. 时间戳增量(Modified Timestamp):源表必须包含 last_modified 或 update_time 字段。ETL 记录上次采集的最大时间戳,每次只拉取 update_time > last_max_time 的数据。适用于大多数业务表,但需注意跨时区问题。
  2. 增量日志捕获(CDC, Change Data Capture):通过解析数据库事务日志(如 MySQL binlog、Oracle Redo Log)获取变更。延迟低(秒级),对源表无侵入,但需要额外配置 Debezium 或 Oracle GoldenGate。适用于现金流周转率监控中的高频交易表。
  3. 增量标记(Flag-based Incremental):源表增加 is_processed 标记字段,ETL 处理后将标记置为已处理。简单可靠,但需要业务系统配合修改表结构。适用于内部自建的成本台账系统。
关键指标:增量采集的“数据新鲜度”目标:成本台账明细数据延迟不超过 30 分钟;现金流周转率监控指标延迟不超过 5 分钟。

3.3 ETL调度频率设计

调度频率需要平衡数据时效性与系统负载。成本台账与现金流监控对时效性要求不同,建议分层设计:

数据层级 采集对象 调度频率 触发方式
ODS层(贴源层) 凭证主表、凭证分录表、科目余额表 每30分钟 定时调度(Cron)
DWD层(明细层) 清洗后的成本台账明细 每1小时 依赖上游ODS完成
DWS层(汇总层) 现金流周转率、应付周转天数 每15分钟 事件驱动(上游DWD更新后触发)
全量校验 所有核心表 每日凌晨02:00 定时调度
避坑提示:不要对ODS层设置过高的调度频率(如1分钟一次),否则源数据库连接池会被耗尽。建议ODS层最小间隔为15分钟,DWS层可通过事件驱动实现秒级响应。

3.4 容错机制:断点续传与死信队列

ETL管道在运行过程中可能遇到网络抖动、源库锁表、数据格式异常等问题。容错机制的核心是不丢数据、不重复处理、可人工介入。

3.4.1 断点续传(Checkpoint-based Resume)

每次增量采集任务启动时,从状态存储(如 ZooKeeper、Redis 或数据库表)读取上次成功处理的位置(如最大时间戳、binlog 偏移量)。任务失败重启后,从该位置继续拉取,避免重复或遗漏。

# 伪代码:增量采集断点续传逻辑
def incremental_pull(table_name, checkpoint_key):
    # 1. 从Redis读取上次检查点
    last_max_ts = redis.get(checkpoint_key) or '1970-01-01 00:00:00'
    
    # 2. 拉取增量数据
    sql = f"SELECT * FROM {table_name} WHERE update_time > '{last_max_ts}' ORDER BY update_time ASC"
    rows = source_db.query(sql)
    
    # 3. 处理数据(清洗、转换)
    processed_count = 0
    for row in rows:
        try:
            transform_and_load(row)
            processed_count += 1
        except Exception as e:
            # 单行异常写入死信队列,不阻塞整体流程
            dead_letter_queue.send(row, error=str(e))
    
    # 4. 更新检查点(取最后一条记录的update_time)
    if rows:
        new_max_ts = rows[-1]['update_time']
        redis.set(checkpoint_key, new_max_ts)
    
    return processed_count

3.4.2 死信队列(Dead Letter Queue, DLQ)

对于格式异常、字段缺失、违反约束的数据行,不直接丢弃,而是写入死信队列(如 Kafka DLQ Topic 或数据库异常表)。运维人员可定期查看死信队列,修复源数据后重新入队。

异常类型 示例 处理动作
字段格式错误 金额字段包含非数字字符 写入DLQ,标记“格式异常”
外键缺失 凭证分录引用了不存在的凭证主表ID 写入DLQ,等待主表数据到达后重试
时间戳乱序 增量采集到的数据时间戳小于上次检查点 写入DLQ,人工确认是否回滚
数据重复 同一笔凭证被多次采集 写入DLQ,去重后重新加载

3.5 数据采集架构总览

下图展示了成本台账数据采集的整体架构,包含全量初始化、增量CDC、断点续传与死信队列的协作关系:

成本台账数据采集架构图 成本台账数据采集架构图 源业务系统 凭证表 / 科目表 全量采集(每日) 增量CDC(30分钟) 检查点存储 Redis / ZooKeeper 死信队列(DLQ) Kafka Topic / 异常表 数据清洗与转换 去重 / 格式校验 / 关联 目标数据仓库 ODS / DWD / DWS 说明: • 首次运行执行全量采集 • 后续以增量CDC为主 • 异常数据进入死信队列

3.6 容错重试策略配置

ETL任务失败后,不能无限重试。建议采用指数退避(Exponential Backoff)策略,并设置最大重试次数:

# 容错重试配置示例(YAML格式)
etl:
  retry:
    max_attempts: 3
    initial_delay_seconds: 30
    backoff_multiplier: 2.0
    max_delay_seconds: 300
  dead_letter:
    enabled: true
    topic: "cost_accounting_dlq"
    max_retention_days: 7
  checkpoint:
    store_type: "redis"
    key_prefix: "etl_checkpoint:"
    ttl_seconds: 86400
监控指标:建议为数据采集管道设置以下告警阈值:
• 增量采集延迟 > 30分钟 → 触发P3告警
• 死信队列积压 > 1000条 → 触发P2告警
• 连续3次重试失败 → 触发P1告警并暂停任务

3.7 增量采集与全量采集的切换流程

在某些场景下(如数据修复、月末关账、源表结构变更),需要临时从增量模式切换为全量模式。切换流程必须保证数据不丢失:

  1. 暂停增量任务:停止当前正在运行的增量采集调度,记录当前检查点位置。
  2. 执行全量采集:拉取源表的完整快照,覆盖目标表对应分区。
  3. 重置检查点:将检查点更新为全量采集完成的时间戳。
  4. 恢复增量任务:从新的检查点开始继续增量采集。
注意:全量采集期间,增量任务暂停可能导致数据延迟。建议在业务低峰期(如凌晨)执行全量切换,并提前通知下游监控系统。

通过上述策略,成本台账数据采集管道能够在保证数据完整性的前提下,实现分钟级的增量更新,同时具备完善的容错与人工介入能力,为后续的现金流周转率监控提供可靠的数据基础。