【从零开始学架构】DDIA 精要:一套关于“数据系统架构”的分层理论

《Designing Data-Intensive Applications》(DDIA)不应被简单视为数据库说明书,而应被理解为一本以数据为中心的后端系统架构书。它没有按"数据库、缓存、消息队列"等产品类别来组织,而是按照数据从诞生到消亡的生命周期,构建了一套从底向上的分层理论。

其核心演化路径为:

数据如何表示 → 如何存储 → 如何跨机器扩展 → 如何处理并发与故障 → 如何在多系统间流动 → 如何形成完整应用。


一、全局架构视角

DDIA 的架构图包含两种逻辑关系:

  1. 上下层依赖:上层能力建立在下层机制之上。
  2. 横向约束:可靠性、可伸缩性和可维护性(RAS)以及故障模型,贯穿并约束所有层级。

#mermaid-svg-XsTcopSrwY1sitU5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XsTcopSrwY1sitU5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XsTcopSrwY1sitU5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XsTcopSrwY1sitU5 .error-icon{fill:#552222;}#mermaid-svg-XsTcopSrwY1sitU5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XsTcopSrwY1sitU5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XsTcopSrwY1sitU5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XsTcopSrwY1sitU5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XsTcopSrwY1sitU5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XsTcopSrwY1sitU5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XsTcopSrwY1sitU5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XsTcopSrwY1sitU5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XsTcopSrwY1sitU5 .marker.cross{stroke:#333333;}#mermaid-svg-XsTcopSrwY1sitU5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XsTcopSrwY1sitU5 p{margin:0;}#mermaid-svg-XsTcopSrwY1sitU5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XsTcopSrwY1sitU5 .cluster-label text{fill:#333;}#mermaid-svg-XsTcopSrwY1sitU5 .cluster-label span{color:#333;}#mermaid-svg-XsTcopSrwY1sitU5 .cluster-label span p{background-color:transparent;}#mermaid-svg-XsTcopSrwY1sitU5 .label text,#mermaid-svg-XsTcopSrwY1sitU5 span{fill:#333;color:#333;}#mermaid-svg-XsTcopSrwY1sitU5 .node rect,#mermaid-svg-XsTcopSrwY1sitU5 .node circle,#mermaid-svg-XsTcopSrwY1sitU5 .node ellipse,#mermaid-svg-XsTcopSrwY1sitU5 .node polygon,#mermaid-svg-XsTcopSrwY1sitU5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XsTcopSrwY1sitU5 .rough-node .label text,#mermaid-svg-XsTcopSrwY1sitU5 .node .label text,#mermaid-svg-XsTcopSrwY1sitU5 .image-shape .label,#mermaid-svg-XsTcopSrwY1sitU5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-XsTcopSrwY1sitU5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XsTcopSrwY1sitU5 .rough-node .label,#mermaid-svg-XsTcopSrwY1sitU5 .node .label,#mermaid-svg-XsTcopSrwY1sitU5 .image-shape .label,#mermaid-svg-XsTcopSrwY1sitU5 .icon-shape .label{text-align:center;}#mermaid-svg-XsTcopSrwY1sitU5 .node.clickable{cursor:pointer;}#mermaid-svg-XsTcopSrwY1sitU5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XsTcopSrwY1sitU5 .arrowheadPath{fill:#333333;}#mermaid-svg-XsTcopSrwY1sitU5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XsTcopSrwY1sitU5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XsTcopSrwY1sitU5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XsTcopSrwY1sitU5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XsTcopSrwY1sitU5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XsTcopSrwY1sitU5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XsTcopSrwY1sitU5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XsTcopSrwY1sitU5 .cluster text{fill:#333;}#mermaid-svg-XsTcopSrwY1sitU5 .cluster span{color:#333;}#mermaid-svg-XsTcopSrwY1sitU5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XsTcopSrwY1sitU5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XsTcopSrwY1sitU5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-XsTcopSrwY1sitU5 .icon-shape,#mermaid-svg-XsTcopSrwY1sitU5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XsTcopSrwY1sitU5 .icon-shape p,#mermaid-svg-XsTcopSrwY1sitU5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XsTcopSrwY1sitU5 .icon-shape .label rect,#mermaid-svg-XsTcopSrwY1sitU5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XsTcopSrwY1sitU5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XsTcopSrwY1sitU5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XsTcopSrwY1sitU5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 横向约束
核心数据流
数据密集型应用
业务访问模式
数据模型与查询语言
存储引擎与索引
复制与分区
事务与一致性
批处理与流处理
缓存/搜索/数仓/推荐/报表
可靠性
可伸缩性
可维护性
故障模型


