Skip to content

数据质量闭环怎么落地 ​

难度与前置

难度:中级
前置:有日批主题表、分区 dt、调度依赖;知道主键唯一、空值、波动校验是什么。
读完能做什么:给一张 DWD/DWS 挂分级规则,打通「告警→认领→修复→同分区复验」,并用清单验收闭环是否真的能关掉。

适用场景 ​

  • 主题表已上线,下游依赖稳定,需要发现问题能闭环,而不是只堆规则条数
  • 对账、日报、看板经常「数不对」但事后说不清谁修、修没修好
  • 想把质量从「人肉抽查」升级成「可阻断 / 可统计」的机制

不适用:

  • 还在一次性探索取数、表随时改字段(先稳住契约再挂闭环)
  • 只有离线脚本、没有调度与通知渠道(闭环缺「告警→认领」载体)
  • 把所有对账都想做成实时秒级(本篇按日批分区闭环设计)

真实场景(一条) ​

投放 DWD dwd_ad_spend_detail_di 上线两周后,运营反馈「某渠道日报消耗比渠道后台少约 8%」。

当时已有 30+ 条 DQ 规则,但:

  1. 告警群里刷屏,无人认领,三天后才有人翻日志
  2. 开发重跑了 ODS→DWD,没记分区、没复验,第二天同问题又出现
  3. 事后才发现:渠道侧含赠款,我方口径不含赠款——规则从未校验「与渠道对账差异带原因码」

改造后:

  • P0:主键唯一、金额非空 → 失败阻断下游 DWS
  • P1:日环比波动超阈、与渠道对账差异超阈 → 告警并强制认领
  • 问题单字段:表、dt、规则、负责人、根因、修复动作、同分区复验结果
  • 该 case 关闭条件:同 dt 复验 P0 全过 + 对账差异落入「赠款」原因码且金额对齐

墙钟上:从「群里吵三天」变成「当日认领、当日复验关闭」。

怎么做(步骤清单) ​

1. 先定对象与 SLA(一张问题单的最小单元) ​

每条闭环至少写清:

项示例
对象表dwd_ad_spend_detail_di
分区dt = 业务日
出门禁点DWD 完成后、DWS 启动前
SLAP0 失败 15 分钟内认领;当日分区复验关闭
值班主题 owner + 备份人 + 告警群

TIP

闭环的最小单元是「表 + 分区 + 规则」,不是「某条 SQL」。认领与复验都按这个粒度记。

2. 规则分层:P0 阻断 / P1 告警 / P2 观察 ​

级别含义典型规则失败动作
P0错了就不能给下游主键唯一、核心金额非空、分区行数=0、强依赖维表缺失调度失败或下游不触发
P1能出数但要人看日环比/周同比波动、对账差异超阈、枚举突变告警 + 强制认领;可带熔断开关
P2观察与趋势新枚举出现、空值率缓慢爬升周报汇总,不刷屏

分级口诀:

  1. 错了会让下游金额/主键直接错 → P0
  2. 可能是业务波动也可能是事故 → P1
  3. 暂无证据、需要积累基线 → P2

示意:主键唯一(P0)与波动(P1):

sql
-- P0:当日分区主键重复(应返回 0 行)
SELECT bill_id, COUNT(*) AS cnt
FROM dwd_ad_spend_detail_di
WHERE dt = '${biz_date}'
GROUP BY bill_id
HAVING COUNT(*) > 1
LIMIT 100;

-- P0:正式口径金额空值(应返回 0)
SELECT COUNT(*) AS null_cost_cnt
FROM dwd_ad_spend_detail_di
WHERE dt = '${biz_date}'
  AND is_valid = true
  AND cost_amount IS NULL;

-- P1:日环比波动(结合基线阈值,示意)
WITH today AS (
  SELECT SUM(cost_amount) AS cost
  FROM dwd_ad_spend_detail_di
  WHERE dt = '${biz_date}' AND is_valid = true
),
yest AS (
  SELECT SUM(cost_amount) AS cost
  FROM dwd_ad_spend_detail_di
  WHERE dt = date_sub('${biz_date}', 1) AND is_valid = true
)
SELECT
  t.cost AS cost_today,
  y.cost AS cost_yest,
  (t.cost - y.cost) / NULLIF(y.cost, 0) AS dod
FROM today t CROSS JOIN yest y;
-- 告警条件示例:ABS(dod) > 0.3 且非大促日历日

3. 挂载点:出门禁,而不是「跑完再看看」 ​

推荐挂载:

text
ODS 完成
  → DWD 加工
  → 【DQ 出门禁】P0 全过才继续
  → DWS / ADS
  → 【DQ 对账/波动】P1 异步告警 + 认领

原则:

  • P0 挂在依赖边上:失败 = 下游不跑(或明确进入「熔断人工放行」流程)
  • P1 可异步:不阻塞 SLA 内出数,但必须进问题单
  • 规则 SQL 与主题任务同仓同口径(同一 is_valid、同一金额字段),避免「规则一套、报表一套」

4. 告警 → 认领 → 根因 → 修复 → 同分区复验 ​

固定状态机(字段写进问题表 / 工单):

text
OPEN(告警产生)
  → CLAIMED(有人认领,记下开始时间)
  → FIXING(定位根因:源 / 口径 / 任务 / 基础设施)
  → FIXED_PENDING_RECHECK(已修数或已改逻辑)
  → CLOSED(同表同 dt 复验通过)
  或 WAIVED(带审批的豁免,必须写原因与有效期)

根因三选一(先归类再深挖):

