数据契约核心要素:Schema定义、数据质量规则、SLA承诺、版本管理

好,咱们进入正题。上一章聊了数据契约是什么,这一章咱们拆开看看——一份能用的数据契约,到底该写什么。

我见过不少团队,一上来就搞契约模板,列了二三十个字段,结果没人填、没人用。说白了,契约不是写,是拿来干活儿的。核心要素就四个:Schema定义、数据质量规则、SLA承诺、版本管理。少一个,契约就瘸腿;多一个,反而累赘。

核心观点:数据契约的四个要素不是并列关系,而是层层递进的关系。Schema是地基,质量规则是围墙,SLA是屋顶,版本管理是维护通道。缺了任何一个,这房子都住不踏实。

数据契约核心要素架构 Schema 定义 字段名称 · 类型 · 约束 · 描述 数据质量规则 完整性 · 准确性 · 一致性 · 及时性 SLA 承诺 延迟 · 可用性 · 吞吐量 · 响应时间 版本管理 语义化版本 · 变更记录 · 兼容性策略 层级关系 越往上 越接近 业务承诺 越往下 越接近 技术实现 底层支撑上层 上层约束底层

一、Schema定义:契约的骨架

Schema是什么?说白了,就是告诉数据生产方和消费方:你要给我什么,我要收什么,长什么样,叫什么名字。没有Schema,契约就是一张废纸。

我个人习惯,Schema定义至少包含这几样东西:

  • 字段名称——用蛇形命名法,全小写,下划线分隔。别搞什么驼峰、帕斯卡混着来,那是给自己挖坑。
  • 数据类型——精确到长度和精度。比如 decimal(18,2) 而不是笼统的 number。
  • 是否必填——required: true/false,别含糊。
  • 默认值——没有值的时候怎么办?给个兜底。
  • 字段描述——一句话说清楚这个字段是干嘛的。别写「用户ID」,写「用户在CRM系统中的唯一标识,UUID格式」。

我的经验:有一次接手一个数据同步项目,消费方说「我要用户信息」,生产方给了个JSON,里面有个字段叫 info,类型是 string。结果一查,里面塞了姓名、地址、手机号,用逗号拼在一起。这就是没有Schema定义的后果——数据能传,但没法用。

一个标准的Schema定义,我建议用这样的格式:

{
  "schema": {
    "name": "user_profile",
    "version": "1.0.0",
    "fields": [
      {
        "name": "user_id",
        "type": "string",
        "format": "uuid",
        "required": true,
        "description": "用户唯一标识"
      },
      {
        "name": "user_name",
        "type": "string",
        "max_length": 64,
        "required": true,
        "description": "用户昵称"
      },
      {
        "name": "email",
        "type": "string",
        "format": "email",
        "required": false,
        "default": null,
        "description": "用户邮箱"
      },
      {
        "name": "created_at",
        "type": "datetime",
        "format": "yyyy-MM-dd HH:mm:ss",
        "required": true,
        "description": "注册时间"
      }
    ]
  }
}

嗯,这里要注意:字段描述一定要写清楚。我见过太多人偷懒,觉得「字段名已经说明一切了」。你想想看,status 这个字段,是订单状态还是用户状态?是数字枚举还是字符串枚举?值范围是什么?不写清楚,消费方只能靠猜。

二、数据质量规则:契约的肌肉

Schema定义好了,数据就能用了吗?不一定。我遇到过最典型的情况:字段名对、类型对,但数据全是脏的——手机号少一位、邮箱格式不对、金额字段出现负数。这就是为什么需要数据质量规则。

数据质量规则,说白了就是数据进来之前,先过一遍安检。我一般把规则分成四类:

规则类型 说明 示例
完整性规则 必填字段不能为空 user_id != null
准确性规则 数据值在合理范围内 age BETWEEN 0 AND 150
一致性规则 数据格式符合规范 email MATCHES regex
及时性规则 数据时间戳在预期窗口内 event_time >= now() - 1h

我曾经在一个金融项目中,就因为没加金额字段的准确性规则,导致下游报表多算了三百万。排查了两天才发现,是上游一个系统把「分」当成了「元」在传。从那以后,我所有契约里都会加一条:amount >= 0 AND amount <= 99999999.99。

避坑指南:质量规则不是越多越好。我曾经见过一个团队,给每个字段加了十几条规则,结果数据同步延迟从5分钟飙升到2小时。规则要精,不要滥。核心字段加核心规则,非关键字段可以放宽。