二、地基:业务访问模式决定架构

DDIA 的第一原则是:不要先问用什么技术,先问应用如何访问数据。

架构推导链条如下:

业务事实 → 访问模式 → 数据模型 → 存储结构 → 系统部署

不同的访问模式对基础设施的要求截然不同:

访问模式 关注点 典型技术倾向
主键查单条记录 点查询、低延迟 KV存储、B+树
时间范围查询 范围索引、排序 LSM树、时间序列DB
多表关联分析 Join能力、关系完整性 关系型数据库
关键词检索 倒排索引 搜索引擎 (Elasticsearch)
聚合统计 列式扫描、压缩 数据仓库 (OLAP)
推荐与画像 图遍历、实时计算 图数据库、流处理

三、第一层:数据模型------逻辑抽象

数据模型是应用与存储之间的桥梁,决定了业务对象的关系表达方式。

  • 关系模型:擅长表达复杂的多对多关系和强一致性约束。
  • 文档模型:擅长表达聚合数据,读写单元与业务对象对齐。
  • 图模型:擅长表达复杂的连接关系和路径搜索。

关键点:数据模型的选择直接影响后续的查询能力、数据冗余策略及分区方式。它是整个系统架构的地基。


四、第二层:存储引擎------物理实现

存储引擎负责将逻辑模型落地为物理结构。应用发出 SELECT,引擎内部则需解决写入路径、索引构建、崩溃恢复等问题。

DDIA 重点剖析了两条经典路线:

  1. LSM 树(Log-Structured Merge-Tree)
    • 路径 :写入日志 →\to→ 内存表 →\to→ SSTable →\to→ 后台合并。
    • 特点:顺序写优化,高吞吐,适合写多读少,但需要处理 Compaction 带来的写放大。
  2. B 树家族
    • 路径 :固定页面 →\to→ 树状索引 →\to→ 原地更新。
    • 特点:稳定的随机读性能,适合读多写少,但写入可能涉及多次随机 I/O。

架构推论:为了满足不同的访问模式,同一份业务数据往往需要多种物理表示(如订单主表、用户索引、搜索索引、分析宽表),这自然推动了架构从单一数据库向多系统演进。


五、第三层:分布式系统------复制与分区

当单机无法承载时,架构必须横向扩展。核心手段只有两种:

  • 复制(Replication) :解决可靠性 (容错)和伸缩性(读扩展)。
  • 分区(Partitioning) :解决数据容量写负载的分散。

现实中,二者通常结合使用:

全量数据集 $\to$ 切分为多个分区 $\to$ 每个分区再复制多副本。

核心认知转变 :分布式不仅仅是"加机器"。它将单机时代隐式保证的原子性、顺序性等特性,变成了需要显式设计的复杂协议。例如,网络分区、副本不一致、时钟不同步等问题,迫使我们必须直面部分失败的现实。


六、第四层:语义保障------事务、一致性与共识

在不可靠的分布式环境下,我们需要定义"用户能看到什么"。

  1. 事务(Transaction):解决并发操作之间的正确性(原子性、隔离性),防止脏写、丢失更新。
  2. 一致性(Consistency):解决客户端视角的观测问题(读己之写、单调读、前缀一致)。
  3. 共识(Consensus):解决多个节点之间的决策问题(选主、锁管理、状态机复制)。

三者关系:事务 关注操作间的纠葛,一致性 关注观察者的视角,共识关注集群的决策。它们是构建可信赖系统的语义层。


