图形注册和数据演变
为什么需要一个计划注册表
模式注册表是数据合同(API,事件,线程,消息,存储)的集中真理源,可提供:- 可预测的演变:兼容性规则和"切片"自动验证。
- 可重复性和透明度:版本,谁/何时/为什么更改的历史记录。
- 标准化:统一名称、错误格式、跟踪字段、PII标签。
- 与CI/CD集成:阻止中断更改直到生产。
注册表将协议第一和合同互操作性联系起来,从而使更改变得快速和安全。
格式和应用领域
JSON计划:REST/HTTP有效载荷、文档、配置。
Avro:事件总线(Kafka/Pulsar),通过ID字段进行压缩/演变。
Protobuf:gRPC/RPC,二进制有效,严格的标签。
SDL GraphQL:类型和指令图,通过"@deprecated"演变。
SQL DDL作为工件:我们捕获约定的视图(例如外部店面)-谨慎。
兼容性模式
BACKWARD:新模式读取旧数据/消息。适合以加法方式扩展付费的制作人。
FORWARD:老消费者正确阅读新数据(需要tolerant reader)。
FULL:将两者结合起来(更严格,更方便公共合同)。
NONE:没有检查-仅适用于沙箱。
- 事件:更常见的是BACKWARD(制作人可选地扩展付费负载)。
- 公共API:客户端上的FULL或BACKWARD+严格的tolerant阅读器。
- 内部原型:暂时NONE,但不在trunk上。
安全(加法)vs.危险变化
加法(OK):- 添加可选字段/类型。
- 扩展新值enum(在tolerant reader中)。
- 添加替代投影/事件(".enriched")。
- 放宽限制("minLength","maximum" ↑但不↓)。
- 删除/重命名字段或更改其类型/强制性。
- 更改线程中的状态/编解码器/顺序的语义。
- 重新使用protobuf标签。
- 更改事件中的参与密钥。
登记册的组织
Neiming和寻址
组/空间:"payments","kyc","audit"。
名称: 'payment。authorized.v1` (events), `payments.v1.CaptureRequest` (gRPC), `orders.v1.Order` (JSON Schema).
名称中的专业,次要专业-在元数据/模式版本中。
元数据
"owner"(命令),"domain","slas"(SLO/SLA)和"security"。tier` (PII/PCI), `retention`, `compatibility_mode`, `sunset`, `changelog`.
生命周期管理
Draft → Review → Approved → Released → Deprecated → Sunset.
自动验证器/linter,手动设计评论(API Guild),发布注释。
集成到CI/CD中
1.预注:本地linters (Spectral/Buf/Avro工具)。
2.公关管道:schema-diff →可比性检验;阻止破裂。
3.Artifact publish:在注册表中建立一致的计划;生成SDK/模型。
4.Runtime-guard(可选):Gateway/Producer验证付费与当前电路。
- `openapi-diff --fail-on-breaking`
- `buf breaking --against
` - `avro-compat --mode BACKWARD`
- 生成金色样本并运行CDC测试。
模式演变: 实践
Additive-first: новые поля — `optional/nullable` (JSON), `optional` (proto3), default в Avro.
反向金字塔模型:核心稳定,富集-相邻且可选。
大调的双emit/双 write:我们同时发布"v1"和"v2"。
日落计划:日期,用途,警告,适配器。
Tolerant reader:客户忽略未知字段并正确处理新的enum。
模式和检查示例
JSON计划(片段,加法场)
json
{
"$id": "orders.v1.Order",
"type": "object",
"required": ["id", "status"],
"properties": {
"id": { "type": "string", "format": "uuid" },
"status": { "type": "string", "enum": ["created", "paid", "shipped"] },
"risk_score": { "type": "number", "minimum": 0, "maximum": 1 }
},
"additionalProperties": true
}
Avro(默认兼容性)
json
{
"type": "record",
"name": "PaymentAuthorized",
"namespace": "payment.v1",
"fields": [
{ "name": "payment_id", "type": "string" },
{ "name": "amount", "type": "long" },
{ "name": "currency", "type": "string" },
{ "name": "risk_score", "type": ["null", "double"], "default": null }
]
}
Protobuf(不要重新使用标签)
proto syntax = "proto3";
package payments.v1;
message CaptureRequest {
string payment_id = 1;
int64 amount = 2;
string currency = 3;
optional double risk_score = 4; // additive
}
// tag=4 зарезервирован под risk_score, его нельзя менять/удалять без v2
事件登记和聚会
事件命名: "域。action.v{major}` (`payment.captured.v1`).
分期付款密钥是合同的一部分("payment_id","user_id")。
Core vs Enriched:'.v1'(内核)和'.enriched。v1'(零件)。
注册表兼容性:主题/类型级别的模式;CI拒绝不兼容的更改。
移民管理
Expand → Migrate → Contract (REST/gRPC):
1.添加字段/表格;2)开始编写/阅读新字段;3)在日落后删除旧的。
双emit (Events):平行于"v1"/"v2",迁移消费者/投影,然后删除"v1"。
Replay:将投影从日志重新组合到新方案(仅在兼容性和迁移器的情况下)。
适配器:为复杂客户端翻译"v1↔v2"的网关/代理。
安全和合规性
方案中的PII/PCI标签:"x-pii:true","x-sensitivity:high"。
访问策略:谁可以发布/修改模式(RBAC),签名发布。
密码学:模式的签名版本,不可变审核日志(WORM)。
遗忘权:指定需要加密/加密擦除的字段;注册表中的指导。
可观察性和审计
Dashbords:更改次数,类型(次要/专业),拒绝公关的比例以及版本的使用。
审核跟踪:谁更改了模式,链接到PR/ADR和相关版本。
运行时度量:未通过验证的消息百分比;兼容性事件。
工具(近似堆栈)
OpenAPI/JSON Schema: Spectral, OpenAPI Diff, Schemathesis.
Protobuf/gRPC: Buf, buf-breaking, protoc linters.
Avro/Events: Confluent/Redpanda Schema Registry, Avro-tools, Karapace.
GraphQL: GraphQL Inspector, GraphQL Codegen.
注册表/目录:Artifact注册表,基于Git的注册表,Backstage Catalog,定制UI。
文档:Redocly/Stoplight,Swagger-UI,GraphiQL。
反模式
Swagger-wash:该方案不反映服务的现实(反之亦然)。
禁用的兼容性检查:"我们必须紧急"→插件破裂。
重新使用protobuf标签:安静的数据损坏。
单一兼容模式"适用于所有":不同的域需要不同的模式。
原始CDC作为公共计划:DB模型向外泄漏,无法进化。
实施支票清单
- 跨域定义了工件格式和兼容性模式。
- 在CI中设置了林特和schema-diff,公关在断裂时被锁定。
- 包括客户端的tolerant reader; 'additionalProperties=true'(如果适用)。
- 主要更改通过RFC/ADR进行,有日落计划和双emit/双写。
- 电路标有PII/PCI和访问级别;已启用审计。
- 版本使用和兼容性故障的Dashbords。
- 从注册表生成SDK/模型是 pipline的一部分。
- 文档和金色样本自动更新。
FAQ
没有注册表-可以将电路存储在Git中吗?
是的,但是注册表添加了兼容性API,搜索,元数据,集中式策略和"即时"验证。最好的选择是Git作为存储+UI/策略。
如何选择兼容性模式?
查看更改方向:如果制作人扩展了付费负载-BACKWARD。对于公共API/SDK-FULL。对于快速原型-暂时NONE(不在trunk上)。
如果需要切片,该怎么办?
准备v2: dual-emit/dual-run、日落日期、适配器、使用遥测、迁移海德。
是否需要在rantime中验证付费负载?
对于关键域-是的:它可以防止"垃圾"消息并加快诊断速度。
结果
计划注册表将数据的演变从风险即兴创作转变为可管理的过程:统一的兼容性规则,自动验证,可理解的版本和透明的历史记录。添加一个附加的第一,tolerant阅读器,dual-emit和sunset的纪律-您的合同将迅速发展,没有断裂和夜间事件。