跳转至

Vertica 低延迟优化最佳实践

编译:JiangChong

原文:Low-Latency Optimizations(2023-09-05)

📝 文章说明:本文基于 Vertica 官方 KB 原文翻译整理。原文发布于 2023 年 9 月,讨论了 Enterprise 模式下的低延迟优化手段(平台硬件、单节点查询、资源管理器调优等),但原文引用的技术栈停留在 Vertica 7.2.x 时代,未涉及 Eon 模式(计算-存储分离)的优化方案。译者根据当前 Vertica 技术架构,补充了 Eon 模式下的三种低延迟优化方案:子集群隔离(消除嘈杂邻居)、Depot 预热与固定(消除冷启动延迟)、以及公共存储延迟管理,并更新了方案对比表和低延迟决策框架。新增内容位于「Eon 模式下的低延迟优化方案」章节。

Vertica 与低延迟应用

Vertica 通常用于运行时间较长的分析查询。但也可以使用 Vertica 处理低延迟应用,这类查询通常在十秒内完成。低延迟查询通常用于用户需要实时或近实时响应的场景,例如仪表板(dashboard)应用。

通常,低延迟应用同时具有高并发要求。在这种情况下,应最大化 Vertica 集群的吞吐量(以每秒查询数衡量)。

请遵循本文档中的建议来优化您的特定用例。本文档涵盖 两大类共六种优化维度

Enterprise 模式通用优化(原文):

  1. 平台与硬件建议
  2. 单节点查询设计
  3. 查询优化(Projection / 分段 / 聚合 / 反规范化)
  4. 应用配置(连接池 / 负载均衡 / 数据加载窗口)
  5. 资源管理器调优(并发 / 内存 / 优先级)

Eon 模式专属优化(补充):

  1. 子集群隔离(消除嘈杂邻居,计算物理隔离)
  2. Depot 预热与固定(消除冷启动延迟,LRU 缓存命中保障)
  3. 公共存储延迟管理(网络带宽监控、Depot 容量规划)

平台与硬件建议

对于低延迟应用,建议使用裸金属(bare-metal)或物理硬件,而不是虚拟机。虚拟机和云平台不是低延迟应用的理想平台。虚拟化软件在运行 Vertica 所需的软件堆栈中增加了额外的一层。堆栈中的每一层都会增加延迟。因此,堆栈中的层数越少越好。

为实现低延迟,应使用尽可能少的节点数,但至少需要三个节点以保持容错能力。

有关 VMWare 和调优延迟敏感型工作负载的更多信息,请参阅 Best Practices for Performance Tuning of Latency-Sensitive Workloads in vSphere VMs

存储建议

使用企业级直连存储(DAS)而不是存储区域网络(SAN)。这通常可以加快数据检索速度。使用 SAN 可能会增加查询延迟。

为低延迟应用设置硬件

对于裸金属部署,按以下步骤在 Windows 操作系统上配置 BIOS 以获得最大性能:

  1. 导航至 System Configuration > BIOS/Platform Configuration (RBSU) > Power Management > HP Power Profile
  2. 选择 Maximum Performance
  3. /etc/grub.conf 文件中,在内核条目后追加以下命令行参数:
Intel_idle.max_cstate=0 processor.max_cstate=0.

有关硬件配置的更多信息,请参见 Vertica Hardware Guide(本 vault 翻译版:Vertica 数据库硬件配置指南)。

在 Amazon Web Services (AWS) 上使用 Vertica 的建议

不建议在云平台上为低延迟应用运行 Vertica。如果您选择 AWS 等云平台,以下是一些需要遵循的最佳实践。

AWS 提供两种存储选项:

  • Elastic Block Store (EBS)
  • Ephemeral storage(临时存储)

EBS 存储(类似 SAN 存储)不是本地存储,而临时存储是实例本地的。低延迟应用应使用临时存储。从临时存储读写数据比 EBS 存储更快,因为存储更靠近实例。有关 AWS 最佳实践的更多信息,请参见官方文档:Vertica on AWS

虽然 AWS 最佳实践建议用户使用 8 盘 EBS 软件 RAID-0 阵列,但这对于低延迟查询并不理想。使用单个 EBS 卷可以实现更低的延迟。

请按优先级顺序使用以下存储类型:

  1. Ephemeral storage(临时存储)
  2. 单个 EBS 卷
  3. 8 盘 EBS 软件 RAID-0 阵列

vnetperf 工具

运行 vnetperf 工具来测量主机的网络性能。该工具可以测量网络延迟。对于低延迟查询,最大 RTT(往返时间)延迟为 200 微秒。通过最小化网络跳数可以降低 RTT 延迟。

