{T}

存储引擎与查询

0. 引言

分布式数据库的复制、事务、恢复等机制,最终都依赖单机存储引擎的能力:WAL 既是恢复的基础,也是逻辑复制的数据源;索引结构决定了查询路径。理解存储引擎,是理解数据库性能与可靠性的前提。本文先给出"最小分布式数据库"的整体设计,再深入存储引擎类型、日志型存储的代价、分布式索引,最后展望计算存储分离与 HTAP 趋势。

1. 最小分布式数据库:三层架构

设计一个支持基本 CRUD、可水平扩展、节点故障不丢数据的分布式 KV 数据库,约束为:数据按 Key 哈希分片、每个分片 3 个副本、写入需多数派(Quorum)确认。其架构包含三层:

图表渲染中…
  • 接入层(Proxy):接收客户端请求,按 Key 定位分片;
  • 协调节点:负责分片路由、事务协调,作为 Leader 将写入同步给副本;
  • 存储节点:实际持有分片副本,由存储引擎落盘。

1.1 读写流程

写入流程(Put(key, value)):

  1. 客户端向 Proxy 发起写入;
  2. Proxy 计算 hash(key) 定位目标分片及其 3 个副本节点;
  3. 协调节点作为 Leader 将写入同步给 3 个副本,等待多数派(≥2)确认;
  4. 多数派确认后,写入对客户端返回成功。

读取流程:同样定位分片,向多数派副本读取并取最新版本(基于时间戳或版本号);读多写少时也可读单个副本以降低延迟。

该流程结合了分片与复制(详见《数据分布:分片与复制》)的思想,并通过 Quorum 在可用性与一致性间折中;副本故障时将其移出可用集合,剩余副本仍满足 Quorum,Leader 故障则触发选举接管分片(详见《分布式协调》章)。

2. 存储引擎的职责与三大类型

存储引擎是数据库负责数据落盘、读取与组织的底层组件,核心职责包括:

  • 数据的物理组织(页、行、列);
  • 索引的维护;
  • 写入缓冲与刷盘策略;
  • 崩溃后的恢复。

主流存储引擎可按组织方式分为三类:

引擎类型组织方式优点缺点典型负载/代表
B+ 树叶子节点有序链表,支持高效范围查询与点查读友好、范围查询强随机写产生大量随机 I/O事务型、读多写少(MySQL InnoDB、PostgreSQL)
LSM-Tree写先入 MemTable,刷成有序 SSTable,读取合并多层顺序写、写入吞吐高读需合并多层(读放大),需后台 Compaction写密集、高吞吐(Cassandra、RocksDB)
列式按列存储,同列数据连续高压缩比、聚合查询快点查与单行写入效率低分析型 OLAP(ClickHouse、HBase 列族)
图表渲染中…

3. 日志型存储:LSM-Tree 的代价与收益

传统原地更新(In-Place Update)的 B+ 树存在随机写问题:一次更新可能涉及多次随机磁盘 I/O。日志型存储(Log-Structured Storage)将所有写都转化为顺序追加,充分利用磁盘的顺序写带宽,是 LSM-Tree 等现代引擎的基础。

3.1 核心思想

图表渲染中…
  1. 写入先进入内存的 MemTable(有序结构);
  2. MemTable 达到阈值后,整体刷盘为不可变的 SSTable 文件;
  3. 读取时从 MemTable 与各层 SSTable 合并出最新值;
  4. 后台通过 Compaction 合并多层 SSTable,回收过期数据。

3.2 三类放大

日志型存储引入三类代价,工程优化围绕降低它们展开:

放大类型定义缓解策略
写放大(Write Amplification)Compaction 时同一份数据被反复读写调整分层大小比、合并阈值
读放大(Read Amplification)一次读可能要查多层 SSTable布隆过滤器、缓存、层级合并
空间放大(Space Amplification)过期数据在 Compaction 前仍占空间及时 Compaction、分层策略(Leveled / Size-Tiered)

3.3 与 WAL 的关系

日志型存储的"日志"思想与预写日志(WAL)一致:先写日志再改内存,保证崩溃后可重放恢复。WAL 是事务处理与恢复的基础(详见《事务与恢复》章),也是物理复制的数据源。

4. 分布式索引

数据被分片到多个节点后,分布式索引解决的是:如何快速定位目标数据,避免全节点扫描。无索引时,一次查询需广播到所有分片(Scatter-Gather),延迟与开销随节点数线性上升。

4.1 本地索引 vs 全局索引

维度本地索引全局索引
覆盖范围仅覆盖本分片数据记录每个索引键到分片的映射,覆盖全量数据
优点构建与维护成本低,与分片生命周期一致点查可一次定位目标分片
缺点跨分片查询仍需访问多个分片,全局有序性需额外处理写入需额外维护,存在索引与数据的一致性问题;索引本身可能成为热点,需再次分片

全局索引本身也需分片:按索引键哈希分片分布均匀但范围查询需访问多分片;按索引键范围分片范围查询友好但易热点。

4.2 二级索引的一致性与范围查询

在分布式数据库中,二级索引的更新与数据写入通常不在一个原子操作中,可能出现索引与数据短暂不一致。常见方案:

  • 将索引作为本地索引,查询时各分片并行查再合并;
  • 通过异步补偿(数据可靠传播与反熵)修复不一致。

范围查询在分片环境下需处理跨分片合并:若数据按索引键有序分片,可缩小扫描分片集合;否则需对所有分片执行查询并归并。

5. 主流引擎分类与演进趋势

5.1 三大系代表

  • LSM-Tree 系:RocksDB(嵌入式 LSM 引擎,被 TiDB、CockroachDB 用作单机存储底座)、Bigtable / HBase(分布式列族)、Cassandra(去中心化 LSM,无主架构);
  • B+ 树系:InnoDB(MySQL 默认引擎,聚簇索引 + WAL)、PostgreSQL(堆表 + 索引,MVCC 实现);
  • 列式系:ClickHouse(MPP 列式)、Parquet / ORC(列存文件格式,常见于数据湖)。

5.2 计算存储分离与 HTAP

现代分布式数据库普遍采用计算与存储分离:计算节点无状态、弹性扩缩,存储层独立扩展、基于对象存储或分布式文件系统——代表如 TiDB(TiKV + 计算节点)、Snowflake、Amazon Aurora。

融合趋势:

  • HTAP:同一引擎同时服务 OLTP 与 OLAP(如 TiDB 的行存 + 列存);
  • 内存 + 持久化:内存表加速,WAL 保证持久。

6. 小结

  • 最小分布式数据库 = Proxy 接入层 + 协调节点 + 存储节点三层,Quorum 多数派确认保证不丢已提交数据;
  • 存储引擎选型看负载:B+ 树(读多/事务)、LSM-Tree(写密集)、列式(分析型);
  • 日志型存储以顺序追加换写吞吐,代价是写/读/空间三类放大,WAL 是其与恢复、复制的连接点;
  • 分布式索引:本地索引简单但跨分片慢,全局索引定位快但需解决一致性与热点;
  • 演进方向:计算存储分离 + HTAP,让一套引擎同时服务事务与分析。

下一章讲解事务与恢复:分布式事务协议与崩溃恢复机制。