Vertica 集群 Rebalance 完全指南¶
综合翻译整理自 Vertica Knowledge Base 三篇文章:
Best Practices for Preparing Your Cluster for Rebalance(Rakesh Bankula & Soniya Shah 合著)
Understanding Rebalancing, Part 1: What Happens During Rebalancing
Understanding Rebalancing, Part 2: Optimizing for Rebalancing
前言¶
在 Vertica 集群中增删节点后,必须执行 rebalance 操作来重新分布数据。Rebalance 是一个 CPU、磁盘和网络密集型的复杂过程,涉及大量数据迁移,可能耗时数小时到数十小时。
本文整合了 Vertica 官方三篇关于 rebalance 的核心文档,涵盖:内部原理 → 准备工作 → 执行监控 → 事后验证 → 耗时估算的完整闭环。无论你是第一次操作 rebalance,还是已有经验想做更精细的规划,都可以在本文中找到对应的指导和 SQL 脚本。
第一部分:Rebalance 内部原理¶
来源:Understanding Rebalancing, Part 1: What Happens During Rebalancing
在开始准备之前,先理解 rebalance 过程中到底发生了什么,这有助于你理解每项准备工作的意义。
1.1 何时需要 Rebalance¶
| 场景 | 说明 |
|---|---|
| 数据量增长 | 磁盘接近写满,需要增加节点扩容 |
| 分析负载增加 | 查询并发量或复杂度上升,现有节点 CPU/内存不足 |
| 提高 K-safety | 增加节点以提升高可用性(更多 buddy projection 副本) |
| 节点下线 | 缩容、硬件维护、升级替换(swap 不需要 rebalance) |
重要:Vertica 不允许在违反 K-safety 的前提下移除节点。例如 K-safety=1 时,如果移除某节点会导致部分数据只剩 0 个副本,操作将被拒绝。
1.2 数据如何移动¶
Rebalance 的核心目标:将数据从 N 个节点上各占 1/N 重新分布到 M 个节点上各占 1/M。Vertica 通过以下策略最小化数据移动量:
- 新节点插入位置经过优化:新节点不是简单追加到集群末尾,而是插入到能最小化数据迁移的位置
- 分段投影(segmented projection):原有节点上的 ROS container 被拆分(split),然后将相应的数据段转移到目标节点
- 非分段投影(unsegmented projection):直接从 buddy 节点完整复制到新节点,因为每个节点本身就存有全量副本
- rebalance 完成后:目标节点上的数据分段由 Tuple Mover 在下次 mergeout 时合并,这一步不属于 rebalance 本身
数据移动量取决于:
- 集群原有节点数和新增/移除节点数
- 分段投影 vs 非分段投影的数量比例
示例(基于 Part 1 原文的 3→4 节点场景):每个节点从持有 1/3 数据变为持有 1/4 数据。Vertica 将新节点插入到数据迁移最少的位置,仅移动约 4/12(约 1/3)的总数据量——Node1 移出 1/12、Node2 移出 2/12、Node3 移出 1/12。对于 4→5 节点场景原理相同,移动比例类似。
磁盘空间不足时的级联 rebalance:如果现有节点剩余空间很少,Vertica 不得不分多阶段执行 rebalance:
- 第一阶段:将数据分布到新节点
- 第二阶段:数据从释放了空间的节点继续向其他节点迁移
- 后续阶段:重复上述过程直到平衡
每多一个阶段,总耗时大幅增长。这解释了为什么确保 40% 以上空闲空间至关重要。
1.3 REFRESH 资源池¶
Rebalance 始终使用内置的 REFRESH 资源池(不是 General pool,也不是用户自定义 pool)。
| 参数 | 说明 |
|---|---|
PLANNEDCONCURRENCY |
控制同时 rebalance 的 projection buddy group 数量。这是唯一有效的并发控制参数 |
MAXCONCURRENCY |
对 REFRESH 资源池无效(官方文档明确说明) |
建议:优先使用默认设置,不要随意调大
PLANNEDCONCURRENCY,过高的并发可能导致 I/O 争抢反而拖慢进度。
1.4 Rebalance 的四个阶段¶
阶段一:插入新节点¶
Vertica 将新节点插入到数据迁移最小的位置。对于大规模集群,插入位置对性能影响显著。
阶段二:数据重分段(Resegmenting)¶
这是 rebalance 最耗时的阶段,最多可占总耗时的 80%。
对非分段投影(unsegmented projection):
- 对每个 projection 获取 X 锁(排他锁)
- 在新节点上执行
CREATE PROJECTION ... UNSEGMENTED ALL NODES KSAFE - 从 buddy projection 刷新数据
对分段投影(segmented projection):
- 对表获取 S 锁(共享锁),对 projection 获取 X 锁(排他锁)
- 分离 primary、buddy、live aggregate projection 的数据段
- 刷新 projection
重分段过程需要临时存储空间作为分段数据的暂存区,因此 Vertica 每次只处理少量表和 projection,以高效利用临时空间。
阶段三:数据传输(Transferring)¶
Vertica 使用哈希函数决定数据在节点间的分布。
- 非分段投影传输:源节点读数据,目标节点写数据。多个源节点可以并行向多个目标节点传输,CPU 开销很小
- 分段投影传输:源节点需要完成读、拆分、写三个步骤,需要时间和临时磁盘空间。这一步最消耗资源
阶段四:数据合并(Merging)¶
这一步不属于 rebalance 过程本身。Rebalance 完成后,Tuple Mover 在下次 mergeout 时将目标节点上的数据片段合并。如果有 ephemeral 节点(缩容场景),Vertica 会在此阶段删除不再需要的非分段投影。
1.5 影响 Rebalance 耗时的因素¶
| 因素 | 影响 |
|---|---|
| Projection 数量 | 每个 projection 都要独立处理,数量越多越慢 |
| 每张表的分区数 | 分区越多,ROS container 越多 |
| 数据量和行数 | 直接影响 split 和 transfer 的数据量 |
| 目标节点上的 merge 时间 | 取决于 Tuple Mover 的后续 mergeout |
| 最繁忙节点的读写总量 | 决定了整体耗时下限 |
| 数据倾斜 | 倾斜越严重,某些节点需要移动的数据越多 |
| 网络吞吐 | 1Gbps vs 10Gbps,传输时间差一个数量级 |
| I/O 瓶颈 vs 网络瓶颈 | 取决于集群的硬件瓶颈在哪 |
| 集群上的其他负载 | ETL、用户查询抢占资源 |
关键认知:分段投影的 resegment 和 ROS container split 可占 总耗时的 80%。这就是为什么准备工作要围绕「减少 ROS 数量」和「加速 split」展开。
第二部分:准备工作¶
来源:Best Practices for Preparing Your Cluster for Rebalance + Understanding Rebalancing Part 1 & 2
分为「必须执行」和「强烈推荐」两类。
2.1 必须执行的操作¶
① 清理无用的数据库对象¶
Rebalance 耗时与数据库中的对象数量强相关。每个 projection、每个 ROS container 都需要参与 rebalance。
删除冗余 schema 和表:已废弃但未删除的表仍占用对象计数。
检查并删除冗余 projection:一张表上可能有多个 projection(不同排序键、分段键用于优化不同查询),但并非越多越好。每个 projection 都需要独立完成 ROS split 和 transfer。
-- 查看每张表的 projection 数量
SELECT projection_schema, anchor_table_name, count(distinct projection_name) proj_count
FROM projections
GROUP BY 1, 2
ORDER BY 3 DESC;
proj_count 特别高的表值得审视——super projection 是基础投影,其他多为 live aggregate projection 或 top-K projection。如果某些查询场景已不再使用,对应的 projection 可以删除。
清理历史分区:事实表通常按时间分区,过期分区如果不再需要查询,其中的 ROS container 仍在 storage_containers 中。
-- 查看分区数异常多的表
SELECT table_schema, projection_name, count(distinct partition_key) partition_count
FROM partitions
GROUP BY 1, 2
ORDER BY 3 DESC;
可用 DROP_PARTITION 或 MOVE_PARTITIONS_TO_TABLE 清理不再需要的分区。
② 推进 AHM 并清理删除记录¶
Vertica 使用 MVCC(多版本并发控制),DELETE 操作不物理删除数据,仅标记为删除。这些记录直到 AHM(Ancient History Mark)推进后、Tuple Mover mergeout 时才真正清除。
如果 AHM 滞后于 current_epoch 太多,rebalance 中 split ROS container 时将触发 replay delete(重放历史删除操作),对 CPU 和 I/O 造成沉重负担。
-- 第一步:推进 AHM 到最近的 epoch
SELECT make_ahm_now();
-- 第二步:验证 AHM 是否接近 current_epoch(相差 1 以内理想)
SELECT get_ahm_epoch(), get_last_good_epoch(), get_current_epoch();
确认 AHM 已推进后,对事实表(尤其是存在数百万条已删除记录的表)执行 PURGE:
⚠️
PURGE物理删除已标记删除的记录,一旦执行无法回滚。务必确认备份可用。
③ 关闭 Rebalance 期间的磁盘空间检查¶
Rebalance 过程中 Vertica 多次查询 storage_containers 来确定 projection 的 rebalance 顺序(避免中间状态写满磁盘)。对于拥有数十万 ROS container 的数据库,单次查询可能耗时数分钟,多次重复累计可超过数小时。
如果你的集群磁盘空间充足(远未达到容量上限),可以关闭此检查:
低于此版本建议先升级再执行 rebalance。
关于磁盘空间的定量建议:Part 1 文档建议至少保留数据库大小的 40% 作为空闲空间。如果低于此阈值,Vertica 会进入多阶段 rebalance,耗时显著增加。可以用以下方式确认:
-- 检查各节点磁盘使用情况
SELECT host_name, disk_space_used_mb, disk_space_total_mb
FROM host_resources;
-- 更细粒度的存储信息(也可查看 DISK_STORAGE / COLUMN_STORAGE 系统表)
SELECT node_name, projection_name, used_bytes
FROM projection_storage;
④ 调整资源池配置¶
-- 查看当前 REFRESH 资源池配置
SELECT name, is_internal, plannedconcurrency, maxmemorysize
FROM resource_pools
WHERE name = 'REFRESH';
建议将 PLANNEDCONCURRENCY 设为与单节点 CPU 核数相同,以便 rebalance 的 ROS split 操作能充分利用 CPU 并行度。
如果在维护窗口执行 rebalance,临时释放用户自定义资源池占用的内存:
rebalance 完成后恢复原值。
⑤ 新增节点硬件和系统验证¶
如果是扩容场景,新节点配置必须不低于现有节点:
| 检查项 | 工具 | 说明 |
|---|---|---|
| 磁盘 I/O | vioperf |
直接决定 ROS split 和 transfer 的 IO 吞吐 |
| 网络吞吐 | vnetperf |
决定 ROS transfer 阶段的传输速度 |
| CPU | vcuperf |
决定 ROS split 时的并行计算能力 |
| OS 参数 | 对比 sysctl、limits.conf 等 | 内存锁定、文件句柄、网络缓冲区必须一致 |
新节点性能低于现有节点 → rebalance 以最慢节点为瓶颈 → 日常查询性能也退化。
⑥ 禁用本地分段¶
在执行 rebalance 之前,必须禁用 local segmentation:
Local segmentation 默认是禁用的,但建议在操作前确认。
⑦ 验证 Rebalance 成功¶
成功时返回 节点数 + 1 行。例如 10 节点集群返回 11 行,每行包含 10 个 1 或 0。行数异常或数值异常说明 rebalance 未完全成功。
2.2 强烈推荐的操作¶
① 升级 Vertica 版本¶
使用 Vertica 8.0.1 以下版本建议先升级。新版本改进:
- ROS split 并行度提升(多线程处理不同尺寸范围的 ROS)
rebalance_table_status和rebalance_projection_status监控表效率优化- Vertica 8.0 新增
rebalance_operations系统表,可按操作步骤实时追踪进度
② 执行全量备份¶
增删节点和 rebalance 是对集群的重大变更。尽管 rebalance 自身可失败回滚,但硬件故障、磁盘满、网络中断等极端情况仍可能导致数据丢失。
③ 在维护窗口中执行¶
理想情况下应完全停止:
- ETL / 数据加载(COPY 语句创建新 ROS,干扰 split 执行计划)
- UPDATE / DELETE(产生新 delete vector)
- 所有用户查询(抢占 CPU、内存、磁盘 I/O)
如果无法独占窗口,至少做到最小化 DML 操作,只保留必要的 SELECT 查询。
④ 重启数据库¶
长时间运行的数据库 catalog 持续膨胀,拖慢 catalog 更新操作。重启后 catalog 完全加载到内存并重新组织,读写效率显著提升。
第三部分:执行与监控¶
来源:Understanding Rebalancing, Part 2: Optimizing for Rebalancing
3.1 启动 Rebalance¶
有三种方式:
| 方式 | 说明 |
|---|---|
| admintools UI | 图形界面操作 |
| Management Console (MC) | Web 管理控制台 |
| SQL 函数 | SELECT REBALANCE_CLUSTER();(最灵活) |
SQL 方式适合脚本化和自动化场景。注意:全局只能有一个 rebalance 操作在运行。
3.2 监控查询大全¶
以下查询可在 rebalance 执行期间随时运行,帮助判断进度和发现问题。
当前正在 rebalance 的表¶
如果 DML/DDL 操作干扰了 rebalance,会看到:
当前活跃的 rebalance 操作¶
SELECT node_name, session_id, session_start_timestamp, description
FROM system_sessions
WHERE session_type = 'REBALANCE_CLUSTER'
AND is_active;
通过 session_start_timestamp 可以了解 rebalance 已运行了多久。
整体进度概览¶
SELECT rebalance_method AS Rebalance_method,
Status,
COUNT(*) AS Count
FROM (
SELECT rebalance_method,
CASE
WHEN (separated_percent = 100 AND transferred_percent = 100)
THEN 'Completed'
WHEN (separated_percent <> 0 AND separated_percent <> 100)
OR (transferred_percent <> 0 AND transferred_percent <> 100)
THEN 'In Progress'
ELSE 'Queued'
END AS Status
FROM rebalance_projection_status
WHERE is_latest
) AS tab
GROUP BY 1, 2
ORDER BY 1, 2;
结果示例:
| Rebalance_method | Status | Count |
|---|---|---|
| ELASTIC_CLUSTER | Completed | 8 |
| ELASTIC_CLUSTER | In Progress | 2 |
| ELASTIC_CLUSTER | Queued | 2 |
| REPLICATE | Completed | 50 |
ELASTIC_CLUSTER= 分段投影的 rebalanceREPLICATE= 非分段投影的复制REFRESH= 投影刷新
非分段投影的刷新进度¶
SELECT session_id, projection_name, refresh_status, refresh_method, refresh_phase
FROM projection_refreshes
WHERE refresh_method = 'rebalance'
AND is_executing;
refresh_phase 可能值:
current:正在刷新当前数据historical:正在刷新历史数据
分段投影的分离和传输进度¶
SELECT projection_name, rebalance_method, separated_percent, transferred_percent
FROM rebalance_projection_status
WHERE rebalance_method = 'ELASTIC_CLUSTER'
AND ((separated_percent <> 0 AND separated_percent <> 100)
OR (transferred_percent <> 0 AND transferred_percent <> 100))
AND is_latest;
separated_percent:ROS container 已分离的百分比
transferred_percent:已传输到目标节点的百分比
Tuple Mover 正在执行分离操作¶
SELECT TM.projection_name, TM.node_name, TM.operation_start_timestamp
FROM tuple_mover_operations TM
JOIN system_sessions USING (session_id)
WHERE system_sessions.is_active
AND session_type = 'REBALANCE_CLUSTER'
AND operation_status = 'Running';
ROS Container 创建/删除统计¶
SELECT CASE
WHEN is_destroyed THEN 'deleted'
ELSE 'created'
END AS container,
projection_name,
SUM(row_count) AS rows_processed,
COUNT(*) n_containers
FROM vs_rebalance_separated_storage_containers
GROUP BY 1, 2
ORDER BY 1, 2;
数据传输详情¶
SELECT projection_name,
from_node_name,
to_node_name,
SUM(row_count) AS rows_transferred,
SUM(size_in_bytes) AS bytes_transferred
FROM vs_rebalance_transferred_storage_containers
GROUP BY 1, 2, 3
ORDER BY 1, 2, 3;
每个 Projection 的 Rebalance 耗时¶
SELECT node_name, projection_schema, projection_name,
start_time,
time - start_time AS duration
FROM dc_rebalanced_projections
ORDER BY 5 DESC;
可以帮助你识别哪些 projection 是耗时大户。
3.3 锁竞争处理¶
如果在 ETL 作业运行期间执行 rebalance,可能出现锁竞争,导致 ETL 作业或 rebalance 操作失败。
哪些操作会与 rebalance 竞争锁:
DELETEUPDATEDROP_PARTITIONSWAP_PARTITION_BETWEEN_TABLESMOVE_PARTITION_TO_TABLE
三种应对策略:
策略一:调整 LockTimeout¶
LockTimeout 参数决定 ETL 作业等待锁释放的超时时间,默认 300 秒(5 分钟)。如果 ETL 作业超时则报错退出。
先查看哪些事务曾经持锁超过 5 分钟:
SELECT DATE_TRUNC('hour', grant_time), node_name,
COUNT(*) number_of_tx,
MAX(time - grant_time) max_time_lock_held
FROM dc_lock_releases
WHERE time - grant_time > '5 min'
AND mode IN ('X', 'S', 'O')
AND object_name NOT LIKE 'ElasticCluster'
GROUP BY 1, 2
ORDER BY 4 DESC;
精确定位具体锁竞争的事务和 SQL 请求:
\x
SELECT t2.time, t2.node_name, t2.grant_time, t2.mode,
t2.object_name, t2."time" - t2.grant_time AS lockheld,
(t2."time" - t2.grant_time) * 1000 AS millisecond,
t3.request
FROM dc_lock_releases t2
JOIN query_requests t3 ON t2.transaction_id = t3.transaction_id
AND t2.statement_id = t3.statement_id
WHERE t2."time" - t2.grant_time > '5 min'
AND t2.mode IN ('X', 'S', 'O')
AND t2.object_name NOT LIKE 'ElasticCluster'
ORDER BY millisecond DESC;
\x
加大 LockTimeout:
-- 查看当前值
SELECT GET_CONFIG_PARAMETER('LockTimeout');
-- 默认 300 秒
-- 调大到 600 秒
SELECT SET_CONFIG_PARAMETER('LockTimeout', 600);
rebalance 完成后记得恢复原值!
策略二:优先保障 Rebalance(设置 DMLCancelTM)¶
默认情况下,如果 DML 作业试图访问被 rebalance 锁定的表,DML 作业会抢占锁并取消 rebalance,5 分钟后 rebalance 重新尝试。
如果希望 rebalance 不受干扰完成,设置:
-- 禁止 DML 抢占 rebalance 的锁
SELECT SET_CONFIG_PARAMETER('DMLCancelTM', false);
-- 执行 rebalance
SELECT REBALANCE_CLUSTER();
-- 完成后恢复
SELECT SET_CONFIG_PARAMETER('DMLCancelTM', true);
⚠️ 如果 DML 作业是关键业务(如实时数据加载),不要改
DMLCancelTM,而应该把 rebalance 安排在没有 DML 作业的时间窗口。
策略三:手动分批 Rebalance 大表¶
如果集群表非常多,一个维护窗口无法完成,可以每个窗口手动 rebalance 固定数量的表:
-- 单表 rebalance
SELECT REBALANCE_TABLE('schema.table_name');
-- 查看哪些表已完成/进行中/未开始
SELECT table_name,
CASE
WHEN separated_percent + transferred_percent = 200 THEN 'REBALANCED'
WHEN (separated_percent + transferred_percent) < 200
AND (separated_percent + transferred_percent) > 0 THEN 'REBALANCING'
ELSE 'NOT REBALANCED YET'
END AS status
FROM rebalance_table_status
WHERE is_latest;
手动 rebalance 时确保没有 ETL 作业在运行。
3.4 常见竞争错误¶
| 错误 | 原因 | 处理 |
|---|---|---|
ERROR 3007: DDL statement interfered with this statement |
其他作业对 rebalance 锁定的表执行了 DDL | 等待 DDL 完成或错开时间 |
ERROR 5157: Unavailable: lock table for query - Locking failure: Timed out |
获取锁超时 | 增大 LockTimeout 或错开负载 |
ERROR 7121: Staging table and target table do not match |
在两个 rebalance 状态不一致的表之间 SWAP PARTITION | 只允许两张都已 rebalance 或两张都未 rebalance 的表之间交换分区 |
Rebalance 失败后的重启机制:
如果 rebalance 因错误失败或被 DML 取消,Vertica 会在 300 秒(5 分钟)后自动尝试重新运行。
重要:一旦故障原因解决,rebalance 将从失败点继续执行,而不是从头开始。这避免了对已完成工作的重复浪费。
查询失败原因:
SELECT time, session_id, error_level, node_name, log_message
FROM dc_errors
WHERE session_id IN (
SELECT DISTINCT session_id
FROM dc_session_starts
WHERE session_type = 'REBALANCE_CLUSTER'
)
ORDER BY time DESC;
第四部分:完成后验证¶
来源:Understanding Rebalancing, Part 2: Optimizing for Rebalancing
4.1 确认成功¶
返回行数 = 节点数 + 1 即成功。
4.2 检查 K-safety¶
确认 K-safety 与预期一致(通常为 1 或 2)。
4.3 清理过期的 Projection¶
如果 rebalance 失败后重试,可能留下过期的 projection,需手动清理:
SELECT projection_name, anchor_table_name, is_prejoin, is_up_to_date
FROM projections
WHERE is_up_to_date = FALSE;
对 is_up_to_date = FALSE 的 projection 执行 DROP PROJECTION。
4.4 建立新基线¶
Rebalance 完成后,在空闲时段运行 vioperf 和 vnetperf 建立新集群的性能基线,便于日后对比。
⚠️ 这些工具对系统性能影响显著,不要在 rebalance 期间运行。
第五部分:Rebalance 耗时估算¶
来源:Best Practices for Preparing Your Cluster for Rebalance
完整的 rebalance 生命周期包含四个阶段:
5.1 ROS Split 耗时估算¶
Split ROS container 的耗时等于同尺寸 ROS 的 mergeout 耗时(操作逻辑对称)。
公式:
计算示例(24 核,105,901 个 <1GB ROS + 94 个 1-2GB ROS):
关键洞察:小 ROS 数量决定了 split 耗时的主体部分。每个 ROS 的 split 操作有固定的启动开销(打开文件、解析元数据、初始化排序上下文),ROS 再多再小也得逐个处理。这也是为什么「清理无用对象」是准备工作中的第一优先级。
5.2 ROS Transfer 耗时估算¶
取决于网络带宽和每节点数据量。
示例(10Gbps,每节点 3TB,扩容 1 倍):
多线程并行、带宽共享、TCP 拥塞控制等因素使实际耗时落在 1-1.5 小时。如果是 1Gbps 网络,传输时间增长约 10 倍,成为瓶颈。
5.3 系统表查询¶
对于 50 万 ROS container 的数据库,单次 storage_containers 查询可能耗时 3-5 分钟。rebalance 过程中 10-20 次查询累计可达 1-2 小时。
优化:磁盘使用率低于 50-60% 时,设置 RebalanceQueryStorageContainers = 0 可安全跳过。
5.4 杂项操作¶
包括 catalog 更新、node dependencies 计算、projection 统计刷新、事务提交等。
根据对 250+ 客户 scrutinize 的分析,每个 projection 平均耗时约 250ms,单线程串行处理(catalog 更新必须独立以避免锁冲突)。
示例(30,000 个 projection):
这个阶段的耗时主要取决于 projection 总数,与硬件配置关系不大。
5.5 客户案例验证¶
某客户(v7.1.2-6,HP Gen8 24 核 256GB,10Gbps,每节点 2.1TB,36,000 个 projection)从 16 节点缩容至 11 节点(移除 5 个):
| 阶段 | 估算 | 实际 |
|---|---|---|
| ROS Split | ~8-9 小时 | — |
| ROS Transfer | ~1-1.5 小时 | — |
| 系统表查询 | ~1-2 小时 | — |
| 杂项操作 | ~2.5 小时 | — |
| 合计 | ~12.5-15 小时 | 13 小时 |
高度吻合。客户在无 ETL/用户查询的独占维护窗口中执行。
第六部分:附录¶
A. 各尺寸 ROS 平均 Mergeout / Split 耗时¶
基于 250+ 客户 scrutinize 统计(未采集本库数据时可作参考):
| 尺寸范围 | 代码 | 平均耗时 (秒) |
|---|---|---|
| < 100MB | A_Less_than_100MB |
0.844 |
| 100MB - 200MB | B_Between_100MB_to_200MB |
2.000 |
| 200MB - 400MB | C_Between_200MB_to_400MB |
6.833 |
| 400MB - 600MB | D_Between_400MB_to_600MB |
11.095 |
| 600MB - 800MB | E_Between_600MB_to_800MB |
13.000 |
| 800MB - 1GB | F_Between_800MB_to_1GB |
23.000 |
| 1GB - 2GB | G_Between_1GB_to_2GB |
35.000 |
| 2GB - 4GB | H_Between_2GB_to_4GB |
68.000 |
| 4GB - 8GB | I_Between_4GB_to_8GB |
137.846 |
| 8GB - 16GB | J_Between_8GB_to_16GB |
320.444 |
| 16GB - 32GB | K_Between_16GB_to_32GB |
617.650 |
| > 32GB | L_Greater_than_32GB |
2528.500 |
注意:
ROS 大小与 split 耗时非线性。
一个 32GB+ ROS 平均耗时 42 分钟,远超 32 个 1GB ROS 的总耗时(32 × 35 = 1120 秒 ≈ 19 分钟)。
这说明过大的 ROS 对 rebalance 更加不利——Tuple Mover 的后台 mergeout 将小 ROS 合并的原因之一正是在寻找这个平衡点。
B. 精确估算脚本(可选)¶
如果需要从本库统计实际 mergeout 耗时(比附录 A 经验值更准确)。
B1. 创建 merge_time 表¶
填充数据(从 dc_tuple_mover_events 提取历史 mergeout 耗时):
INSERT INTO merge_time
SELECT ros_size, max(avg_duration) time_sec
FROM (
SELECT
s.node_name,
CASE
WHEN s.total_size_in_bytes < 100000000 THEN 'A_Less_than_100MB'
WHEN (s.total_size_in_bytes > 100000000
AND s.total_size_in_bytes < 200000000) THEN 'B_Between_100MB_to_200MB'
WHEN (s.total_size_in_bytes > 200000000
AND s.total_size_in_bytes < 400000000) THEN 'C_Between_200MB_to_400MB'
WHEN (s.total_size_in_bytes > 400000000
AND s.total_size_in_bytes < 600000000) THEN 'D_Between_400MB_to_600MB'
WHEN (s.total_size_in_bytes > 600000000
AND s.total_size_in_bytes < 800000000) THEN 'E_Between_600MB_to_800MB'
WHEN (s.total_size_in_bytes > 800000000
AND s.total_size_in_bytes < 1000000000) THEN 'F_Between_800MB_to_1GB'
WHEN (s.total_size_in_bytes > 1000000000
AND s.total_size_in_bytes < 2000000000) THEN 'G_Between_1GB_to_2GB'
WHEN (s.total_size_in_bytes > 2000000000
AND s.total_size_in_bytes < 4000000000) THEN 'H_Between_2GB_to_4GB'
WHEN (s.total_size_in_bytes > 4000000000
AND s.total_size_in_bytes < 8000000000) THEN 'I_Between_4GB_to_8GB'
WHEN (s.total_size_in_bytes > 8000000000
AND s.total_size_in_bytes < 16000000000) THEN 'J_Between_8GB_to_16GB'
WHEN (s.total_size_in_bytes > 16000000000
AND s.total_size_in_bytes < 32000000000) THEN 'K_Between_16GB_to_32GB'
ELSE 'L_Greater_than_32GB'
END AS ros_size,
avg(DATEDIFF(SECOND, s.time, c.time)) as avg_duration
FROM dc_tuple_mover_events s
JOIN dc_tuple_mover_events c
ON s.node_name = c.node_name
AND s.projection_oid = c.projection_oid
AND s.transaction_id = c.transaction_id
AND s.session_id = c.session_id
WHERE s.operation = 'Mergeout'
AND c.operation = 'Mergeout'
AND s.event = 'Start'
AND c.event = 'Complete'
AND s.container_count > 1
AND c.container_count > 1
AND s.transaction_id NOT IN (
SELECT DISTINCT transaction_id
FROM dc_tuple_mover_events
WHERE event ILIKE '%replay delete%'
)
GROUP BY 1, 2
) f
GROUP BY 1;
COMMIT;
关键过滤条件说明:
container_count > 1:只统计真正合并至少 2 个 ROS 的 mergeout,排除单 ROS resize/moveouttransaction_id NOT IN (... replay delete ...):排除涉及 replay delete 的 mergeout——这些操作的耗时包含了重放删除的开销,会高估纯 split 时间(前提是已按本文要求推进 AHM,split 阶段不会触发 replay delete)。此外该估算也不考虑与用户发起 purge 操作相关的 mergeout 操作- 如果
dc_tuple_mover_events历史数据不足(数据库刚启动),直接用附录 A 的经验值
B2. 创建 ros_count 表¶
CREATE TABLE public.ros_count (
ros_size varchar(25),
ros_count int
);
INSERT INTO ros_count
SELECT ros_size, max(ros_count) max_ros_cnt
FROM (
SELECT
node_name,
CASE
WHEN used_bytes < 100000000 THEN 'A_Less_than_100MB'
WHEN (used_bytes > 100000000
AND used_bytes < 200000000) THEN 'B_Between_100MB_to_200MB'
WHEN (used_bytes > 200000000
AND used_bytes < 400000000) THEN 'C_Between_200MB_to_400MB'
WHEN (used_bytes > 400000000
AND used_bytes < 600000000) THEN 'D_Between_400MB_to_600MB'
WHEN (used_bytes > 600000000
AND used_bytes < 800000000) THEN 'E_Between_600MB_to_800MB'
WHEN (used_bytes > 800000000
AND used_bytes < 1000000000) THEN 'F_Between_800MB_to_1GB'
WHEN (used_bytes > 1000000000
AND used_bytes < 2000000000) THEN 'G_Between_1GB_to_2GB'
WHEN (used_bytes > 2000000000
AND used_bytes < 4000000000) THEN 'H_Between_2GB_to_4GB'
WHEN (used_bytes > 4000000000
AND used_bytes < 8000000000) THEN 'I_Between_4GB_to_8GB'
WHEN (used_bytes > 8000000000
AND used_bytes < 16000000000) THEN 'J_Between_8GB_to_16GB'
WHEN (used_bytes > 16000000000
AND used_bytes < 32000000000) THEN 'K_Between_16GB_to_32GB'
ELSE 'L_Greater_than_32GB'
END AS ros_size,
COUNT(*) AS ros_count
FROM storage_containers
GROUP BY 1, 2
ORDER BY 1, 2
) f
GROUP BY 1;
COMMIT;
使用 max(ros_count) 取各节点中的最大值——基于最坏情况估算,因为 rebalance 期间所有节点同时进行 ROS split,耗时由 ROS 最多的节点决定。
B3. 计算最终预估¶
SELECT sum(duration_sec * ros_count) AS split_time_seconds
FROM merge_time m
JOIN ros_count r ON r.ros_size = m.ros_size;
结果单位秒,除以单节点 CPU 核数得到 ROS Split 阶段预估时间。加上 transfer、系统表查询、杂项操作三个阶段的估算即得总耗时。
总结¶
一个高效可控的 rebalance 操作,核心在于四点:
- 准备阶段做减法:清理无用对象、推进 AHM 清理删除记录、关闭不必要的系统表检查——目标是减少 rebalance 需要处理的对象数量
- 资源配置对齐:确保 40% 以上空闲磁盘空间(避免多阶段 rebalance)、REFRESH pool 并发数合理、释放用户池抢占的内存
- 监控驱动决策:利用本文第三部分的 SQL 查询实时追踪进度,遇到了锁竞争用 LockTimeout / DMLCancelTM / 手动分批三种策略应对
- 事后验证闭环:
get_node_dependencies()确认成功、清理过期 projection、运行 vioperf/vnetperf 建立新基线
参考¶
- Best Practices for Preparing Your Cluster for Rebalance
- Understanding Rebalancing, Part 1: What Happens During Rebalancing
- Understanding Rebalancing, Part 2: Optimizing for Rebalancing
扩展阅读¶
- Vertica 弹性伸缩功能介绍与配置 — Enterprise 与 Eon 模式弹性伸缩完整指南
- K-Safety 最佳实践 — K-safety 与节点依赖
- Vertica 监控最佳实践 — 监控重平衡进度
- Vertica 资源池配置的最佳实践 — REFRESH 资源池配置