vnetperf 工具示例如下:

  test   | date                   | node        | index  | rtt latency (us) | clock skew (us)
  latency| 2015-06-18_11:33:28,873| 10.54.10.227| 1      | 182              | 55
  latency| 2015-06-18_11:33:28,873| 10.54.10.228| 2      | 183              | -98

更多信息请参见 Vertica 文档中的 vnetperf utility

单节点查询

可以设计工作负载使用单节点查询来实现低延迟。要使用单节点查询,必须以特定的方式设计投影和查询谓词。更多信息请参见 Vertica 文档中的 Routing JDBC Queries Directly to a Single Node

如果使用单节点查询,则"使用尽可能少的节点数"的建议不适用。

下图展示了如何在包含所需数据的单个节点上高效执行查询。

Low Latency Query

某些查询类型与单节点查询推荐的规格不同。有关这些查询类型的更多信息,请参见 Vertica Community 中的 The Benefits of Single Node Queries

优化查询

可以通过以下任一方法优化查询以获得更低的延迟:

  • 使用 WHERE 子句。投影的排序顺序必须与 WHERE 子句匹配。
  • 在投影定义子句中使用适当的分段,以最小化节点间的网络流量,并确保所有节点负载均衡。
  • 在需要大量聚合(GROUP BY)的查询中使用实时聚合投影(live aggregate projections)。
  • 反规范化(Denormalize)模式以优化数据库的连接性能。

应用配置

可以通过以下方法配置 Vertica 数据库以降低延迟:

  • 使用 JDBC 连接池来减少重复打开客户端和服务器之间网络连接的开销。
  • 如果有中间防火墙或负载均衡设备终止空闲 TCP 连接,请禁用空闲连接终止功能。
  • 在非高峰时段加载数据。数据加载后,运行 ANALYZE_STATISTICS 函数以保持表统计信息最新。
  • 在低延迟查询不运行时执行更新、删除和 ETL 作业。
  • 使用本地连接负载均衡(native connection load balancing)将数据均匀分布到集群中所有节点。

资源管理器 (Resource Manager)

资源管理器控制系统资源以提供稳定且可预测的结果。资源管理器使用资源池灵活地管理查询可用的资源。

资源管理器参数

对查询使用大量线程对于实现低延迟并非最优。一些返回少量行的低延迟查询在减少并行度(更少线程)时可能表现更好。EXECUTIONPARALLELISM 配置参数控制用于处理单个查询的线程数。

还可以通过限制每个查询分配的内存量来降低延迟。这种方法通常适用于使用 hash 运算符(如 JOIN 和 GROUP BY)的查询。PLANNEDCONCURRENCY 配置参数控制查询内存预算。应该给查询提供精确所需的内存量以获得理想性能。可以计算低延迟查询所需的内存,然后在较小的范围内尽可能精确地设置资源池内存。有关设置这些值的示例,请参见 Vertica 文档中的 Scenario: The CEO Query

如果处理的是 CPU 密集型工作负载,应设置并发的硬上限。该上限应等于或小于 Vertica 节点上的处理器数量。调整 EXECUTIONPARALLELISMPLANNEDCONCURRENCY 的值,使得两者的乘积等于或小于可用物理 CPU 数量。有关设置并发硬上限的示例,请参见 Vertica 文档中的 Best practices for managing workload resources

管理内存

MEMORYSIZE 值表示该池可用的最小内存量。应将该值设置为尽可能接近实际所需的内存量。还可以设置 MAXMEMORYSIZE 值来指定资源池可以从 GENERAL 池借用内存而达到的最大大小。应将 MEMORYSIZEMAXMEMORYSIZE 值设置在尽可能接近低延迟查询实际所需内存的范围内。

在某些情况下,两个查询同时需要内存或其他资源。为获得最佳结果,应将低延迟查询分配给具有更高优先级的资源池。有关示例,请参见 Vertica 文档中的 Best practices for managing workload resources

在 Vertica 中,查询在执行的前两秒内获得最高的 nice 优先级。可以通过更改运行低延迟查询的资源池的 RUNTIMEPRIORITYTHRESHOLD 来调整这两秒的优先级时间。但是,仅对低延迟查询执行此操作;不要在其他场景中更改 RUNTIMEPRIORITYTHRESHOLD

示例:资源调优

以下是一个使用本文讨论的概念进行低延迟调优的典型过程示例。为正确调优,应创建合成基准测试(synthetic benchmark),以便在过程的每一步都能验证调优参数对查询基准测试的影响。

