3、数据契约定义与规范:契约定义语言(CDL)、字段命名规范、数据类型映射、元数据标签体系
数据契约这东西,说白了就是给实时数仓立规矩。没有规矩,你想想看,上游随便改个字段类型,下游直接崩掉。我在项目里见过太多次这种惨案了。所以这一章,咱们就把契约的定义、命名、映射和标签体系彻底讲透。
3.1 契约定义语言(CDL)
CDL 不是什么新语言,而是一套轻量级的 YAML/JSON 规范。我个人习惯用 YAML,可读性更好。一个完整的 CDL 文件长这样:
# 数据契约定义示例
contract:
version: "1.0"
domain: "order"
dataset: "order_detail"
owner: "data-platform@company.com"
schema:
- name: order_id
type: string
description: "订单唯一标识"
constraints:
- not_null
- unique
- name: user_id
type: string
description: "用户ID"
constraints:
- not_null
- name: amount
type: decimal(18,2)
description: "订单金额"
constraints:
- not_null
- min: 0
producer:
system: "order_service"
topic: "ods_order_detail"
partition: 12
retention: "7d"
consumer:
- system: "flink_dwd"
usage: "实时宽表加工"
- system: "clickhouse"
usage: "实时报表查询"
quality:
- metric: "null_rate"
threshold: 0.01
- metric: "duplicate_rate"
threshold: 0.001
这里有几个关键点:
- version:契约版本号,每次变更必须升级
- producer/consumer:明确谁生产、谁消费
- quality:数据质量阈值,这是实时数仓的生命线
我曾经踩过一个坑:契约里没写 retention,结果上游 topic 数据只保留 24 小时,下游离线任务跑批时数据已经过期了。从那以后,我强制所有 CDL 必须包含 retention 字段。
3.2 字段命名规范
命名规范这事,看起来简单,做起来全是坑。我见过一个项目,字段名有驼峰、有下划线、有匈牙利命名法,混在一起简直灾难。我的建议是:
3.2.1 核心原则
- 全小写 + 下划线:这是 Flink 和 Kafka 生态的通用做法
- 业务前缀:比如订单域用
ord_,用户域用usr_ - 避免缩写歧义:
create_time不要写成crt_tm
3.2.2 分层命名示例
| 分层 | 命名规则 | 示例 |
|---|---|---|
| ODS | ods_{源系统}_{表名} | ods_mysql_order_detail |
| DWD | dwd_{业务域}_{主题} | dwd_order_payment_rt |
| DWS | dws_{业务域}_{维度}_{指标} | dws_order_daily_summary |
| ADS | ads_{应用}_{场景} | ads_realtime_dashboard |
小技巧:字段名长度控制在 30 个字符以内。太长的话,Kafka schema registry 和 Flink 状态后端都会有点吃不消。
3.3 数据类型映射
实时数仓里,数据类型映射是最容易出问题的地方。MySQL 的 DECIMAL 到 Flink 的 DECIMAL,看起来一样,精度却可能丢失。我整理了一份常用映射表:
| MySQL 类型 | Flink SQL 类型 | Kafka Avro 类型 | 注意事项 |
|---|---|---|---|
| INT | INT | int | 无符号类型需转为 BIGINT |
| BIGINT | BIGINT | long | 注意溢出问题 |
| DECIMAL(p,s) | DECIMAL(p,s) | bytes(decimal) | 精度 p 最大 38 |
| VARCHAR(n) | STRING | string | Flink 无长度限制 |
| DATETIME | TIMESTAMP(3) | string(iso8601) | 时区统一用 UTC |
| JSON | STRING | string | Flink 1.15+ 支持原生 JSON |
核心原则:所有时间字段统一使用 TIMESTAMP(3) 类型,时区固定为 UTC+0。下游消费时再根据业务需求转换。这样可以避免跨时区带来的各种诡异问题。
3.4 元数据标签体系
元数据标签,说白了就是给数据打上各种标记,方便管理和检索。我习惯把标签分为三类:
3.4.1 技术标签
- 数据源:mysql、kafka、log、binlog
- 采集方式:全量、增量、CDC
- 存储引擎:HDFS、Kafka、ClickHouse
- 压缩格式:snappy、gzip、lz4
3.4.2 业务标签
- 业务域:订单、支付、用户、商品
- 数据等级:核心、重要、一般
- 敏感等级:P0(公开)、P1(内部)、P2(敏感)、P3(机密)
- 生命周期:热数据、温数据、冷数据
3.4.3 治理标签
- 质量状态:正常、告警、阻塞
- 负责人:团队或个人
- SLA 等级:99.9%、99.99%
- 审计状态:未审计、已审计、待复核
这些标签最终会写入元数据中心,比如 Apache Atlas 或自研的元数据平台。每次数据流转时,标签会自动继承和更新。
注意:标签不是越多越好。我见过一个团队给一张表打了 50 多个标签,结果维护成本比数据本身还高。建议每张表不超过 10 个核心标签。
3.5 数据契约全流程
说了这么多,咱们用一张图把整个流程串起来:
这张图展示了数据契约从定义到消费的完整链路。核心在于:契约先行,校验紧随,标签兜底。没有契约,实时数仓就是一团乱麻。
我的经验:刚开始推行数据契约时,团队会觉得麻烦。但坚持一个月后,你会发现线上故障减少了 80%。这就是规矩的力量。