业务库↔数仓↔BI三方数据对不上——跨系统对账框架怎么落地?
本文目录
先说结论
跨系统对账三层架构:源端对账(OLTP↔ODS)、中间对账(ODS↔DWD/DWS)、应用对账(DWS↔BI/服务API)。每一层负责本层数据传输/计算的正确性。三层独立运作,差异定位才能精准到层。
对账核心三要素:对账主键(用什么Key对)、对账粒度(按什么维度对)、对账时点(什么时候对最准)。这三要素不定下来,对账就是糊涂账。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
「业务系统看到的订单数是10000,数仓里查是9985,BI报表上又是9990」——这种三方对不上的问题在中大型公司几乎每天都在发生。这道题在数据架构师/Tech Lead面试里几乎必问,因为它考的是端到端的数据可观测能力。我在出海硬件公司搭过一套跨系统对账平台,今天聊聊怎么落地。
典型的三方对账链路
# 数据从产生到展示的完整链路
[业务系统(MySQL)]
↓ Binlog/CDC
[ODS层(MaxCompute)]
↓ ETL
[DWD/DWS层]
↓ ADS聚合
[BI看板(QuickBI/Tableau)] / [服务API]
↑
业务方/老板看到的最终数字
# 任何一环出错,下游都会感知,但根因可能在上游任何位置
第一层:业务库 ↔ ODS 对账
CDC同步、批量抽取,最容易出问题的就是这一层。常见根因:CDC丢消息、抽取时点不一致、字段类型转换问题、删除事件没正确处理。
-- 行数对账:最基本但最有效
-- 业务库MySQL端
SELECT COUNT(*) FROM mysql.orders
WHERE create_time < '${bizdate} 00:00:00';
-- ODS端
SELECT COUNT(*) FROM ods_orders
WHERE create_time < '${bizdate} 00:00:00' AND dt = '${bizdate}';
-- 关键字段汇总对账(金额、数量这类聚合敏感字段)
-- MySQL
SELECT SUM(amount) AS total_amt FROM mysql.orders
WHERE create_time < '${bizdate} 00:00:00';
-- ODS(必须查同一时点的快照)
SELECT SUM(amount) AS total_amt FROM ods_orders
WHERE create_time < '${bizdate} 00:00:00' AND dt = '${bizdate}';
-- 对账:差异 = ABS(MySQL总额 - ODS总额) / MySQL总额
-- 阈值:< 0.01% 通过,> 0.1% 阻断
注意点:一定要锁定时点。MySQL是实时变化的,ODS是T+1的快照。对账SQL必须严格按业务时间点对齐,不能用CURRENT_TIMESTAMP这类活的时间。
第二层:ODS ↔ DWD/DWS 对账
这一层考验的是ETL逻辑的正确性。常见问题:Join丢数据、过滤条件写错、聚合维度不全。
-- 一致性对账:ODS聚合 vs DWS
-- 聚合维度必须完全对齐
WITH ods_agg AS (
SELECT country, DATE(create_time) AS d, SUM(amount) AS amt
FROM ods_orders WHERE dt = '${bizdate}'
GROUP BY country, DATE(create_time)
),
dws_agg AS (
SELECT country, dt AS d, SUM(amount) AS amt
FROM dws_country_daily_revenue WHERE dt = '${bizdate}'
GROUP BY country, dt
)
SELECT o.country, o.d,
o.amt AS ods_amt, w.amt AS dws_amt,
ABS(o.amt - w.amt) AS diff
FROM ods_agg o FULL OUTER JOIN dws_agg w
ON o.country = w.country AND o.d = w.d
WHERE ABS(COALESCE(o.amt,0) - COALESCE(w.amt,0)) > 0.01;
-- 输出有差异的行,逐个排查
第三层:DWS ↔ BI/API 对账
最容易被忽视的一层。BI报表展示的数字和数仓里查出来的不一样,常见原因:BI做了二次过滤、聚合维度不一致、缓存未更新、口径理解差异。
-- 在数仓里复现BI报表的查询
-- 假设BI报表显示「过去7天订单数 = 7000」
-- 数仓里同样口径查
SELECT COUNT(DISTINCT order_id) AS order_cnt
FROM dws_order_daily
WHERE dt BETWEEN DATE_SUB('${bizdate}', 7) AND DATE_SUB('${bizdate}', 1)
-- 注意:BI可能加了「is_test=0」过滤,对账时要保持一致
AND is_test = 0;
-- 如果差异仍存在,检查BI侧:
-- 1. 是否做了去重(DISTINCT vs COUNT)
-- 2. 是否有时区问题(UTC vs PT)
-- 3. 是否有缓存未刷新(Tableau Extract、QuickBI物化)
跨系统对账三要素
| 要素 | 含义 | 示例 |
|---|---|---|
| 对账主键 | 用什么字段做关联 | order_id(粒度细)/ country+dt(粗粒度汇总) |
| 对账粒度 | 按什么维度做对账 | 全表汇总 / 按天 / 按维度细分 |
| 对账时点 | 什么时间点的数据 | T+1日结后2小时(业务库稳定+ODS同步完成) |
对账框架的工程实现
# 对账框架的核心数据结构
@dataclass
class ReconciliationRule:
rule_id: str
layer: str # source / middle / app
source_query: str # 源端SQL
source_engine: str # mysql / maxcompute / hologres
target_query: str # 目标端SQL
target_engine: str
join_keys: List[str] # 对账主键
metrics: List[str] # 要对的指标
threshold: float # 容忍阈值
severity: str # P0/P1/P2
# 框架核心逻辑
def run_reconciliation(rule):
src_df = execute(rule.source_engine, rule.source_query)
tgt_df = execute(rule.target_engine, rule.target_query)
diff = compare(src_df, tgt_df, rule.join_keys, rule.metrics)
if diff.max_pct > rule.threshold:
save_diff_detail(rule.rule_id, diff)
alert(rule.severity, rule.rule_id, diff.summary)
return 'FAIL'
return 'PASS'
面试高频追问
追问一:跨系统对账的频率怎么定?
源端对账T+1(业务库稳定后);中间对账T+1+若干小时(ETL跑完后);应用对账每周一次或重大发布前。频率不是越高越好,太频繁导致告警疲劳;太低又来不及发现问题。我在出海硬件公司核心表用T+1对账+月度全量盘点的组合。
追问二:对账数据本身也可能错怎么办?
两个原则:第一,对账规则要简单——对账逻辑越复杂,自身越容易错。能用COUNT、SUM搞定就别用复杂Join;第二,对账规则要做版本管理——所有对账SQL进Git,code review必须过。我们把对账SQL当生产代码一样对待,不允许临时手写。
追问三:发现差异后怎么定位根因?
分层下钻法:先看哪一层对账失败 → 在那一层做维度下钻 → 找到差异最大的维度组合 → 把差异行查出来逐条对比 → 看具体是「源有目标无」还是「源无目标有」 → 反查链路。这是个体力活,但有了对账框架,把这套SOP工具化,10分钟内能定位到根因。
实战踩坑:BI看板和数仓「永远」差0.5%的诡异bug
出海硬件公司有个GMV报表,业务方反馈BI看板和数仓查询永远差0.5%,跑了多次对账都说「PASS」,但业务方坚持说不一致。
查了三天才发现:BI工具(QuickBI)的报表用了数据集预聚合(物化),物化表是T+1凌晨1点跑的,但DWS表是T+1凌晨3点产出的,物化表的数据其实是T+2的旧版本。我们对账SQL都查的是DWS最新数据,自然PASS。
解决方案:对账SQL必须模拟BI实际查询路径——查物化表而不是查DWS。后来在对账框架里加了一项:对每个BI数据源标注「实际使用的物理表名」,对账查这个物理表。问题立刻定位:物化表更新延迟。修了调度依赖之后差异降到<0.01%。
教训:对账SQL必须模拟用户的实际数据消费路径,而不是「我们认为正确的路径」。BI工具的物化、缓存、视图嵌套都可能引入差异,这些都得对账框架感知。
总结
跨系统对账三层(源/中/应用)+ 三要素(主键/粒度/时点)+ 工程化框架。每层独立对账才能精准定位。面试时讲清楚分层架构、三要素、再用一个BI物化的故事收尾,立刻显出端到端思维。
下一篇聊一个超容易踩坑的话题:迟到数据(Late Arriving Data)怎么处理才不破坏历史质量?
你们公司有跨系统对账平台吗?多少层?评论区聊聊~
关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长