跳转至

MPP 资源管理与工作负载隔离 —— 为什么分析型数据库需要「主动拒绝」而非「尽力而为」

作者:JiangChong | 撰写时间:2026年06月

适用场景:你需要在同一套 MPP 集群上同时运行 ETL 批处理、实时仪表盘查询、临时分析查询等多种工作负载,且不希望它们互相拖垮——本文帮你理解 Vertica 的资源管理架构设计,从而做出正确的资源池和子集群配置决策。

关联文章Vertica 资源池最佳实践 | Vertica 多租户实现最佳实践 | Vertica 资源拒绝排查与资源池调优 | Vertica 内存压力诊断与调优 | Vertica 弹性伸缩功能介绍与配置

MPP 框架声明: 本文以 Vertica 为主要剖析对象,但在所有环节对比其他 MPP 系统的不同实现。「MPP 共性」与「Vertica 专属」将在文中明确区分。参与对比的系统:Greenplum(PostgreSQL 系 MPP)、Redshift(AWS 托管 MPP)、ClickHouse(列存分布式)、Doris/StarRocks(现代向量化 MPP)、Snowflake(云原生数仓)。

理解全文脉络

本文从「为什么 MPP 数据库需要专门的资源管理」出发,逐步展开 Vertica 的资源池机制、设计取舍、以及 Eon 模式下的子集群隔离。如果你正在处理 RESOURCE_REJECTED 报错或排队问题,可以直接跳到第 2 节理解核心机制,再读第 4 节的配置思路和第 5 节的案例;如果你在规划新集群的资源架构,建议从第 1 节读起,理解设计哲学后再看第 2-3 节做技术选型。


1. 问题背景 — 这个架构要解决什么问题

1.1 在它出现之前

在 MPP 资源池概念成熟之前,大多数数据库对多工作负载并发的态度可以概括为四个字:尽力而为

传统 OLTP 数据库(如 PostgreSQL)的内存模型是「全局缓冲区 + 每连接工作内存」——shared_buffers 负责缓存数据页,work_mem 控制每个排序/Hash 操作的内存上限。当并发查询增多时,每个查询分到的 work_mem 不变,总内存消耗线性增长。但系统并不阻止你提交第 101 个查询——它只是变慢,慢到 swap,慢到 OOM。

这套模型在 OLTP 场景下勉强可用,因为 OLTP 查询通常只访问少量行、执行时间短。但放到 MPP 分析型数据库上,问题就炸了。

1.2 一个具体场景

假设你有一个 10 节点的 Vertica 集群,每节点 256 GB 内存。上面同时跑着三种工作负载:

工作负载 典型查询特征 单查询内存消耗 并发数 SLA 要求
ETL 批处理 INSERT SELECT, 宽表加载, 大量 Hash Join 20-50 GB 3-5 个 小时级完成
实时仪表盘 聚合查询, GROUP BY, 扫描最近 1 小时数据 2-5 GB 20-30 个 秒级响应
临时分析 复杂多表 JOIN, 全表扫描, 不可预测 5-100 GB 2-3 个 分钟级完成

SLA(Service Level Agreement,服务等级协议):业务方与数据平台约定的响应时间或完成时间目标,如「仪表盘刷新 P99 ≤ 2 秒」「ETL 在凌晨 6:00 前完成」。资源管理的第一性目标就是确保各类工作负载的 SLA 不被互相干扰所打破。

如果没有资源管理,会发生什么?上午 10 点业务高峰,30 个仪表盘查询正在执行,突然来了一个分析师的「select count(distinct ...) from 3 年数据 group by ...」——这条查询估算需要 80 GB 内存。如果系统让它直接执行,它可能挤占其他 30 个查询的内存预算,导致仪表盘响应时间从 0.5 秒飙升到 30 秒,甚至触发节点 OOM。

这不是推测。某运营商 Vertica 数据库性能问题处理报告 中记录了一个 138 节点集群的真实场景:某条 SQL 因为统计信息过期,实际消耗了 28 GB 内存——而当时资源池的 query_budget 只有 1 GB,导致 40% 的查询在执行中需要反复申请额外内存,业务高峰期平均响应时间从 13 秒恶化到 94 秒

因此我们需要一套机制,能在查询执行之前就判断「该不该让它跑」,而不是等到系统撑不住了再被动应对。

1.3 资源管理的核心矛盾

MPP 分析型数据库的资源管理面临一个三角矛盾:

           资源利用率高
              /\
             /  \
            /    \
           /      \
          /________\
   工作负载隔离    系统不崩溃
  • 资源利用率高:你希望集群的 CPU 和内存尽量用满,不浪费硬件投资
  • 工作负载隔离:你希望 ETL 慢一点别拖死仪表盘,分析师查询别挤占 ETL 的内存
  • 系统不崩溃:你希望无论查询多复杂,节点不会 OOM、集群不会宕机

这三者互相制约:提高隔离性通常意味着预留资源(降低利用率);提高利用率意味着减少预留(降低隔离性);而不设上限的资源竞争最终会导致 OOM。

Vertica 的资源管理架构,本质上就是对这三者的一种工程权衡。下面我们来看它的具体设计。


2. 核心概念与机制 —— 从 MPP 共性问题到 Vertica 具体实现

2.1 共同架构模式:资源管理的核心矛盾

所有 MPP 分析型数据库在支持多工作负载并发时,都面临同一个不可能三角(利用率 ↔ 隔离 ↔ 稳定性)——已在 §1.3 详细论述,这里不再重复。

这不是 Vertica 独有的问题。 Greenplum 在多租户场景下会遭遇资源队列耗尽,Redshift 的 WLM 队列在突发流量时排队深度可达数百,ClickHouse 的 max_concurrent_queries 达到上限后直接拒绝新查询,Snowflake 的 Virtual Warehouse 在并发打满后 STATEMENT_QUEUED_TIMEOUT 到期即报错。

因此,所有 MPP 系统都需要一套专门的资源管理机制——在查询执行之前就判断「该不该让它跑」,而不是等到系统撑不住了再被动应对。这套机制需要回答三个问题:

  1. 资源如何切分? 不同工作负载之间的内存和并发如何分配?
  2. 并发如何控制? 多少查询可以同时跑?
  3. 超限时怎么办? 排队还是拒绝?拒绝后怎么重试?

以下逐层展开,每层先讲 MPP 共性,再深入 Vertica 实现,最后做跨系统对比。


2.2 第一层:资源切分模型 —— 如何在不同工作负载之间分配资源

MPP 共性: 所有 MPP 系统都需要将集群资源划分为多个逻辑单元,每个单元服务于一类工作负载。区别在于切分的粒度、弹性(能否互相借用)、以及是否需要额外硬件。

Vertica 的实现:资源池(Resource Pool)

资源池(Resource Pool)是 Vertica 资源管理的基本单元。官方文档定义得简洁:「系统资源的预分配子集,带有一个关联队列」(来源:Vertica 官方文档)。

通俗理解:把集群的内存和并发槽位想象成一栋公寓楼的房间。没有资源池时,所有人同时冲进去抢房间——力气大的占大房间,后来的睡走廊。有了资源池,你提前划定「这批房间给 ETL 组、那批给报表组」,每组有自己的入住上限和排队规则。

每个资源池有五个核心参数(以及多个辅助参数),它们共同决定了一个查询能不能执行、以多少资源执行:

