<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>存算分离 on FXIO 技术博客</title><link>https://fxio.site/tags/%E5%AD%98%E7%AE%97%E5%88%86%E7%A6%BB/</link><description>Recent content in 存算分离 on FXIO 技术博客</description><generator>Hugo -- 0.157.0</generator><language>zh-cn</language><lastBuildDate>Tue, 04 Aug 2026 12:14:32 +0800</lastBuildDate><atom:link href="https://fxio.site/tags/%E5%AD%98%E7%AE%97%E5%88%86%E7%A6%BB/index.xml" rel="self" type="application/rss+xml"/><item><title>从 Hive 到 Presto：一个「快」字背后，是三次豪赌式的设计取舍</title><link>https://fxio.site/posts/ai/2026-08-04-presto-architecture-philosophy/</link><pubDate>Tue, 04 Aug 2026 12:14:32 +0800</pubDate><guid>https://fxio.site/posts/ai/2026-08-04-presto-architecture-philosophy/</guid><description>&lt;h1 id="从-hive-到-presto一个快字背后是三次豪赌式的设计取舍"&gt;从 Hive 到 Presto：一个「快」字背后，是三次豪赌式的设计取舍&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;2012 年，Facebook 的工程师们受够了「跑个查询去喝杯咖啡」的日子。Presto 的诞生不是又一个 SQL 引擎的堆料，而是一连串清醒的放弃。本文用「舍与得」的视角，拆开 Presto 三项核心架构决策——以及它们各自的账单。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="引言大数据时代的等待焦虑"&gt;引言：大数据时代的「等待焦虑」&lt;/h2&gt;
&lt;p&gt;先讲一个老故事。&lt;/p&gt;
&lt;p&gt;2012 年前后，任何在 Facebook 规模的数据仓库上工作过的人，都熟悉这种体验：你写了一段 SQL，想看看昨天某个功能的用户留存。提交给 Hive，底层翻译成 MapReduce，然后——&lt;/p&gt;
&lt;p&gt;等。&lt;/p&gt;
&lt;p&gt;第一个 Map 阶段读数据、算完、&lt;strong&gt;写磁盘&lt;/strong&gt;；第二个 Reduce 阶段再读磁盘、算完、&lt;strong&gt;再写磁盘&lt;/strong&gt;；三五个阶段下来，一个「简单的问题」要等十分钟到一小时。磁盘 I/O 像一道钝刀子，把「交互式分析」切成了「批处理作业」。工程师们甚至形成了独特的应对文化：提交查询，然后去开会、喝咖啡、改别的 bug——因为等待是确定会发生的。&lt;/p&gt;
&lt;p&gt;问题出在哪？不是 Hadoop 不行，而是 &lt;strong&gt;MapReduce 的设计目标本来就不是交互式查询&lt;/strong&gt;。它为容错而生：每个阶段的中间结果必须落盘，任何一台机器挂了，从磁盘上的中间结果重跑就行。这份「保险」在批处理场景物有所值，但对「我想马上知道答案」的分析师来说，是在为用不到的容错付全价。&lt;/p&gt;
&lt;p&gt;Presto 的研发初衷就一句话：&lt;strong&gt;为交互式 SQL 查询专门造一台引擎，PB 级数据，秒级响应。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;注意「专门」这个词。Presto 没有试图做一个「又能批处理、又能交互、又能点查」的全能选手——它从一开始就决定，为了快，该扔的就扔。下面是三次关键的「舍」。&lt;/p&gt;
&lt;h2 id="取舍一内存流水线扔掉容错换速度"&gt;取舍一：内存流水线——扔掉容错，换速度&lt;/h2&gt;
&lt;h3 id="舍task-级中间落盘与断点重试"&gt;舍：Task 级中间落盘与断点重试&lt;/h3&gt;
&lt;p&gt;MapReduce 的哲学是「每一步都存档」。Presto 反其道而行：&lt;strong&gt;查询被切成多个 Stage，Stage 内的算子组成流水线（Pipeline），数据以「页」（Page）为单位在算子间流动，全程驻留内存，中间结果不落盘。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;伪代码对比一下两种执行模型：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# MapReduce 式：每个阶段落盘存档
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;for stage in stages:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; results = stage.run(input)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; write_to_disk(results) # ← 每一步都付磁盘 I/O 的钱
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; checkpoint(results) # ← 为容错买单
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 下一阶段再 read_from_disk()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Presto 式：内存流水线
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pipeline = build_pipeline(scan, filter, agg, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;for page in source_pages: # 一页一页流过去
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; yield pipeline.process(page) # 算子间直接传递，不落地
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;差别有多直观？MapReduce 的一次「阶段交接」= 一次序列化 + 一次磁盘写 + 一次磁盘读 + 一次反序列化。Presto 的阶段交接 = 一次内存中的数据页传递。磁盘 I/O 从执行路径里被整个删掉了，这正是秒级响应的物理基础。&lt;/p&gt;</description></item></channel></rss>