3. 数据采集策略
数据采集策略是成本台账清洗与现金流周转率监控的“第一公里”。错误的采集策略会导致数据延迟、重复计算或丢失关键交易记录。本章节围绕全量采集与增量采集两种模式,设计ETL调度频率与容错机制,确保数据管道稳定、高效、可追溯。
3.1 全量采集 vs 增量采集:适用场景与决策矩阵
全量采集适用于数据量小、需要完整快照的场景;增量采集适用于数据量大、仅需捕获变更的场景。成本台账通常采用“首次全量 + 后续增量”的混合策略。
| 维度 | 全量采集 | 增量采集 |
|---|---|---|
| 数据量 | 适合单表 < 500万行 | 适合单表 > 500万行 |
| 采集频率 | 每日/每周一次 | 每小时/每15分钟一次 |
| 变更捕获方式 | 全表覆盖 | 时间戳、CDC日志、增量标记 |
| 对源系统压力 | 高(全表扫描) | 低(仅读取变更) |
| 数据一致性 | 强(完整快照) | 弱(需处理乱序/延迟) |
| 适用阶段 | 初始化、数据修复、月末关账 | 日常流水、实时监控 |
3.2 增量采集的三种实现方式
增量采集的核心是可靠地识别“哪些数据发生了变化”。以下是三种主流实现方式及其在成本台账场景下的适用性:
- 时间戳增量(Modified Timestamp):源表必须包含
last_modified或update_time字段。ETL 记录上次采集的最大时间戳,每次只拉取update_time > last_max_time的数据。适用于大多数业务表,但需注意跨时区问题。 - 增量日志捕获(CDC, Change Data Capture):通过解析数据库事务日志(如 MySQL binlog、Oracle Redo Log)获取变更。延迟低(秒级),对源表无侵入,但需要额外配置 Debezium 或 Oracle GoldenGate。适用于现金流周转率监控中的高频交易表。
- 增量标记(Flag-based Incremental):源表增加
is_processed标记字段,ETL 处理后将标记置为已处理。简单可靠,但需要业务系统配合修改表结构。适用于内部自建的成本台账系统。
3.3 ETL调度频率设计
调度频率需要平衡数据时效性与系统负载。成本台账与现金流监控对时效性要求不同,建议分层设计:
| 数据层级 | 采集对象 | 调度频率 | 触发方式 |
|---|---|---|---|
| ODS层(贴源层) | 凭证主表、凭证分录表、科目余额表 | 每30分钟 | 定时调度(Cron) |
| DWD层(明细层) | 清洗后的成本台账明细 | 每1小时 | 依赖上游ODS完成 |
| DWS层(汇总层) | 现金流周转率、应付周转天数 | 每15分钟 | 事件驱动(上游DWD更新后触发) |
| 全量校验 | 所有核心表 | 每日凌晨02:00 | 定时调度 |
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、断点续传与死信队列的协作关系:
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 增量采集与全量采集的切换流程
在某些场景下(如数据修复、月末关账、源表结构变更),需要临时从增量模式切换为全量模式。切换流程必须保证数据不丢失:
- 暂停增量任务:停止当前正在运行的增量采集调度,记录当前检查点位置。
- 执行全量采集:拉取源表的完整快照,覆盖目标表对应分区。
- 重置检查点:将检查点更新为全量采集完成的时间戳。
- 恢复增量任务:从新的检查点开始继续增量采集。
通过上述策略,成本台账数据采集管道能够在保证数据完整性的前提下,实现分钟级的增量更新,同时具备完善的容错与人工介入能力,为后续的现金流周转率监控提供可靠的数据基础。