考虑以下模式。meter_data 表包含居民用电量的时间点数据。

DROP TABLE meter_data cascade;
CREATE TABLE meter_data
(
   data_id int NOT NULL,
   meter_id char(32) NOT NULL,
   reading_ts timestamp NOT NULL,
   reading_value float NOT NULL
)
;
CREATE PROJECTION meter_data_p1
(
 data_id,
 meter_id,
 reading_ts,
 reading_value
)
AS
 SELECT data_id,
     meter_id,
     reading_ts,
     reading_value
 FROM meter_data
 ORDER BY reading_ts
 SEGMENTED BY HASH(meter_id) ALL NODES KSAFE 1;
/*
COPY meter_data FROM '/home/skeswani/mem_mgmt/data1.txt.bz2' BZIP;
COPY meter_data FROM '/home/skeswani/mem_mgmt/data2.txt.bz2' BZIP;
COPY meter_data FROM '/home/skeswani/mem_mgmt/data3.txt.bz2' BZIP;
*/

以下是资源调优示例所需的初始设置:

DROP RESOURCE POOL dashboard_pool;
CREATE RESOURCE POOL dashboard_pool;
CREATE USER dashboard_user;
GRANT USAGE ON RESOURCE POOL dashboard_pool TO dashboard_user;
ALTER USER dashboard_user RESOURCE POOL dashboard_pool;
GRANT ALL on meter_data TO dashboard_user;

以下查询从 Web 仪表板运行。该查询显示指定日期的最高电表读数,并展示该日期和时间的峰值使用情况图表。

SELECT reading_ts, reading_value
FROM meter_data
WHERE reading_ts between '2005-05-01' and '2005-05-02'
ORDER BY reading_value desc limit 1;

以下是一个用于验证本例中资源池调优的合成并发查询基准测试。该基准测试模拟 Web 仪表板的行为,同时运行 15 个查询。调优资源池后,应在每次更改后重新运行基准测试,以验证工作负载的总执行时间是否逐步改善。持续时间从第一个查询开始到最后一个查询结束的时间计算。

[username@ip-address mem_mgmt]$ cat benchmark.sh
#!/bin/bash
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-01' and '2005-05-02' order by reading_value desc limit 1;" &
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-02' and '2005-05-03' order by reading_value desc limit 1;" &
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-03' and '2005-05-04' order by reading_value desc limit 1;" &
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-04' and '2005-05-05' order by reading_value desc limit 1;" &
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-05' and '2005-05-06' order by reading_value desc limit 1;" &
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-06' and '2005-05-07' order by reading_value desc limit 1;" &
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-07' and '2005-05-08' order by reading_value desc limit 1;" &
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-08' and '2005-05-09' order by reading_value desc limit 1;" &
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-09' and '2005-05-10' order by reading_value desc limit 1;" &
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-10' and '2005-05-11' order by reading_value desc limit 1;" &
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-11' and '2005-05-12' order by reading_value desc limit 1;" &
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-12' and '2005-05-13' order by reading_value desc limit 1;" &
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-13' and '2005-05-14' order by reading_value desc limit 1;" &
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-14' and '2005-05-15' order by reading_value desc limit 1;" &
vsql -U dashboard_user -c "select /* +label(dashboard) */ reading_ts, reading_value from meter_data where reading_ts between '2005-05-15' and '2005-05-16' order by reading_value desc limit 1;" &
wait
SELECT count(*),
        min(start_timestamp),
        max(end_timestamp),
        (max(end_timestamp)-min(start_timestamp))SECOND(3) duration
        FROM query_requests WHERE request_label='dashboard';
 count |           min            |           max            | duration
-------+--------------------------+--------------------------+----------
    15 | 2015-11-12 11:36:45.062353-05 | 2015-11-12 11:36:46.425296-05 | 1.363

示例中进行的调优调整

  • 优化投影,设置 EXECUTIONPARALLELISM=1 以提高运行速度:
ALTER RESOURCE POOL dashboard_pool EXECUTIONPARALLELISM 1;
  • 由于仪表板每次显示 15 天的峰值使用情况,预计可同时运行 15 个查询并获得快速响应:
ALTER RESOURCE POOL dashboard_pool PLANNEDCONCURRENCY 15;
  • 对查询进行 profiling 以查看其所需内存:
