数据系统与存储架构

从数据库内核到数据密集型应用,从数据工程到湖仓架构,再到企业级数据治理——系统整理数据基础设施的核心知识。

来源书目

| 书名 | 作者 | 核心贡献 | |------|------|---------| | 数据库系统内幕 | Alex Petrov | 存储引擎底层实现(B-Tree/LSM-Tree、MVCC、WAL、Raft) | | 数据密集型应用系统设计(DDIA) | Martin Kleppmann | 分布式数据系统的设计哲学与权衡 | | 数据工程之道 | Joe Reis & Matt Housley | 数据生命周期管理与工程实践 | | 湖仓架构 | 高拉夫·阿肖克·塔尔帕提 | 湖仓一体的技术选型与落地路径 | | DAMA数据管理知识体系指南 | DAMA国际 | 企业级数据治理与管理框架 |


一、存储引擎:B-Tree vs LSM-Tree

所有数据库差异的根源,本质上就是存储引擎的选择。

两种流派的根本差异

| 特性 | B-Tree(页面结构) | LSM-Tree(日志结构) | |------|-------------------|---------------------| | 写入方式 | 原地更新,需写WAL | 追加写入,极快 | | 读取性能 | 通常一次磁盘查找 | 需查多层SSTable,读放大 | | 写入性能 | 写放大高(读旧页+写WAL+写新页+写父页) | 写放大低(内存MemTable→刷盘) | | 空间放大 | 低 | 较高(旧版本需合并清理) | | 范围查询 | 天然支持(叶子节点链表) | 需合并多个SSTable | | 代表 | MySQL InnoDB, PostgreSQL | RocksDB, Cassandra, LevelDB |

核心权衡:选B-Tree还是LSM-Tree,本质上是在读放大、写放大和空间放大三者之间做取舍。读多写少选B-Tree,写多读少选LSM-Tree。

——《数据库系统内幕》Alex Petrov

LSM-Tree 关键优化

  • 布隆过滤器:用少量内存判断键"肯定不在"或"可能在"某层SSTable,显著减少读放大
  • 合并策略:Size-Tiered(写吞吐高但读放大大)vs Leveled(读放大小但写放大大)vs FIFO(时序数据专用)
  • Deletion Vectors(Delta Lake 3.0):用RoaringBitmap标记已删除行,避免整文件重写

OLTP vs OLAP 存储选型

| 场景 | 推荐引擎 | 存储结构 | |------|---------|---------| | 高并发事务 | MySQL, PostgreSQL | B+Tree行式存储 | | 高写入吞吐 | Cassandra, RocksDB | LSM-Tree | | 大规模聚合分析 | ClickHouse, DuckDB | 列式存储 | | 灵活半结构化 | MongoDB, CouchDB | 文档模型 | | 图关系分析 | Neo4j | 图存储 | | 时序数据 | InfluxDB, TimescaleDB | 时序优化 |

列式存储适合分析查询(OLAP),因为扫描单列时CPU缓存利用率高、SIMD指令友好;行式存储适合事务查询(OLTP),因为一次取出一整行。——《DDIA》Martin Kleppmann


二、事务与并发控制

ACID 的真正含义

ACID 不是四个独立的要求,而是一组有代价的承诺。隔离级别越高,锁争用越多,吞吐越低。

| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 写倾斜 | 典型实现 | |---------|------|-----------|------|--------|---------| | Read Uncommitted | ✗ | ✗ | ✗ | ✗ | 无锁 | | Read Committed | ✓ | ✗ | ✗ | ✗ | 短期读锁 | | Repeatable Read | ✓ | ✓ | ✗ | ✗ | MVCC / 两阶段锁 | | Serializable | ✓ | ✓ | ✓ | ✓ | 范围锁 / 悲观锁 |

写倾斜(Write Skew)是一个容易被忽视的异常:两个事务各自修改不同行,却违反了业务约束(如"至少一个值班医生在岗")。Repeatable Read 无法防止,需要 Serializable 或显式锁。

MVCC(多版本并发控制)

现代数据库高并发的基石。核心思路:不阻塞读,给每个事务看到数据的"快照"。

  • PostgreSQL:旧版本存在堆文件里,需要 VACUUM 清理
  • InnoDB:旧版本存在 undo log 里
  • LMDB:写时复制(Copy-on-Write)

