跳转至

K-Safety 最佳实践

编译:JiangChong

原文:K-Safety Best Practices | 作者:Shrirang Kamat、Soniya Shah

📝 文章说明:本文基于 Vertica 官方 KB 原文翻译整理。原文仅讨论了 Enterprise 模式下的 K-safety 机制(buddy projection、节点依赖环),未涉及 Eon 模式。译者根据 Vertica 26.2.x 官方架构文档 和 vault 已有知识,补充了 Eon 模式分片订阅机制、Quorum + 分片覆盖双条件模型、Elastic K-safety 自动保护、双主子集群容错、Fault Group 实操配置(含自动/手动两种类型)、节点恢复流程、以及 Enterprise/Eon K-Safety 方案对比。新增内容位于「Eon 模式下的 K-Safety 与高可用」章节。

概述

本文档涵盖 K-safety、数据安全性及节点依赖关系的核心概念,是理解 Vertica 高可用与恢复机制的基础。原文仅覆盖 Enterprise 模式;本文补充了 Eon 模式(计算-存储分离)下的高可用机制,包括分片订阅(Shard Subscription)、双主子集群容错、以及两种模式的方案对比与选型决策框架。

K-Safety

K-safety 衡量数据库集群的容错能力。K 值表示数据库中数据副本的数量。要在 Vertica 中实现高可用,分段投影必须至少有 1 个 buddy projection非分段投影则必须在所有节点上复制。Vertica 通过 K-safety 来强制执行这些投影要求。

K=1 的约束

在 K-safety = 1 的数据库中,Vertica 自动创建的投影会带有 buddy projection。但如果手动创建投影时未指定 ksafe1 关键字,该投影就不会有 buddy projection,并将被标记为 unsafe(不安全),受到以下限制:

  • 不会更新(not up to date)
  • 无法刷新
  • 无法接收加载的数据
  • 不能用于查询

检查 K-Safety

SELECT GET_DESIGN_KSAFE();

监控系统级 K-safety 状态(来源:v_monitor.SYSTEM 表):

SELECT node_count, node_down_count, current_fault_tolerance
FROM v_monitor.system;
-- node_count: 集群总节点数
-- node_down_count: 当前 DOWN 的节点数
-- current_fault_tolerance: 当前 K-safety 级别

数据安全性(Data Safety)

非分段投影在集群每个节点上都有一份数据副本。对于 K=1 的数据库,每个分段投影都有一个包含数据副本的 buddy projection。

分段与 Buddy 节点

在分段投影中,数据根据投影设计中指定的分段表达式拆分为多个 segment。属于分段投影及其 buddy projection 的数据 segment 在节点上偏移分布

拥有某个数据 segment 及其副本的两个节点称为 buddy 节点。它们之间共享依赖关系

下图展示了节点依赖关系。节点 1 和节点 2 是 buddy 节点,共享数据 segment S1 的依赖;节点 2 和节点 3 共享 segment S2 的依赖,以此类推:

KSafetyBP NodeDependencies

查询节点依赖

方法 1 — buddy pair 列表:

SELECT dependency_id, min(node_name) AS node_x, max(node_name) AS node_y
FROM vs_node_dependencies JOIN nodes ON node_oid = node_id
GROUP BY 1 HAVING count(*) = 2 ORDER BY 1;

输出示例:

dependency_id |        node_x        |        node_y
--------------+----------------------+----------------------
0             |        node1         |        node3
1             |        node2         |        node4
2             |        node3         |        node4
3             |        node2         |        node5
4             |        node1         |        node5
(5 rows)

方法 2 — 位图方式:

SELECT GET_NODE_DEPENDENCIES();

输出示例:

get_node_dependencies
-----------------------------------------------------------------------------
Deps:
00110 - cnt: 2
01001 - cnt: 2
01100 - cnt: 2
10001 - cnt: 2
10010 - cnt: 2
11111 - cnt: 9
00001  name: Node 2
00010  name: Node 1
00100  name: Node 3
01000  name: Node 4
10000  name: Node 5
(1 row)

方法 3(8.0.1+)— 带节点名称的详细输出:

SELECT get_node_dependencies_verbose();

位图解读

8.0.1 之前的版本中,get_node_dependencies 不提供位到节点的映射。最右 bit 代表 node_id 最小的节点,最左 bit 代表 node_id 最大的节点。