参数 作用 通俗类比
MEMORYSIZE 池的独占内存,其他池不能借用 你买的私人车位,别人不能用
MAXMEMORYSIZE 池能使用的内存总上限 你家最多能停几辆车(含借用邻居车位的)
PLANNEDCONCURRENCY 预期的并发查询数,用于计算每查询预算 你预计同时有几个家人要开车
MAXCONCURRENCY 池的最大并发查询硬限制 你家的车位硬上限,超过就等
EXECUTIONPARALLELISM 单个查询能用的最大线程数 每辆车最多几个缸工作

这些参数不是孤立的——它们通过 query_budget 串联在一起(详见 §2.3)。

GENERAL 池:公共缓冲池

Vertica 的资源切分模型有一个独特设计:GENERAL 池充当「公共缓冲池」。其他用户定义池在独占内存不够时,可以从 GENERAL 借用,直到各自的 MAXMEMORYSIZE。这在整个资源管理架构中提供了弹性——让短期内存尖峰不至于直接触发拒绝。但代价是:如果多个池同时找 GENERAL 借钱,按 PRIORITY 排队——PRIORITY 高的先拿到。

内置资源池:系统运转的隐形骨架

除了用户自定义池,Vertica 预配置了 9 个内置资源池,它们的职责和关键默认值如下(来源:17-04-operations-and-monitoring.md Built-in resource pools configuration 节):

内置池 职责 MEMORYSIZE MAXMEMORYSIZE 特殊设置
GENERAL 未分配池的查询 不可设 物理内存的 95% PLANNEDCONCURRENCY=AUTO
TM Tuple Mover 操作 5% of GENERAL + 2GB Unlimited PRIORITY=105, MAXCONCURRENCY=7
SYSQUERY 系统表查询 1G 取决于版本 PRIORITY=110
RECOVERY 节点恢复 0% NONE PRIORITY=107 (Enterprise) / 110 (Eon)
METADATA Catalog 内存 0%(自动增长) Unlimited 用户不可修改参数
REFRESH 投影刷新 0% NONE PRIORITY=-10
DBD Database Designer 0% Unlimited QUEUETIMEOUT=0
JVM Java UDx 0% min(10% RAM, 2GB) 会话结束才释放
BLOBDATA 机器学习内存对象 0% 10%

跨系统对比:资源切分模型

系统 资源管理单元 切分粒度 弹性借用 零硬件成本
Vertica Resource Pool 内存 + 并发 ✅ GENERAL 池充当全局缓冲
Greenplum Resource Group (5.x+) / Resource Queue CPU + 内存 + 并发 ❌ 资源组之间不借用
Redshift WLM Queue(Auto / Manual) 内存 + 并发 + 查询组 ❌ 队列独立
ClickHouse Settings Profile + max_memory_usage 内存(无正式池概念) ❌ 无池间借用机制
Doris/StarRocks Workload Group CPU + 内存 + 并发 ❌ 组间独立
Snowflake Virtual Warehouse (t-shirt sizing) 完整计算资源独立 ❌ Warehouse 之间完全独立 ❌ 需额外计算资源

核心差异: Vertica 是少数在逻辑层面提供「弹性借用」的 MPP 系统——GENERAL 池的设计让资源池模型兼具预分配的安全感和共享池的弹性。Greenplum Resource Group 和 Doris Workload Group 走的是「严格隔离」路线——每个组的资源完全不共享——更适合多租户场景但利用率可能更低。Snowflake 的 Virtual Warehouse 则彻底跳出了「逻辑切分」的范畴,直接用独立计算资源做物理隔离(与 Vertica 的 Eon 子集群类似,见 §2.6)。

上表非 Vertica 条目为基于各产品公开架构文档的归纳,具体参数名以各产品最新 GA 版本文档为准。


2.3 第二层:并发控制策略 —— 多少查询可以同时跑

MPP 共性: 所有 MPP 系统都需要限制并发查询数,否则内存和 CPU 会被不可控的并发撑爆。区别在于并发控制与内存预算之间如何耦合。

Vertica 的双层并发控制

Vertica 的并发控制通过两个参数实现:

  • PLANNEDCONCURRENCY:用于计算 query_budget。它告诉 Resource Manager「我预计这个池同时跑多少个查询」,从而计算每个查询应该分多少内存。
  • MAXCONCURRENCY:用于硬限制并发数。超过这个数的查询要么排队要么拒绝。

分开设计的收益:你可以让 query_budget 基于较小的 PLANNEDCONCURRENCY 来「多给每个查询一些内存」,同时用较大的 MAXCONCURRENCY 来允许多一些并发。也可以反过来——PLANNEDCONCURRENCY 大(query_budget 小,每个查询内存少),MAXCONCURRENCY 小(硬限制并发数)。

一个常见误解:PLANNEDCONCURRENCY 越小 query_budget 越大,所以应该尽量设小。不完全对——query_budget 太大意味着在并发达到 PLANNEDCONCURRENCY 时,总内存消耗就会达到 MAXMEMORYSIZE,之后的查询全部排队。你需要匹配的是 95% 查询的实际内存消耗分布,而不是极致压缩 PLANNEDCONCURRENCY。

query_budget:串联内存与并发的枢纽

query_budget 是 Vertica Resource Manager 在查询执行前,为该查询估算并分配的初始内存预算。它是决定查询性能的最关键数字(C-Store 7 Years §4,The Vertica Analytic Database: C-Store 7 Years Later)。

计算公式因池的类型而异(来源:17-04-operations-and-monitoring.md Query budgeting 节)。GENERAL 池的 MAXMEMORYSIZE 有特殊含义——当设为百分比时,代表物理内存的百分比;而用户自定义池的 MAXMEMORYSIZE 百分比是相对于 GENERAL 池的 MAXMEMORYSIZE(即物理内存 × 95%)再折算。

GENERAL 池(默认池)

MAXMEMORYSIZE = 物理内存 × 95%
query_budget ≈ MAXMEMORYSIZE / PLANNEDCONCURRENCY

例如:物理内存 256 GB,MAXMEMORYSIZE = 95%,则 MAXMEMORYSIZE(绝对值) = 256 × 95% ≈ 243 GB,即该节点上的Vertica进程所能使用的最大内存为 243 GB。

用户自定义池(MEMORYSIZE 未设,MAXMEMORYSIZE 已设)

MAXMEMORYSIZE(绝对值) = 物理内存 × 95% × MAXMEMORYSIZE%
query_budget ≈ MAXMEMORYSIZE(绝对值) / PLANNEDCONCURRENCY

例如:物理内存 256 GB,MAXMEMORYSIZE = 40%,则 MAXMEMORYSIZE(绝对值) = 256 × 95% × 40% ≈ 97 GB,即该资源池在该节点上所能使用的最大内存为 97 GB。

用户自定义池(MEMORYSIZE 已设非零值)

query_budget = MEMORYSIZE / PLANNEDCONCURRENCY

这种情况下池有独占内存,不从 GENERAL 借用,query_budget 直接由独占内存和预期并发算出。

以 10 节点、每节点 256 GB 的集群为例:

资源池 MAXMEMORYSIZE PLANNEDCONCURRENCY MAXMEMORYSIZE(绝对值) query_budget 适用场景
general 95%(特殊:物理内存的 95%) AUTO(≈48,等于核数) 256 × 95% ≈ 243 GB 243 / 48 ≈ 5 GB 默认,所有未分配池的查询
etl_pool 40% 4 243 × 40% ≈ 97 GB 97 / 4 ≈ 24 GB 大内存批量处理
dashboard_pool 30% 24 243 × 30% ≈ 73 GB 73 / 24 ≈ 3 GB 高并发轻查询
analyst_pool 20% 3 243 × 20% ≈ 49 GB 49 / 3 ≈ 16 GB 低并发复杂分析