规则怎么写在契约里?我推荐用声明式的方式:

"quality_rules": [
  {
    "rule_id": "QR-001",
    "field": "user_id",
    "type": "completeness",
    "expression": "user_id IS NOT NULL",
    "severity": "critical",
    "description": "用户ID不能为空"
  },
  {
    "rule_id": "QR-002",
    "field": "email",
    "type": "accuracy",
    "expression": "email REGEXP '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'",
    "severity": "warning",
    "description": "邮箱格式必须合法"
  }
]

三、SLA承诺:契约的牙齿

Schema和质量规则都有了,数据就能按时到吗?不一定。我见过最离谱的情况:契约签了,数据也对了,但每天凌晨3点才到,下游的日报系统早上8点就要跑数,结果天天报错。

这就是SLA承诺要解决的问题。SLA不是空话,是白纸黑字的承诺,违约了要有后果。

我个人习惯,SLA承诺至少包含三个维度:

  • 数据延迟——生产方必须在T+1的早上6点前完成数据交付。超过就算违约。
  • 数据可用性——99.9%的时间数据可被正常消费。不可用时间要计入SLA。
  • 数据吞吐量——每秒至少支持1000条数据的写入/读取。低于这个阈值算降级。

关键点:SLA一定要可量化、可监控、可追责。别写「尽快交付」「保证质量」这种废话。写清楚:延迟不超过30分钟,数据完整率不低于99.99%,否则扣服务分或者触发告警。

一个典型的SLA定义长这样:

"sla": {
  "data_latency": {
    "max_delay_minutes": 30,
    "measurement_window": "sliding_24h",
    "penalty": "99.9% 达标率,低于则触发P1告警"
  },
  "availability": {
    "target": "99.9%",
    "excluded_maintenance_windows": ["每周三凌晨2:00-3:00"],
    "measurement_period": "月度"
  },
  "throughput": {
    "min_records_per_second": 1000,
    "burst_capacity": 5000
  }
}

你想想看,没有SLA的契约,就像没有违约条款的合同——签了也白签。生产方可以拖,消费方只能等。有了SLA,双方才有约束力。

四、版本管理:契约的进化

最后一个要素,也是最容易被忽略的——版本管理。数据契约不是写一次就完事了。业务在变,Schema在变,规则在变,SLA也在变。怎么管?

我推荐用语义化版本,跟软件版本一个道理:

版本号 变更类型 示例
主版本号 不兼容的Schema变更 删除字段、修改字段类型
次版本号 向后兼容的新增 新增可选字段、新增质量规则
修订号 不影响Schema的修正 修改字段描述、调整SLA阈值

嗯,这里有个坑:主版本变更一定要有兼容性评估。我曾经在一个项目中,生产方把 user_id 从 int 改成了 string,只改了次版本号,结果下游所有系统都崩了。为什么?因为消费方的代码里写死了 int 类型解析。

我的建议:每次版本变更,都要在契约里附带一个 changelog,写明变更原因、变更内容、兼容性影响。消费方看到版本号变了,第一件事就是去看changelog,而不是直接升级。

版本管理的完整示例:

"version_management": {
  "current_version": "2.1.0",
  "changelog": [
    {
      "version": "2.1.0",
      "date": "2025-03-15",
      "type": "minor",
      "changes": [
        "新增字段:phone_number(可选)",
        "新增质量规则:QR-003 手机号格式校验"
      ],
      "compatibility": "向后兼容"
    },
    {
      "version": "2.0.0",
      "date": "2025-01-10",
      "type": "major",
      "changes": [
        "字段类型变更:user_id 从 int 改为 string",
        "删除字段:deprecated_status"
      ],
      "compatibility": "不兼容,需消费方适配",
      "migration_guide": "消费方需将 user_id 解析方式从整数改为字符串"
    }
  ],
  "deprecation_policy": "主版本变更后,旧版本保留30天,30天后停止服务"
}

说白了,版本管理就是给契约装上一个「时光机」。出了问题能回溯,变了东西有记录,升级了有指引。没有版本管理的契约,用不了多久就会变成一团乱麻。


好,四个要素都讲完了。总结一下我的经验:Schema定义要细,质量规则要精,SLA承诺要硬,版本管理要勤。这四个要素缺一不可,但也不用一开始就追求完美。我建议先从Schema和SLA入手,跑通了再加质量规则,最后补版本管理。循序渐进,比一步到位更靠谱。