查看节点按 node_id 升序排列的名称:

SELECT node_name FROM nodes ORDER BY node_id;
  • bit 值 1 = 该节点与另一个同样 bit=1 的节点互为 buddy
  • 例如位图 00110:node_id 第二小的节点和 node_id 第三小的节点是 buddy
  • cnt = 该依赖关系对应的 projection buddy pair 数量
  • 全 1 的位图(如 11111 = 非分段投影,cnt 表示数据库中非分段投影的数量

依赖环

如果将节点视为顶点、节点间的依赖关系视为边画成图,K=1 的数据库会形成一个,每个顶点有 2 条边:

KSafetyBP NodeDependenciesRing

  • 如果环中所有节点都有 3 条边 → K=2
  • 如果仅部分节点有多于 2 条边 → rebalance 未完成

重新计算节点依赖

SELECT RECOMPUTE_NODE_DEPENDENCIES();

高可用与数据安全性

K=1 的 Vertica 数据库在满足以下条件时保持 UP 且完全可用:

  1. 数据库中超过半数节点处于 UP 状态
  2. 依赖环中没有相邻的两个节点同时 DOWN

这个特性称为 data safety

举例

  • 节点 1 和节点 4 同时宕机 → ✅ 数据库仍 UP(不相邻)
  • 节点 1 和节点 5 同时宕机 → ❌ unsafe SHUTDOWN(相邻,数据 segment 不可访问)

查询关键节点

当有节点 DOWN 时,可查询关键节点列表。当数据库管理员计划对多个节点同时进行维护时,该结果表尤其有用:

SELECT * FROM critical_nodes;

最佳实践建议

1. 只用 K=1,不推荐 K=2

K=1 K=2
资源消耗基准 多消耗约 50% 存储空间
不容忍相邻节点同时 DOWN 可容忍相邻两节点同时 DOWN
推荐 不推荐(相邻双节点同时宕机概率极低,得不偿失)

2. 大集群配置 Fault Groups(故障组)

对于跨越两个以上机架的集群,通过定义 fault group 实现机架感知,确保 buddy segment 分布在不同故障域,避免单机架故障导致相邻节点同时 DOWN。

Fault Group 类型(来源:26.2.x 官方文档):

类型 触发条件 说明
自动 集群 ≥120 节点 Vertica 自动围绕控制节点(control nodes)创建 fault group
手动 有相关故障风险 / 需影响控制消息路由 梳理物理拓扑 → 编写输入文件 → 运行 Vertica 脚本生成 SQL → 执行

⚠️ 限制:Fault Group 无法防范单点故障(如单台网络交换机故障导致全集群不可达)。

查看 Fault Group 配置(来源:FAULT_GROUPS):

SELECT * FROM fault_groups;
-- member_name: 节点名或子组名
-- member_type: 'node' 或 'faultgroup'
-- parent_name: 上级 group 名

重新计算节点依赖(配置 Fault Group 后):

SELECT RECOMPUTE_NODE_DEPENDENCIES();

注意:Fault Group 是 Enterprise 模式专属功能。Eon 模式下通过分片订阅的物理节点分布规划实现等效的故障域隔离(见「Eon 模式下的高可用配置」章节)。


数据库恢复与 Data Safety

启动 Vertica 时需要:

  • 超过半数节点形成 quorum(法定人数)
  • 依赖环中不能有相邻节点被排除在外

详见 Vertica 文档:K-Safety


Eon 模式下的 K-Safety 与高可用

以上内容基于 Enterprise 模式(数据存本地磁盘、通过 buddy projection 实现副本)。Vertica 自 9.x 引入 Eon 模式(计算-存储分离,数据存公共存储如 S3/HDFS/MinIO),其高可用机制与 Enterprise 模式有根本性差异。本节补充 Eon 模式下的 K-Safety 原理、故障场景与操作指南。

架构差异:Buddy Projection → Shard Subscription

Enterprise 模式下,每个分段投影有一个 buddy projection(物理副本),节点两两组成 buddy pair,K=1 保证任意两个相邻节点不同时宕机即可。

Eon 模式下,数据不在本地磁盘上——所有数据持久化在公共存储(communal storage),节点只持有本地缓存(Depot)。副本机制通过 分片(Shard) 实现:

维度 Enterprise 模式 Eon 模式
数据位置 节点本地磁盘 公共存储(S3/HDFS/MinIO)
副本机制 Buddy Projection(物理副本) Shard Subscription(分片订阅)
容错单元 Buddy Pair(2 节点互为备份) Shard Replica(同一分片被多个节点订阅)
相邻节点同时宕机 数据库 unsafe shutdown 分片订阅丢失 → 集群进入 READONLY
节点恢复 恢复节点 + AHM 推进 revive_db 复活数据库 / 节点重新订阅分片
弹性伸缩 需要 rebalance(小时~天级) 无需 rebalance(分钟级,见 Vertica 弹性伸缩功能介绍与配置

Eon 模式的 Data Safety:分片订阅机制

Eon 数据库创建时,数据被哈希切分为多个 分片(Shard)。每个分片被 至少 2 个节点订阅(相当于 Enterprise 的 K=1)。节点宕机时的行为:

  • 单个节点宕机:该节点订阅的分片由其他订阅节点继续提供服务,集群正常运行
  • 同一分片的 2 个订阅节点同时宕机:分片数据无法访问 → 集群所有节点进入 READONLY 状态
  • 集群 READONLY 后:恢复宕机节点时,其余节点会自动重启以从 READONLY 切换回 READWRITE

查询分片订阅状态(来源:NODE_SUBSCRIPTIONS):

-- 查看每个节点订阅了哪些分片及其状态
SELECT node_name, shard_name, subscription_state,
       is_primary, is_participating_primary
FROM v_catalog.node_subscriptions
ORDER BY shard_name, node_name;

查询分片订阅的节点对数(判断风险):

-- 检查每个分片有几个订阅节点(少于 2 则为单点风险)
SELECT shard_name, count(*) AS subscriber_count
FROM v_catalog.node_subscriptions
WHERE subscription_state = 'ACTIVE'
GROUP BY 1
HAVING count(*) < 2;

来源:SHARDS 表列出所有分片及其哈希边界。

Eon K-safety:Quorum + 分片覆盖

Eon 模式数据库保持正常运行的两个条件(来源:26.2.x 官方文档):

  1. 维持 Quorum:超过半数(50%+1)的主子集群节点(primary nodes) 处于 UP 状态。例如 6 个 primary 节点,至少需要 4 个 UP。注意:Vertica 只统计 当前归属于数据库的 primary 节点——正常流程移除的节点不再计入 quorum 计算(注:文档未直接说明此行为,推断依据是 Vertica 的 K-safety 下限保护机制:移除前会检查是否低于当前 K-safety 要求的最小节点数)。
  2. 维持分片覆盖(Shard Coverage):每个分片至少有一个订阅它的 primary 节点,该节点负责为该分片执行 Tuple Mover 操作。如果任一 shard 失去所有 primary 订阅者,数据库进入 READONLY 模式。

K=1 下的分片订阅模型

  • 每个分片有 两个订阅者:一个 primary subscriber(负责 Tuple Mover)和一个 secondary subscriber(持有分片 catalog 元数据副本)
  • secondary subscriber 不维护独立的 depot 缓存——接管时直接从公共存储读取,性能会下降
  • 因此宕机后应尽快恢复或替换 primary 节点

Elastic K-safety(弹性 K-safety)

Eon 模式默认启用的自动保护机制:当分片的 primary 或 secondary 订阅者宕机时,Vertica 自动将另一个 primary 节点订阅到该分片。新节点需要获取分片元数据副本,完成后即可作为备份接管。

弹性 K-safety 的限制——以 10 个 primary 节点的 K=1 数据库为例:

UP ≥ 8  → 继续新增弹性订阅(离 quorum 丢失还有 3 个 buffer)
UP = 7  → 停止新增(再失去 1 个就只剩 6,离 quorum 丢失只差 1)
UP ≤ 5  → 丢失 quorum,集群 READONLY

通用公式:停止阈值为 N/2 + K + 1。当 UP 节点数低于等于该值时,新增订阅已无意义——再宕一个 primary 就逼近 quorum 红线(> N/2),多一个备份也救不了。

一旦宕机节点恢复并重新加入集群,Vertica 自动移除弹性 K-safety 期间添加的额外订阅,分片订阅关系恢复原状。

Eon K-safety 级别与最小节点要求

Eon 模式与 Enterprise 模式在 K-safety 设置上的关键区别:Eon 模式下,只要有 3 个或以上 primary 节点,Vertica 自动将 K-safety 设为 1(K=1)——不需要像 Enterprise 那样手动设计物理 schema 并调用 MARK_DESIGN_KSAFE

K-safety 最小 primary 节点数 说明
K=0 1 单节点 Eon,仅推荐用于测试。失去 primary 节点立即 READONLY
K=1(推荐) 3 每个 shard 有 2 个订阅者,容忍 1 个 primary 节点宕机
K=2 5 每个 shard 有 3 个订阅者,容忍 2 个 primary 节点宕机。云环境通常不需要

如需手动调整 K-safety 级别:SELECT MARK_DESIGN_KSAFE(N)SELECT REBALANCE_SHARDS()

查询关键节点与关键子集群

当有 primary 节点宕机时,持有其分片 secondary 订阅的节点变为关键节点(失去它会导致分片覆盖丢失)。Eon 模式还提供了关键子集群的概念:

-- 查关键节点(Enterprise / Eon 通用)
SELECT * FROM critical_nodes;

-- 查关键子集群(Eon 专属,26.2.x 文档)
SELECT * FROM critical_subclusters;

维护前务必检查这两个表,确认计划停止的节点/子集群不在其中。

真实案例:Eon 相邻节点宕机 → 集群 READONLY

以下案例来自某 Eon 集群故障报告,展示了 Eon 模式下「逻辑相邻节点」同时宕机的典型故障链:

  1. 触发:某 SQL 触发产品 Bug,导致 v_db_node0001v_db_node0002 同时 PANIC
  2. 影响:这两个节点恰好订阅了同一个分片,同时宕机后分片订阅丢失
  3. 结果:集群剩余节点全部进入 READONLY 状态
  4. 恢复:启动宕机节点后,READONLY 节点自动重启恢复为 READWRITE

关键启示:Eon 模式下,不仅要关注物理机架分布,更要关注分片订阅的节点分布——两个订阅同一分片的节点如果落在同一机架/同一虚拟机宿主上,存在单点风险。

Eon 模式下的高可用配置

1. 子集群(Subcluster)级别的容错

Eon 模式支持双主子集群(Dual Primary Subcluster) 部署,两个主子集群各自订阅完整的分片集。注意:双主子集群的作用是计划内维护(先降级再关,另一个继续服务),而非自动容错——直接关闭任意一个主子集群会导致集群 READONLY(见下方操作流程)。

⚠️ 来自 Eon双主子集群的注意事项:关闭主子集群前必须先执行 DEMOTE_SUBCLUSTER_TO_SECONDARY(),否则集群立即 READONLY。

-- 关闭主子集群的正确流程
SELECT DEMOTE_SUBCLUSTER_TO_SECONDARY('subcluster2');     -- 先降级
-- 再通过 admintools 停止子集群
-- admintools -t stop_subcluster -c subcluster2 -d <db> -Fi

-- 重启后恢复
-- admintools -t restart_subcluster -c subcluster2 -d <db> -Fi
SELECT PROMOTE_SUBCLUSTER_TO_PRIMARY('subcluster2');      -- 再升回

2. 分片订阅的物理分布(Eon 的 "Fault Domain")

Eon 模式没有 Fault Group 机制(Fault Group 是 Enterprise 专属概念,见 FAULT_GROUPS)。Eon 通过以下方式实现跨故障域的冗余:

a) Vertica 自动分布:创建数据库时,Vertica 自动将同一分片的 primary 和 secondary 订阅分配到不同节点。在规划节点的物理位置时,确保同一分片的订阅节点落在不同机架/交换机下即可。

b) 分片数量规划(来源:26.2.x 官方文档):Vertica 推荐分片数为 12 的倍数,且最好是子集群节点数的倍数。分片数过少会导致节点负载不均,过多则增加元数据开销。