根因类例子修复方向
源渠道晚到、文件缺列、重复推送补数、与源侧对票
口径含税/赠款、时区、过滤条件变更改 DWD 契约并回刷分区
任务依赖漏配、并发写同一分区、逻辑 bug修任务 + 重跑级联

WARNING

修完必须同分区复验。只看「任务变绿」不算关闭;要以规则 SQL 再跑一遍该 dt 的结果为准。

5. 问题表最小字段(可复制) ​

sql
CREATE TABLE IF NOT EXISTS dq_issue_ticket (
  issue_id        STRING  COMMENT '工单 ID',
  table_name      STRING  COMMENT '对象表',
  dt              STRING  COMMENT '业务分区',
  rule_id         STRING  COMMENT '规则编码',
  rule_level      STRING  COMMENT 'P0/P1/P2',
  alert_ts        TIMESTAMP COMMENT '告警时间',
  owner           STRING  COMMENT '认领人',
  claim_ts        TIMESTAMP,
  root_cause      STRING  COMMENT '源/口径/任务/其他',
  fix_action      STRING  COMMENT '补数/改逻辑/豁免等',
  recheck_sql     STRING  COMMENT '复验用的规则或摘要',
  recheck_result  STRING  COMMENT 'PASS/FAIL',
  recheck_ts      TIMESTAMP,
  status          STRING  COMMENT 'OPEN/CLAIMED/.../CLOSED/WAIVED',
  note            STRING
)
COMMENT 'DQ 闭环问题单(示意,可落 Hive/工单系统)';

6. 基线与阈值:没有数字就不要喊「波动」 ​

  • 新主题上线前 7~14 天先跑 P2 观察,沉淀分位数再升 P1
  • 大促 / 渠道切换日写入日历豁免,避免刷屏导致「狼来了」
  • 对账类规则必须带差异原因码(迟到、赠款、过滤、未知),「未知」超阈才升 P0/P1

常见坑 ​

  1. 堆 200 条规则仍漏报
    无分级、无基线、全是 P2 刷屏。先保 P0 出门禁,再加少量高信号 P1。

  2. 只告警无人认领
    群消息 ≠ 闭环。必须有认领人、认领时限;超时升级到 backup / 主管。

  3. 修数不复验
    重跑变绿就关单,同分区问题次日再现。关闭条件写死:规则 SQL 对同一 dt 再跑通过。

  4. 把对账当一次性脚本
    手工 Excel 对一次就丢。对账差异应进 P1 规则 + 原因码,并可按周统计打开→关闭时长。

  5. P0 过多导致「习惯性人工放行」
    出门禁失效。P0 只留真正不能错的几条;其余降级并配豁免审批。

  6. 规则口径与主题口径不一致
    规则扫全量、报表只算 is_valid=true,告警永远对不上业务。规则与 ADS/DWS 同过滤。

如何验收(可量化) ​

  • [ ] 对象表、分区、出门禁点、SLA、值班人写进文档或表注释
  • [ ] 至少 3 条 P0(主键唯一、核心度量非空、空分区)挂在 DWD→DWS 依赖上,失败可阻断
  • [ ] P1 告警能进问题单且强制认领;状态机含复验字段
  • [ ] 抽一条历史问题:能从告警复盘到根因、修复、同分区复验 PASS
  • [ ] 周维度可统计:打开数、关闭数、P0 平均关闭时长、WAIVED 占比
  • [ ] 对账类差异带原因码;「未知」有单独阈值
sql
-- 验收 1:P0 主键重复应为 0
SELECT COUNT(*) AS dup_group_cnt
FROM (
  SELECT bill_id
  FROM dwd_ad_spend_detail_di
  WHERE dt = '${biz_date}'
  GROUP BY bill_id
  HAVING COUNT(*) > 1
) t;

-- 验收 2:问题单闭环完整性(示意)
SELECT
  status,
  COUNT(*) AS cnt,
  AVG(unix_timestamp(recheck_ts) - unix_timestamp(alert_ts)) / 3600.0 AS avg_hours_to_close
FROM dq_issue_ticket
WHERE dt >= date_sub('${biz_date}', 7)
GROUP BY status;
-- 期望:CLOSED 占大多数;OPEN/CLAIMED 不跨日堆积;关闭单 recheck_result = PASS
bash
# 验收 3:调度出门禁(示意:DQ 任务失败则下游不触发)
# 用你们的调度器检查依赖边:dwd_xxx_dq_p0 → dws_xxx
# 人为注入一条重复主键后,确认 DWS 未启动且告警已产生

相关面试题 ​

题库小程序链接待定;先用站内锚点占位。

  • [ ] 题:质量闭环最少要写清哪些出门禁信息?(考察点:对象表/分区/出门禁点/SLA/值班人)→ 占位:#todo-interview-closed-loop-gate-info
  • [ ] 题:P0 挂在依赖上应能做什么?如何人为验证?(考察点:失败可阻断下游 + 注入重复主键后 DWS 不启)→ 占位:#todo-interview-closed-loop-p0-block
  • [ ] 题:一条历史问题怎样才算闭环?(考察点:告警→根因→修复→同分区复验 PASS)→ 占位:#todo-interview-closed-loop-ticket-close
  • [ ] 题:周报看哪些数字证明闭环在转?(考察点:打开/关闭/P0 平均关闭时长/WAIVED 占比)→ 占位:#todo-interview-closed-loop-weekly-metrics

改写说明:结构参考 Wood 原创质量/面试实践,已改写成可执行清单;未包含未公开公司数据与内部工单系统名。