数据库内核实验索引
汇总本站数据库内核文章:PostgreSQL / MySQL InnoDB / 列存引擎 / 数据湖与开放表格式 / 流式数据处理 / 分布式 OLAP 查询引擎 / RocksDB 内核,以及 LSM-Tree 从零实现实验。
发布来自土法炼钢兴趣小组的知识、笔记、进展和应用。主题包括数据结构和算法、编程语言、网络安全、密码学等。
共 131 篇文章 · 返回首页
汇总本站数据库内核文章:PostgreSQL / MySQL InnoDB / 列存引擎 / 数据湖与开放表格式 / 流式数据处理 / 分布式 OLAP 查询引擎 / RocksDB 内核,以及 LSM-Tree 从零实现实验。
闭合存储引擎三角的最后一角:对照 PG B-Tree 与列存 scan,定位 LSM 写优化引擎在 TiKV、Flink、Kafka Streams、ClickHouse Embedded 中的嵌入方式,并划分本系列与 lsm-tree DIY、storage/31–32、stream/12 的分工边界。
以 LevelDB 1.23 为对照基线:拆解单后台 compaction 线程、无 Column Family 的 DBImpl 结构,以及 Write 队列 group commit、Get 层级查找与 SST/MANIFEST 最小语义,为 RocksDB 9.x diff 地图打底。
对照 LevelDB 1.23,用 diff 表与源码路径梳理 RocksDB 9.x 的多线程 flush/compaction、Column Family、RateLimiter、Direct IO、Statistics 与并发 MemTable 写,建立后续读 db_impl 子文件的坐标系。
从 log::Writer 的 32KB Block 分片 record、WriteBatch 二进制布局,到 DBImpl::WriteImpl 中 Group Commit 与 sync/fsync 语义,钉住写路径第一步:先 WAL 后 MemTable 的提交顺序与原子性边界。
从 SkipList MemTableRep、MemTableList 的 immutable 双缓冲队列,到 FlushJob::WriteLevel0Table 与 VersionSet 安装 L0 文件,闭合 WAL 之后 MemTable 如何变成 SST,并对照 lsm-tree DIY 实现。
从 BlockBasedTable 的 Data/Index/Filter Block 与 Footer 定界,到 VersionEdit 增量记录与 VersionSet::LogAndApply 如何维护 LSM 快照,并用 sst_dump 对照磁盘布局。
从 DBImpl::GetImpl 层级查找路径出发,拆解 LookupKey、sequence number 编码、SuperVersion 引用与 Snapshot 可见性边界;对照 PostgreSQL MVCC 的 txn id 语义差异。
沿 DBImpl::NewInternalIterator 拆解 InternalIterator 栈、MergeIterator 多路归并与 LevelIterator;说明 DBIter 上 tombstone/range del 的可见性裁剪及与 compaction 归并堆的同构关系。
沿 TableCache 与 BlockBasedTable 读路径说明 Block Cache、Table Cache、Full/Ribbon Filter 与 Partitioned Index 如何裁剪点查 I/O;读放大度量与调参边界引用 storage/68,不重复全文推导。
从 L0 重叠与 L1+ 不重叠不变式、Size Ratio 与 base_level 动态计算,到 LevelCompactionPicker 如何选 L0→Lbase 与 Intra-L0;三种放大与 storage/31 衔接,exp10 用 db_bench stats 观察层级分布。
对照 Universal/FIFO/TTL compaction 策略,从 GetWriteStallConditionAndCause 与 WriteController 的 Stop/Delay token,到 DBImpl::DelayWrite 状态机、LOG 与 GetProperty 判读;exp11 用极低 L0 阈值触发 stall。
从 CompactionJob 的 Prepare/Run/Install 与 subcompaction 并行,到 Env 高低优先级线程池、MaybeScheduleFlushOrCompaction 调度,以及 GenericRateLimiter 的 kWritesOnly 与 DelayWrite 的争抢关系;exp12 三路中位数对比方法论。
从 RocksDB 3.0 引入的 Column Family 出发,拆解共享 WAL、独立 MemTable/SST/Version 链、`ColumnFamilyHandle` 生命周期与 DBOptions/ColumnFamilyOptions 分层;并对照 Flink 多 state 变量到 CF 的映射边界。
对照 WriteBatch 原子性与 Snapshot MVCC,拆解 TransactionDB 悲观锁、OptimisticTransactionDB 提交时冲突检测、WritePrepared 的 prepare/commit 与 CommitCache 边界;TiKV 分布式事务仅作 B 级前瞻,不替代 Percolator 正文。
拆解 Checkpoint 同盘硬链接快照、BackupEngine 增量备份目录布局、SstFileWriter 离线建表与 IngestExternalFile 的 sequence 分配及 write stall 边界——对接 Flink 增量 checkpoint 与 bulk load 运维路径。
从 RocksDB 内核侧补全 Flink KeyGroup 前缀与增量 checkpoint SST 上传机制,对照 TiKV Region 引擎与 Kafka Streams changelog 容错;不重复 stream/12 作业侧全文,给出 Docker 复现步骤而不伪造 checkpoint 指标。
用 GetProperty 与 LOG 钉住 L0 堆积、compaction 落后、Block Cache 未命中与 ENOSPC write stall 四类生产故障;交叉引用 storage/76 磁盘耗尽链,给出 db_bench 复现步骤而不伪造 stats 数字。
用决策树收束 RocksDB 与 InnoDB、列存、湖仓的适用边界;给出存储引擎三角 + 数据平台全栈阅读地图,对接 query-engine/18 与 postgresql-kernel,并标注 HTAP/TiKV 续作入口。
补全存储引擎三角最后一角:从 LevelDB 基线与 RocksDB 架构演进,到 WAL/MemTable/SST 写路径、Get/Iterator 读路径、Leveled/Universal compaction 与 write stall,再到 Column Family、事务、Checkpoint 与 Flink/TiKV 嵌入对照。
Hive 目录式分区表把『表』等同于『一组目录加 metastore 里的分区行』,于是没有原子提交、planning 要 LIST 目录、schema 与分区演进常要重写。本文用这三个硬伤切入,讲清 lakehouse 把表拆成『不可变数据文件 + 可变元数据指针 + catalog』三层后各自解决了什么,并给出全系列的分层地图。
拆 Parquet 的物理结构:file → row group → column chunk → page,footer 里的 FileMetaData(Thrift)与 PAR1 magic。讲清 PLAIN/RLE-bitpacking/字典/DELTA_BINARY_PACKED/BYTE_STREAM_SPLIT 各自压谁,Dremel 的 repetition/definition level 如何表达嵌套,column index/offset index 与 split-block bloom filter 怎样让谓词在读盘前裁掉 page。基于本机 pyarrow 24.0.0 真实 dump footer 与编码。
ORC 用 stripe 而非 row group、用三级统计(file/stripe/row-group index)而非独立 page index、用 PRESENT/DATA 等 stream 而非 page 组织一列。本文按 ORC 规范拆其文件尾(postscript + footer)、stripe 内部结构与 RLEv2 整数编码,并用本机 pyarrow 24.0.0 把同一份 30 万行数据写成 ORC 与 Parquet,对比真实体积与物理布局,最后给出什么场景仍用 ORC。
拆解 Arrow 列式内存布局(validity bitmap + value buffer + offset buffer)、零拷贝从何而来,以及 C Data Interface、IPC、Flight 三层跨边界传递。讲清 Arrow(内存计算格式)与 Parquet(磁盘存储格式)如何分工衔接。含 pyarrow 实测 C Data Interface 同地址零拷贝。
拆解 Parquet 的两层缩减:专用编码(dictionary / RLE / DELTA_BINARY_PACKED / BYTE_STREAM_SPLIT)降熵,再用 zstd/snappy/lz4/gzip 压字节。用 pyarrow 在同一列上实测不同编码+压缩组合的体积与读取耗时(3M 行,7 轮中位数),并与 ClickHouse CODEC 做同思想不同落地的对照。
对象存储不是网络版 POSIX 文件系统。本文用 S3 官方语义钉住四件事:强一致模型的边界、LIST 随对象数线性增长的代价、没有原子 rename(只能 copy+delete)、条件写(If-None-Match/If-Match)对提交协议的意义,并讲清 multipart 与对象不可改写。
目录式分区表(Hive 表)在对象存储上有三处硬伤:并发写部分提交、list planning 太贵、缺快照隔离与原子提交。本文拆开放表格式补上的四件事——原子提交、快照隔离、文件级统计裁剪、schema 与分区演进,并抽象出三家共有的『元数据指针 + 不可变数据文件』骨架。
拆解 Iceberg 的四层元数据:catalog 指针 → metadata.json → manifest list(snapshot)→ manifest file → data file。讲清 snapshot 与 manifest 里的分区数据和列级 stats(lower/upper bound、null/value count)如何让一次查询不 list 目录就收敛到文件集合,并给出表规范 V1/V2/V3 的版本边界。基于 pyiceberg 0.11.1 真实建表逐层 dump。
拆解 Iceberg 的 partition spec 与 transform(identity/bucket[N]/truncate[W]/year/month/day/hour/void):隐藏分区如何让查询不写分区列谓词也能裁剪,分区演进为何不重写历史数据(文件携带所属 spec),以及与 Hive 静/动态分区的本质差异。基于 pyiceberg 0.11.1 真实演进 spec 并观察新旧文件。
Iceberg 在不可变文件上做行级删除的两条路线:copy-on-write(重写整文件)与 merge-on-read(写 delete 文件,读时合并)。讲清 position delete 与 equality delete 的语义、字段与作用域规则,写放大/读放大的取舍,V2 delete file 到 V3 deletion vector(Puffin 承载)的差异与迁移,以及读路径如何把 data file 与 delete 合并出可见行。基于 pyiceberg 0.11.1 实测 CoW 写放大并观察 MoR 回退。
没有数据库进程,Iceberg 怎么在对象存储上做原子提交与并发控制?拆解提交=catalog 对元数据指针做 compare-and-swap,乐观并发如何基于当前 snapshot 生成新 snapshot、冲突按操作类型与隔离级别重试,不同 catalog 的原子性来源(DB 行锁/CAS、REST 后端、对象存储条件写、文件系统 rename),以及 REST Catalog 的 requirements+updates 提交语义。基于 pyiceberg 0.11.1 实测并发冲突与重试。
拆解 Delta Lake 的 _delta_log:有序 JSON commit 里的 add/remove/metaData/protocol/commitInfo/txn 七类 action、每 N 次 parquet checkpoint 与 _last_checkpoint、protocol 版本与 reader/writer table features、deletion vector(Delta 的 merge-on-read)、liquid clustering 与 Z-order,以及乐观并发如何完全基于日志做冲突检测。
拆解 Apache Hudi 的内核:CoW 与 MoR 两种表类型、.hoodie 下的 timeline 与 instant 三态、file group/file slice 的存储模型、base file 与 log file、compaction/clustering/cleaning,以及 bloom/simple/record-level/bucket 索引体系为何让 Hudi 强在 upsert,最后讲 snapshot/read-optimized/incremental 三种查询类型。锚定 Hudi 1.x 官方文档。
把前面 08–13 章拆过的 Iceberg、Delta、Hudi 放在一个坐标系里对照:元数据模型、行级更新、并发控制、引擎生态四维,每维标清口径。再讲两条互通路线——Delta UniForm(写时同步生成 Iceberg/Hudi 元数据)与 Apache XTable(事后转换元数据),以及它们的边界。最后给一棵按写入模式/引擎栈/更新频率展开的选型决策树,不做排名。
拆解 lakehouse catalog 的两件核心职责——表名到当前元数据指针的映射、以及原子提交点;对比 Hive Metastore、Iceberg REST Catalog、JDBC、Hadoop、Glue、Nessie、Gravitino 的锁与原子性语义,单列 Apache Polaris 与 Unity Catalog 开源后的形态、权限模型与 REST 规范互通。
讲清 Iceberg 的 snapshot 过期、回滚与按时间/快照读如何工作;schema evolution 为何按 field ID 而非位置来增删改名重排;以及演进对老数据文件与老 reader 的兼容边界与陷阱,附 PyIceberg 真实实验验证字段映射与时间旅行。
拆解 lakehouse 小文件的根因(频繁提交、流式、过细分区),以及 bin-pack、sort/z-order/clustering、rewrite manifests、expire snapshots、remove orphan files 这套治理操作;讲清 Puffin 中 Theta NDV sketch 对查询 planning 的作用,附 PyIceberg 真实实验对比 compaction 前后文件数与 planning 耗时。
拆解查询引擎读 Iceberg/Delta 的下推链路:partition pruning(manifest)→ file pruning(manifest stats)→ row-group/page pruning(Parquet column index)→ 字典过滤。对照 Trino/Spark/DuckDB/DataFusion/ClickHouse 的能力差异,讲清 planning 在哪一层完成、stats 从哪来,并用本机 pyiceberg + DuckDB 实测裁剪效果。
拆解流式数据进入 Iceberg/Delta/Hudi 的入湖侧机制:Flink/Kafka Connect/Spark sink 如何提交、exactly-once 怎样把引擎 checkpoint 与表格式的原子提交对齐、CDC 如何借 equality delete 与 record index 做 upsert,以及高频提交与小文件、compaction 的拉扯。只讲入湖侧,流处理引擎本身的窗口与状态留给后续。
把前面 19 篇的机制落到工程决策:从 Hive 表迁移到 Iceberg 的三条路径与风险、湖仓 benchmark 的口径陷阱、生产里最常见的故障模式(孤儿文件、元数据膨胀、提交冲突风暴、快照过期误删、catalog 单点),以及一份可执行的运维清单。
湖仓如何承接 AI 负载:embedding/特征/训练样本存湖、按 snapshot 固定数据版本做可复现训练,以及 Parquet 在随机访问和向量检索上的短板。用本机实测对比 Lance 与 Parquet 的顺序扫描与按行随机 take,讲清 Lance 为何为随机访问与向量而生,并划清湖侧存储与专用向量引擎的边界。
拆解 lakehouse 的两层基础:列式文件格式(Parquet/ORC/Arrow)与开放表格式(Iceberg/Delta/Hudi)。讲清没有数据库进程时,如何在对象存储上做 ACID、行级更新、快照与并发,以及 catalog、查询引擎、流式入湖如何拼成可运维的湖仓。面向数据平台工程师与从 OLAP/数仓转型的开发者。
fsync() 返回 EIO 后再调一次为什么会成功?为什么这反而是灾难?从 2018 fsyncgate 到 Linux errseq_t,再到本机内核 6.6 上用 dm-error 单块故障注入的实测,讲清 writeback 失败时脏页被标记 clean、数据静默丢失的真相,以及 PostgreSQL 为什么选择 PANIC。
数据丢失最令人恐惧的形式不是磁盘报错——而是数据悄无声息地变了,没有任何告警,没有任何日志,直到几个月后你从备份里恢复出一堆损坏的文件,才发现"完整性"这个词从来就不是理所当然的。
行存 vs 列存的带宽、压缩与向量化三角;ClickHouse Server 进程模型、线程池与 MergeTree 引擎家族地图;src/Storages 与 src/Processors 源码入口。对照 PG 行存与 LSM 写优化路径,版本锚定 ClickHouse 24.x LTS。
ClickHouse MergeTree Part 目录结构:columns.txt、checksums.txt、.bin、.mrk2、primary.idx 语义,Granule 与 Mark 的定位作用,Wide/Compact 布局与 MergeTreeDataPart 源码入口。版本锚定 24.x LTS。
ClickHouse 列压缩:LZ4、ZSTD、Delta、DoubleDelta、Gorilla 时序编码与列类型关系;CODEC 链顺序、LowCardinality 与 PG TOAST 对照。压缩比须本机实测,本文不编造倍数。
ClickHouse Block 列向量 batch、IProcessor Pipeline 与 filter/project/aggregate 向量实现;对照 PostgreSQL 火山模型 ExecProcNode。源码入口 src/Processors、src/Columns。24.x LTS。
MergeTree SELECT 读路径:Mark Range 定位 Granule、PREWHERE 与 WHERE、Part 级并行与 max_threads。EXPLAIN indexes=1 解读方法。24.x LTS,无伪造 EXPLAIN 输出。
MergeTree 后台 merge 触发与 selector、ReplacingMergeTree/CollapsingMergeTree 语义、ALTER UPDATE/DELETE mutation 异步路径与危害。对照 LSM compaction。源码 MergeTreeDataMergerMutator。24.x LTS。
ClickHouse PRIMARY KEY 排序键稀疏索引语义、Data Skipping Index(minmax/set/bloom_filter)与 Mark Range 协同;对照 PostgreSQL B-Tree。24.x LTS。
主选 ClickHouse 拆解 MergeTree 存储格式、向量化执行与分布式协调;DuckDB 作为嵌入式 OLAP 对照。覆盖列存文件布局、merge 机制、跳数索引与生产故障模式,面向数据平台工程师与从 PG/MySQL 转 OLAP 的 DBA。
在 Linux 的传统 I/O 路径中,应用程序通过 read() 和 write() 系统调用与文件交互时,数据并不会直接在用户空间缓冲区(User Buffer)和磁盘之间传输。内核会在两者之间插入一层页缓存(Page Cache),作为磁盘数据在内存中的缓存副本。一次典型的写入流程如下:
系统分析小文件在块分配、元数据管理、磁盘寻道和网络协议四个层面的放大效应,用数据量化 slack space、inode 开销和 syscall 成本,给出应用层聚合与对象存储归档两种工程方案。
逐层拆解 ext4、XFS、Btrfs、ZFS 从 70% 填充到 100% 耗尽过程中的块分配退化、碎片化加剧和 ENOSPC 故障模式,给出各文件系统的容量红线、监控阈值和应急恢复方法。
拆解 POSIX 文件锁三大 API 的语义差异,深入 close-any-fd 释放陷阱、OFD 锁机制、F_GETLK 竞态和 NFS 锁恢复的工程真相,给出每种场景的正确选择。
深度复盘 GitLab 2017 数据库事故和 GitHub 2018 存储故障的完整时间线与根因分析,提取跨事故的通用模式,给出构建抗事故存储实践的工程建议。
拆解 O_DIRECT 对齐约束与 io_uring 固定缓冲区(IORING_REGISTER_BUFFERS)如何叠加;对比 buffered/Direct I/O 的 io_uring 实测 IOPS,给出数据库与块设备场景选型。
汇总本站存储工程系列文章,覆盖 HDD、SSD、NVMe、持久内存、索引结构、压缩、分布式存储与对象存储。
深入剖析云块存储——分布式块存储架构原理、AWS EBS与阿里云ESSD架构分析、云盘性能规格解读、性能测试方法与选型成本优化
深入剖析云对象存储——S3的11个9持久性实现、元数据-索引-存储三层架构、跨AZ复制策略、存储类别实现差异与成本模型分析
深入剖析计算存储分离——Aurora日志即存储、TiDB的TiKV+TiFlash分层、Snowflake对象存储+缓存、ClickHouse存算分离模式的架构对比与选型指南
深入剖析新硬件技术——ZNS SSD编程模型、CXL内存扩展对缓存层的影响、计算存储设备(CSD)与DPU在存储路径中的角色与工程实践
展望存储技术未来——DNA存储与冷数据归档、光存储、存内计算(PIM)、统一存储接口(文件+对象+块融合)、AI驱动存储管理与技术雷达
深入剖析存储基准测试的方法论——fio 参数解析、filebench 工作负载定义、YCSB 数据库基准、测试陷阱规避与性能回归测试集成
系统梳理 Linux I/O 性能分析工具——iostat、blktrace、BCC/bpftrace、ftrace、perf 的使用方法,以及 I/O 瓶颈排查流程与常见问题模式
深入分析存储多级缓存架构——Page Cache、Buffer Pool、应用缓存的协同设计,缓存淘汰算法对比,缓存穿透/击穿/雪崩的防护策略
深入分析存储写入性能优化——WAL 分组提交、批量写入、Write Buffer 调优、fsync 频率控制、写入限速与写停顿分析
深入分析存储读取性能优化——索引设计、Bloom Filter 调优、块缓存、压缩的 CPU-I/O 权衡、预读策略与读放大测量
全面剖析存储全链路延迟——从应用到硬件的逐层延迟分解、尾延迟分析、延迟热图、biolatency/ext4dist/fileslower 工具实战
深入分析数据持久性的工程计算——故障率模型、多副本与纠删码的持久性推导、相关故障的影响、实际数据丢失案例与持久性计算器实现
全面分析存储系统的静默故障——比特翻转、扇区错误、丢失写、撕裂写、固件 bug 与灰色故障,以及 CERN/Google 的大规模数据损坏研究
系统剖析存储备份策略——全量/差异/增量备份、逻辑 vs 物理备份、WAL 连续归档、备份验证与恢复测试、MySQL 与 PostgreSQL 备份方案实战
全面剖析灾难恢复架构——RPO/RTO 等级设计、同城双活与异地灾备、两地三中心架构、故障切换机制与灾备演练方法论
深入分析数据生命周期管理——热/温/冷/归档数据分层、自动分层策略、对象存储生命周期规则、数据合规与保留策略、存储成本优化
全面剖析存储层的混沌工程实践——磁盘故障注入、慢 I/O 模拟、数据损坏测试、Chaos Mesh IOChaos、LitmusChaos 与慢盘检测算法
系统剖析分布式存储中的数据分片——哈希分片与范围分片的工程权衡、一致性哈希与虚拟节点、跳跃一致性哈希,以及分片策略在实际系统中的应用
深入分析分布式存储中的数据复制——同步/异步/半同步复制、链式复制、多主复制与冲突解决、Quorum 复制的工程实践
深入分析分布式存储的元数据架构——集中式 vs 分布式 vs 无元数据方案、元数据分片与缓存、HDFS NameNode 与 Ceph CRUSH 的工程实践
深入分析分布式存储的数据均衡——扩容缩容时的数据迁移策略、在线重分片、迁移限速与优先级、Ceph PG 自动均衡与 TiKV Region 调度
全面剖析多租户共享存储集群的工程实践——配额管理、QoS 调度、噪音邻居问题、存储级 RBAC、加密隔离与审计日志
深入分析存算分离架构——Shared-Nothing vs Shared-Disk vs Shared-Storage 的工程权衡,Snowflake/Aurora/TiDB 的存算分离实践,本地缓存策略与网络带宽需求
深入分析对象存储的设计哲学——文件系统与对象存储的本质差异、CAP 权衡、最终一致性到强一致性的演进,以及 S3 API 核心操作实战
全面剖析 S3 API 的工程细节——Multipart Upload、S3 Select、生命周期策略、跨区域复制、性能优化与 boto3 高级用法
深入剖析 MinIO 的分布式架构——Erasure Set、Server Pool、元数据管理、数据修复、IAM 策略系统与集群部署运维实战
深入剖析纠删码的数学原理与工程实践——Reed-Solomon 编码、编码矩阵与恢复过程、参数选择、降级读性能、局部修复码,以及在 MinIO/Ceph 中的配置实战
深入分析 S3 兼容性工程——各厂商兼容差异、对象存储网关架构、跨云数据迁移工具与多云对象存储策略
全面剖析对象存储的性能优化——大文件并发分片、小文件打包策略、列表操作陷阱、CDN 集成、传输加速与基准测试方法论
深入剖析存储系统中的核心编码技术——变长整数、差值编码、字典编码、游程编码、位图编码与位打包,分析各编码方式的空间效率和解码速度
系统对比 LZ4、Zstd、Snappy、Brotli 等压缩算法在存储引擎中的工程实践——压缩率、速度、CPU 开销与选型指南
深入分析存储系统中的数据完整性保障——CRC32C、xxHash、SHA-256 的性能对比,静默数据损坏的检测与防护,端到端校验架构设计
系统对比 Protobuf、FlatBuffers、Cap'n Proto、MessagePack 等序列化格式——性能基准、零拷贝反序列化、兼容性设计与存储系统中的选型实践
全面剖析静态数据加密的工程实践——块级加密、文件级加密与应用级加密的架构对比,AES-XTS/AES-GCM 选型,密钥层次与轮转,硬件加速性能分析
一条典型的分析查询只访问表中数百列里的三四列,行式存储却把整行数据从磁盘搬进内存,绝大多数字节在读入后立刻被丢弃。列式存储(Columnar Storage)把同一列的值连续存放,查询只需要读取涉及到的列,I/O 量可以降低一到两个数量级。但 I/O 减少只是故事的一半——列式布局还为压缩、向量化执行(Vectoriz…
上一篇我们讨论了列式存储(Columnar Storage)的核心思想:把同一列的数据连续存放,让分析查询只读取需要的列,而不是扫描整行。这个思想落地到具体文件格式时,需要回答一系列工程问题:文件内部怎么组织数据才能同时支持并行读取和列裁剪?同一列的数据用什么编码方式才能最大化压缩率?如何在不读取全部数据的前提下跳过不…
在大数据和分析系统的演进过程中,一个反复出现的性能瓶颈不是计算本身,而是数据在不同系统之间搬运时的序列化(Serialization)与反序列化(Deserialization)开销。Pandas 把数据交给 Spark,Spark 把结果传给 R,R 再把子集喂给 TensorFlow——每一次跨系统传递,数据都要从…
监控系统每秒钟从数万台机器上采集 CPU 使用率、内存占用、磁盘 IOPS、网络流量;物联网(IoT)网关把传感器温度、湿度、振动频率汇聚到云端;金融交易系统以毫秒级粒度记录每一笔报价和成交。这些数据有一个共同特征——每条记录都带有一个时间戳(Timestamp),按时间顺序源源不断地涌入,几乎只追加(Append-O…
给定一条 768 维的文本嵌入向量(Embedding),要从一亿条同维度向量中找出最相似的 10 条。暴力计算需要对每条向量做 768 次乘法和一次求和——一亿条就是 768 亿次浮点运算,单核 CPU 跑完需要几十秒。如果这个操作发生在每一次用户搜索请求中,系统根本无法响应。
数据湖(Data Lake)的核心思想是把海量异构数据以开放格式存储在廉价的对象存储(Object Storage)上,用计算引擎按需查询。Apache Parquet 解决了列式编码(Columnar Encoding)问题,让分析查询的 I/O 效率提升了一个数量级。但 Parquet 只是一个文件格式,它不管事务…
在存储引擎(Storage Engine)的设计谱系中,Bitcask 占据着一个独特而优雅的位置: 它用最简单的数据结构——哈希表(Hash Table)与追加日志(Append-Only Log)—— 组合出了一个在特定工作负载下性能极其出色的键值存储引擎。 本文将从核心思想出发,逐层拆解 Bitcask 的架构、…
LSM-Tree 的核心设计是把随机写转换为顺序写,但这个转换不是免费的。写入经过 MemTable 刷盘、再经过多次 Compaction 合并,每一字节的用户数据在磁盘上可能被反复读写数十次。读取一个 key 时,最坏情况下需要逐层搜索,直到命中或遍历全部层级。与此同时,旧版本数据和墓碑标记占用的额外空间,在 Co…
从 Column Family、Write Buffer、Block Cache、Compaction、Rate Limiter 到 Direct I/O 和监控,系统拆解 RocksDB 在生产环境中的关键配置与故障模式,并给出 SSD 场景下的配置模板和 db_bench 基准测试方法。
数据库存储引擎通常自己管理一块内存,维护 Buffer Pool,用 read()/pread() 把磁盘页加载进来,再用 LRU 或 Clock 算法做淘汰。这套方案灵活、可控,但代码量大、调优参数多,且引入了用户态到内核态的数据拷贝。有没有一种方式,让操作系统直接把磁盘文件映射到进程地址空间,数据库只管读指针,不管…
当我们提到"数据库"时,多数人首先想到的是 MySQL、PostgreSQL 这类以独立进程运行的数据库服务器。客户端通过网络协议连接到服务器,服务器管理存储、索引、事务和并发控制。然而,还有一类存储系统以库(Library)的形式直接链接到应用进程中,不需要独立的服务器进程,不需要网络通信,不需要序列化和反序列化——…
数据库系统的架构可以划分为两大层:上层的查询处理层负责解析 SQL、生成执行计划、优化查询;下层的存储引擎(Storage Engine)负责把数据持久化到磁盘,并在需要时高效地把数据取回来。查询处理层决定"做什么",存储引擎决定"怎么存、怎么取"。同一个查询处理层可以对接不同的存储引擎——MySQL 的 InnoDB…
数据库要把数据存到磁盘上,又要以尽可能少的磁盘 I/O 把数据找回来。这个矛盾催生了一系列面向磁盘的索引结构(Disk-oriented Index),其中最成功的就是 B-Tree 家族。从 1970 年 Rudolf Bayer 和 Edward McCreight 在波音科学研究实验室提出 B-Tree 起,这个…
数据库为什么不直接使用操作系统的 Page Cache,而要自己管理一块内存?本文从 double buffering 问题讲起,拆解 Buffer Pool 的架构、页面替换算法、脏页刷新策略、预读机制,再分别剖析 MySQL InnoDB 和 PostgreSQL 的实现细节,最后落到大小调优与监控诊断。
WAL 是数据库持久性的基石,ARIES 是工业界公认最完备的崩溃恢复协议。本文从 WAL 三条规则出发,逐步拆解 ARIES 的 Analysis-Redo-Undo 三阶段,结合 InnoDB 实现分析恢复全流程。
数据库事务的四大特性 ACID 中,隔离性(Isolation)是最复杂的一项。原子性靠 WAL 保证(参见 [WAL 与崩溃恢复](../27-wal-aries/wal-aries.html)),持久性靠 fsync 落盘,一致性是应用层语义——唯独隔离性,需要存储引擎在并发控制层面做出大量取舍。SQL 标准定义了…
数据库里存了一亿行数据,要找出 userid 42 的那一行。没有索引的做法是全表扫描(Full Table Scan)——从第一个数据页读到最后一个数据页,逐行比对。假设每个数据页 16 KB,一亿行占 20 GB,即使顺序读能跑到 500 MB/s,也需要 40 秒。加一个 B+Tree 索引,三次磁盘 I/O 就…
在传统的磁盘分区方案中,分区大小在创建时即被固定,后续调整代价极高。逻辑卷管理(Logical Volume Manager,LVM)在物理磁盘与文件系统之间插入一个抽象层,将离散的物理存储资源池化为可灵活分配的逻辑卷,从根本上解决了静态分区带来的容量规划难题。
RAID(Redundant Array of Independent Disks),即独立磁盘冗余阵列(Redundant Array of Independent Disks),是一种将多块物理磁盘组合成一个逻辑存储单元的技术。RAID 最初由加州大学伯克利分校的 David Patterson、Garth Gib…
拆解 Linux Device Mapper 框架的内核架构、映射表机制与七种核心 target driver,从 dm-linear 到 dm-verity,覆盖 dmsetup 实战和容器存储应用。
在存储系统的安全防线中,加密是最后一道也是最重要的一道屏障。当物理安全措施失效——磁盘被盗、服务器被非法访问、退役硬盘未彻底销毁——只有加密能确保数据不被未授权方读取。块级加密(Block-Level Encryption)在存储栈的最低层工作,对上层文件系统和应用程序完全透明,不需要修改任何一行应用代码就能保护磁盘上…
存储系统有两个看似独立、实则紧密交织的能力:快照(Snapshot)和精简配置(Thin Provisioning)。快照解决的是"时间维度"的问题——在任意时刻冻结数据状态,用于备份、回滚或测试;精简配置解决的是"空间维度"的问题——让存储容量按需分配,避免预先占满物理磁盘。两者的交叉点在于写时复制(Copy-on-…
磁盘是一个线性的块数组,但没有人愿意用"第 48372 号扇区"来定位自己的文档。文件系统(File System)就是那个把"名字"映射到"数据"的翻译层——它把一片平坦的块空间组织成人类可以理解的层级结构,同时维护着每个文件的权限、大小、时间戳等元数据(Metadata)。
ext4 是 Linux 世界中使用最广泛的本地文件系统(Local Filesystem)。从 2008 年合入内核主线至今, 它已经在无数生产服务器、嵌入式设备以及桌面系统上稳定运行了十余年。本文将从磁盘布局、 核心数据结构、日志机制、分配策略等维度,对 ext4 进行全面剖析,并结合实际调优场景给出 可落地的最佳…
XFS 诞生于 1993 年的硅谷图形公司(Silicon Graphics, Inc.),最初运行在 IRIX 操作系统上。 SGI 的核心业务是高性能计算和影视后期制作,客户需要处理的文件动辄几十 GB 甚至数 TB。 当时主流的 EFS(Extent File System)在面对这类工作负载时已经力不从心:元数…
ext4 和 XFS 走的是"就地更新"路线:数据写到哪个块,就直接覆盖那个块。这条路线简单、高效,但有一个根本性的问题——如果写到一半断电,磁盘上的数据处于半新半旧的状态,文件系统就损坏了。日志(Journal)机制可以缓解这个问题,但它本质上是"先写一遍日志,再写一遍数据",写放大不可避免。
在存储系统的世界里,大多数文件系统把"性能"放在第一位,把"完整性"当作锦上添花的特性。ZFS 的做法恰好相反——它把数据完整性视为最基本的不可协商的属性,然后在此基础上构建性能优化。这种设计哲学上的根本差异,使得 ZFS 在诞生近二十年后,仍然是数据保护领域无可替代的存储栈。
在生产环境中,文件系统(Filesystem)的选择直接影响存储栈的性能上限、数据安全边界和运维复杂度。本文将从设计目标、元数据性能、数据吞吐、典型业务场景、基准测试方法论等多个维度,对 ext4、XFS、Btrfs(B-tree Filesystem)、ZFS(Zettabyte File System)四种主流文件…
当应用程序调用一次 write() 系统调用(System Call)时,数据并不会立刻落到磁盘扇区上。 它需要穿越内核中七个以上的软件层次,每一层都有独立的职责、数据结构和延迟开销。 理解这条完整路径,是进行存储性能调优和故障诊断的基础。
文件系统把"写这个文件"翻译成"写这些逻辑块",但逻辑块怎么变成磁盘控制器能执行的命令?中间那一层就是块设备层(Block Layer)。它做的事不复杂——把上层的 I/O 请求收集、合并、排序,然后交给设备驱动——但做得好不好,直接决定了存储栈的吞吐和延迟。
应用程序每一次 read() 或 write() 系统调用,感觉像是直接在操作磁盘上的文件,但实际上,内核在中间插入了一层透明的缓存——页缓存(Page Cache)。这层缓存用物理内存保存最近访问过的文件数据,使得绝大多数读操作不需要触发磁盘 I/O,而写操作可以先落到内存,再由后台线程异步刷回存储设备。
在高吞吐存储系统中,同步 I/O 是性能的天花板。本文系统梳理 Linux 下三代异步 I/O 方案——POSIX AIO、Linux Native AIO(libaio)和 io_uring——的设计原理、编程接口、性能特征与工程实践,帮助你在实际项目中做出正确的技术选型。
HDD 已经被 SSD 抢去了大部分聚光灯,但全球 90% 以上的数据仍然存储在旋转磁盘上。理解 HDD 的物理结构和性能特征,是理解整个存储栈设计决策的基础——从文件系统的块分配策略到数据库的 WAL 设计,几乎每一个存储优化都能追溯到'旋转延迟'和'寻道时间'这两个物理约束。
SSD 已经在大多数性能敏感场景中取代了 HDD,但 SSD 并不是"没有机械部件的硬盘"——它是一个完全不同的存储架构,带来了一组全新的工程约束。理解这些约束,需要从 NAND Flash(NAND 闪存)的物理特性开始,逐层向上推导出 FTL(Flash Translation Layer)、垃圾回收(Garbag…
存储接口(Storage Interface)是连接主机与存储介质的桥梁,其协议设计直接决定了数据访问的延迟、吞吐量和并发能力。从早期的并行接口到现代的非易失性内存快捷通道(Non-Volatile Memory Express,NVMe),存储协议经历了数十年的演进。本文将系统梳理存储接口的发展历程,深入剖析 NVM…
现代计算系统的性能瓶颈,往往不在处理器本身,而在数据的存取速度。从寄存器(Register)到磁带(Tape),存储层次结构跨越了十余个数量级的延迟差异。持久化内存(Persistent Memory,简称 PMem)的出现,试图在易失性内存与持久化存储之间架起一座桥梁,从根本上改变应用程序访问数据的方式。
存储性能不是一个数字,而是 IOPS、吞吐量和延迟在特定工作负载下的函数关系。本文从排队论模型出发,用 fio 实测验证,覆盖从 HDD 到 NVMe SSD 的性能画像,最终落到容量规划和监控体系的工程实践。
存储选型不是'SSD 比 HDD 快所以选 SSD'这么简单。不同工作负载对 IOPS、吞吐、延迟、容量、成本的权重完全不同。本文从性能、可靠性、成本三个维度对比 HDD、SATA SSD、NVMe SSD、Optane/PMem 和磁带,给出面向具体工作负载的选型决策框架和分层存储架构设计方法。