query_budget 决定了每个算子在执行计划中的初始内存分配。如果查询实际需要的内存超过 query_budget,它不会直接失败——Resource Manager 允许它在执行中申请额外内存(AcquireAdditional),但这会增加排队等待和执行时间

跨系统对比:并发控制模型

系统 并发控制机制 与内存预算的耦合
Vertica PLANNEDCONCURRENCY + MAXCONCURRENCY 双层 紧密耦合——query_budget = [MAX]MEMORYSIZE / PLANNEDCONCURRENCY
Greenplum Resource Group: CONCURRENCY / Resource Queue: ACTIVE_STATEMENTS 弱耦合——内存限制独立于并发限制
Redshift WLM concurrency level(每队列槽位数) 中等——每个槽位分得等额内存(占总内存 / 槽位数)
ClickHouse max_concurrent_queries 全局参数 弱耦合——max_memory_usage 按用户/查询设定,非按池分配
Doris/StarRocks Workload Group max_concurrency 中等——组内按 query_memory_limit 控制
Snowflake Virtual Warehouse MAX_CONCURRENCY_LEVEL(默认 8) 弱耦合——Warehouse 内排队等待,无按查询预分配内存预算

Vertica 的独特之处: PLANNEDCONCURRENCY 不只是一个硬限制——它是内存预算公式的分母。这意味着调整并发数会直接改变每个查询能分到的内存量,反之亦然。其他系统(如 Redshift WLM)的并发槽位数与每查询内存之间也有类似关系,但 Vertica 通过 query_budget 把这个关系做成了显式的、可精确计算的机制。Greenplum Resource Group 的内存限制(MEMORY_LIMIT)是组级上限,不按「预期并发数」预分配到单个查询。

上表非 Vertica 条目为基于各产品公开架构文档的归纳。


2.4 第三层:排队与拒绝哲学 —— 资源不足时怎么办

MPP 共性: 当资源不足时,系统必须在「让查询等」和「直接拒绝」之间选择。这是一个工程哲学问题——不同 MPP 系统有不同的倾向。

Vertica 的主动拒绝设计

当资源不足时,Resource Manager 面临两个选择:排队或拒绝。

排队(Queue) 的前提是:

  • 资源池的 QUEUETIMEOUT 不为 0
  • 当前排队请求数量未超过系统上限
  • 请求的内存缺口在合理范围内(可以等待释放)