Profile select reading_ts, reading_value from meter_data where reading_ts between '2005-05-13' and '2005-05-14' order by reading_value desc limit 1;
NOTICE 4788: Statement is being profiled
HINT: Select * from v_monitor.execution_engine_profiles where transaction_id=45035996273715510 and statement_id=1;
NOTICE 3557: Initiator memory for query: [on pool general: 127093 KB, minimum: 127093 KB]
NOTICE 5077: Total memory required by query: [127093 KB]

查询使用了 128 MB 内存,因此内存范围最小值分配为 128MB,上限为 256MB。但在需要时查询可以从 general 池借用更多内存。MEMORYSIZEMAXMEMORYSIZE 值通过将查询的内存大小乘以计划并发数来计算(分别为 128x15 和 256x15)。

ALTER RESOURCE POOL dashboard_pool MEMORYSIZE '1920M';
ALTER RESOURCE POOL dashboard_pool MAXMEMORYSIZE '3840M';
  • 为资源池设置最高优先级。
ALTER RESOURCE POOL dashboard_pool PRIORITY 100;
  • 本例中节点有 32 个 CPU。限制 MAXCONCURRENCY 以防 CPU 过载。
ALTER RESOURCE POOL dashboard_pool MAXCONCURRENCY 32;

其他推荐任务

为在低延迟应用中获得最佳结果,请执行以下任务:

  • 对于多次使用同一视图的查询,使用 WITH 子句 物化视图。这种方法有助于改善低延迟。
  • 重写查询以使其扁平化(flatten)。低延迟查询在包含子查询时性能较差。Vertica 会尝试扁平化这些查询。查看查询计划以判断查询是否已被扁平化。如果未被扁平化,重写查询并手动扁平化可能有助于实现低延迟。
  • 保持表统计信息最新。准确的统计信息能让优化器为查询选择最佳计划。

Eon 模式下的低延迟优化方案

以下内容为译者补充。原文发布于 2023 年 9 月,但技术内容基于 Vertica 7.2.x,仅覆盖 Enterprise 模式(存算一体),未涉及 Eon 模式(计算-存储分离架构)。Eon 模式于 Vertica 9.0 引入,其子集群机制、Depot 缓存层、公共存储架构从根本上改变了低延迟优化的设计空间。

Eon 模式为何改变低延迟优化的格局

Enterprise 模式下,每个节点同时持有数据和执行计算。低延迟优化围绕减少跨节点数据传输展开——如单节点查询、优化投影分段、资源池隔离。但 Enterprise 模式有一个根本限制:所有工作负载共享同一组节点,一个租户的突发查询可能挤占其他租户的 CPU/内存,导致延迟抖动

Eon 模式的计算-存储分离架构引入了几个关键变化:

维度 Enterprise 模式 Eon 模式
数据位置 本地磁盘(CATALOG + DATA),固定分布 公共存储(S3/HDFS/GCS)+ 本地 Depot 缓存
工作负载隔离 仅资源池(内存 + 并发数),同级节点共享 CPU 子集群物理隔离:独立节点、独立 CPU、独立 Depot
节点恢复延迟影响 从 buddy 同步数据,恢复期可达数小时 从公共存储订阅分片元数据,恢复期分钟级
冷启动延迟 无冷启动概念,数据始终在本地磁盘 新节点 Depot 为空 / 重启后 Depot 可能过期 → Depot 预热机制
存储读取延迟 本地磁盘(~0.1-1ms) Depot 命中(~0.1-1ms SSD)vs 公共存储(~10-100ms 取决于网络)
弹性伸缩 加节点需 rebalance(数小时~数十小时) 加节点仅重新分配分片订阅(分钟级)

来源:Vertica 监控最佳实践 §11.1

这些变化带来了新的低延迟优化手段,也引入了新的延迟风险。以下分别介绍。

方案一:子集群隔离 — 消除嘈杂邻居延迟

Enterprise 模式下,低延迟查询面临的最大不可控因素之一是嘈杂邻居(Noisy Neighbor):同一集群上的 ETL 作业、报表查询、批量 DELETE 可能抢占 CPU 和内存,导致低延迟查询的响应时间剧烈抖动。资源池只能控制内存分配,无法隔离 CPU、网络和磁盘 IO。

