专业书籍精读 · Fundamentals of Data Engineering · 第 6 章
Fundamentals of Data Engineering · Ch 6 · Storage · Reis & Housley · 2022
你在手机上翻三年前的订单,或者公司每天早上看的那张销售报表——背后的数据都得先「放」在某个地方。这一章讲的是:数据放在哪、怎么放,才能既放得下、又取得快、还不贵。它是整条数据流水线的地基:采集、整理、出报表,每一步都要从存储里拿、再往存储里放。
今天最流行的大数据存储,竟然不允许你改文件里的一个字。想改一行?只能把整个文件重写一遍。听起来很笨,可正是这种「只能整件放、整件取」的笨办法,让存储变得又便宜又几乎不会丢,于是成了数据湖的标准底座。
多数团队如今的默认做法是:数据统一放进便宜的对象存储,用按列存放的文件格式,需要时再临时调来算力去查;最常用的那部分再放进更快的地方缓存。一句诚实的代价:这套组合便宜又能无限长大,但每一次远程读取都比本地慢,越追求实时,就越得在「快」上额外花钱。
存储不是一块硬盘,而是一整套「快—贵、慢—省」的取舍:把数据放进便宜可靠的寄存柜、按列摆好、用的时候再借算力,常用的放手边。
想看存储的三层(原料 / 系统 / 抽象)、文件 · 块 · 对象存储怎么选、行式与列式、仓 · 湖 · 湖仓的区别、计算存储分离为何其实是「混合」,以及 BigQuery、Parquet、Iceberg 的实证? → 切到精读版
你以为存储就是「选一个数据库」,其实它是一个三层的栈:底下是硬盘、内存、网络这些物理原料,中间是文件 / 块 / 对象存储这些系统,上面才是数仓、数据湖、湖仓这些抽象。本章要建立的认知是:每一层的选择都在「延迟—成本—扩展性—持久性」之间取舍;云时代的默认答案是「对象存储 + 列式文件 + 按需算力」,但「计算存储彻底分离」只是半个真相,真实系统都是分离与就近缓存的混合。
Part II「生命周期详解」第二章。上接第 5 章「数据从哪来」,下启第 7 章采集、第 8 章查询与转换。作者特意把它放在采集之前:存储是贯穿整个生命周期的那块地基,采集、转换、服务每一步都在读写它。现实里对应「S3 / GCS 上的数据湖、Snowflake / BigQuery 数仓、Kafka 的消息保留」这些选型。
数据工程师很少从零造存储,但每天都在选存储,而选错的代价往往几年后才显现。设想一家电商每天新增 1 TB 点击日志、保留三年——约 1 PB。放在本地 SSD 集群上,钱和运维都扛不住;全放在归档层又意味着分析师查一次要等几小时。不懂存储的典型后果:
本章的骨架是一张分层图:最底层是原料(raw ingredients)——磁盘、SSD、内存、网络、CPU,以及序列化、压缩、缓存这些手段;中间是用原料搭起来的存储系统——文件存储、块存储、对象存储、HDFS、缓存、流存储;最上层是数据工程师直接打交道的存储抽象——数仓、数据湖、湖仓。作者的提醒是:别只在最上层选型,上层的性能与成本特性全来自下层。
原料之间的差距不是几成,而是数量级:内存一次访问约 100 纳秒,SSD 约 0.1 毫秒,机械硬盘一次寻道约几毫秒,从对象存储读第一个字节通常要几十毫秒,归档层取回则以小时计。价格大致反过来排。于是有了书里的缓存层级思路:最热的数据放最快最贵的层,越冷越往下放。
另两个常被忽略的原料是序列化与压缩。同样一份数据,存成 CSV 还是列式的 Parquet,读取量可以差一个数量级;压缩则用 CPU 换磁盘和网络——在网络常是瓶颈的云上,通常划算。
行式把一条记录的所有字段连着存,适合「取一张订单的全部信息」这种事务访问;列式把同一列的值连着存,适合「对一列求和、过滤」这种分析访问。分析查询往往只碰几十列里的几列,列式只读这几列;同一列的值类型相同、重复多,压缩效果也好得多。代价是:改一行要动很多列文件,单行写入和更新很慢——所以列式格式天生适合「批量写、大量读」。
文件存储是熟悉的目录树,支持随机读写与原地修改,云上有托管的网络文件系统。块存储是操作系统看到的「裸盘」,数据库和虚拟机的系统盘都建在它上面——云上的虚拟化块存储可以快照、挂载到实例;而实例自带的本地盘最快,但实例一停数据就没了。
对象存储(S3、GCS、Azure Blob)是本章分量最重的系统:数据以「对象」形式按键存放在扁平的桶里,对象不可变——不能改其中一部分,只能整件覆盖或删除。这个限制换来的是:几乎无限的容量、极高的并行读写吞吐(成百上千个任务同时读不同对象)、多副本带来的高持久性(S3 宣称的设计持久性是 11 个 9),以及按用量付费。它的短板是单次请求延迟高、不适合频繁小更新。S3 在 2020 年底改为强读后写一致性,此前写后立刻读可能读到旧版本——这是书里特别提醒的历史坑。对象存储还提供多个存储类别:标准、低频访问、归档,越冷越便宜,但取回更慢、还有取回费。
其余几种系统各有位置:HDFS 把大文件切块、多副本存在集群各节点上,并让计算就近执行(脱胎于 Google 的 GFS);缓存(Memcached、Redis)把热数据放内存;流存储(Kafka)按保留期存事件,可回放。另外,数仓不再靠传统索引,而靠分区与聚簇——按日期切分、把相近的值放一起,让查询跳过大量不相关的数据块(如 Snowflake 的微分区)。
数据仓库是结构严格、为分析优化的中心库;云数仓已经把存储放到对象存储之上、计算按需伸缩。数据湖把原始文件扔进对象存储,先存后定结构;第一代数据湖的教训是容易变成「数据沼泽」——没有事务、没有 schema 管理,改一条记录要重写整个分区。湖仓(lakehouse)是两者的合流:数据仍是对象存储上的开放列式文件,但上面加一层表格式(Delta Lake、Apache Iceberg、Apache Hudi),用元数据记录「哪些文件构成这张表的哪个版本」,从而支持事务、更新删除、schema 演化和时间旅行。书里还提到流转批存储架构:数据写进流存储,同时落到批存储供长期查询。
计算与存储分离。旧的 Hadoop 时代讲「数据就近计算」(colocation):数据在哪台机器,就在哪台机器上算。云把它倒过来:数据放对象存储,计算集群临时拉起、用完即毁(短暂集群),存储和算力各自扩展、各自计费。但作者强调,真实系统是混合的:云数仓会把热数据缓存到计算节点的本地 SSD,Spark 等引擎也会把中间结果放在本地盘——分离带来弹性,就近缓存找回速度。
数据生命周期与保留。按访问频率把数据分为热、温、冷三档,配合对象存储的生命周期规则自动降级;同时要按合规要求定保留期——该删的必须删,不只是省钱。
schema 的时机:写入时定结构(schema on write,数仓的做法)保证质量但不灵活;读取时定结构(schema on read,数据湖的做法)灵活但把解析的麻烦推给每个读者。此外书里还点到数据目录(让人找得到、看得懂数据)、数据共享(云数仓之间直接授权读,不拷贝)、零拷贝克隆(复制一张表只复制元数据),以及单租户 vs 多租户存储的隔离与成本取舍。
表 1 · 三种存储系统
| 系统 | 适合 | 代价 |
|---|---|---|
| 块存储(云盘 / 本地盘) | 数据库、需要低延迟随机读写的单机负载 | 容量与单实例绑定;本地盘随实例消失 |
| 文件存储(NFS 类) | 多台机器共享目录、需要原地修改文件 | 扩展性与吞吐有上限,比对象存储贵 |
| 对象存储(S3 / GCS) | 数据湖、湖仓底座、备份、海量并行扫描 | 不可原地修改;单次请求延迟高,频繁小写入代价大 |
表 2 · 存储抽象
| 抽象 | 好处 | 代价 |
|---|---|---|
| 数据仓库 | 结构严格、SQL 好用、治理成熟 | 主要服务结构化数据;格式常是封闭的,换引擎难 |
| 数据湖 | 什么都能放、最便宜、格式开放 | 无事务、无 schema 管理,易成数据沼泽 |
| 湖仓(表格式) | 开放文件 + 事务、更新删除、时间旅行,多引擎共享 | 要维护元数据与小文件合并;运维比托管数仓重 |
表 3 · 冷热分层
| 层 | 典型放什么 | 代价 |
|---|---|---|
| 热(内存 / SSD / 数仓缓存) | 近几天、被仪表盘反复查询的数据 | 单位容量最贵 |
| 温(对象存储标准 / 低频) | 近几个月、偶尔分析 | 首字节延迟几十毫秒;低频层有取回费 |
| 冷(归档层) | 合规留存、几乎不查的历史 | 取回以小时计,还要付取回费与最短存放期 |
判据:先问访问模式(随机小更新还是大批扫描),再问数据多热、要留多久,最后问要不要多个引擎共用同一份数据——要,就倾向开放表格式的湖仓。
面试里「每天 1 TB 日志、保留三年、分析师要能查」这类题,好的答案会这样落地:原始数据以 Parquet 写入对象存储、按日期分区;用表格式管理事务与 schema;近 30 天的数据由数仓或查询引擎缓存加速;一年以上的数据用生命周期规则降到归档层;计算集群按查询负载伸缩。每一步都对应本章的一个权衡。
大厂与开源实证
① 存储是三层栈:原料(盘、内存、网络、序列化、压缩)→ 系统(文件 / 块 / 对象)→ 抽象(仓 / 湖 / 湖仓)。上层特性来自下层。
② 原料延迟差数量级:内存百纳秒、SSD 约 0.1 毫秒、对象存储几十毫秒、归档以小时计;缓存层级是对此的回应。
③ 行式适合事务访问,列式适合分析扫描:只读需要的列、压缩好,代价是更新慢。
④ 对象存储是数据湖的底座:不可变、近乎无限、高持久、按量付费;短板是单次延迟高、不能原地改。
⑤ 湖仓 = 对象存储上的开放列式文件 + 表格式元数据,补上事务、更新删除与时间旅行。
⑥ 计算存储分离带来弹性与独立计费,但真实系统都靠就近缓存找回速度——是混合,不是二选一。
⑦ 按冷热分层并设生命周期规则;保留期既是成本问题,也是合规问题。
⑧ 小文件、归档取回费、频繁小写对象存储,是最常见的三个坑。