从 Hive 到 Presto:一个「快」字背后,是三次豪赌式的设计取舍

从 Hive 到 Presto:一个「快」字背后,是三次豪赌式的设计取舍 2012 年,Facebook 的工程师们受够了「跑个查询去喝杯咖啡」的日子。Presto 的诞生不是又一个 SQL 引擎的堆料,而是一连串清醒的放弃。本文用「舍与得」的视角,拆开 Presto 三项核心架构决策——以及它们各自的账单。 引言:大数据时代的「等待焦虑」 先讲一个老故事。 2012 年前后,任何在 Facebook 规模的数据仓库上工作过的人,都熟悉这种体验:你写了一段 SQL,想看看昨天某个功能的用户留存。提交给 Hive,底层翻译成 MapReduce,然后—— 等。 第一个 Map 阶段读数据、算完、写磁盘;第二个 Reduce 阶段再读磁盘、算完、再写磁盘;三五个阶段下来,一个「简单的问题」要等十分钟到一小时。磁盘 I/O 像一道钝刀子,把「交互式分析」切成了「批处理作业」。工程师们甚至形成了独特的应对文化:提交查询,然后去开会、喝咖啡、改别的 bug——因为等待是确定会发生的。 问题出在哪?不是 Hadoop 不行,而是 MapReduce 的设计目标本来就不是交互式查询。它为容错而生:每个阶段的中间结果必须落盘,任何一台机器挂了,从磁盘上的中间结果重跑就行。这份「保险」在批处理场景物有所值,但对「我想马上知道答案」的分析师来说,是在为用不到的容错付全价。 Presto 的研发初衷就一句话:为交互式 SQL 查询专门造一台引擎,PB 级数据,秒级响应。 注意「专门」这个词。Presto 没有试图做一个「又能批处理、又能交互、又能点查」的全能选手——它从一开始就决定,为了快,该扔的就扔。下面是三次关键的「舍」。 取舍一:内存流水线——扔掉容错,换速度 舍:Task 级中间落盘与断点重试 MapReduce 的哲学是「每一步都存档」。Presto 反其道而行:查询被切成多个 Stage,Stage 内的算子组成流水线(Pipeline),数据以「页」(Page)为单位在算子间流动,全程驻留内存,中间结果不落盘。 伪代码对比一下两种执行模型: # MapReduce 式:每个阶段落盘存档 for stage in stages: results = stage.run(input) write_to_disk(results) # ← 每一步都付磁盘 I/O 的钱 checkpoint(results) # ← 为容错买单 # 下一阶段再 read_from_disk() # Presto 式:内存流水线 pipeline = build_pipeline(scan, filter, agg, ...) for page in source_pages: # 一页一页流过去 yield pipeline.process(page) # 算子间直接传递,不落地 差别有多直观?MapReduce 的一次「阶段交接」= 一次序列化 + 一次磁盘写 + 一次磁盘读 + 一次反序列化。Presto 的阶段交接 = 一次内存中的数据页传递。磁盘 I/O 从执行路径里被整个删掉了,这正是秒级响应的物理基础。 ...

August 4, 2026 · FXIO