WAL 与崩溃恢复

WAL(Write-Ahead Logging) 是数据库持久性的最后防线:先写日志,再写数据页。崩溃恢复用 ARIES 算法:先 Redo(重做已提交事务)再 Undo(回滚未提交事务)。

如果你不对日志做 fsync,所有的持久性保证都是空中楼阁。——《数据库系统内幕》


三、分布式系统的核心权衡

CAP 定理的正确理解

CAP 说的是:网络分区发生时,一致性和可用性不可兼得。但现实不是二元选择——通过可调的一致性级别(QUORUM、因果一致性等),可以在两个极端之间找到平衡。

一致性光谱

| 级别 | 保证 | 代价 | 适用场景 | |------|------|------|---------| | 线性一致性 | 所有操作看起来在单一时间线上 | 性能差,需共识算法 | 银行转账、锁服务、配置管理 | | 因果一致性 | 有因果关系的操作保持顺序 | 比线性一致性便宜很多 | 社交网络(先发帖再评论) | | 最终一致性 | 无新写入后所有副本最终一致 | 最便宜 | 缓存、CDN、搜索索引 |

实践建议:大多数场景用最终一致性 + 合理的应用层处理就够了。需要线性一致性时,用成熟的共识库(etcd/ZooKeeper),不要自己实现。

复制策略

| 策略 | 写入复杂度 | 可用性 | 代表 | |------|-----------|--------|------| | 单主同步复制 | 低 | 低(主挂了从不能接管) | 传统 MySQL | | 单主异步复制 | 低 | 中(可能丢数据) | MySQL 默认 | | 无主 Quorum | 低 | 高 | Cassandra, DynamoDB |

共识算法

| 算法 | 理解难度 | 应用 | |------|---------|------| | Paxos | ⭐⭐⭐⭐⭐ | Google Chubby | | Raft | ⭐⭐⭐ | etcd, Consul, TiKV(当前主流) |

Raft 把共识拆成三个清晰子问题:Leader 选举、日志复制、安全性。是工程实践的首选。

分布式事务

  • 2PC(两阶段提交):能防止不一致,但协调者是单点故障,阻塞协议
  • Saga 模式:拆成多个本地事务 + 补偿操作,可用性更好,适合最终一致性

四、数据架构的演进

从数据仓库到湖仓

| 维度 | 数据仓库 | 数据湖 | 湖仓一体 | |------|---------|--------|---------| | 数据格式 | 结构化 | 任意格式 | 开放格式(Parquet/ORC/Avro) | | ACID事务 | 支持 | 不支持 | 支持 | | Schema管理 | 严格 | 无/弱 | Schema演进+约束 | | 查询性能 | 高 | 低 | (数据跳读+缓存) | | 存储成本 | 高 | 低 | 低 | | ML/AI支持 | 弱 | 强 | 强 |

核心观点:数据仓库贵但可靠,数据湖便宜但混乱,湖仓试图缝合两者。底层依赖开放表格式和事务日志。

——《湖仓架构》

开放表格式选型

| 特性 | Delta Lake | Apache Iceberg | Apache Hudi | |------|-----------|---------------|-------------| | 起源 | Databricks | Netflix→Apache | Uber→Apache | | 元数据存储 | JSON事务日志 | 分层元数据文件 | 时间线 | | 引擎兼容性 | Spark为主 | 多引擎全覆盖 | Spark/Flink为主 | | Schema演进 | 支持 | 完整支持(列重命名等) | 支持 | | 新项目推荐 | Spark重度使用 | 首选(多引擎兼容) | CDC增量场景 |

选表格式就像选数据库引擎——一旦定下来,迁移成本极高。宁可多花两周调研,也不要选错后花两年填坑。——《湖仓架构》

数据湖三大致命问题

  1. 数据沼泽:存了数据之后找不到、看不懂、不敢用
  2. 缺乏事务:写完就不管,数据一致性无保证
  3. 治理缺失:开放格式降低了访问门槛,反而让泄露风险上升

五、数据工程生命周期

数据生命周期五阶段

生成 → 采集 → 存储 → 转换 → 服务

采集模式