拒绝(Reject) 发生在:

  • 排队超时(超过 QUEUETIMEOUT
  • MAXCONCURRENCY 已达上限,且池不允许排队
  • 请求的内存超过 MAXQUERYMEMORYSIZE
  • 请求的内存超过物理内存总量
  • 数据目录磁盘空间不足

拒绝会被记录到 v_monitor.resource_rejections(按池、类型、原因聚合)和 v_monitor.resource_rejection_details(逐条记录)。查询层面会收到 RESOURCE_REJECTED 错误。

这个「主动拒绝」的设计哲学与传统数据库截然不同。传统数据库的默认行为是「来者不拒,撑不住再说」——查询全都放进来,内存不够就 swap,swap 不够就 OOM。Vertica 的哲学是「宁可拒绝,不让系统崩溃」。被拒绝的查询可以重试、可以改写、可以错峰执行;但节点 OOM 宕机意味着数据恢复、集群 rebalance、业务中断——代价要大几个数量级。

级联(CASCADE TO):用时间换空间

CASCADE TO 参数允许指定一个「后备资源池」,当查询超过当前池的 RUNTIMECAP 时自动级联过去。这个机制的意图是用时间换空间:短查询走专门的「快速通道」,长时间运行的查询自动升级到更宽松的池。

级联有两种模式(来源:Vertica 资源池最佳实践):

  • 模式 A(不重新规划):query_budget 不变,只改变 RUNTIMECAP 和记账归属。适合大多数查询都是短查询的场景。
  • 模式 B(重新规划):查询在目标池上重新规划,获得更大的 query_budget。需要设置 CascadeResourcePoolAlwaysReplan=1。适合混合长短查询的场景,短查询用大预算池会浪费——重新规划虽然消耗 CPU,但换来了更匹配的内存预算。

级联的边界条件在官方文档里有详细说明(来源:17-04-operations-and-monitoring.md Defining secondary resource pools 节):目标池没有可用内存时查询可能被终止并重新排队;如果目标池的 MAXCONCURRENCY 已达上限,查询会继续在原池运行(不级联)。Eon 模式下,全局池只能级联到全局池,子集群池可以级联到全局池或同子集群的其他池。

跨系统对比:排队与拒绝策略

系统 默认行为 排队机制 拒绝条件 级联/跳跃
Vertica 主动拒绝(宁可拒绝,不让崩溃) QUEUETIMEOUT + 按 PRIORITY 队列 排队超时 / MAXCONCURRENCY 打满 / 超 MAXQUERYMEMORYSIZE ✅ CASCADE TO(多级)
Greenplum 排队等待 Resource Queue 无超时(一直等) 仅当队列满或语句超时(statement_timeout) ❌ 无级联机制
Redshift 排队等待(WLM queue) WLM queue timeout(可配) queue timeout 到期 ✅ 队列跳跃(query group hopping)
ClickHouse 直接拒绝 无排队机制 max_concurrent_queries 达到上限即拒绝 ❌ 无级联
Doris/StarRocks 排队等待 Workload Group queue queue timeout / 并发打满 ❌ 无级联
Snowflake 排队等待 STATEMENT_QUEUED_TIMEOUT_IN_SECONDS(默认 0,即不排队直接拒绝) queue timeout / Warehouse 并发打满 ❌ 无级联,但可动态调整 Warehouse SIZE

核心差异: Vertica 是少数同时提供「主动拒绝 + 排队 + 级联升级」三层机制的 MPP 系统。Greenplum 的 Resource Queue 偏向「一直等」,可能造成队列无限堆积;ClickHouse 最简单粗暴——直接拒绝;Snowflake 默认也不排队(QUEUED_TIMEOUT=0)。Vertica 的 CASCADE TO 是唯一将「查询时间」作为资源管理维度的机制——它承认「查询的内存需求与执行时间是相关的」这一事实,并通过级联让长查询获得渐进更多的资源。

上表非 Vertica 条目为基于各产品公开架构文档的归纳。


2.5 Vertica 专属:执行引擎的 Zone 机制

Vertica 独有: Zone 机制是 Vertica 执行引擎的特有设计,其他 MPP 系统没有直接等价物。它解决的是「单查询内部多个算子之间如何共享内存」的问题,与资源池层面的「查询间如何分配内存」是不同层级的概念。

Resource Manager 不只是给查询发一张「内存支票」就撒手不管了。在查询编译阶段,每个算子根据其资源池的 query_budget 获得自己的内存预算。但流水线执行引擎面临一个挑战:如果所有算子都按最坏情况预留内存,总内存需求会远大于实际可用内存。

Vertica 的解决方案是将执行计划切分为多个 Zone(来源:C-Store 7 Years §4) —— 同一 Zone 内的算子共享资源,不同 Zone 之间不能同时执行。下游 Zone 的算子可以回收上游 Zone 已释放的资源。这个设计的收益是:每个 Zone 内的算子实际可用内存比分段预留模式要多,减少了不必要的 Spill 到磁盘。

这是一个巧妙的设计——它用流水线的天然串行化特征,在不增加物理内存的前提下放大了单个查询的有效内存。代价是:如果 Zone 划分不合理,可能导致不必要的 Spill。不过 Zone 划分完全由优化器自动完成,用户无需干预。

为什么其他 MPP 不需要 Zone? Greenplum 和 Redshift 基于 PostgreSQL 的 executor,其算子间的内存管理通过 work_mem 和磁盘 spill 实现,没有 Zone 的概念。ClickHouse 的 Pipeline 执行引擎每个 stage 天然隔离,不需要额外的 Zone 抽象。Snowflake 在 micro-partition 级别管理列数据,执行模型与 Vertica 的投影级流水线不同。Zone 是 Vertica 在「投影级列存 + 全流水线执行」这个特定组合下的工程解决方案。


2.6 Vertica 专属:Eon 子集群物理隔离

说明: Eon 子集群是 Vertica 在计算-存储分离架构下的物理隔离方案。类似的概念存在于 Snowflake(Virtual Warehouse)中,但 Greenplum/ClickHouse/Doris 无法以同样的低成本实现物理隔离——因为它们没有共享存储层。

资源池提供的是逻辑隔离——它限制内存和并发,但所有查询仍在同一组节点上执行,CPU、网络、磁盘 I/O 仍会互相影响。Eon 模式引入了物理隔离:子集群(Subcluster)。

子集群是一组独立的计算节点,共享同一份公共存储(S3/MinIO/HDFS)。每个子集群上的查询只在该子集群的节点上执行,不会影响其他子集群的 CPU、内存或网络(来源:07-architecture.md Workload isolation 节)。

这带来了质变:

隔离层级 隔离内容 适用模式 成本
资源池 内存、并发槽位 Enterprise / Eon 零硬件成本
子集群 CPU、内存、网络、磁盘 I/O 仅 Eon 需额外计算节点
Sandbox 以上 + 数据独立性 仅 Eon 需额外计算节点 + 存储

子集群级别的资源池覆盖(ALTER RESOURCE POOL ... FOR SUBCLUSTER ...)允许为每个子集群独立配置资源池参数。例如:ETL 子集群的 TM 池可以调大 MAXCONCURRENCY 加速 mergeout,而仪表盘子集群可以完全禁用 TM 池释放内存给查询使用(来源:17-04-operations-and-monitoring.md Managing workload resources in an Eon Mode database 节)。

从 Vertica 23.3 开始,工作负载路由规则(Workload Routing Rules) 可以根据客户端的 --workload 参数自动将连接路由到对应子集群,不再依赖客户端 IP(来源:25-sql-reference.d/03-system-tables.md WORKLOAD_ROUTING_RULES 定义)。这让子集群隔离的运维成本进一步降低。

与 Snowflake Virtual Warehouse 的对比

Snowflake 的 Virtual Warehouse 与 Vertica Eon 子集群在概念上有相似之处——两者都利用计算-存储分离架构提供物理隔离。但关键差异在于:

维度 Vertica Eon 子集群 Snowflake Virtual Warehouse
隔离粒度 子集群级(一组节点) Warehouse 级(t-shirt sizing: XS-6XL)
资源池覆盖 ✅ 子集群级资源池参数覆盖 ❌ Warehouse 内无细粒度资源池概念
弹性启停 手动或脚本控制 自动 suspend/resume(可配超时)
数据共享 共享公共存储 通过 Secure Data Sharing 跨 Warehouse 共享
成本模型 节点数 × 时长 Credit/小时 × Warehouse SIZE

为什么 Greenplum/ClickHouse/Doris 无法以同样低成本做物理隔离? Greenplum 是 shared-nothing 架构,每个 segment 持有独立数据分片——要隔离就需要为每个工作负载建独立集群并复制全部数据(存储成本 ×N)。ClickHouse 单机也可以独立部署,但同样需要数据复制。Doris 走的是类似路径。Vertica Eon 和 Snowflake 的共同优势在于「存储不复制,只增加计算」——这是计算-存储分离架构对隔离成本的结构性降维。


2.7 Vertica 完整链路:从查询提交到执行

当一条查询提交到数据库后,Resource Manager 的介入分为以下几个阶段(来源:17-04-operations-and-monitoring.md Resource manager impact on query execution 节):

  1. 解析与优化:查询被解析、优化,生成执行计划,分发到参与节点
  2. 资源评估:每个节点上的 Resource Manager 估算该查询需要的资源,与当前已用资源对比:
    • 如果查询所需内存超过物理内存 → 直接拒绝(极少发生)
    • 如果当前资源不足但有排队空间 → 进入队列等待
    • 如果资源充足 → 允许执行
  3. 启动执行:只有当所有参与节点都允许该查询执行时,查询才开始执行
  4. 运行时管理:查询执行过程中,Resource Manager 通过 RUNTIMEPRIORITYRUNTIMEPRIORITYTHRESHOLD 持续管理资源分配
  5. 超时级联:查询超过池的 RUNTIMECAP 时,自动级联到 CASCADE TO 指定的后备池,获得更宽松的时间预算(和可选的更大内存预算)

这里有一个容易忽视的关键细节:第 3 步意味着在 MPP 环境下,查询必须等所有参与节点都放行才能开始。如果某个节点上资源紧张而其他节点空闲,查询会在所有节点上排队等待——这就是分布式资源管理的「木桶效应」。这一效应在 Greenplum(所有 segment 必须同时放行)、Redshift(所有 slice 必须同步启动)、Doris(所有 BE 需同时分配资源)中同样存在——这是 MPP 分布式执行的共性约束,非 Vertica 独有。


3. 设计决策与 Trade-off

3.1 为什么用「资源池」而不是「全局内存管理」

这是 Vertica 最根本的设计选择之一。

全局统一内存管理(如传统数据库的 shared_buffers + work_mem 模型)——所有查询共享同一块内存池,系统不主动区分查询的优先级或来源。收益是简单、无需用户配置。代价是无隔离能力:一条大查询可能耗尽所有可用内存,拖死所有其他查询。

Vertica 的选择:资源池模型——将系统资源预分配为多个子集,每个子集有自己的内存上限、并发上限和排队规则。收益是零硬件成本实现内存和并发隔离,GENERAL 池提供弹性缓冲(池间可借用内存)。代价是 CPU 和网络仍共享,不能防止 CPU 密集型查询对其他查询的影响;配置复杂度也高于方案 A。

  • 表现优异场景:工作负载类型可预测、内存消耗是主要瓶颈
  • 表现短板场景:CPU 密集型查询和 I/O 密集型查询混跑(资源池只隔离内存,不管 CPU)。如果 CPU 争用成为瓶颈,需要升级到物理隔离——详见 §3.4 的资源池 vs 子集群对比。

3.2 为什么 MEMORYSIZE 和 MAXMEMORYSIZE 要分开设计

这两个参数的设计反映了 Vertica 对「独占 vs 共享」的权衡:

配置方式 行为 适用场景 风险
MEMORYSIZE=0, MAXMEMORYSIZE=设置值 池没有独占内存,但从 GENERAL 借用可达 MAXMEMORYSIZE 大部分场景 可能与其他池争抢 GENERAL
MEMORYSIZE=MAXMEMORYSIZE 池有完全独占内存,不能从 GENERAL 借 需要严格 SLA 保证的关键业务 独占内存在空闲时也不能被其他池利用
MEMORYSIZE < MAXMEMORYSIZE 有保底内存,还可以借用 混合:日常够用,高峰有弹性 借不到时仍排队

关键取舍:GENERAL 池扮演了「公共资金池」角色,但它的资金不是无限的——其 MAXMEMORYSIZE 默认是物理内存的 95%。当多个池同时借钱时,PRIORITY 高的先得。这带来一个隐性约束:如果你把某个池的 PRIORITY 设得过高,它可能在内存紧张时「挤兑」掉其他池的借用额度。

3.3 为什么 PLANNEDCONCURRENCY 和 MAXCONCURRENCY 是分开的

这是很多新手配置时的困惑点——为什么需要两个并发参数?

  • PLANNEDCONCURRENCY:用于计算 query_budget。它告诉 Resource Manager「我预计这个池同时跑多少个查询」,从而计算每个查询应该分多少内存。
  • MAXCONCURRENCY:用于硬限制并发数。超过这个数的查询要么排队要么拒绝。

分开设计的收益:你可以让 query_budget 基于较小的 PLANNEDCONCURRENCY 来「多给每个查询一些内存」,同时用较大的 MAXCONCURRENCY 来允许多一些并发。也可以反过来——PLANNEDCONCURRENCY 大(query_budget 小,每个查询内存少),MAXCONCURRENCY 小(硬限制并发数)。

3.4 资源池隔离 vs 子集群隔离:什么时候逻辑不够用

资源池是逻辑隔离——它管理内存和并发槽位,但同一个节点上如果跑了 10 个查询(来自不同资源池),它们的 CPU 时间片由操作系统分配,网络带宽共享网卡,磁盘 I/O 共享存储控制器。

CPU 密集型场景是资源池的盲区。假设你的 ETL 池有 4 个 Hash Join 查询同时在对十亿行数据做重分区,每个查询的 EXECUTIONPARALLELISM=48——这 192 个线程会把所有 CPU 核占满。此时即使 dashboard_pool 的 query_budget 充足,dashboard 查询也会因为 CPU 调度延迟而变慢。

子集群解决了这个问题——物理隔离意味着独立的 CPU、独立的内存、独立的网络路径。当你的工作负载之间存在不可调和的资源冲突时,子集群是正确答案。

但子集群也有代价:

  • 公共存储虽然共享,但 depot 缓存不共享——每个子集群需要独立预热
  • 主子集群单点风险:primary 子集群故障会影响整个数据库
  • 管理复杂度增加:需要配置路由规则、负载均衡组、子集群级资源池覆盖

选型思路:先尝试资源池调优。只有当资源池层面的内存/并发调优已经做到极致、但 CPU 或网络争用仍无法解决时,才考虑引入子集群。Vertica 多租户实现最佳实践 里有完整的多租户方案对比和决策树。

3.5 与其他 MPP 系统的对比

说明: 本表涵盖不同架构类型(shared-nothing、计算-存储分离、云原生)。非 Vertica 条目为基于各产品公开架构文档的归纳,具体参数名以各产品最新 GA 版本文档为准。

维度 Vertica Greenplum Redshift ClickHouse Snowflake
资源管理单元 资源池(Resource Pool)+ Eon 子集群 资源队列(Resource Queue)/ 资源组(Resource Group) 工作负载管理(WLM)队列 Settings Profile + max_memory_usage Virtual Warehouse (t-shirt sizing)
隔离粒度 内存 + 并发 + (Eon) CPU/网络/IO 并发 + 内存(RG 支持内存限制) 内存 + 并发 + (多集群) 物理隔离 内存 + 并发(全局参数,无池概念) 完整计算资源独立(物理隔离层级)
弹性借用 ✅ GENERAL 池充当全局缓冲 ❌ 资源组之间不借用 ❌ 队列独立 ❌ 无池间借用机制 ❌ Warehouse 之间完全独立
物理隔离 ✅ Eon 子集群(分钟级启停,存储共享) ❌ 需独立集群 + 数据复制 ✅ 多集群(但需数据复制) ❌ 需独立部署 + 数据复制 ✅ Virtual Warehouse(存储共享,天然隔离)
并发与内存耦合 紧密(query_budget = MEM / PLANNEDCONCURRENCY) 弱(独立参数) 中等(槽位等额内存) 弱(全局 max_concurrent_queries 弱(MAX_CONCURRENCY_LEVEL
执行时参数切换 ✅ 级联(CASCADE TO)+ 运行时优先级 ❌ 静态分配 ✅ 队列跳跃 ❌ 无动态切换 ❌ 无级联,可动态调 SIZE
配置复杂度 中等(5 核心参数 + 级联配置) 低(队列模式)到中等(RG 模式) 低(简单模式)到中等(Auto WLM) 低(全局参数,无正式池概念) 极低(t-shirt sizing,零参数调优)
运维自动化 中等(需监控排队/拒绝/借出三项指标) 中高(需调度 VACUUM 等) 中等(Auto WLM 自动适配) 低(全自动,极少干预) 极低(全托管,零运维)

隔离粒度全景

从纯逻辑到纯物理的连续谱:

逻辑隔离 ←————————————————————————————→ 物理隔离

ClickHouse     Greenplum RG    Vertica 资源池    Redshift WLM    Vertica Eon 子集群    Snowflake VW
(全局参数)     (资源组)         (池 + 弹性借用)    (队列 + 跳跃)    (计算独立+存储共享)    (完全独立计算)
  • 处于左端的系统(ClickHouse、Greenplum):零硬件成本实现隔离,但无法隔离 CPU/IO 争用。
  • 处于右端的系统(Snowflake VW、Vertica Eon 子集群):完整物理隔离,但需要额外计算资源(以及 Vertica Eon 和 Snowflake 都因存储共享而免于数据复制成本)。
  • Vertica 的独特位置:同时提供左端(资源池)和右端(Eon 子集群),且两者可在同一集群内组合(子集群内再分资源池)。

核心结论: Vertica 最独特的竞争力在于子集群隔离 + 资源池级联的组合——前者提供物理隔离但只增加计算成本(不复制数据),后者在单子集群内提供精细化的内存/并发管理。这是 Eon 计算-存储分离架构的直接红利。Snowflake 的 Virtual Warehouse 提供了比 Vertica 更简单的物理隔离体验(t-shirt sizing, 零参数),但牺牲了细粒度的内存/并发控制能力(Warehouse 内只有 MAX_CONCURRENCY_LEVEL 一个参数)。选择取决于你的工作负载是否需要精细化的单查询内存预算控制。


4. 设计对实际使用的影响

4.1 查询层面

自动生效的部分

  • 每条进入 GENERAL 池的查询不需要任何配置就能获得合理的 query_budget
  • query_budget 不足时,Resource Manager 自动尝试获取额外内存(AcquireAdditional)
  • 单个查询内存需求超过 MAXQUERYMEMORYSIZE 时被自动拦截

需要手动干预的部分

  • v_monitor.resource_acquisitions 显示大量 AcquireAdditional 时 → query_budget 偏小,应调小 PLANNEDCONCURRENCY(让单个查询分到更多内存)或适当调大 MAXMEMORYSIZE
  • v_monitor.resource_rejections 出现 Memory 类型拒绝时 → 检查是整个池的 MAXMEMORYSIZE 太小,还是单条查询内存需求过大(需设 MAXQUERYMEMORYSIZE 拦截)
  • v_monitor.resource_queues 有持续排队时 → 判断排队原因是 MAXCONCURRENCY 打满(并发瓶颈)还是内存打满(内存瓶颈),两者调优方向不同

4.2 加载层面

ETL 加载操作默认进入创建连接的用户的资源池(通常是 GENERAL),但也可以显式分配。一个经常被忽略的事实是:Tuple Mover(TM)有自己的内置池,其 mergeout 操作的并发和内存独立于用户查询池(来源:17-04-operations-and-monitoring.md TM pool 节)。

这意味着即使你的 ETL 池被查询占满,TM 的 mergeout 仍然能正常推进——前提是 TM 池没有被错误调小。TM 池默认 MAXCONCURRENCY=7、PLANNEDCONCURRENCY=7、MEMORYSIZE 约为 GENERAL 的 5% + 2GB。在写入密集型场景,可能需要调大 TM 池的 MAXCONCURRENCY 以加速 ROS container 合并。

数据加载中另一个容易被忽视的交互是:Refesh(PROJECTION_REFRESHES)操作使用 REFRESH 内置池,PRIORITY=-10。这意味着在高负载时,投影刷新会排在其他查询之后。如果 ETL 加载后需要立即刷新投影,要注意 REFRESH 池的排队情况。

4.3 运维层面

监控的核心视角

v_monitor.resource_pool_status → 每个池的实时内存/并发状态
v_monitor.resource_queues      → 当前排队的请求
v_monitor.resource_rejections  → 拒绝的聚合统计
v_monitor.resource_acquisitions → 查询的资源获取历史
dc_resource_pool_move          → 级联事件记录

容量规划的核心公式

  • 总可用内存 = GENERAL.MAXMEMORYSIZE (默认 95% 物理内存)
  • 每个用户池的 MAXMEMORYSIZE 之和不应长期超过 GENERAL.MAXMEMORYSIZE × 80%(因为还有系统开销、Catalog 内存、JVM 池等)
  • 如果 v_monitor.resource_pool_status 显示 GENERAL 的 GENERAL_MEMORY_BORROWED_KB 持续 > 0,说明有池在持续借钱——要么调大借钱池的 MAXMEMORYSIZE,要么查明为什么它的独占内存不够

常见误解澄清

  • ❌ 「多建几个资源池就能提高并发」→ 资源池不增加总内存,只改变分配方式。池越多,每池的 MAXMEMORYSIZE 越小,某些池可能常年独占比它实际需要更多的内存
  • ❌ 「把 MEMORYSIZE 设大就能让查询更快」→ query_budget 由 MEMORYSIZE/PLANNEDCONCURRENCY 决定。如果你设了大 MEMORYSIZE 但 PLANNEDCONCURRENCY 也很高,query_budget 可能并不大
  • ❌ 「MAXCONCURRENCY 设得越大越好」→ MAXCONCURRENCY 超过 PLANNEDCONCURRENCY 时,每个查询的实际可用内存会被稀释。大量查询同时跑在超额的并发下,单个查询会更慢、更容易 Spill

5. 案例验证

📝 虚构案例 1:ETL 拖死仪表盘

场景:某电商平台的 Vertica 集群(8 节点,每节点 128 GB),所有查询默认使用 GENERAL 池。每天早上 8 点,ETL 批量加载当天订单明细(INSERT INTO order_detail SELECT ...),同时业务部门的实时销售额仪表盘每 5 秒刷新一次(SELECT sum(amount) FROM orders WHERE ... GROUP BY ...)。

现象:8:00-8:30 期间,仪表盘刷新时间从正常的 0.3 秒飙升到 15-30 秒,运维收到大量慢查询告警。

排查:查看 resource_pool_status,GENERAL 池的 MEMORY_INUSE_KB 在 8:00-8:30 期间达到 MAX_MEMORY_SIZE_KB 的 98%。ETL 的批量 INSERT 消耗了 query_budget 的 3-5 倍内存(实际执行中 AcquireAdditional),占用了大量 GENERAL 池内存。仪表盘查询虽然 query_budget 充足,但由于总池内存已被占满,新查询排队等待,RESOURCE_QUEUES 显示 queue 深度峰值 27。

根因:所有工作负载共享一个资源池,没有隔离。ETL 的大内存消耗挤压了仪表盘查询的可用空间。

修复:创建 etl_pool(MAXMEMORYSIZE 40%, PLANNEDCONCURRENCY 4, EXECUTIONPARALLELISM 8)和 dashboard_pool(MAXMEMORYSIZE 30%, PLANNEDCONCURRENCY 12, EXECUTIONPARALLELISM 4),通过用户级别 RESOURCE POOL 分配将 ETL 用户和仪表盘用户分别绑定到对应池。修复后仪表盘查询的 95% 响应时间 < 1 秒。

回溯原理:当 ETL 和仪表盘共享 GENERAL 池时,GENERAL 的弹性内存机制反而成了问题——ETL 的 AcquireAdditional 不断从 GENERAL 借入内存,直到整个池的 MAXMEMORYSIZE 被占满,仪表盘查询被挤出。将两者隔离到不同资源池后,ETL 的 MAXMEMORYSIZE 被限制在 40%(约 49 GB),仪表盘始终有独立的 30%(约 37 GB)可用。

📝 虚构案例 2:跨系统对比——同场景下不同 MPP 的资源管理行为

📝 跨系统模拟案例

场景:同一套硬件规格(8 节点,每节点 256 GB 内存),三种工作负载:ETL 批处理(凌晨 2-6 点,大内存低并发)、实时仪表盘(全天,高并发轻查询)、分析师临时查询(工作时间,不可预测)。未做任何资源隔离配置(全部使用默认设置)。

系统 默认行为 内存分配方式 并发控制 超载时表现 手动干预需求
Vertica 全部进入 GENERAL 池,PLANNEDCONCURRENCY=AUTO query_budget ≈ 243 GB / 48 ≈ 5 GB MAXCONCURRENCY 不受限(AUTO) 内存打满后新查询排队或拒绝(RESOURCE_REJECTED) 需创建多个资源池并绑定用户
Greenplum 全部进入默认 Resource Queue 无内存预算概念,work_mem 按连接分配 ACTIVE_STATEMENTS=20(默认) 队列无超时,一直等待 需创建 Resource Group 并设置 MEMORY_LIMIT
Redshift 全部进入默认 WLM 队列 总内存 / 5 槽位 = 每查询等额 concurrency=5(默认) queue timeout 到期后取消查询 需创建多队列 + 查询组路由规则
ClickHouse 所有查询共享全局内存 max_memory_usage 按用户设定 max_concurrent_queries 全局限制 达到上限直接拒绝(无排队) 需配置 Settings Profile + 用户级限制
Snowflake 全部进入默认 Virtual Warehouse (L) Warehouse SIZE 决定总内存 MAX_CONCURRENCY_LEVEL=8 queued timeout 到期取消(默认不排队) 需创建多 Warehouse + 调整 SIZE

核心结论: 无论在哪个 MPP 系统上,默认配置都无法同时满足 ETL + 仪表盘 + 临时分析的混合负载需求。所有系统都需要主动创建隔离单元(资源池/资源组/队列/Warehouse)才能实现工作负载隔离。区别在于隔离的粒度和弹性:

  • Vertica 的资源池在隔离中保留了弹性借用(GENERAL 池),且通过 query_budget 精确控制每查询内存
  • Greenplum/Redshift 的队列/资源组隔离更刚性,但运维更简单
  • ClickHouse 最轻量但也最粗暴——无排队,直接拒绝
  • Snowflake 运维最省心但成本最高——物理隔离需要额外 Warehouse

📝 虚构案例 3:级联池处理临时分析查询的不确定性

场景:某金融机构的 Vertica 集群上,分析师团队经常提交复杂且不可预测的查询。有的查询 1 秒跑完(简单的按天汇总),有的需要跑 10 分钟(多维交叉分析 + 窗口函数)。他们为分析师团队创建了一个资源池 analyst_pool(MAXMEMORYSIZE 30%,PLANNEDCONCURRENCY 6, query_budget ≈ 11 GB)。

现象:偶尔有分析师的复杂查询跑了 2 分钟以上,占着大内存预算不释放,其他分析师的短查询排队等候。

根因:所有分析查询共享同一个预算较大的池,长查询不释放资源导致短查询排队。

修复:采用级联模式 B(重新规划),创建三个级联池:

MAXMEMORYSIZE PLANNEDCONCURRENCY query_budget RUNTIMECAP CASCADE TO
analyst_fast 15% 18 2 GB 10 秒 analyst_medium
analyst_medium 20% 6 7.6 GB 60 秒 analyst_slow
analyst_slow 10% 2 11.4 GB 300 秒

设置 CascadeResourcePoolAlwaysReplan=1。所有分析师查询初始路由到 analyst_fast,10 秒内跑完的就用了小预算;超时的自动级联到 medium→slow,逐级获得更大预算。

效果:90% 的查询在 fast 池完成(平均 3 秒),8% 在 medium 池完成(平均 25 秒),2% 在 slow 池完成(平均 2 分钟)。级联重新规划的开销约为查询总时间的 5-8%,但换来了精细化的资源分配。

回溯原理:级联机制将「先验预算分配」转化为「在线预算匹配」。对于不可预测的工作负载,与其给每条查询都分配「够大的」预算(浪费),不如先用小预算试,不够再升级。CascadeResourcePoolAlwaysReplan=1 是模式 B 的关键——如果不重新规划,级联后的查询仍按初始池的 query_budget 执行,级联只是换了记账归属,没有获得更大的内存预算,级联变得意义不大。

📋 真实案例 · 来源:某运营商 Vertica 数据库性能问题处理报告

行业:某运营商 集群规模:138 节点,Vertica v11.1.1 故障现象:每天上午 9:00-12:00 业务高峰期,app_poolhz_pool 出现大量排队。6 月 23 日中午 12 点平均响应时间达到 94 秒,而 4 天前(6 月 19 日)同期仅为 13 秒——恶化超过 7 倍。

排查关键发现

  1. query_budget 不匹配app_pool 的 query_budget 为 1 GB,但对该池历史查询的分析发现 40% 的 SQL 消耗内存超过 1 GB——这意味着近半数查询需要在执行中反复申请额外内存(AcquireAdditional),在高峰期因资源紧张导致额外申请失败或长时间等待。
  2. 统计信息过期导致内存放大:某条核心 SQL 因 user_dtal 表的统计信息过期,优化器错误地将该表(实际 14.5 亿行,条件过滤后仍有 1500 万行)选为驱动表,导致该查询消耗了 28 GB 内存——远超 query_budget 的 1 GB。
  3. 临时表统计信息缺失:批处理脚本中的中间临时表在 INSERT 后数据被删除,批量统计信息收集时跳过这些空表。后续使用这些表的查询因无统计信息,执行计划偏差导致额外内存消耗。

根因:query_budget 设置过低(1 GB),与实际工作负载的 95% 分位数(约 4 GB)严重不匹配。统计信息过期进一步放大了部分查询的内存需求,双重叠加导致高峰期资源池内存和并发全部打满。

修复与效果

  • app_poolPLANNEDCONCURRENCY 从默认值调整为 10,MAXCONCURRENCY 调整为 25——query_budget 从 1 GB 提升到约 4 GB
  • 设置 MAXQUERYMEMORYSIZE=50G 拦截异常内存消耗的查询
  • 改进批处理脚本,在 INSERT 后立即收集统计信息
  • 预期效果:需要 AcquireAdditional 的查询比例从 40% 降至 < 5%

启示query_budget 的调优不是拍脑袋,而是基于历史工作负载的统计分析——你需要知道该池中 95% 查询的实际内存消耗分布,然后将 query_budget 设到覆盖这个分位数。仅凭经验或默认值大概率不匹配。

📋 真实案例 · 来源:某零售企业 Vertica 数据库性能问题处理

行业:某零售企业

集群规模:6 节点,每节点 384 GB 物理内存

故障现象:数据库性能慢,任务等待资源的时间普遍较长。同时节点 1 和节点 6 发生异常宕机(收到 SIGQUIT 信号)。

排查关键发现

Azkaban 资源池配置:最大内存 292 GB(76% 物理内存),执行并发度 16,最大并发数 22。连续监控发现:

  • Azkaban 资源池同时达到最大并发数(22)和最大内存使用(292 GB)
  • 无夯死任务或异常长时间执行的任务——说明查询本身没有卡住
  • 任务的等待时间全部来自排队等待资源池释放并发槽位和内存

根因:资源池的 MAXCONCURRENCY(22)和 MAXMEMORYSIZE(292 GB)同时被打满。这属于典型的「资源池配置不足」——业务高峰期的并发需求超过了池的容量上限。两个节点的宕机与资源池无直接关系(SIGQUIT 信号来源是外部而非 OOM),但资源紧张加剧了系统不稳定性。

修复方向

  • 根据实际业务并发需求,评估是否需要增加 MAXCONCURRENCY
  • 分析 Azkaban 池中各查询的内存消耗分布,判断是否需要拆分为多个资源池以减少单一池的压力
  • 考虑将不同优先级的任务分配到不同资源池,避免低优先级任务占据槽位

启示MAXCONCURRENCY 和 MAXMEMORYSIZE 是一对联动参数——当并发打满时,每条查询分到的实际内存可能远小于 query_budget;当内存打满时,即使 MAXCONCURRENCY 还有余量,新查询也会因内存不足而被拒绝或排队。监控时需要同时看这两个指标,而不是只看其中一个。


6. 设计原则总结

以下前 4 条为跨系统通用原则,后 4 条为 Vertica 专属。

1. 【通用】资源管理应在查询执行前介入,而非在执行中补救

  • 为什么:MPP 查询的内存消耗可达数十 GB,执行中补救(swap、OOM kill)的成本远高于事前拒绝或排队。Vertica 的 Resource Manager 在查询优化阶段就评估资源需求并决策放行/排队/拒绝,遵循「主动拒绝 > 被动崩溃」的原则。在 Greenplum 中同理:Resource Queue 在查询提交时即判断是否放行;Snowflake 的 STATEMENT_QUEUED_TIMEOUT 也是事前控制。
  • 反例:不限制 MAXMEMORYSIZE、不监控 resource_rejections,等收到 OOM 告警时才排查——此时节点可能已经宕机。

2. 【通用】query_budget / 每查询内存限制的调优基础是历史工作负载的统计分析,不是猜测

  • 为什么:每查询内存预算应该覆盖池中 95% 查询的实际内存消耗。设得太小(如某运营商案例:1 GB vs 实际 4 GB 需求)会导致大量 AcquireAdditional 操作在高峰期排队;设得太大则牺牲并发数。这一原则同样适用于 Redshift WLM 的每槽位内存分配——基于历史查询的 query_peak_memory 统计来设定 memory_percent。
  • 反例:凭经验将 ETL 池的 query_budget 设到 50 GB,但 80% 的 ETL 查询只用了 5 GB——浪费的内存本可以支撑更多并发。

3. 【通用】资源池/资源组隔离的是内存和并发,不是 CPU——CPU 密集型工作负载需要物理隔离

  • 为什么:同一节点上来自不同资源池的查询共享 CPU。当某个池的查询因并行度过高占满 CPU 时,其他池的查询即使内存充足也会因 CPU 调度延迟而变慢。这在所有逻辑隔离方案中都成立——Greenplum Resource Group 的 CPU_RATE_LIMIT 可以限制 CPU 使用率但不能做物理隔离,Redshift WLM 同理,ClickHouse 的 max_threads 只能限制单查询线程数。
  • 反例:在一个 48 核节点上同时跑 ETL(EXECUTIONPARALLELISM AUTO)和仪表盘查询,只用不同资源池隔开——ETL 的 48 线程 Hash Join 会吃掉所有 CPU,仪表盘的轻聚合查询在 CPU 队列中等待,响应时间从毫秒级退化到秒级。

4. 【通用】监控资源管理的指标组合是使用率 + 排队深度 + 拒绝率,而不是单一指标

  • 为什么:Vertica 看 GENERAL_MEMORY_BORROWED_KB + RESOURCE_QUEUES + RESOURCE_REJECTIONS;Greenplum 看 rsgqueueduration + resource_group_cpu_usage;Redshift 看 queue_time + query_aborted;Snowflake 看 QUEUED_OVERLOAD_TIME + BLOCKED。三者联立才能还原资源争用的全景。
  • 反例:只看 RESOURCE_REJECTIONS——发现拒绝率为 0 就认为资源管理没问题,但实际可能有大量查询在排队(QUERY_TIMEOUT 未触发)。排队是「软拒绝」,超时后的影响和直接拒绝一样。

5. 【Vertica】MEMORYSIZE 和 MAXMEMORYSIZE 的组合决定了「保证」和「弹性」的边界

  • 为什么:MEMORYSIZE 是独占内存(保证),MAXMEMORYSIZE 是上限(弹性)。对 SLA 敏感的工作负载(如实时仪表盘),设 MEMORYSIZE=MAXMEMORYSIZE 消除借不到内存的风险;对可排队等待的工作负载(如批处理),设 MEMORYSIZE=0 让 GENERAL 吸收波动。
  • 反例:把所有池都设 MEMORYSIZE=MAXMEMORYSIZE——每个池都独占一块内存,空闲时也不能共享,整体内存利用率极低。

6. 【Vertica】级联(CASCADE)替换的不是好的池设计,而是池设计的「安全气囊」

  • 为什么:级联的核心价值是处理不可预测的查询——大部分查询在快池中用小预算完成,少数长查询自动升级。但如果 40% 的查询都在级联,说明快池的 RUNTIMECAP 或 query_budget 配置有问题。其他 MPP 系统中 Redshift 的队列跳跃最接近此概念,但 Snowflake/ClickHouse 没有等价机制。
  • 反例:设 RUNTIMECAP=1 秒同时 query_budget=1 GB,但 60% 的查询需要 3 秒且 4 GB 内存——超过一半的查询都在级联,重新规划的开销成了主要成本。

7. 【Vertica】Eon 子集群隔离的成本优势来自「计算独立、存储共享」

  • 为什么:传统多集群方案需要为每个集群复制完整数据(存储成本 ×N),而 Eon 子集群复用同一份公共存储,只增加计算节点。Snowflake 的 Virtual Warehouse 共享同一优势——两者都是计算-存储分离架构的直接红利。Greenplum/ClickHouse 的 shared-nothing 架构无法获得此优势。
  • 反例:在 Eon 模式下仍为每个租户创建独立数据库而非使用子集群——每个数据库需要独立 Catalog 和独立的公共存储(或独立的 Schema 组织),丧失了共享存储的成本优势。

8. 【Vertica】内置资源池的参数修改要极其谨慎,尤其是 SYSQUERY 和 TM

  • 为什么:SYSQUERY 池(PRIORITY=110)保证系统表查询永不被阻塞——如果你把它调小了,排查问题时连 resource_pool_status 都可能查不出来。TM 池的 MAXCONCURRENCY 直接影响 mergeout 速度——调太小会导致 ROS Pushback(ROS 容器数达上限进而拒绝写入)。其他 MPP 没有等价的内置池体系——Greenplum 的 VACUUM、Redshift 的 Auto VACUUM、ClickHouse 的后台 merge 都无专属资源池概念。
  • 反例:为了给用户池腾内存,将 TM 池的 MEMORYSIZE 从默认值砍到 0——mergeout 因内存不足变慢,ROS 容器堆积,最终触发 Tuple Mover 无法跟上写入速度导致 ROS Pushback。

Vertica 的资源管理架构在 MPP 领域有一个鲜明特点:它是少数同时提供「逻辑隔离 + 物理隔离 + 弹性借用 + 级联升级」四层机制的 MPP 系统。GENERAL 池的公共缓冲设计让资源池在预分配的安全感与共享池的弹性之间取得了平衡,而 Eon 子集群借助计算-存储分离架构将物理隔离的成本从「数据复制 ×N」降为「只增加计算节点」。但其中的核心原则——执行前资源评估、并发与内存预算的耦合、主动拒绝优于被动崩溃——是所有 MPP 系统在解决多工作负载资源管理问题时绕不开的课题。


7. 延伸阅读

按建议的阅读顺序:

  1. Vertica 资源池最佳实践 — 本文的理论配套实操手册。包含 fastAnalytics 和 quickAnalytics 两个完整场景的资源配置矩阵和参数推导过程。读完本文理解「为什么」之后,用这篇来指导「怎么做」。【Vertica 专属操作指南】
  2. Vertica 资源拒绝排查与资源池调优 — 当你的集群已经出现 RESOURCE_REJECTED 时,这篇提供了从系统级监控发现 → 定位根因 → 修复的一整套排查流程。第 7 节的快速诊断 SQL 工具箱可以作为日常巡检脚本。【Vertica 专属操作指南,排查方法论通用】
  3. Vertica 内存压力诊断与调优 — 深入 Vertica 内存模型的完整文档,涵盖三种压力表现形式(拒绝、排队、溢出)和 6 步排查流程。与本文第 2 节的 query_budget 机制互补。【Vertica 专属,内存诊断方法论通用】
  4. Vertica 多租户实现最佳实践 — 如果你需要服务多个租户/部门且要求物理隔离,这篇覆盖了从多 Schema 到 Eon Sandbox 的五种方案和完整决策树。本文第 2.6 节讨论的子集群隔离在这里有完整的配置示例。【Vertica 专属,多租户设计原则通用】
  5. Vertica 弹性伸缩功能介绍与配置 — Eon 子集群的启停操作指南,包括 SHUTDOWN_WITH_DRAINSANDBOX_SUBCLUSTER 等关键操作的语法和注意事项。子集群隔离配置好之后,如何根据业务高低峰弹性启停节点,都在这篇里。【Vertica 专属】
  6. The Vertica Analytic Database: C-Store 7 Years Later — 本文多次引用的核心论文。§4 描述了执行引擎和 Zone 机制,§5 讨论了运行时资源管理。理解 Vertica 如何在单查询内部管理内存分配(Zone → 算子 budget → Spill 回退),会帮助你更深刻地理解为什么资源池层面需要 PLANNEDCONCURRENCY 和 EXECUTIONPARALLELISM 这些参数。【MPP 通用 — 理论源头,Vertica 为主要载体】
  7. Vertica 官方文档 — Resource manager — 官方文档的资源管理专题。当你需要确认某个参数的精确默认值、语法边界、或版本差异时,直接查这一章。本文的所有参数表格和计算公式均来自这里。【Vertica 官方参考】