七、第五层:故障模型------现实的残酷面

DDIA 强调,设计系统前必须先定义"什么会坏"。

  • 单机思维:函数调用非成即败,时间统一。
  • 分布式现实:消息丢失/重复/乱序、节点假死、时钟漂移、网络延迟。

超时并不等于失败 。一个请求超时,服务端可能已经执行成功,只是响应丢失。因此,幂等性重试机制状态机防护令牌成为分布式架构的标准配置。


八、第六层:数据流架构------衍生数据的艺术

前九章聚焦于单一系统的存储,后三章则上升到多系统协作

大型应用通常由多个针对不同场景优化的数据系统组成。DDIA 提出了两个关键概念:

  1. 记录系统(System of Record):权威数据源(Source of Truth),如订单主库。
  2. 衍生数据系统(Derived Data Systems):从记录系统转换而来,可丢弃并重建,如缓存、索引、数仓。

架构模式由此从"单一的CRUD"转变为"基于日志的数据流":
#mermaid-svg-2nbPZ0pGAiDrQyuH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2nbPZ0pGAiDrQyuH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2nbPZ0pGAiDrQyuH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2nbPZ0pGAiDrQyuH .error-icon{fill:#552222;}#mermaid-svg-2nbPZ0pGAiDrQyuH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2nbPZ0pGAiDrQyuH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2nbPZ0pGAiDrQyuH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2nbPZ0pGAiDrQyuH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2nbPZ0pGAiDrQyuH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2nbPZ0pGAiDrQyuH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2nbPZ0pGAiDrQyuH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2nbPZ0pGAiDrQyuH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2nbPZ0pGAiDrQyuH .marker.cross{stroke:#333333;}#mermaid-svg-2nbPZ0pGAiDrQyuH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2nbPZ0pGAiDrQyuH p{margin:0;}#mermaid-svg-2nbPZ0pGAiDrQyuH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2nbPZ0pGAiDrQyuH .cluster-label text{fill:#333;}#mermaid-svg-2nbPZ0pGAiDrQyuH .cluster-label span{color:#333;}#mermaid-svg-2nbPZ0pGAiDrQyuH .cluster-label span p{background-color:transparent;}#mermaid-svg-2nbPZ0pGAiDrQyuH .label text,#mermaid-svg-2nbPZ0pGAiDrQyuH span{fill:#333;color:#333;}#mermaid-svg-2nbPZ0pGAiDrQyuH .node rect,#mermaid-svg-2nbPZ0pGAiDrQyuH .node circle,#mermaid-svg-2nbPZ0pGAiDrQyuH .node ellipse,#mermaid-svg-2nbPZ0pGAiDrQyuH .node polygon,#mermaid-svg-2nbPZ0pGAiDrQyuH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2nbPZ0pGAiDrQyuH .rough-node .label text,#mermaid-svg-2nbPZ0pGAiDrQyuH .node .label text,#mermaid-svg-2nbPZ0pGAiDrQyuH .image-shape .label,#mermaid-svg-2nbPZ0pGAiDrQyuH .icon-shape .label{text-anchor:middle;}#mermaid-svg-2nbPZ0pGAiDrQyuH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2nbPZ0pGAiDrQyuH .rough-node .label,#mermaid-svg-2nbPZ0pGAiDrQyuH .node .label,#mermaid-svg-2nbPZ0pGAiDrQyuH .image-shape .label,#mermaid-svg-2nbPZ0pGAiDrQyuH .icon-shape .label{text-align:center;}#mermaid-svg-2nbPZ0pGAiDrQyuH .node.clickable{cursor:pointer;}#mermaid-svg-2nbPZ0pGAiDrQyuH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2nbPZ0pGAiDrQyuH .arrowheadPath{fill:#333333;}#mermaid-svg-2nbPZ0pGAiDrQyuH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2nbPZ0pGAiDrQyuH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2nbPZ0pGAiDrQyuH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2nbPZ0pGAiDrQyuH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2nbPZ0pGAiDrQyuH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2nbPZ0pGAiDrQyuH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2nbPZ0pGAiDrQyuH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2nbPZ0pGAiDrQyuH .cluster text{fill:#333;}#mermaid-svg-2nbPZ0pGAiDrQyuH .cluster span{color:#333;}#mermaid-svg-2nbPZ0pGAiDrQyuH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2nbPZ0pGAiDrQyuH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2nbPZ0pGAiDrQyuH rect.text{fill:none;stroke-width:0;}#mermaid-svg-2nbPZ0pGAiDrQyuH .icon-shape,#mermaid-svg-2nbPZ0pGAiDrQyuH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2nbPZ0pGAiDrQyuH .icon-shape p,#mermaid-svg-2nbPZ0pGAiDrQyuH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2nbPZ0pGAiDrQyuH .icon-shape .label rect,#mermaid-svg-2nbPZ0pGAiDrQyuH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2nbPZ0pGAiDrQyuH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2nbPZ0pGAiDrQyuH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2nbPZ0pGAiDrQyuH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户操作
记录系统
CDC/事件日志
缓存
搜索索引
数据仓库
推荐系统