-- 查看当前分片分布
SELECT shard_name, shard_type, is_replicated,
       lower_hash_bound, upper_hash_bound
FROM v_catalog.shards
ORDER BY shard_name;

c) 节点订阅分布检查:确认同一分片的订阅节点未集中在同一物理位置:

-- 列出每个分片的所有订阅节点
SELECT shard_name, node_name, subscription_state, is_primary
FROM v_catalog.node_subscriptions
ORDER BY shard_name, is_primary DESC;

如需调整分片订阅分布,使用 SELECT REBALANCE_SHARDS();

3. Eon 节点替换 vs. 恢复

Eon 模式下节点替换与 Enterprise 模式的关键区别:

场景 Enterprise 模式 Eon 模式
单节点故障 恢复节点,AHM 推进 新节点重新订阅分片,从公共存储拉数据
全部节点故障 需从备份恢复 revive_db 从公共存储复活数据库
替换节点后启动 通常正常 可能卡在 Waiting for Cluster Invite(Catalog >20GB 时需设 TSCatalogInvite=0

revive_db 复活数据库(来源:Eon 数据库替换节点过后节点启动卡在等待邀请步骤且重启数据库失败):

# 先做 dry-run 检查
admintools -t revive_db --display-only \
  --communal-storage-location=webhdfs://hacluster/verticaeon/<dbname> \
  -d <dbname>

# 正式复活(需指定所有节点)
admintools -t revive_db \
  --communal-storage-location=webhdfs://hacluster/verticaeon/<dbname> \
  -s 'v001,v002,...' --force \
  -d <dbname>

# 启动
admintools -t start_db -d <dbname> -F

常见坑(来源:Eon数据库性能问题原因):

  • 节点替换/恢复时会触发 drop/remove subscription 操作,产生 GCL-X 锁,可能导致短期性能下降
  • 若 GCL-X 锁 30 分钟内无法获取(公共存储 NN 异常),可能导致集群宕机
  • Catalog >20GB 时需设置 TSCatalogInvite=0 避免启动超时

Enterprise vs Eon:K-Safety 方案对比

维度 Enterprise K=1 Eon 单主子集群 Eon 双主子集群
容错能力 容忍非相邻节点宕机 容忍非同一 shard 节点宕机 同单主子集群;额外支持计划内维护不停服
相邻节点全宕 Unsafe SHUTDOWN 集群 READONLY 同上;但可通过降级→关闭→升级实现零停机维护
恢复方式 恢复节点 + AHM 恢复节点 / revive_db 恢复节点 / 切换主子集群
额外资源 基准 公共存储成本 公共存储 + 双倍计算资源
弹性伸缩 需 rebalance(小时~天) 分钟级,无需 rebalance 分钟级,无需 rebalance
适用场景 传统硬件部署、固定规模 云部署、弹性规模 高 SLA 要求、零停机维护

决策框架:选 Eon 还是 Enterprise?

需要弹性伸缩(分钟级加减节点)?
├── 是 → Eon 模式
│   ├── SLA 要求 >99.9%?→ 双主子集群
│   └── SLA 要求 ≤99.9%? → 单主子集群 + 跨故障域分布分片订阅
└── 否 → Enterprise 模式
    ├── 多机架?→ 配置 Fault Group
    └── 单机架?→ K=1 即可,不推荐 K=2

更多 Eon 模式与 Enterprise 模式的对比详见 Vertica 弹性伸缩功能介绍与配置,Eon 模式分片规划详见 Vertica Eon 模式中分片、节点和 Depot 选择的最佳实践


扩展阅读


关键 SQL 速查

用途 SQL 适用模式
查 K-safety SELECT GET_DESIGN_KSAFE(); Enterprise / Eon
查系统级 K-safety 状态 SELECT node_count, node_down_count, current_fault_tolerance FROM v_monitor.system; Enterprise / Eon
查 buddy pair SELECT ... FROM vs_node_dependencies JOIN nodes ... Enterprise
查依赖位图 SELECT GET_NODE_DEPENDENCIES(); Enterprise
查依赖位图+名称(8.0.1+) SELECT get_node_dependencies_verbose(); Enterprise
重算节点依赖 SELECT RECOMPUTE_NODE_DEPENDENCIES(); Enterprise / Eon
查关键节点 SELECT * FROM critical_nodes; Enterprise / Eon
查关键子集群 SELECT * FROM critical_subclusters; Eon
查分片订阅状态 SELECT * FROM v_catalog.node_subscriptions; Eon
查分片信息 SELECT * FROM v_catalog.shards; Eon
查 Fault Group SELECT * FROM fault_groups; Enterprise
查 READONLY 事件 SELECT * FROM active_events WHERE event_code = 20; Eon
设置 Eon K-safety 级别 SELECT MARK_DESIGN_KSAFE(N);SELECT REBALANCE_SHARDS(); Eon
复活 Eon 数据库 admintools -t revive_db ... Eon