Eon 模式通过子集群(Subcluster) 机制提供了更强的隔离:每个子集群拥有独立的计算节点,CPU、内存、网络、Depot 完全隔离。可以将低延迟查询路由到专属子集群,与 ETL、报表等批量工作负载物理分离。

                         ┌─────────────────────────────┐
                         │    公共存储 (S3/MinIO/HDFS)  │
                         │      所有子集群共享           │
                         └──────┬──────────┬───────────┘
                                │          │
                   ┌────────────┴──┐  ┌────┴──────────────┐
                   │ Subcluster    │  │  Subcluster       │
                   │ sc_dashboard  │  │  sc_etl           │
                   │ (低延迟查询)    │  │  (批量 ETL/报表)   │
                   │ 3 节点         │  │  5 节点           │
                   │ SSD Depot     │  │  HDD Depot        │
                   └───────────────┘  └───────────────────┘
                          ↑                     ↑
                   仪表板应用客户端           ETL 调度 / 分析师
               (通过 Routing Rule 路由)  (默认子集群或 Routing Rule)

适用场景

  • 生产环境中间歇性延迟抖动,排查后发现与 ETL 作业或报表查询时间重叠
  • 需要为仪表板 / API 查询提供 SLA 保障(如 P99 < 5 秒)
  • 多个应用共享同一数据库,但各自对延迟的敏感度不同

优势

  • CPU/内存/网络/IO 物理隔离:比资源池隔离强得多。低延迟子集群的性能不受其他工作负载影响
  • 独立 Depot:每个子集群有独立的 Depot 缓存。查询子集群的 Depot 不会被 ETL 子集群的数据加载挤占,热数据保留率更高
  • 弹性伸缩:secondary 子集群可随时启停(SHUTDOWN_WITH_DRAIN() / 重启),不影响数据库稳定性
  • 存储不复制:所有子集群共享公共存储中同一份数据,无额外存储成本

劣势

  • 额外节点成本
  • 编录锁(GCL-X)仍全局共享,极端情况下可能成为瓶颈
  • 需要配置路由规则确保查询定向到正确子集群

配置示例

1. 创建低延迟专属子集群:

# 为低延迟仪表板创建 3 节点的 secondary 子集群,使用 SSD 作为 Depot 路径
admintools -t db_add_subcluster -d mydb \
  -c sc_dashboard \
  --hosts=node10,node11,node12 \
  --is-secondary \
  --depot-path=/ssd_depot

2. 配置子集群级别资源池覆盖(精细控制低延迟子集群的计算资源):

-- 低延迟子集群:调整 General 池内存(FOR SUBCLUSTER 仅支持 MEMORYSIZE/MAXMEMORYSIZE/MAXQUERYMEMORYSIZE)
ALTER RESOURCE POOL general FOR SUBCLUSTER sc_dashboard
  MEMORYSIZE '50%'
  MAXMEMORYSIZE '70%'
  MAXQUERYMEMORYSIZE '4GB';

-- 低延迟子集群的专属资源池(全局设置,由连接到 sc_dashboard 的用户使用)
CREATE RESOURCE POOL dashboard_pool;
ALTER RESOURCE POOL dashboard_pool
  PRIORITY 100
  RUNTIMEPRIORITYTHRESHOLD 1
  PLANNEDCONCURRENCY 15
  MAXCONCURRENCY 16
  EXECUTIONPARALLELISM 2;

-- 将仪表板用户绑定到该资源池
ALTER USER dashboard_user RESOURCE POOL dashboard_pool;

子集群级资源池覆盖从 Vertica 11.0 开始支持。注意:FOR SUBCLUSTER内置资源池(如 general)仅支持 MEMORYSIZEMAXMEMORYSIZEMAXQUERYMEMORYSIZE 三个参数;自定义资源池无此限制,所有参数均可按子集群覆盖。来源:SUBCLUSTER_RESOURCE_POOL_OVERRIDES

3. 配置连接路由,将低延迟客户端定向到 sc_dashboard 子集群:

-- 创建负载均衡组,绑定低延迟子集群
CREATE LOAD BALANCE GROUP lbg_dashboard
  WITH SUBCLUSTER sc_dashboard FILTER '0.0.0.0/0'
  POLICY 'ROUNDROBIN';

-- 创建路由规则:仪表板应用的 IP 段路由到低延迟组
CREATE ROUTING RULE rr_dashboard
  ROUTE '10.2.0.0/24' TO lbg_dashboard;

从 Vertica 23.3 开始,还可以使用 WORKLOAD_ROUTING_RULES 按工作负载类型路由(不依赖客户端 IP)。例如:CREATE WORKLOAD ROUTING RULE wrr_dashboard ROUTE WORKLOAD 'dashboard' TO SUBCLUSTER sc_dashboard;。来源:Vertica 多租户实现最佳实践

4. 弹性伸缩操作:

-- 业务低谷期:优雅关闭低延迟子集群(等待活跃会话排空,超时 300 秒)
SELECT SHUTDOWN_WITH_DRAIN('sc_dashboard', 300);
# 业务高峰期前:重启子集群
admintools -t restart_subcluster -c sc_dashboard -d mydb

