首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >DataOps 真不是“把数据跑起来”:真正难的是出了问题,你能不能找到锅在哪

DataOps 真不是“把数据跑起来”:真正难的是出了问题,你能不能找到锅在哪

原创
作者头像
Echo_Wish
发布2026-09-01 08:09:39
发布2026-09-01 08:09:39
260
举报

DataOps 真不是“把数据跑起来”:真正难的是出了问题,你能不能找到锅在哪

大家好,我是 Echo_Wish

很多公司刚开始搞 DataOps 的时候,目标都很朴素:

“把每天的数据任务自动跑起来。”

于是开始上调度平台、写 ETL、接 Kafka、搞 Airflow、配监控,再整几个告警机器人。

看起来挺现代。

但真正运行几个月以后,问题往往来了:

  • 昨天报表里的数据为什么少了 20%?
  • 这个指标到底是谁算出来的?
  • 为什么凌晨 2 点开始数据就不对了?
  • 是源库数据变了,还是 ETL 脚本改了?
  • 是某个任务失败了,还是上游虽然成功但数据已经“坏了”?
  • 产品问:“这个数字你敢保证吗?”

这时候很多团队才发现:

DataOps 最难的从来不是“让数据流动起来”,而是让数据变得可信、可追踪、可恢复。

所以今天不聊特别玄乎的概念,就站在一个运维人的角度,聊聊 DataOps 真正落地时,我认为最值得做好的三件事:

数据质量、流水线、可追溯性。

而且我一直有个比较“土”的判断:

没有质量检测的数据流水线,只是一个跑得很快的数据污染器。


一、第一关:数据质量,不是最后看报表才发现错了

传统的数据处理流程经常是这样的:

代码语言:text
复制
MySQL
  ↓
ETL
  ↓
ODS
  ↓
DWD
  ↓
DWS
  ↓
BI报表

看起来非常漂亮。

但是如果源头突然出现:

代码语言:text
复制
订单数量:10000

变成:

代码语言:text
复制
订单数量:100

整个链路可能依然:

代码语言:text
复制
任务成功
SQL成功
数据库成功
报表成功

最终:

所有系统都是绿色,业务数据却已经凉了。

这就是很多 DataOps 系统最容易踩的坑:

技术层面的成功 ≠ 数据层面的成功。

所以数据流水线里面必须加入 Data Quality。


二、数据质量至少要检查这几个东西

我自己比较推荐把数据质量检查简单拆成 5 类。

1. 完整性

比如订单表:

代码语言:sql
复制
SELECT COUNT(*)
FROM orders
WHERE order_id IS NULL;

如果结果:

代码语言:text
复制
0

说明暂时正常。

如果:

代码语言:text
复制
1523

那就别继续跑了。

因为后面所有数据都可能建立在一堆“无主订单”上。


2. 唯一性

比如订单号应该唯一:

代码语言:sql
复制
SELECT
    order_id,
    COUNT(*) AS cnt
FROM orders
GROUP BY order_id
HAVING COUNT(*) > 1;

正常情况:

代码语言:text
复制
0 rows

如果出现:

代码语言:text
复制
ORD20260901001   2
ORD20260901008   5

那就说明数据出现重复。

这种问题如果不拦住,到了统计层面可能直接变成:

“今天销售额怎么突然翻倍了?”


三、范围校验也非常重要

例如订单金额:

代码语言:sql
复制
SELECT *
FROM orders
WHERE amount < 0
   OR amount > 1000000;

你可能觉得:

“金额大一点有什么问题?”

问题是:

假设正常订单金额:

代码语言:text
复制
10 ~ 5000

突然出现:

代码语言:text
复制
999999999

这很可能不是一个超级大客户。

而是:

代码语言:python
复制
amount = price * quantity

某个地方类型转换或者数据异常了。

所以我一直认为:

数据质量规则,本质上就是给业务数据加了一层“防火墙”。


四、不要只检查“有没有数据”,还要检查“数据有没有变得奇怪”

这个特别重要。

例如每天订单量:

代码语言:text
复制
周一:10231
周二:10532
周三:10982
周四:10123
周五:10321

突然:

代码语言:text
复制
周六:231

SQL 可能完全成功。

数据库也没有报错。

但是人一眼就能看出来:

不对劲。

所以可以做同比、环比或者基线检测。

例如:

代码语言:python
复制
today = 231
yesterday = 10321

change_rate = (today - yesterday) / yesterday

if abs(change_rate) > 0.5:
    raise Exception("订单量异常波动")

这其实已经开始从传统 ETL 走向真正的 DataOps 了。

因为我们不再只是问:

“任务跑成功了吗?”

而是在问:

“这次产生的数据合理吗?”


五、第二关:流水线不要只是“能跑”,而要做到“失败可控”

很多团队的 Pipeline 长这样:

代码语言:text
复制
任务A
 ↓
任务B
 ↓
任务C
 ↓
任务D
 ↓
任务E

其中任务 C 失败。

然后呢?

不知道。

人工去服务器:

代码语言:bash
复制
ps
tail -f xxx.log
grep ERROR xxx.log

然后开始:

“谁昨天改了代码?”

这其实已经不是 DataOps 了。

这是:

半自动人工救火系统。


六、一个真正靠谱的 Data Pipeline,至少应该有状态

例如:

代码语言:python
复制
class JobStatus:
    PENDING = "PENDING"
    RUNNING = "RUNNING"
    SUCCESS = "SUCCESS"
    FAILED = "FAILED"
    RETRYING = "RETRYING"

任务执行的时候:

代码语言:python
复制
def run_job(job):
    update_status(job.id, "RUNNING")

    try:
        extract()
        transform()
        load()

        update_status(job.id, "SUCCESS")

    except Exception as e:
        update_status(job.id, "FAILED")
        send_alert(job, e)
        raise

看起来很简单。

但这里面有一个非常重要的思想:

任何任务都必须知道自己现在处于什么状态。

这样调度平台才能真正做到:

代码语言:text
复制
PENDING
   ↓
RUNNING
   ↓
SUCCESS

或者:

代码语言:text
复制
RUNNING
   ↓
FAILED
   ↓
RETRYING
   ↓
SUCCESS

七、重试不是越多越好

这是很多 DataOps 新手特别容易犯的错误。

看到失败:

代码语言:python
复制
for i in range(10):
    try:
        run()
        break
    except:
        time.sleep(10)

觉得:

“多重试几次,总能成功。”

其实不一定。

如果 SQL 写错了:

代码语言:sql
复制
SELECT xxx
FROM abc

你重试 100 次也没有用。

如果上游数据库临时网络抖了一下:

代码语言:text
复制
第一次失败
第二次成功

重试才有价值。

所以应该区分:

代码语言:text
复制
临时性故障
    ↓
可以 Retry

和:

代码语言:text
复制
业务/代码错误
    ↓
直接 Fail

例如:

代码语言:python
复制
RETRYABLE_ERRORS = (
    TimeoutError,
    ConnectionError
)

try:
    run_job()

except RETRYABLE_ERRORS:
    retry()

except Exception:
    fail()

这就是运维思维进入 DataOps 的地方。


八、第三关:可追溯性,往往比“监控”更重要

这是我认为 DataOps 最容易被低估的一部分。

假设业务人员问:

“报表里面这个 128932 到底怎么算出来的?”

你回答:

“SQL 算出来的。”

这句话其实等于没回答。

真正应该能够回答:

代码语言:text
复制
128932
  ↓
DWS.sales_amount
  ↓
DWD.order_detail
  ↓
ODS.order
  ↓
MySQL订单库
  ↓
订单 ORD20260901001

这就是:

Data Lineage,数据血缘。


九、为什么数据血缘这么重要?

因为数据出了问题以后,我们最想知道的不是:

“现在错了。”

而是:

“从哪里开始错的?”

例如:

代码语言:text
复制
源数据库
    ↓
ODS
    ↓
DWD
    ↓
DWS
    ↓
BI

如果 BI 出现异常,我们应该能够反向追踪:

代码语言:text
复制
BI指标异常
   ↓
DWS异常
   ↓
DWD正常
   ↓
ODS异常
   ↓
源系统异常

那么问题就非常清楚:

不是 BI 的锅。

这就是可追溯性真正的价值。


十、最简单的办法:给每一次数据处理建立 Trace ID

这个思路其实和微服务链路追踪非常像。

例如:

代码语言:python
复制
import uuid

trace_id = str(uuid.uuid4())

context = {
    "trace_id": trace_id,
    "job_name": "order_daily",
    "start_time": datetime.now()
}

后续所有日志都带上:

代码语言:python
复制
logger.info(
    "start transform",
    extra={"trace_id": trace_id}
)

数据库也记录:

代码语言:text
复制
trace_id
job_name
source_table
target_table
start_time
end_time
status
row_count
error_message

这样以后查问题的时候:

代码语言:sql
复制
SELECT *
FROM data_job_log
WHERE trace_id = 'xxx';

就可以把一次完整的数据处理过程串起来。


十一、再进一步:记录数据版本

如果数据非常重要,我甚至建议记录:

代码语言:text
复制
数据版本
代码版本
配置版本
Schema版本
任务版本

例如:

代码语言:json
复制
{
    "trace_id": "202609010001",
    "job": "order_daily",
    "git_commit": "8f31a2c",
    "schema_version": "v12",
    "config_version": "prod-20260901",
    "source_version": "2026-09-01",
    "row_count": 102331
}

这时候如果有人问:

“为什么昨天的销售额和今天重新计算的不一样?”

你至少有机会回答:

代码语言:text
复制
昨天:
代码 8f31a2c
Schema v11

今天:
代码 9a72bc1
Schema v12

然后继续追。

否则只能:

“应该是哪里改了吧……”

这句话在生产环境里,杀伤力很大。


十二、把三件事情真正串起来

我比较推荐的一套 DataOps 思路,可以画成这样:

代码语言:text
复制
              ┌──────────────┐
              │   数据源      │
              └──────┬───────┘
                     ↓
              ┌──────────────┐
              │ Data Quality │
              └──────┬───────┘
                     ↓
              ┌──────────────┐
              │   Pipeline   │
              └──────┬───────┘
                     ↓
              ┌──────────────┐
              │ 数据处理      │
              └──────┬───────┘
                     ↓
              ┌──────────────┐
              │ Quality Gate │
              └──────┬───────┘
                     ↓
              ┌──────────────┐
              │   数据仓库    │
              └──────┬───────┘
                     ↓
              ┌──────────────┐
              │   BI / AI    │
              └──────────────┘

旁边再挂一套:

代码语言:text
复制
日志
 ↓
Trace ID
 ↓
数据血缘
 ↓
指标监控
 ↓
告警
 ↓
审计

这时候才算比较完整的 DataOps。


十三、我特别推荐一个原则:数据质量要“左移”

很多公司都是:

代码语言:text
复制
数据产生
 ↓
数据加工
 ↓
数据入库
 ↓
BI报表
 ↓
用户发现异常
 ↓
开发排查

这其实太晚了。

更好的方式是:

代码语言:text
复制
数据进入
 ↓
立即校验
 ↓
异常拦截
 ↓
告警
 ↓
人工/自动处理
 ↓
继续流水线

也就是说:

不要让脏数据一路跑到报表层才被发现。

这跟 DevOps 里的:

代码语言:text
复制
代码提交
 ↓
CI
 ↓
测试
 ↓
安全扫描
 ↓
部署

是一个道理。

DataOps 本质上也是:

把质量控制融入流水线,而不是等事故发生以后再人工排查。


十四、最终可以形成一个 DataOps 生产闭环

一个比较成熟的数据平台,我认为至少应该形成:

代码语言:text
复制
数据产生
   ↓
质量检查
   ↓
流水线调度
   ↓
数据加工
   ↓
质量检查
   ↓
数据发布
   ↓
指标监控
   ↓
异常告警
   ↓
问题定位
   ↓
血缘追踪
   ↓
版本回溯
   ↓
修复
   ↓
重新处理

注意最后两个字:

重新处理。

这其实非常关键。

如果今天数据错了,我们不是简单地:

代码语言:text
复制
DELETE
INSERT

然后祈祷。

而应该能够根据:

代码语言:text
复制
Trace ID
+
数据版本
+
代码版本
+
任务版本
+
血缘关系

重新构建数据。

这才是真正意义上的:

可恢复的数据系统。


写在最后

我越来越觉得,DataOps 这个东西没有想象中那么“高大上”。

说到底就是解决三个非常接地气的问题:

第一:数据到底对不对?

靠:

代码语言:text
复制
完整性
唯一性
一致性
范围校验
异常波动

第二:任务到底有没有正常跑?

靠:

代码语言:text
复制
Pipeline
状态管理
Retry
超时
依赖
告警

第三:出了问题到底是谁的锅?

靠:

代码语言:text
复制
Trace ID
日志
数据血缘
版本
审计

所以如果让我用一句话总结 DataOps,我会说:

DataOps 不是把数据流水线做得多复杂,而是让数据从“产生”到“消费”的每一步,都能够被验证、被观察、被追踪、被恢复。

尤其是现在 AI、RAG、实时数仓越来越普及以后,数据质量的重要性只会越来越高。

模型可以暂时不够聪明。

但如果你喂进去的数据本身就是错的——

那模型再聪明,也只能非常认真地胡说八道。

这可能才是 DataOps 最值得我们认真思考的地方。

我是 Echo_Wish。

如果说 DevOps 解决的是“代码怎么稳定地交付”,那么 DataOps 真正要解决的,其实是:

数据怎么稳定地流动,并且让所有人敢相信它。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • DataOps 真不是“把数据跑起来”:真正难的是出了问题,你能不能找到锅在哪
  • 一、第一关:数据质量,不是最后看报表才发现错了
  • 二、数据质量至少要检查这几个东西
    • 1. 完整性
    • 2. 唯一性
  • 三、范围校验也非常重要
  • 四、不要只检查“有没有数据”,还要检查“数据有没有变得奇怪”
  • 五、第二关:流水线不要只是“能跑”,而要做到“失败可控”
  • 六、一个真正靠谱的 Data Pipeline,至少应该有状态
  • 七、重试不是越多越好
  • 八、第三关:可追溯性,往往比“监控”更重要
  • 九、为什么数据血缘这么重要?
  • 十、最简单的办法:给每一次数据处理建立 Trace ID
  • 十一、再进一步:记录数据版本
  • 十二、把三件事情真正串起来
  • 十三、我特别推荐一个原则:数据质量要“左移”
  • 十四、最终可以形成一个 DataOps 生产闭环
  • 写在最后
    • 第一:数据到底对不对?
    • 第二:任务到底有没有正常跑?
    • 第三:出了问题到底是谁的锅?
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档