数据中心数据质量线上监控的实践

作者: 侨歌
来源: 有赞技术团队原文
原文日期: 2021 年 9 月 3 日

有赞数据报表中心向商家提供多维度、多渠道、多周期的数据,帮助商家运营店铺并作出分析决策。维度覆盖正向和逆向交易、商品、客户、流量与营销活动;渠道包括全渠道、H5、App 和小程序;周期包括实时、自然日、自然周、自然月、近 7 天、近 30 天、季度和自定义区间。

这类数据会影响商家的运营策略,因此准确性和及时性都很重要。除了功能发布可能引入问题,每日调度中的依赖表缺失、组件异常或数据异常也会造成数据问题。线上监控的目标,是尽早发现并拦截这些问题。原文介绍了离线批处理和实时流处理的监控实践:当时商家数据大多在早上 7 点前产出,所以许多规则从 7 点开始调度;为更早发现问题,也开始在业务层表(Kylin)构建完成后触发监控。

数据从哪里来

有赞的数据主要来自交易、商品、客户等业务方以及面向消费者的埋点日志。处理阶段同时提供离线与实时数据,应用层既有通用数据报表,也有定制业务数据。原文将离线数据、实时数据、应用服务放在一条链路中考虑,强调要根据每层数据的特征安排对应规则与执行时机。

离线数据:准确性与产出及时性

离线数据指昨天及以前时间范围内的统计数据,主要通过 Hive SQL 处理和聚合,时间粒度包括自然日、自然周、自然月、近 7 天、近 30 天、季度和自定义区间。原文把离线准确性监控分成指标、表和应用三个层次。

准确性规则

指标层包含三类判断:

  • 跨表对比: 比较不同表中含义相同的指标。有赞数据中心当时仍有一些页面上的同名指标由不同底层表提供;随着底层表统一模型建设,这类比较的比重预计会逐步下降。
  • 同表逻辑判断: 检查同一张表中不同指标之间应满足的逻辑关系,例如支付人数不应大于支付订单数。
  • 指标自身判断: 对指标本身检查枚举值、唯一性、非空性等规则。

表层包括全表或分区表的行数和数据量大小检查:既可以与过去某个时间点作同比、环比变化比较,也可以校验是否落在指定范围内。

应用层检查历史数据回归:在指标定义没有变化的前提下,对过去某天、某周或某月重复调用接口,确认其返回值没有变化。

这些规则需要结合数据链路来确定触发点。离线处理链路较长,每层的数据特征不同,不能把一种判断简单地安排在所有层统一执行。

产出及时性与触发时间

影响离线数据产出时间的上层因素主要有四项:

  1. 开始调度时间: 作业开始进入队列的时间,不等于开始执行的时间。
  2. 执行时长: 从开始执行到结束的耗时,通常受作业优先级、执行引擎和 SQL 效率影响。
  3. deadline: 从开始调度起允许的最长执行时间。
  4. 规则校验时间: 表更新时触发所配置的校验规则及电话告警。原文记载当时最多执行 8 分钟,超过后便开始下游调度。

更底层的影响因素是作业开发平台和大数据组件的稳定性。基于这些因素,原文介绍了商用指标工作流优先级至少为 P3、规划数仓时间基线,以及将 deadline 与电话告警结合等保障思路。

当数据尚未产出时,应用代码可能把指标默认为 0,也可能直接返回空。实践中还用接口返回指标值大于 0 作兜底判断,并监控 deadline 告警。这个大于零的规则只适用于业务上确认此时应该有正值的指标:合法的零值需要单独建模,不能因此直接当成数据缺失。

离线监控示例

原文给出的实践包括两种准确性检查:

  • 在元数据管理平台配置“同表逻辑性”规则,并在数据变更时自动触发校验。
  • 在接口自动化平台配置历史数据回归用例。监控时段为 7:00 至 24:00,每 10 分钟触发一次;除验证历史返回值外,也用于观察数仓刷数和应用发布的影响。

及时性示例则是在 7 点定时调用数据接口,检查指标值是否大于 0。原文还展示了覆盖情况和规则界面截图;本文保留其文字说明,不复制或重绘截图。

实时数据:比对上下游并观察延迟

原文把实时统计口径描述为当天零时起至当前更新时间。数据按店铺、商品等维度组织,覆盖交易(正向和逆向)、流量、营销、商品等业务,使用 Flink 处理,结果写入 Druid 和 TiDB 等底层存储。

