18.2 数据架构、派生视图与安全演进
成熟数据架构很少由一个系统承担全部工作,也不应从第一天就堆齐所有组件。更稳妥的做法是保留清晰权威核心,按可证需求增加派生读模型,并让每个派生系统都可重建、可观测、可退出。
从单库开始的演进顺序
text
transaction database
-> add indexes and query fixes
-> read replica / partitioning when measured
-> cache for hot reconstructable reads
-> outbox + event log for reliable propagation
-> search index / analytical store / graph projection这条检查顺序用来控制复杂度,并非强制迁移路线。每加一层都应明确解决哪个 SLO,并带来哪些新故障模式。
派生视图必须能追溯来源
搜索索引、缓存和分析表中的每条数据最好带:
- 来源实体或事件 ID;
- source version / LSN / offset / event time;
- 投影 schema 版本;
- 最后成功更新时间与错误状态。
这样才能回答“这是旧数据、重复数据,还是转换逻辑错了”,并支持从确定位置重放。
Lambda 与 Kappa 不应只剩架构图
Lambda 架构同时维护批处理和流处理路径,再在 serving 层合并结果。它能用批处理纠正流计算,却要维护两套逻辑,容易出现语义漂移。
Kappa 架构把可重放事件日志作为主要输入,用同一流处理逻辑重算。它减少两套代码,但前提是日志保留足够长、事件 schema 可演进、重放不会压垮 sink,外部参考数据也能还原。
选择时看下面这些条件,名称不重要:
- 权威历史能否完整重建;
- 迟到和更正如何表达;
- 状态和 checkpoint 如何恢复;
- 重算期间怎样与在线结果切换;
- 结果的 freshness 与 completeness 如何观测。
Lakehouse 是表协议与治理问题
对象存储价格低、容量大,但裸文件缺少事务提交、快照、schema 演进和小文件治理。Lakehouse 表格式在对象之上维护元数据与快照,让多个计算引擎能看见一致表版本。
仍需治理:
- partition 与 clustering 设计;
- 小文件 compaction;
- schema/partition evolution;
- snapshot expiration 与 orphan files;
- catalog 权限、血缘和数据质量;
- 写入并发与不同引擎兼容性。
“把数据放到对象存储”不自动成为湖仓。
双写迁移为什么危险
应用同时写旧库和新库时,任一步超时都会留下不确定状态。不要把两次普通 API 调用当作事务。
更安全的迁移一般包含:
- 从权威库全量快照回填新系统;
- 通过 WAL/CDC/outbox 持续捕获增量;
- 用稳定 checkpoint 衔接全量与增量,避免缺口;
- shadow read 对比语义结果;
- 小比例切读,保留快速回退;
- 切换权威写入前冻结并验证旧写入口;
- 保留审计窗口后再退役旧系统。
对比不能只算行数。排序、NULL、浮点、时区、重复键和聚合舍入都可能造成语义差异。
可逆性是选型要求
引入系统时就准备退出:
- 是否能导出完整数据、schema、offset 和 ACL?
- 导出速度能否满足迁移窗口?
- 专有函数或数据类型如何映射?
- 加密密钥、审计记录和备份能否转移?
- 许可证和托管服务是否限制数据搬迁?
没有验证过的导出与恢复路径,等同于没有退出方案。
一份 ADR 骨架
text
Decision:
为商品搜索增加独立倒排索引,订单事实仍以 PostgreSQL 为准。
Context:
关键词、同义词和排序需求无法由当前 B+ 树索引满足;允许 30 秒陈旧。
Correctness boundary:
搜索结果不是库存和价格裁决来源;下单时回权威库校验。
Sync:
Outbox + CDC;event_id 幂等;监控 source LSN 与 index checkpoint。
Failure behavior:
索引不可用时降级为分类浏览;不允许搜索系统反写订单库。
Exit:
全量重建脚本、事件保留期、索引 schema 与导出流程。全卷的专业主线
这一卷沿着一条连续链组织二十个主题:
text
关系与约束
-> 物理页、索引、日志与恢复
-> 查询执行、优化与 CPU 效率
-> 事务、MVCC 与并发控制
-> 特殊数据模型
-> 分片、复制与跨分片事务
-> 事件传播
-> 派生读模型和架构演进下一章进入最常见的派生读模型——缓存。重点转向缓存与权威数据之间的正确性协议,而非 GET/SET API。