| 模式 | 延迟 | 适用场景 | 工具 | |------|------|---------|------| | 批量采集 | 小时~天 | 历史迁移、每日报表 | Airflow + JDBC | | CDC | 秒级 | 实时数据库同步 | Debezium, Flink CDC | | 事件流 | 毫秒级 | 用户行为、IoT | Kafka, Pulsar |

垃圾进,垃圾出不是一句玩笑——采集阶段的质量问题会在下游被放大10倍。——《数据工程之道》

ELT vs ETL

  • ETL:先转换再加载。适合数据量小、需在上游清洗的场景
  • ELT:先原样加载到目标系统,再在目标系统内转换。云时代默认选择

计算架构演进

| 架构 | 特点 | 复杂度 | 适用场景 | |------|------|--------|---------| | 纯批处理 | 简单可靠 | 低 | 日报、历史分析 | | Lambda | 批处理+流处理双管道 | (双倍心智负担) | 兼顾实时和准确性 | | Kappa | 一切皆流 | 中 | 事件驱动型业务 |

Lambda架构的真正问题不是多了一套代码,而是多了一倍的心智负担。——《湖仓架构》

Medallion 数据分层(Databricks)

Bronze(铜层):原始数据摄入,保留原始格式,追加写入为主
    ↓
Silver(银层):清洗+去重+关联,Schema标准化,数据质量校验
    ↓
Gold(金层):业务聚合+指标,面向分析优化,供BI直接消费

六、数据质量与可观测性

数据质量五维度

| 维度 | 检测方法 | 示例 | |------|---------|------| | 完整性 | NULL值统计 | 客户手机号缺失率 < 5% | | 准确性 | 抽样验证、交叉引用 | 地址与邮编匹配率 > 95% | | 一致性 | 跨系统对账 | CRM与ERP金额差异率 < 1% | | 时效性 | SLA监控 | T+1数据在次日8点前就绪 | | 唯一性 | 主键去重 | 客户去重后重复率 < 0.1% |

质量门禁模型

[数据源] → 质量检查1(Schema验证)→ [采集管道]
    → 质量检查2(完整性+准确性)→ [存储层]
    → 质量检查3(一致性+时效性)→ [转换层]
    → 质量检查4(业务规则)→ [服务层]

不合格数据路由到死信队列(Dead Letter Queue),不直接污染下游。


七、数据治理框架

DAMA 车轮图(11个知识领域)

数据治理为中心,辐射:数据架构、数据建模与设计、数据存储与操作、数据安全、数据集成与互操作、文档与内容管理、参考数据与主数据、数据仓库与BI、元数据管理、数据质量管理。

治理组织架构

数据治理委员会(战略决策层)
    ↓
数据治理办公室 DGO(协调执行层)
    ↓
数据管家(各业务域操作层)
    ↓
数据生产者 → 数据存储 → 数据消费者(价值链层)

数据治理成熟度(1-5级)

| 等级 | 特征 | |------|------| | 1 初始级 | 无正式流程,靠个人英雄主义 | | 2 可重复级 | 局部实践,不系统 | | 3 已定义级 | 组织级标准和流程已建立 | | 4 已管理级 | 流程被量化监控 | | 5 优化级 | 数据管理成为核心竞争力 |


八、关键技术决策清单

数据库选型

工作负载是什么?
├── 读多写少 → B-Tree(MySQL, PostgreSQL)
├── 写多读少 → LSM-Tree(RocksDB, Cassandra)
├── 大量聚合分析 → 列式存储(ClickHouse, DuckDB)
└── 灵活关系查询 → 图数据库(Neo4j)或 关系DB+索引

一致性级别选择

业务需要多强的一致性?
├── 必须线性一致 → Raft/etcd
├── 需要因果一致 → 版本向量
└── 最终一致就行 → 异步复制 + 应用层处理

湖仓表格式选型

| 场景 | 推荐 | |------|------| | 全新项目 | Iceberg | | Spark重度 | Delta Lake | | 实时CDC入湖 | Hudi |

数据成熟度模型

Level 1 临时脚本 → Level 2 团队管道 → Level 3 自助平台
→ Level 4 数据即产品 → Level 5 AI原生

整理时间:2026-05-02 | 来源:读书笔记精华提取