Vertica 客户端连接负载均衡配置¶
作者:JiangChong | 发布时间:2026-05-05
适用场景: 当集群中部分节点 CPU 持续偏高、SQL 准备阶段耗时异常、或发现所有客户端连接集中在少数甚至单个节点时,说明连接未做负载均衡,本文提供从检测到修复的完整方案。
关联文章¶
- Vertica CPU 持续高负载诊断与优化 — 连接倾斜是 CPU 高负载的常见根因
- Vertica JDBC Routable Query API 最佳实践 — JDBC 可路由查询的高级用法
- Vertica 低延迟优化最佳实践 — 低延迟场景中的负载均衡建议
- Vertica 资源拒绝排查与资源池调优 — 连接集中导致的资源拒绝
- Vertica 集成 DBeaver — DBeaver 中的负载均衡配置
- Vertica 集成 Tableau 完整指南 — Tableau TDC 中的负载均衡配置
理解全文脉络¶
本文从原理到实战共 8 节,按三层递进组织:
- 不管有没有问题,先读第 1 节:理解 Vertica 原生负载均衡的底层机制,为什么「连接集中」是性能杀手。
- 怀疑有连接倾斜时,从第 2-3 节入手:用系统表快速诊断连接分布,定位倾斜来源。
- 需要修复时,跳到第 4 节:JDBC/ODBC 参数配置 + 服务端路由规则,覆盖原生和外部的完整方案。
- 想学习典型案例时,看第 5-6 节:4 个案例(2 真实 + 2 虚构)+ 完整演练。
1. 原理理解¶
1.1 什么是连接负载均衡¶
Vertica 是一个无共享架构(shared-nothing)的 MPP 数据库,集群中每个节点都存储数据的一部分,也都能独立接收客户端连接。当客户端发起连接时,它连接到集群中的某一个节点。此后,该客户端的所有 SQL 请求都由这个节点作为 启动节点(initiator node) 来接收、解析、生成执行计划,然后将计划分发到所有相关节点执行。
如果所有客户端都连接到同一个节点,意味着什么?
类比:一个工厂有 10 条流水线,但所有订单都从 1 号窗口递进来,由 1 号窗口的调度员统一拆解任务后再分发给 10 条线。当订单少时没问题,但当订单量上去后,调度员本身就成了瓶颈——其他 9 条线空闲,而调度员忙不过来。
在 Vertica 中,这个「调度员」就是 initiator node 上的以下阶段:
- BeforePlan / AnalyzeRewrite:解析和重写 SQL
- CompilePlan:访问 Catalog 获取元数据、生成执行计划
- PreparePlan:锁表、资源预留、计划分发
这些阶段全部在 initiator node 上串行执行,不涉及数据节点。当上百个并发连接都集中在一个节点时,该节点的 CPU 和 Catalog 访问被大量争抢,单条 SQL 的准备时间从毫秒级飙升至秒级甚至几十秒。
1.2 原生负载均衡的原理¶
Vertica 内置了原生连接负载均衡(Native Connection Load Balancing),机制如下:
| 策略 | server 端配置 | 客户端配置 | 工作原理 |
|---|---|---|---|
| NONE(默认) | SET_LOAD_BALANCE_POLICY('NONE') |
不需要 | 关闭原生均衡,客户端始终连接 URL 中指定的主机 |
| ROUNDROBIN | SET_LOAD_BALANCE_POLICY('ROUNDROBIN') |
ConnectionLoadBalance=1 |
客户端首次连接 URL 中指定的主机后,从该节点获取集群节点列表,后续新连接按循环顺序依次分配到各个节点 |
| RANDOM | SET_LOAD_BALANCE_POLICY('RANDOM') |
ConnectionLoadBalance=1 |
与 ROUNDROBIN 类似,但使用随机选择而非轮转 |
关键前提:原生负载均衡需要服务端和客户端双端配置,缺一不可:
- 服务端只配策略 → 白配,客户端不感知
- 客户端只配参数 → 无效,因为服务端策略是 NONE
- 两端都配 → 客户端从初始化节点获取节点列表和策略,后续连接按策略分配到不同节点
原生负载均衡的另一个重要特性是连接级生效,而非 SQL 级。也就是说:同一个连接内的所有 SQL 始终在同一个 initiator node 上执行。均衡的是连接,不是每条 SQL。
1.3 路由规则(Routing Rules)—— 进阶控制¶
当集群有多个子集群(subcluster)时,仅靠 ROUNDROBIN/RANDOM 策略不够精细。你可能希望:
- 一批客户端只连到子集群 A,另一批只连到子集群 B
- 特定 IP 段的连接路由到特定子集群
这可以通过 LOAD BALANCE GROUP + ROUTING RULE 实现。工作方式:
路由规则在 v_catalog 中以两张表存储:
LOAD_BALANCE_GROUPS:定义负载均衡组,包含哪些节点或子集群,以及使用的策略ROUTING_RULES:定义 IP 地址到负载均衡组的映射关系
从 Vertica 23.3 开始,还引入了 Workload Routing,通过 --workload 参数按工作负载类型(而非 IP)路由连接。相关表为 WORKLOAD_ROUTING_RULES。
1.4 原生负载均衡 vs 外部负载均衡¶
| 对比维度 | 原生负载均衡 | 外部负载均衡(F5 / HAProxy / Nginx / K8s Service) |
|---|---|---|
| 实现方式 | Vertica 内置,客户端驱动感知节点列表 | 在 Vertica 前方放置 TCP/HTTP 代理 |
| 配置复杂度 | 低:服务端一条 SQL + 客户端一个参数 | 中-高:需配置代理软件,维护节点列表 |
| 故障转移 | 客户端内置 BackupServerNode 参数 | 代理层健康检查 + 自动摘除 |
| 均衡粒度 | 连接级(新连接均衡) | 连接级,可做更细粒度的负载算法 |
| 节点感知 | 客户端内建节点列表,感知拓扑 | 代理层不感知 Vertica 内部拓扑 |
| 推荐的场景 | 大多数 Vertica 场景 | K8s 部署、需要高级路由/健康检查、TCP idle timeout 防护 |
| 注意事项 | 与外部 LB 同时启用会导致双层均衡,ROUNDROBIN 可能表现为随机 | 需确保代理的 TCP idle timeout > 客户端最长事务时间 |
重要:不要同时启用原生负载均衡和外部负载均衡。详见 Vertica Docker CE 与 Kubernetes 常见问题 中的讨论——K8s Service 已做一层均衡,再开原生均衡会导致行为不可预期。
1.5 所有可能来源/原因总结¶
| 来源 | 表现 | 发生条件 |
|---|---|---|
| 客户端未配负载均衡参数 | 所有连接落在同一节点 | JDBC URL / ODBC DSN 缺少 ConnectionLoadBalance |
| 服务端策略为 NONE | 原生负载均衡不生效 | 默认值,未执行 SET_LOAD_BALANCE_POLICY |
| 调度工具固定 IP 连接 | 某类用户/任务集中在单一节点 | ETL 工具硬编码了某个节点的 IP |
| 路由规则缺失或错误 | 某些 IP 段的路由不符合预期 | 子集群隔离场景未配 ROUTING RULE |
| 外部 LB 仅指向一个节点 | 看起来有 LB 但实际只转发到一个后端 | LB 配置中只有一个 upstream server |
| 连接池未释放连接 | 长期复用的连接永远不会被重新均衡 | 应用使用连接池(如 HikariCP)且生命周期很长 |
| 故障转移后回切失败 | 某节点故障恢复后,客户端未重新均匀连接 | BackupServerNode 生效后未清理 |
2. 系统级监控(从宏观入手)¶
2.1 检查负载均衡策略状态¶
首先确认服务端当前配置:
如何解读结果:
none→ 原生负载均衡未启用,所有客户端必然连到 URL 中指定的主机roundrobin或random→ 服务端已启用,但客户端仍需配置ConnectionLoadBalance=1才能生效
2.2 检查负载均衡组与路由规则¶
SELECT name, policy, filter, type, object_name FROM v_catalog.load_balance_groups;
SELECT name, source_address, destination_name FROM v_catalog.routing_rules;
SELECT workload, subcluster_name, priority FROM v_catalog.workload_routing_rules;
如何解读结果:
load_balance_groups为空 → 没有定义任何负载均衡组,所有客户端按全局策略(DATABASES.LOAD_BALANCE_POLICY)分配routing_rules为空 → 没有 IP 级别的路由规则,所有客户端统一处理- 每行的
destination_name应匹配一个load_balance_groups.name,如果匹配不上则该规则无效 workload_routing_rules为空 → 未使用工作负载路由(v23.3+ 特性)
2.3 检查各节点当前连接分布¶
实时会话分布——查看每个节点上当前有多少个活跃客户端会话:
SELECT
nvl(n.subcluster_name, 'Enterprise Mode') AS subcluster_name,
s.node_name,
COUNT(*) AS session_count
FROM v_monitor.sessions s
LEFT JOIN v_catalog.nodes n ON s.node_name = n.node_name
WHERE s.user_name <> 'dbadmin'
GROUP BY 1, 2
ORDER BY 1, 2;
如何解读结果:
- 均衡期望:每个节点的
session_count应大致相等(差异不超过 2 倍为健康) - 倾斜告警:如果某节点 session 数是其他节点的 5 倍以上,连接倾斜已严重
- 空节点告警:如果有节点 session_count = 0 而其他节点 > 0,说明该节点完全未被使用
近期查询发起分布——查看过去 1 天内每个节点发起过多少查询:
SELECT
node_name,
COUNT(*) AS query_count
FROM v_internal.dc_requests_issued
WHERE "time" > sysdate() - 1
GROUP BY 1
ORDER BY 1;
如何解读结果:
- 期望每个节点的
query_count大致相等 - 如果 80% 以上的查询集中在少于 30% 的节点上 → 确认连接未均衡
- 此查询是 Vertica 官方推荐的负载均衡快速检查方法
历史连接启动分布——查看各节点、各客户端 IP 的连接历史分布:
SELECT
nvl(n.subcluster_name, 'Enterprise Mode') AS subcluster_name,
dss.node_name,
regexp_substr(client_hostname, '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') AS client_ip,
COUNT(*) AS connection_cnt
FROM v_internal.dc_session_starts dss
LEFT JOIN v_catalog.nodes n ON dss.node_name = n.node_name
WHERE user_name <> 'dbadmin'
AND regexp_not_like(client_hostname, '\w]:\d+')
AND client_hostname <> ''
GROUP BY 1, 2, 3
ORDER BY 3, 2, 1;
如何解读结果:
- 按
client_ip排序后,检查每个客户端 IP 的连接数是否均匀分布到多个节点 - 如果某个
client_ip只出现在一个node_name下 → 该客户端未开启负载均衡 - 多个客户端 IP 集中在同一节点 → 可能是外部 LB 或调度工具配置问题
3. 逐步定位根因(从宏观到微观)¶
步骤 1:确认是服务端还是客户端的问题¶
做什么:先用 2.1 节的 SQL 检查 LOAD_BALANCE_POLICY。
如何解读:
none→ 服务端没有启用负载均衡。跳到第 4 节先配服务端,再配客户端。roundrobin或random→ 服务端已配好。问题在客户端,继续步骤 2。
如果不是 → 进入步骤 2。
步骤 2:检查具体哪些客户端连接未均衡¶
做什么:用 2.3 节的历史连接分布 SQL,按 client_ip 分析。
如何解读:
按以下模式判断:
| 模式 | 解读 | 下一步 |
|---|---|---|
| 所有 client_ip 都集中在同一个 node | 服务端策略可能未生效或外部 LB 只指向一个节点 | 检查服务端策略 + 外部 LB 配置 |
| 有的 client_ip 均衡、有的不均衡 | 部分客户端配置了 ConnectionLoadBalance,部分没配 | 排查未均衡的客户端连接串 |
| 同一个 IP 段所有客户端都在一个 node | 可能存在 ROUTING RULE 但配置错误 | 检查 routing_rules 表 |
| 所有连接都均衡但仍有性能问题 | 连接均衡不一定够——考虑连接池复用导致长期连接永不重分配 | 跳至第 4 节连接池部分 |
如果不是 → 进入步骤 3。
步骤 3:排查外部负载均衡器配置¶
如果使用了 F5 / HAProxy / Nginx / K8s Service 等外部负载均衡器:
- 确认 upstream 节点列表完整:所有 Vertica 节点的 IP:5433 都应该在 LB 后端列表中
- 确认健康检查正常:LB 是否能正确检测节点 UP/DOWN
- 确认均衡算法:round-robin 或 least-connections,不要用 IP-hash(会导致每个客户端始终连同一个节点)
检查外部 LB 的效果——从 Vertica 端看各节点的总连接数:
如果外部 LB 做了均衡、但 Vertica 端连接仍不均衡,可能原因:
- 长连接连接池:连接建立后长期不释放,LB 的均衡只在新建连接时生效
- K8s Service 的
sessionAffinity: ClientIP导致同一客户端始终连到同一 Pod
步骤 4:排查连接池导致的「伪均衡」¶
即使连接建立时是均衡的,如果应用侧使用连接池(如 HikariCP、C3P0、Druid)且连接生命周期很长,那么:
- 新连接已经均衡分配了
- 但已有的旧连接一直在复用,连接分布仍然是老的不均衡状态
检查方式——查看同一客户端 IP 的 session 创建时间分布:
SELECT
node_name,
client_hostname,
MIN(login_timestamp) AS earliest_session,
MAX(login_timestamp) AS latest_session,
COUNT(*) AS session_count
FROM v_monitor.sessions
WHERE user_name <> 'dbadmin'
GROUP BY 1, 2
ORDER BY client_hostname, node_name;
如何解读:
- 如果某个 client_hostname 在一个 node 上有大量 session,且
earliest_session是很久之前(数天或数周),说明连接池中的老连接一直在复用,长期占据了该节点 - 解决方案:配置连接池的最大空闲时间和最大生命周期(见第 4 节)
4. 解决方案(从快速见效到根本治理)¶
4.1 立即措施:启用原生负载均衡(当天可执行)¶
4.1.1 服务端配置¶
为什么推荐 ROUNDROBIN 而不是 RANDOM?
ROUNDROBIN 保证所有节点被均匀轮转使用,不会出现随机导致的短期倾斜。RANDOM 在连接数不够大时可能出现显著不均。
执行后验证策略已生效:
此操作不需要重启数据库,立即生效。
4.1.2 JDBC 客户端配置¶
在 JDBC 连接 URL 中添加 ConnectionLoadBalance=1:
完整推荐的 JDBC URL 模板:
jdbc:vertica://node01:5433/dbname?ConnectionLoadBalance=1&BackupServerNode=node02:5433,node03:5433&loginTimeout=30&socketTimeout=0
各参数说明:
| 参数 | 推荐值 | 含义 | 为什么这个值 |
|---|---|---|---|
ConnectionLoadBalance |
1 或 true |
启用客户端负载均衡 | 告诉驱动从初始节点获取节点列表并按策略分配新连接 |
BackupServerNode |
node02:5433,node03:5433 |
备用节点列表 | 如果初始节点(URL 中的 host)恰好宕机,客户端自动连接到备用节点。至少配 2 个备用节点以覆盖初始节点 + 1 个备用节点同时宕机的情况 |
loginTimeout |
30(秒) |
连接超时 | 避免客户端在节点宕机时无限等待 |
socketTimeout |
0(禁用) |
查询超时 | 设为 0 表示无超时限制。不要设太短的值——分析查询可能运行数分钟甚至数小时。如果网络不稳定可设较长值如 3600 |
关键注意:ConnectionLoadBalance 对新连接生效,但不改变已有连接分配到的节点。已经在使用的连接池中的连接不会自动迁移。
4.1.3 ODBC 客户端配置¶
在 ODBC 连接串中添加 ConnectionLoadBalance=1:
Driver=/opt/vertica/lib64/libverticaodbc.so
Database=dbname
Servername=node01
Port=5433
ConnectionLoadBalance=1
BackupServerNode=node02:5433,node03:5433
或通过 DSN 文件(/etc/odbc.ini 或 ~/.odbc.ini):
[VerticaDSN]
Driver=/opt/vertica/lib64/libverticaodbc.so
Database=dbname
Servername=node01
Port=5433
ConnectionLoadBalance=1
BackupServerNode=node02:5433,node03:5433
4.1.4 VSQL 命令行客户端¶
# -C 启用 ConnectionLoadBalance
# -B 指定 BackupServerNode 列表
vsql -C -h node01 -B node02:5433,node03:5433 -U dbadmin -c "SELECT 1;"
4.2 短期优化:配置路由规则实现子集群隔离(当周执行)¶
如果集群有多个子集群,可以用路由规则实现精细化的连接分配。
4.2.1 创建负载均衡组¶
-- 为每个子集群创建独立的负载均衡组
CREATE LOAD BALANCE GROUP LBG_analytics WITH SUBCLUSTER analytics_cluster FILTER '0.0.0.0/0';
CREATE LOAD BALANCE GROUP LBG_etl WITH SUBCLUSTER etl_cluster FILTER '0.0.0.0/0';
POLICY 参数可选,默认继承全局策略(DATABASES.LOAD_BALANCE_POLICY)。也可以显式指定:
CREATE LOAD BALANCE GROUP LBG_analytics
WITH SUBCLUSTER analytics_cluster
FILTER '0.0.0.0/0'
POLICY 'ROUNDROBIN';
FILTER 的含义:'0.0.0.0/0' 表示不限制 IP。如果只想特定 IP 段的连接进入该组,可以写如 '192.168.1.0/24'。
4.2.2 创建路由规则¶
-- 将来自 192.168.1.x 的连接路由到分析子集群
CREATE ROUTING RULE rr_analytics ROUTE '192.168.1.0/24' TO LBG_analytics;
-- 将来自 10.0.0.x 的连接路由到 ETL 子集群
CREATE ROUTING RULE rr_etl ROUTE '10.0.0.0/24' TO LBG_etl;
路由规则匹配逻辑:客户端 IP 与 source_address 的 CIDR 做匹配,匹配到的第一个规则生效。如果没有任何规则匹配,使用全局策略。
4.2.3 修改已有负载均衡组¶
-- 添加子集群到已有组
ALTER LOAD BALANCE GROUP LBG_analytics ADD SUBCLUSTER new_cluster;
-- 修改策略
ALTER LOAD BALANCE GROUP LBG_analytics SET POLICY TO 'RANDOM';
4.2.4 修改路由规则¶
-- 修改路由目标 IP 段
ALTER ROUTING RULE rr_analytics SET ROUTE TO '192.168.2.0/24';
-- 修改路由目标组
ALTER ROUTING RULE rr_analytics SET GROUP TO 'LBG_etl';
4.3 连接池层面的配合措施¶
即使连接建立时做了负载均衡,如果连接池长期持有连接不释放,均衡效果也会被稀释。以下配置可配合使用:
HikariCP 示例
# HikariCP 连接池配置(Java/Spring Boot)
hikari:
maximumPoolSize: 30
minimumIdle: 5
maxLifetime: 1800000 # 连接最大生命周期 30 分钟,到期强制回收
idleTimeout: 600000 # 空闲连接 10 分钟回收
connectionTestQuery: "SELECT 1"
为什么配置 maxLifetime?
连接在池中驻留太久 → 新建连接(被均衡的)占比越来越低 → 老连接(可能不均衡的)占比越来越高。设置 30 分钟的最大生命周期确保连接定期被回收和重建,每次新建都会触发负载均衡。
C3P0 示例
<!-- c3p0 连接池配置 -->
<property name="maxIdleTime">600</property> <!-- 空闲 10 分钟回收 -->
<property name="maxConnectionAge">1800</property> <!-- 最大寿命 30 分钟 -->
4.4 外部负载均衡器配置方案¶
外部方案,优先级低。本库暂无外部 LB 集成案例,以下配置为通用参考。
HAProxy 示例
# /etc/haproxy/haproxy.cfg
frontend vertica_frontend
bind *:5433
default_backend vertica_backend
timeout client 24h # 关键:必须足够长以容纳长查询
backend vertica_backend
balance roundrobin
option tcp-check
timeout server 24h # 关键:与 client timeout 一致
server node01 10.0.1.1:5433 check
server node02 10.0.1.2:5433 check
server node03 10.0.1.3:5433 check
关键点:TCP idle timeout 必须设置得足够长。如果 timeout 太短而查询运行了 10 分钟,HAProxy 会断开连接导致客户端收到 java.io.EOFException。相关问题排查可参考 Vertica 错误日志解读与常见错误处理。
K8s Service 示例
apiVersion: v1
kind: Service
metadata:
name: vertica-service
spec:
type: ClusterIP
sessionAffinity: None # 关键:不要用 ClientIP,否则同一客户端始终连同一 Pod
ports:
- port: 5433
targetPort: 5433
selector:
app: vertica
重要:K8s 场景下建议关闭 Vertica 原生负载均衡(SET_LOAD_BALANCE_POLICY('NONE')),让 K8s Service 的 iptables/ipvs 做 TCP 层均衡。双层均衡会导致行为不可预期。
5. 深入案例¶
案例 1:调度程序连接集中导致 SQL 准备 20 秒¶
真实案例
场景描述:某运营商 48+4 节点 Vertica 9.0.1 集群,2023 年 11 月 14 日凌晨开始,数仓整体性能明显下降,部分程序耗时翻倍。
诊断过程:
- 数据库节点全部 UP,资源池无排队,无高开销 SQL,硬件指标正常
- 分析典型慢 SQL(插入 1 条日志记录):
| 阶段 | 耗时 | 执行节点 |
|---|---|---|
| BeforePlan | 4.8 秒 | node0037 |
| PreparePlan | 10.8 秒 | node0037 |
| CompilePlan | 4.8 秒 | node0037 |
| ExecutePlan | 0.6 秒 | 所有节点 |
- 检查各节点 session 分布:批处理用户
schedule的所有连接全在 node0037
根因分析:调度程序的数据库连接串未配置负载均衡参数,所有连接固定指向 node0037。48+4 节点集群中,所有 SQL 的 BeforePlan / CompilePlan / PreparePlan 全部在该节点串行执行,Catalog 访问争抢严重。
修复方案:在调度服务器的 JDBC 连接串中添加 ConnectionLoadBalance=1。
效果对比:
- 修复前:单条 SQL 准备阶段 20 秒(Execute 仅 0.6 秒)
- 修复后:单条 SQL 准备阶段 < 1 秒
- 集群整体平均响应时间在 15 点调整完成后恢复至正常水平
案例 2:外部 LB 未覆盖所有节点¶
虚构案例
场景描述:某金融机构 12 节点 Vertica 集群,前端使用 HAProxy 做 TCP 负载均衡。运维反馈集群性能不均衡:前 4 个节点 CPU 持续 > 70%,后 8 个节点 CPU 在 20-30%。
诊断过程:
-- 检查各节点查询发起分布
SELECT node_name, COUNT(*)
FROM v_internal.dc_requests_issued
WHERE "time" > sysdate() - 1
GROUP BY 1 ORDER BY 1;
输出显示 node01~node04 各有约 50,000 条查询,node05~node12 各只有几百条。进一步检查 HAProxy 配置:
backend vertica_backend
server node01 10.0.1.1:5433 check
server node02 10.0.1.2:5433 check
server node03 10.0.1.3:5433 check
server node04 10.0.1.4:5433 check
# node05~node12 未加入 upstream 列表
根因分析:HAProxy 配置时只添加了前 4 个节点作为后端,遗漏了后 8 个节点。
修复方案:将全部 12 个节点加入 HAProxy backend 配置。
效果对比:
- 修复前:前 4 节点 CPU 70%,后 8 节点 20%
- 修复后:所有节点 CPU 均衡在 35-45%
案例 3:连接池老连接长期未回收¶
虚构案例
场景描述:某电商平台 8 节点 Vertica 集群,使用 HikariCP 连接池,maximumPoolSize=50。负载均衡已配置(ConnectionLoadBalance=1 + SET_LOAD_BALANCE_POLICY('ROUNDROBIN')),但运行 2 周后发现 node02 的 CPU 仍然偏高。
诊断过程:
-- 检查 session 的创建时间分布
SELECT
node_name,
MIN(login_timestamp) AS earliest,
MAX(login_timestamp) AS latest,
COUNT(*) AS cnt
FROM v_monitor.sessions
WHERE user_name = 'app_user'
GROUP BY 1;
输出显示 node02 有 48 个 session,最早的可追溯到 14 天前(应用部署日),而其他节点的 session 都在最近 1 天内。
根因分析:HikariCP 默认 maxLifetime=1800000(30 分钟),但该应用的部署配置中显式设置了 maxLifetime=0禁用了连接生命周期管理,导致连接一旦建立就永不回收。首次部署时连接池在 node02 上大量建立连接(当时调度工具启动了高并发批量任务),这些连接存活了 14 天一直没有被回收重建。虽然新连接均衡分配了,但老连接占据了 node02。
修复方案:在 HikariCP 配置中显式设置 maxLifetime=600000(10 分钟)并滚动重启应用实例。
效果对比:
- 修复前:node02 有 48 个 14 天前的长连接
- 修复后:连接在每个生命周期(10 分钟)结束后回收重建,分布回归均衡
案例 4:未启用负载均衡导致连接倾斜¶
真实案例
场景描述:某运营商集群出现性能问题,排查发现大量连接集中在少数节点,导致节点间负载严重不均。
诊断过程:
- 检查
LOAD_BALANCE_POLICY:仍为 NONE(默认值) - 检查各节点
dc_requests_issued分布:查询集中在少数节点 - 检查客户端连接配置:未使用负载均衡参数
根因分析:客户端连接串中未添加 -C(连接负载均衡)和 -B(备用节点)参数,所有连接固定指向同一节点。
修复方案:在连接串中加入 -C 和 -B 参数。同时检查客户端驱动版本——旧版驱动对负载均衡的支持可能不完整,建议升级至与服务端匹配的版本。
提示:本案例和案例 1 的共同教训是——连接负载均衡是「默认关闭」的功能,需要在服务端和客户端两端显式启用,切勿假定它已经生效。
6. 完整诊断流程实战¶
虚构场景 · 完整演练
场景:某企业 6 节点 Vertica v24.x 集群,DBA 收到告警:「node03 CPU 持续 > 85%,其他节点 30-40%」。集群 KSAFE=1,所有节点 UP,最近未做任何变更。
时间线(模拟排查全过程):
09:00 — 收到告警,登录数据库。
09:05 — Step 1:检查服务端负载均衡策略。
→ 结果:roundrobin。服务端已启用,不是服务端问题。
09:08 — Step 2:检查查询发起分布。
SELECT node_name, COUNT(*) AS query_count
FROM v_internal.dc_requests_issued
WHERE "time" > sysdate() - 1
GROUP BY 1 ORDER BY 1;
输出:
node_name | query_count
node01 | 3,245
node02 | 2,891
node03 | 158,432 👈 异常!
node04 | 2,567
node05 | 3,012
node06 | 2,789
09:10 — 确认:node03 处理了全集群 90% 的查询。
09:12 — Step 3:检查哪些客户端连接集中在 node03。
SELECT
regexp_substr(client_hostname, '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') AS client_ip,
COUNT(*) AS conn_count
FROM v_monitor.sessions
WHERE node_name = 'node03' AND user_name <> 'dbadmin'
GROUP BY 1
ORDER BY 2 DESC;
输出:
09:15 — Step 4:锁定问题来源。IP 10.2.3.100 是调度服务器。
SSH 登录该服务器检查 ETL 工具的 JDBC 连接配置:
发现:
没有 ConnectionLoadBalance=1,且 Host 硬编码为 node03 的 IP。
09:20 — 修复:修改连接串。
jdbc:vertica://node01:5433/prod_db?ConnectionLoadBalance=1&BackupServerNode=node02:5433,node03:5433,node04:5433,node05:5433,node06:5433&user=etl_user&password=***
注意:URL 中的 host 改为 node01(任意节点均可),BackupServerNode 列出了其余所有节点作为备选。
09:30 — 滚动重启调度应用的 worker 进程。
10:00 — 验证效果:
SELECT node_name, COUNT(*) AS session_count
FROM v_monitor.sessions WHERE user_name = 'etl_user'
GROUP BY 1 ORDER BY 1;
输出:
10:15 — 检查 node03 CPU:
SELECT
node_name,
AVG(average_cpu_usage_percent) AS avg_cpu
FROM v_monitor.system_resource_usage
WHERE end_time > sysdate() - 1/24
GROUP BY 1;
→ node03 CPU 从 85% 降至 38%,与其他节点持平。
结论:根因是调度 ETL 工具的 JDBC 连接串硬编码了 node03 且未开启负载均衡。修复耗时 1 小时,性能恢复。
7. 快速诊断 SQL 工具箱¶
| 诊断目标 | SQL | 说明 |
|---|---|---|
| 查看当前负载均衡策略 | SELECT LOAD_BALANCE_POLICY FROM V_CATALOG.DATABASES; |
返回 none/roundrobin/random |
| 启用负载均衡 | SELECT SET_LOAD_BALANCE_POLICY('ROUNDROBIN'); |
立即生效,无需重启 |
| 查看负载均衡组 | SELECT name, policy, filter, type, object_name FROM v_catalog.load_balance_groups; |
为空表示未定义任何组 |
| 查看路由规则 | SELECT name, source_address, destination_name FROM v_catalog.routing_rules; |
为空表示无 IP 路由规则 |
| 查看工作负载路由 | SELECT workload, subcluster_name, priority FROM v_catalog.workload_routing_rules; |
v23.3+ 特性 |
| 查看节点状态和地址 | SELECT node_name, node_state, export_address, subcluster_name FROM v_catalog.nodes ORDER BY 1; |
export_address 是客户端连接的目标地址 |
| 查看各节点查询发起数(1 天) | SELECT node_name, COUNT(*) AS cnt FROM v_internal.dc_requests_issued WHERE "time" > sysdate() - 1 GROUP BY 1 ORDER BY 1; |
差异大 = 连接不均衡 |
| 查看各节点活跃会话数 | SELECT s.node_name, COUNT(*) AS cnt FROM v_monitor.sessions s WHERE s.current_statement IS NOT NULL GROUP BY 1 ORDER BY 1; |
差异大 = 连接不均衡 |
| 查看各节点总会话数 | SELECT node_name, COUNT(*) AS cnt FROM v_monitor.sessions WHERE user_name <> 'dbadmin' GROUP BY 1 ORDER BY 1; |
全局视角 |
| 按客户端 IP 查看连接分布 | SELECT node_name, regexp_substr(client_hostname, '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') AS ip, COUNT(*) FROM v_monitor.sessions WHERE user_name <> 'dbadmin' GROUP BY 1, 2 ORDER BY 2, 1; |
定位哪个客户端未均衡 |
| 查看网络地址定义 | SELECT name, node, address, port, is_enabled FROM v_catalog.network_addresses; |
显式定义的网络地址 |
| 查看节点导出地址 | SELECT node_name, export_address, node_address FROM v_catalog.nodes; |
export_address ≠ node_address 时说明有 NAT |
8. 最佳实践清单¶
-
服务端和客户端必须同时配置 — 只配一端等于没配。服务端
SET_LOAD_BALANCE_POLICY('ROUNDROBIN')+ 客户端ConnectionLoadBalance=1,缺一不可。 -
BackupServerNode 至少配 2 个备用节点 — 避免初始节点和唯一备用节点同时宕机的极端场景。列出所有节点最安全。
-
JDBC URL 中 socketTimeout 不要设太短 — 设为 0(禁用)或至少 3600 秒。分析查询可能运行数分钟甚至数小时,短超时会误杀正常查询。
-
连接池配合 maxLifetime — 无论 HikariCP / C3P0 / Druid,设置连接的最大生命周期(建议 10-30 分钟),确保老连接定期回收重建,触发负载均衡。
-
不要同时启用原生负载均衡和外部负载均衡 — 双层均衡会导致 ROUNDROBIN 行为偏离预期(如 K8s Service 场景)。
-
外部 LB 的 TCP idle timeout 必须 > 最长事务时间 — 否则长查询会被 LB 断开,客户端收到 EOFException。
-
每季度巡检连接分布 — 使用第 7 节工具箱中的 SQL 定期检查各节点连接分布。建议设置
(max - min) / max > 0.3作为告警阈值。 -
客户端驱动版本与服务端匹配 — 旧版驱动可能不完全支持 ConnectionLoadBalance 或存在已知 Bug。升级驱动往往比排查配置更高效。
-
多子集群场景务必配置路由规则 — 不要依赖客户端自行选择子集群。用 LOAD BALANCE GROUP + ROUTING RULE 明确隔离工作负载。
-
新建应用/工具时默认配置负载均衡 — 将包含
ConnectionLoadBalance=1的 JDBC URL 模板写入团队 Wiki,避免因遗漏导致的重蹈覆辙。
扩展阅读¶
- Vertica 弹性伸缩功能介绍与配置 — 子集群级别的连接路由与弹性伸缩配合
- Vertica 客户端驱动兼容性与升级指南 — 驱动版本兼容策略与升级步骤
- Vertica CPU 持续高负载诊断与优化 — 连接倾斜是 CPU 高负载的常见根因
- Vertica JDBC Routable Query API 最佳实践 — JDBC 可路由查询的高级用法
- Vertica 低延迟优化最佳实践 — 低延迟场景中的负载均衡建议
- Vertica Docker CE 与 Kubernetes 常见问题 — 外部 LB 与原生均衡的冲突讨论
- Vertica 错误日志解读与常见错误处理 — HAProxy 超时导致的 EOFException 排查