⚠️ SHUTDOWN_SUBCLUSTER() 仅适用于 secondary 子集群。建议优先使用 SHUTDOWN_WITH_DRAIN() 优雅关闭。来源:Vertica 弹性伸缩功能介绍与配置

监控子集群隔离效果

-- 按子集群对比资源池排队深度,验证隔离效果
SELECT n.subcluster_name,
       rps.pool_name,
       MAX(rps.running_query_count) AS max_running,
       NVL(MAX(rq.queue_cnt), 0) AS max_queue_depth
FROM resource_pool_status rps
JOIN (SELECT node_name, subcluster_name FROM nodes) n USING (node_name)
LEFT JOIN (
  SELECT node_name, pool_name, MAX(position_in_queue) AS queue_cnt
  FROM resource_queues
  GROUP BY 1, 2
) rq USING (node_name, pool_name)
GROUP BY 1, 2
ORDER BY 1, max_running DESC;

低延迟子集群 max_queue_depth 应持续为 0。来源:Vertica 监控最佳实践 §11.5

方案二:Depot 预热与固定 — 消除冷启动延迟

Eon 模式下,节点本地只保留 Depot(LRU 磁盘缓存),数据实际存储在公共存储中。一个新启动节点或重启节点的 Depot 为空(或数据过期),查询所需数据必须从公共存储拉取——首次访问延迟从 ~1ms(本地 SSD)变为 ~10-100ms(公共存储网络 IO),对低延迟应用是致命的。

Depot 预热(Depot Warming)和对象固定(Pinning)是应对这一问题的手段。

Depot 预热机制

来源:Vertica 26.2.x 官方文档 — 术语表 Depot warming

从 Vertica 24.x+ 起,节点启动时可启用 Depot 预热:节点在启动阶段预加载频繁查询和已固定的数据到 Depot,完成启动后查询可直接命中缓存,无需经历冷 Depot 的延迟惩罚。

  • 预热对象:频繁查询的表/投影 + 通过 pinning policy 固定的对象
  • 代价:预热会延长节点启动时间(取决于预热数据量)
  • 适用场景:节点计划内重启、子集群扩容后、故障节点替换后

控制参数:

-- 查看 Depot 预热相关配置
SELECT parameter_name, current_value, default_value
FROM configuration_parameters
WHERE parameter_name IN (
  'DepotWarmingEnabled',
  'UseDepotForReads',
  'DepotOperationsForQuery'
);

Depot 对象固定(Pinning)

对于低延迟应用中频繁查询的热表/分区,可以通过 Pinning Policy 将其标记为优先保留在 Depot 中,降低被 LRU 淘汰的概率:

-- 表级别固定:低延迟仪表板的热表优先保留在 Depot
SELECT SET_DEPOT_PIN_POLICY_TABLE('meter_data', '', TRUE);

-- 分区级别固定:当前活跃分区固定在 Depot(min=max=同一分区键值)
SELECT SET_DEPOT_PIN_POLICY_PARTITION('meter_data', '2025-06-01', '2025-06-01', '', TRUE);

-- 投影级别固定:特定投影(更细粒度)
SELECT SET_DEPOT_PIN_POLICY_PROJECTION('meter_data_p1', '', TRUE);

表/投影/分区函数中最后一个参数 TRUE 表示立即排队下载(而非等到查询时再拉取)。不指定子集群时需传空字符串 ''

强制完成固定对象的下载:

-- 等待所有排队下载的 pinned 对象完成(在有低延迟查询前执行)
SELECT FINISH_FETCHING_FILES();

来源:Vertica 26.2.x Eon Mode 文档 — Depot management § Pinning policies

子集群级别的 Depot 策略隔离

子集群的核心价值之一是 Depot 互相隔离:ETL 子集群的全表扫描即使频繁 evict 自己的 Depot,也完全不影响低延迟子集群的缓存命中率。所有子集群均应保持 UseDepotForReads = 1(默认),按各自工作集规划 Depot 容量。

子集群间的差异体现在 对象固定策略 上,而非 Depot 大小或禁用读取:

  • 低延迟子集群:Pinning Policy 固定仪表板查询的热表/热分区
  • ETL 子集群:Pinning Policy 固定频繁 JOIN 的维表、元数据表,如果存储空间足够,热事实表的热分区也应固定在本地

对于读密集型子集群,可以微调 DepotOperationsForQuery