通过 CDC(变更数据捕获)将数据库的变更转化为事件流,驱动下游所有衍生系统的更新。


九、批处理与流处理:一体两面

批处理和流处理本质上是同一种模式:输入 $\to$ 处理 $\to$ 输出

  • 批处理:处理有界历史数据,适合全量构建和修复(如重建搜索索引)。
  • 流处理:处理无界实时事件,适合增量更新(如实时风控)。

统一视角 :批处理是"重放全部历史",流处理是"增量消费变化"。二者的桥梁是事件日志 (Event Log)和物化视图(Materialized View)。数据库、消息队列、流计算框架,本质上都是这条数据流上的不同环节。


十、总结:四层架构模型

为了便于记忆,可以将全书浓缩为四层架构,外嵌 RAS(可靠性、可伸缩性、可维护性)三大目标:

L1:数据表示层

  • 内容:数据模型(关系/文档/图)、查询语言、编码(Schema Evolution)。
  • 核心:如何表达业务事实。

L2:数据存储层

  • 内容:存储引擎(LSM/BTree)、索引、事务。
  • 核心:如何高效落地数据。

L3:数据分布层

  • 内容:复制、分区、故障模型、一致性、共识。
  • 核心:如何在多机上可靠地存储。

L4:数据处理层

  • 内容:批处理、流处理、CDC、物化视图、数据集成。
  • 核心:如何让数据在多系统中流动并产生价值。

最终结论 :DDIA 教给我们的,不是如何使用某个具体的数据库,而是如何将一个应用视为多个数据系统的有机整体,并能清晰地回答:每一份数据从哪里来,在哪里存,如何复制,如何更新,如何传播,以及在失败后如何恢复。

相关推荐
亲爱的马哥2 小时前
Vue3 + Element Plus 低代码表单设计器架构拆解与私有化落地实践
低代码·架构·敏捷流程
LONGZETECH3 小时前
工业实训仿真设计实践:电机拆装软件的 DAG 流程建模、工具精度分级与数据体系搭建
大数据·算法·unity·架构·汽车
张忠琳5 小时前
【NVIDIA】k8s-device-plugin v0.19.3 — CDI / MIG / vGPU 模块超深度代码分析之五
云原生·容器·架构·kubernetes·nvidia
StarkCoder5 小时前
AI 会做多、看少、不收尾:七种失效和拦住它们的办法
人工智能·架构
冷莫溪5 小时前
Docker——3.Harbor 核心架构与原理详解
docker·容器·架构
beibeix20155 小时前
3D Slicer 架构分析
架构·slicer
snow@li6 小时前
命名规范:企业级微服务模块前缀命名规范全景梳理
微服务·云原生·架构
roman_日积跬步-终至千里6 小时前
【从零开始学架构】系统设计的价值:从业务目标到可演进系统
架构
JL156 小时前
Java 分层架构迁移到 Go:controller/service/dao 怎么落?
java·架构·golang