实时准确性

实时准确性校验分为两类:

  • 上下游比对: 业务方的 binlog 日志进入数据侧后,明细先写入 TiDB;数据平台按指标统计规则处理,再把统计结果与底层存储中的结果进行比较。
  • 昨日实时与昨日离线比对: 等昨天的实时数据完全落库后,通过接口分别取出昨日实时指标和昨日离线指标,再比较结果。

实时及时性

上层表现可能是实时指标长时间不变或变化缓慢;下层可能是 Kafka 出现积压。原文将延迟的主要影响因素归于 Flink 配置和集群资源,并说明集群及 Kafka 的监控由运维同学负责,所以没有在这篇文章中展开。

上下游重试比较与告警代码

原文中的示例每 20 分钟执行一轮上下游检查,一轮最多尝试 500 次;如果仍不相等,则在比较汇总支付订单数后决定是否告警。展示的 Druid 检查代码如下:

@Override
@Scheduled(cron="0 0/20 * * * ?")
public void teamOrderCheck() {
    tidbCheck();
    druidCheck();
}

public void druidCheck() {
    boolean druidAlert = true;
    try {
        // druid
        for (int i = 0; i < 500; i++) {
            boolean res = checkOnceTeamOrder();
            if (res) {
                druidAlert = false;
                break;
            }
            Thread.sleep(2000);
        }
        String druidPayCnt = getDruidPayCnt();
        String detailPayCnt = getDetailPayCnt();
        if (druidAlert && !druidPayCnt.equals(detailPayCnt)) {
            log.warn("500次检测均不通过.");
            String content =
                "实时交易数据异常预警:druid 统计支付订单数:%s, 交易明细支付订单数:%s";
            alertBiz.commonAlert(
                String.format(content, druidPayCnt, detailPayCnt)
            );
        }
    } catch (Exception e) {
        log.warn("team order check error.");
    }
}

循环中一旦某次检查函数返回相等,就结束重试,不再发出这次 Druid 检查的告警。若一直未通过,代码再比较 Druid 汇总支付订单数和明细支付订单数;只有两者仍不相等时才告警。这里的重试是在观察上下游数据逐渐一致的过程,并不构成快照级或逐条记录一致性的证明。

每次不通过后休眠 2 秒,500 次重试的名义等待时间约为 1,000 秒(16 分 40 秒),还没有计入每次查询本身的执行时间。它可能长于 20 分钟的调度间隔;若 TiDB、Druid 检查以串行方式运行,还要评估重试对任务调度、并发和超时的影响。示例的异常分支只写日志,没有展示检查器自身失效的告警处理。生产实现还需为检查任务增加可观测性,并明确失败、超时和重试的处理方式。

对于“昨日实时与昨日离线”比较,原文使用接口自动化平台,分别调用数据应用的实时指标统计接口和离线接口。由于要等待昨日离线数据落库,执行从每天早上 7 点开始,并采用每 10 分钟轮询调度。

原文报告的效果与后续规划

文章报告:2021 年上半年以来,线上监控累计预警问题 25 次以上,其中 18 个与延迟有关,1 个问题升级为故障。作者认为这些规则有助于在商家发现问题前响应和处理。该数字是作者当时的实践记录,不能据此推断其他平台或当前系统会得到相同覆盖率或效果。

作者还提出两项尚未落地的规划:

  • 评估告警影响范围: 告警发生时明确影响了哪些业务,帮助客服更准确地回应商家;问题修复后也可以据此进行有针对性的回归测试。
  • 建设数据质量监控大盘: 由于监控数据分散在多个平台,需要汇总各平台的监控数据,并完成指标设计、实时任务和前后端开发。

实施时的边界

这是一篇 2021 年的数据平台实践记录。规则界面、告警平台和比较函数是作者所在环境中的实现,并不是可直接照搬的完整产品。接入前应重新核对自身的数据口径、调度平台与依赖组件;对指标大于零等假设,要先区分合法零值和真正缺数;对实时重试策略,要评估计算负载、任务超时和检查器自身故障。原文给出的预警数量与截图反映的是作者的案例,不代表已经覆盖所有数据表或所有质量风险。

来源说明: 本文依据有赞技术团队指定原文整理。原文页标注作者“侨歌”,日期为 2021 年 9 月 3 日;页面未提供单独的文章转载许可说明。本文保留作者署名和原始链接。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容