-- 低延迟用户:当 Depot 空间满时不 evict 已有热数据,转而直读公共存储
ALTER USER dashboard_user SET PARAMETER DepotOperationsForQuery = 'FETCHES';

UseDepotForReadsUseDepotForWrites 可在 database/user/session 级别设置。来源:Vertica 26.2.x Eon Mode 文档 — Depot gateway parameters

查询级别的 Depot 控制

单个查询也可以通过 hint 控制 Depot 行为:

SELECT /*+ DEPOT_FETCH(ALL) */ reading_ts, reading_value
FROM meter_data
WHERE reading_ts BETWEEN '2025-06-01' AND '2025-06-02'
ORDER BY reading_value DESC LIMIT 1;

DEPOT_FETCH hint 可选值:ALL(默认,可 evict)、FETCHES(有空间才拉取)、NONE(不拉取到 Depot)。

监控 Depot 命中效果

核心查询见 Vertica 监控最佳实践 §11.3。低延迟优化的关键指标:

-- 检查 Depot 容量是否充足
SELECT node_name,
       (current_usage_bytes / 1073741824.0)::NUMERIC(10,2) AS usage_gb,
       (max_size_bytes / 1073741824.0)::NUMERIC(10,2) AS max_gb,
       ROUND(current_usage_bytes * 100.0 / max_size_bytes, 1) AS pct_used
FROM v_monitor.depot_sizes
ORDER BY node_name;

告警规则pct_used 持续 >90% 说明 Depot 容量不足,需要扩容或调整固定策略。

-- 检查 Depot 拉取频率:高频率 = 缓存未命中多 = 延迟风险
SELECT node_name,
       COUNT(*) AS fetch_count,
       (SUM(file_size_bytes) / 1048576.0)::NUMERIC(12,2) AS total_mb
FROM v_monitor.depot_fetches
WHERE start_time > SYSDATE - INTERVAL '1 hour'
GROUP BY node_name
ORDER BY fetch_count DESC;

方案三:管理公共存储延迟

Eon 模式下,当数据不在 Depot 中时,节点必须从公共存储(S3/HDFS/GCS)读取。公共存储的延迟受以下因素影响:

  • 网络带宽与延迟:节点到对象存储之间的网络跳数、带宽
  • 公共存储性能:HDFS NameNode 响应、S3 API 限流、GCS 并发连接数
  • Depot 容量:Depot 不够大 → 频繁 eviction → 更频繁访问公共存储

公共存储延迟对查询的影响量化

官方文档明确警告:禁用 Depot 后查询性能下降 30% ~ 4000%,具体取决于工作负载类型。

来源:Vertica 26.2.x Eon Mode 文档 — Deciding whether to disable the depot

这意味着公共存储延迟在低延迟场景中是必须管理的变量。以下为具体管理手段。

1. Depot 容量规划 — 让工作集完全驻留在 Depot 中

低延迟应用的最佳状态是:工作集(频繁查询的数据)完全驻留在 Depot 中,查询 100% 命中 Depot,零访问公共存储。

估算所需 Depot 大小(来源:Vertica 26.2.x 官方文档):

单节点 Depot 大小 ≥ 压缩后工作集大小 / 子集群节点数

例如:工作集压缩后 600GB,低延迟子集群 3 节点 → 每节点 Depot ≥ 200GB。加上 20% buffer → 建议 240GB/节点。

-- 查看当前 Depot 容量与用量
SELECT node_name, location_path,
       (max_size_bytes / 1073741824.0)::NUMERIC(10,2) AS max_gb,
       (current_usage_bytes / 1073741824.0)::NUMERIC(10,2) AS cur_gb,
       ROUND(current_usage_bytes * 100.0 / max_size_bytes, 1) AS pct
FROM v_monitor.depot_sizes;

2. 监控公共存储带宽消耗

-- 网络带宽持续高 + Depot fetch 频繁 = 存在公共存储延迟风险
SELECT node_name,
       AVG(rx_kbytes_per_sec) AS avg_rx_kbs,
       MAX(rx_kbytes_per_sec) AS peak_rx_kbs
FROM v_monitor.network_usage
WHERE start_time > SYSDATE - INTERVAL '1 hour'
GROUP BY node_name
ORDER BY peak_rx_kbs DESC;

来源:NETWORK_USAGEVertica 监控最佳实践 §11.4

3. 已知的公共存储延迟故障模式

现象 原因 排查/修复
周期性性能下降(如每周六) 存储阵列定时整理任务 → IO 性能下降 错峰或关闭存储端定时任务
Depot fetch 频繁失败(is_successful='f' 公共存储连接异常 检查 HDFS/S3 连通性、Kerberos 票据刷新
查询 pending 阶段长 公共存储 NameNode 异常 检查 NN 状态、max open files 配置是否实际生效
节点恢复期间性能下降 恢复过程中 drop/remove subscription 产生 GCL-X 锁 避免在业务高峰期做节点替换操作
节点启动卡在 Check Storage 循环 Depot 存储路径 I/O 错误 检查 dmesg 中文件系统报错
Depot 抖动(同一对象反复 fetch → evict → fetch) Depot 远小于工作集 扩大 Depot 或调整查询模式减少数据访问范围

4. 前置预防:生产环境外验证

在低延迟应用上线前,使用 vnetperf 测量节点间和到公共存储的网络性能:

# 测试节点间 UDP/TCP 带宽
/opt/vertica/bin/vnetperf --hosts node1,node2,node3

# 到 HDFS NameNode 的延迟
ping <hdfs-namenode>

对于 RTT 延迟 >200μs 的节点对,低延迟查询性能可能不达标。

方案对比表

优化维度 Enterprise 原文方案 Eon 子集群隔离 Eon Depot 预热与固定 Eon 公共存储延迟管理
解决的问题 SQL 执行延迟 嘈杂邻居导致的延迟抖动 节点冷启动延迟 Depot 未命中时的公共存储读取延迟
隔离级别 资源池(内存+并发) 物理节点(CPU+内存+网络+IO+Depot) 缓存层(Depot LRU) 网络+存储层
额外成本 无(纯配置) 额外节点成本 无(Depot 已有)或扩大 Depot 的存储成本 带宽成本、更大 Depot
实施复杂度 低(SQL 配置) 中(子集群创建+路由+资源池覆盖) 低(SQL 配置) 低(监控+容量规划)
效果持续性 受同一节点其他负载影响 持续有效(节点物理隔离) 启动后即生效,正常运行中依赖 Depot 容量 持续有效(监控驱动)
适用规模 任意 租户数 <20,每个租户值得独立分配节点 所有 Eon 部署(建议默认启用) 所有 Eon 部署
版本要求 7.x+ 9.0+(子集群),12.x+(子集群资源池覆盖),23.3+(Workload Routing Rules) 24.x+(Depot 预热完整支持),11.0+(Pinning Policies) 9.0+

低延迟优化决策框架(更新版)

低延迟需求
├── 部署模式?
│   ├── Enterprise → 继续按原文五步方案(硬件+查询+应用+资源管理器调优)
│   └── Eon → 继续以下决策
├── 延迟抖动是否与特定时间窗口重叠(如 ETL 作业时段)?
│   ├── 是 → 实施「子集群隔离」:创建低延迟专属子集群
│   │   ├── 设置子集群资源池覆盖(PRIORITY 100, EXECUTIONPARALLELISM 低值)
│   │   ├── 配置 Routing Rule 将低延迟流量路由到该子集群
│   │   └── 监控:各子集群 max_queue_depth 对比
│   └── 否 → 继续
├── 节点重启或扩容后,低延迟查询性能是否明显下降?
│   ├── 是 → 实施「Depot 预热与固定」
│   │   ├── 启用 DepotWarming
│   │   ├── 对热表/热分区执行 SET_DEPOT_PIN_POLICY_*
│   │   ├── 节点启动后执行 FINISH_FETCHING_FILES()
│   │   └── 监控:depot_fetches 频率变化、depot_sizes.pct_used
│   └── 否 → 继续
├── Depot 命中率低,depot_fetches 频繁?
│   ├── pct_used > 90%? → Depot 太小 → 扩大 Depot 或增加节点
│   ├── 工作集 > Depot 总量? → 方案 A:扩大 Depot 让工作集完全驻留
│   │                          → 方案 B:使用 Depot pinning 固定热数据,冷数据接受公共存储延迟
│   └── 网络 rx_kbytes_per_sec 持续高? → 公共存储带宽瓶颈 → 升级网络或增加 Depot 容量
└── 综合实施:子集群隔离 + Depot 固定 + 公共存储延迟监控
    ├── 低延迟子集群:SSD Depot、Depot 容量覆盖工作集、Pinning Policy 固定热数据
    ├── ETL 子集群:按工作集规划 Depot 容量(成本敏感可用 HDD)、Pinning Policy 固定维表/元数据
    └── 持续监控:depot_fetches、network_usage、subcluster resource queues

扩展阅读

Enterprise 优化相关:

Eon 模式优化相关: