跳转至

Vertica 错误日志解读与常见错误处理

作者:JiangChong | 发布时间:2026-04-16

适用场景:当你在 vertica.log 中看到报错、收到用户投诉「查询执行失败了」、发现集群出现 PANIC 宕机、或需要建立一套错误日志监控告警机制时,本文提供从零开始的全套方法论。

关联文章

理解全文脉络

本文的组织逻辑遵循从原理到实战、从宏观到微观的递进路径:

  • 如果你刚接触 Vertica 错误日志,从第 1 节开始,理解 Data Collector 架构和错误生命周期
  • 如果你需要快速定位当前问题,跳到第 3 节,按错误严重度和类型选择对应的诊断入口
  • 如果你想建立监控方案,第 2 节提供完整的系统表监控组合,第 4 节给出实施方案
  • 如果你想看别人怎么做,第 5 节有 4 个涵盖不同场景的案例,第 6 节有一个完整的端到端演练
  • 如果你只需要一个 SQL 参考,直接跳到第 7 节的工具箱表格

1. 原理理解:Vertica 错误日志的底层机制

1.1 错误从哪里来?

Vertica 是一套大规模并行处理(MPP)数据库。当一条 SQL 被提交到集群时,它会在多个节点上并行执行。每个节点上每个算子的每次异常,都可能产生一条错误记录。这意味着一条失败的查询可能在多个节点上留下数十条错误信息。

与传统非 MPP 架构数据库不同——后者的集群方案(如 PostgreSQL 流复制/Patroni 或 MySQL Group Replication)主要用于高可用和读写分离,单条 SQL 通常只在一个节点上执行——Vertica 作为 MPP 数据库,一条查询会在所有节点上并行执行,每个节点上每个算子的异常都可能产生错误记录。换言之,一组相关的错误可能分散在多个节点上,而不是集中于一处。你需要理解三层结构:

层级 数据来源 特点 典型场景
vertica.log 节点级文件系统日志 文本文件,按时间追加,包含所有级别信息 深度排查(含 DEBUG 级别)、宕机分析
Data Collector (dc_errors) 内存缓冲区 → 磁盘表 结构化存储于 v_monitor.ERROR_MESSAGES,自动按策略淘汰 日常监控、错误统计、趋势分析
Monitoring Events 系统事件框架 按事件触发/清除模型运作,当前持续的问题 实时告警、问题追踪

1.2 Data Collector 架构:理解错误日志的「水管」

Data Collector 是 Vertica 的数据收集框架。可以把它理解成一根水管:

vertica 进程 → 内存缓冲区(Memory Buffer)→ 磁盘存储(Disk Table)→ 策略驱动的自动清理

每个 Data Collector 组件对应一张系统表。对于错误日志,核心组件是 Errors,对应 v_monitor.ERROR_MESSAGES关键特征

  • 实时性:错误产生后几乎立即出现在 ERROR_MESSAGES 中(内存缓冲区级别)
  • 容量限制:Errors 组件的磁盘配额通常较小——本文验证环境(Vertica v26.1.0-2 标准镜像)中 DISK_SIZE_KB = 10000(约 10 MB),且 INTERVAL_SET = false 暗示未被修改过,推测为出厂默认值。配额用满后最旧记录按策略淘汰
  • 存在丢数据风险:如果缓冲区满(高并发错误场景下),LOST_RECORDS > 0 表示有错误记录被丢弃

这就是为什么你不能只依赖 v_monitor.ERROR_MESSAGES:在高负载宕机场景下,瞬间产生的数千条 PANIC 可能撑爆缓冲区,导致最关键的早期错误被淘汰。此时 vertica.log 是唯一的完整记录。

1.3 错误严重度体系

Vertica 将错误分为五个严重级别。理解它们的含义是日志分析的第一步:

ERROR_LEVEL 含义 数据库影响 行动优先级
NOTICE 信息提示,非错误 无影响 无需行动
INFO 正常操作记录 无影响 无需行动
WARNING 潜在问题预警 当前无影响但可能恶化 ⚠️ 近期关注
ERROR 某个操作失败 当前语句失败,数据库继续运行 🔴 需处理
FATAL 致命错误 会话断开、节点退出或进程终止 🚨 立即处理

关键认知FATAL 不总是等于全库宕机。例如「Client canceled session」被记录为 FATAL 级别(错误码 67371461),但这只是客户端主动断开会话,对数据库运行无影响。判断严重度要看 MESSAGE 内容,而非只看级别标签

1.4 错误来源全景图

Vertica 错误日志覆盖的触发源非常广泛。下表列出所有可能产生 ERROR 以上级别记录的场景:

来源类别 典型错误 严重度范围 相关系统表/日志
SQL 编译错误 语法错误、列不存在、表不存在 ERROR ERROR_MESSAGES
SQL 执行错误 除零、类型溢出、连接超时 ERROR/FATAL ERROR_MESSAGES, QUERY_REQUESTS
内存资源拒绝 查询内存超预算 WARNING/ERROR RESOURCE_REJECTIONS, RESOURCE_REJECTION_DETAILS
磁盘资源拒绝 存储位置无空间 WARNING/ERROR DISK_RESOURCE_REJECTIONS
进程崩溃 SIGSEGV、SIGABRT、VIAssert 失败 FATAL/PANIC vertica.log, ErrorReport.txt
锁超时 Global Catalog X Lock 超时 → 集群 PANIC FATAL vertica.log, dc_errors
网络通信失败 节点间消息接收失败(4534) ERROR ERROR_MESSAGES, vertica.log
OOM Killer Linux 内核杀死 Vertica 进程 FATAL(无声) /var/log/messages, vertica.log
认证失败 密码错误、Kerberos 票据过期、LDAP 故障 ERROR LOGIN_FAILURES
数据加载失败 COPY 拒绝行、格式不匹配、UDF 错误 ERROR DATA_LOADER_EVENTS, LOAD_STREAMS
Tuple Mover Mergeout 失败、ROS Pushback ERROR vertica.log, dc_tuple_mover_events
配置变更 参数修改导致的连锁故障 WARNING/ERROR CONFIGURATION_CHANGES

2. 系统级监控:从宏观入手

在跳入具体错误排查之前,先建立对集群错误态势的整体视图。以下 6 张系统表构成错误监控的最小组合。

2.1 错误态势总览:v_monitor.ERROR_MESSAGES

这是错误监控的核心表。先看整体分布,再看细节。

看整体分布 — 按严重度和时间段聚合:

SELECT
    ERROR_LEVEL,
    COUNT(*) AS error_count,
    MIN(EVENT_TIMESTAMP) AS first_seen,
    MAX(EVENT_TIMESTAMP) AS last_seen
FROM v_monitor.ERROR_MESSAGES
WHERE EVENT_TIMESTAMP > CURRENT_TIMESTAMP - INTERVAL '24 hours'
GROUP BY ERROR_LEVEL
ORDER BY error_count DESC;

如何解读结果

  • 如果 ERROR + FATAL 数量在几十以内:正常范围,逐个排查即可
  • 如果 ERROR 数量 > 100/天:系统存在反复发生的错误模式,需要按错误码归类分析
  • 如果 FATAL > 0 且 MESSAGE 不是 Client canceled:需要立即关注,可能涉及节点断开或进程异常
  • 如果 NOTICE 和 INFO 占比 > 90%:正常,大多数日志都是信息级

按错误码归类 — 找重复性错误:

SELECT
      ERROR_CODE,
      ERROR_LEVEL,
      COUNT(*) AS cnt,
      MAX(EVENT_TIMESTAMP) AS latest,
      MAX(MESSAGE) AS sample_message  --取一条代表性错误信息
 FROM v_monitor.ERROR_MESSAGES
WHERE EVENT_TIMESTAMP > CURRENT_TIMESTAMP - INTERVAL '24 hours'
  AND ERROR_LEVEL IN ('ERROR', 'FATAL')
GROUP BY ERROR_CODE, ERROR_LEVEL
ORDER BY cnt DESC
LIMIT 20;

如何解读结果

  • cnt 降序看,排名前 3 的高频错误就是你当前最需要解决的问题
  • 如果某个错误码每小时出现 > 10 次,说明有自动化任务在反复失败
  • sample_message 帮助你快速识别错误性质,但如果同一个错误码对应多种不同 MESSAGE,需要进一步按 MESSAGE 分组

2.2 查看当前活跃的严重事件:v_monitor.ACTIVE_EVENTS

ACTIVE_EVENTS 显示当前仍存在的严重问题。它与 ERROR_MESSAGES 的区别在于:后者是历史流水账,前者是待处理清单。

SELECT
    EVENT_SEVERITY,
    EVENT_CODE,
    EVENT_CODE_DESCRIPTION,
    EVENT_PROBLEM_DESCRIPTION,
    EVENT_POSTED_TIMESTAMP,
    NODE_NAME
FROM v_monitor.ACTIVE_EVENTS
ORDER BY
    CASE EVENT_SEVERITY
        WHEN 'Critical' THEN 1
        WHEN 'Warning' THEN 2
        WHEN 'Informational' THEN 3
    END,
    EVENT_POSTED_TIMESTAMP DESC;

如何解读结果

  • Low Disk Space (EVENT_CODE=0):最常见的事件。检查对应节点的磁盘使用率,清理旧日志或扩展存储
  • Node State Change (EVENT_CODE=6):节点状态变更。如果有节点长时间处于 DOWN/RECOVERING 状态,这是一个紧急问题
  • 如果该表为空或只有 Informational 级别事件:集群当前健康,没有需要立即介入的问题
  • 如果出现 Warning 或 Critical 且持续超过 1 小时未被自动清除:根因仍在,需要人工介入

2.3 全局健康检查:v_monitor.SYSTEM

最快判断集群是否处于紧急状态,只需看这一行:

SELECT
    NODE_COUNT,
    NODE_DOWN_COUNT,
    CURRENT_FAULT_TOLERANCE,
    DESIGNED_FAULT_TOLERANCE,
    CURRENT_EPOCH,
    AHM_EPOCH,
    LAST_GOOD_EPOCH
FROM v_monitor.SYSTEM;

如何解读结果

  • NODE_DOWN_COUNT > 0:立即行动!有节点宕机。如果 CURRENT_FAULT_TOLERANCE = 0 则数据库已经不安全,再多一个节点宕机全库停服
  • CURRENT_FAULT_TOLERANCE < DESIGNED_FAULT_TOLERANCE:K-safety 已经降级,有节点不在线
  • LAST_GOOD_EPOCHCURRENT_EPOCH 差距过大:恢复可能严重滞后

我们以一个常见的判断逻辑为例

  • 如果 NODE_DOWN_COUNT > 0 → 跳到 3.2 节(节点宕机排查)
  • 如果 NODE_DOWN_COUNT = 0 但有 RESOURCE_REJECTIONS → 跳到 3.3 节(资源拒绝错误)
  • 如果都正常但用户报错 → 跳到 3.4 节(SQL 执行错误)

2.4 Data Collector 健康检查:v_monitor.DATA_COLLECTOR

监控 Data Collector 本身是否健康是常被忽略的一环。如果 Data Collector 丢数据了,你看的 ERROR_MESSAGES 就不完整:

SELECT
    COMPONENT,
    TABLE_NAME,
    DISK_SIZE_KB,
    LOST_BUFFERS,
    LOST_RECORDS,
    RECORD_TOO_BIG_ERRORS,
    CURRENT_DISK_BYTES,
    KB_PER_DAY
FROM v_monitor.DATA_COLLECTOR
WHERE LOST_RECORDS > 0
   OR LOST_BUFFERS > 0
   OR RECORD_TOO_BIG_ERRORS > 0
ORDER BY LOST_RECORDS DESC;

如何解读结果

  • LOST_RECORDS > 0COMPONENT = 'Errors':这是最危险的信号——错误被丢弃了,你看到的 ERROR_MESSAGES 是残缺的。此时必须查阅 vertica.log 获取完整记录
  • LOST_RECORDS > 0 但限于 AllocationPoolStatistics:相对不紧急,是内存分配统计丢失。但如果持续增长,说明系统在内存压力下
  • RECORD_TOO_BIG_ERRORS > 0:某些错误消息体过大(如含超长 SQL 文本),被截断或丢弃

2.5 登录安全监控:v_monitor.LOGIN_FAILURES

登录失败通常暗示三类问题:密码即将过期、应用配置错误、或外部攻击尝试:

SELECT
    USER_NAME,
    CLIENT_HOSTNAME,
    REASON,
    COUNT(*) AS fail_count,
    MAX(LOGIN_TIMESTAMP) AS latest_fail
FROM v_monitor.LOGIN_FAILURES
WHERE LOGIN_TIMESTAMP > CURRENT_TIMESTAMP - INTERVAL '1 hour'
GROUP BY USER_NAME, CLIENT_HOSTNAME, REASON
ORDER BY fail_count DESC
LIMIT 20;

如何解读结果

  • 同一 CLIENT_HOSTNAME 在短时间内 > 10 次失败:可能是应用侧密码配置过期,或有人在做连接测试
  • USER_NAME 为空或为系统不存在用户:有人在扫端口或尝试弱口令
  • REASON 含 Kerberos/No PREAUTH:Kerberos 票据问题,详见 vault 中 Kerberos 相关案例

2.6 Linux 层面的快速健康检查

并非所有错误都记录在数据库系统表中。以下 Linux 命令帮助你验证操作系统层面是否正常:

检查 OOM Killer 是否最近杀过 Vertica 进程

dmesg -T | grep -i "out of memory" | tail -20

如果输出非空,说明 Linux 内核因内存不足而杀死了进程。这类事件在 ERROR_MESSAGES不会有记录,因为进程是被 SIGKILL 直接终止的,来不及写入错误日志。

检查系统整体负载

uptime

关注 15 分钟负载平均值。对于 N 核服务器,如果负载 > N × 2,系统已经严重过载。此时 vertica 进程可能因得不到 CPU 调度而响应超时,产生网络通信类错误(如 ERROR 4534)。

检查磁盘使用率

df -h / /data 2>/dev/null

如果根分区或数据分区使用率 > 85%,Vertica 可能产生磁盘空间不足的拒绝错误(DISK_RESOURCE_REJECTIONS),Tuple Mover 的 Mergeout 也会受影响。


3. 逐步定位根因:从宏观到微观

按照排查优先级,本节将错误分析拆分为四个独立诊断入口。每个入口都有明确的触发条件。

3.1 步骤一:错误严重度分类(所有问题的起点)

做什么:拿到一堆错误日志时,先不要直接看详情。按严重度分类,先处理最致命的。

用什么 SQL

SELECT
    ERROR_LEVEL,
    COUNT(*) AS cnt,
    MIN(EVENT_TIMESTAMP) AS first_time,
    COUNT(DISTINCT NODE_NAME) AS affected_nodes,
    COUNT(DISTINCT SESSION_ID) AS affected_sessions,
    COUNT(DISTINCT USER_NAME) AS affected_users
FROM v_monitor.ERROR_MESSAGES
WHERE EVENT_TIMESTAMP > CURRENT_TIMESTAMP - INTERVAL '1 hour'
GROUP BY ERROR_LEVEL
ORDER BY
    CASE ERROR_LEVEL
        WHEN 'FATAL' THEN 1
        WHEN 'ERROR' THEN 2
        WHEN 'WARNING' THEN 3
        WHEN 'NOTICE' THEN 4
        WHEN 'INFO' THEN 5
    END;

如何解读

  • affected_nodes 接近集群总节点数:这是集群级别的系统性故障,不是某个节点的问题
  • affected_sessions 集中在少数几个会话:问题可能出在某个应用的特定查询模式
  • affected_users 只有 1 个:可能是该用户的权限或环境配置问题
  • 如果 FATAL 行数 > 0 且包含大量节点:跳到 3.2 节

判断逻辑

有 FATAL → 3.2 节点/进程级排查
  ↓ 无 FATAL
有大量 ERROR 且涉及 RESOURCE_REJECTED → 3.3 资源拒绝排查
  ↓ 不是资源问题
用户报查询失败 → 3.4 SQL 执行错误排查
  ↓ 无明显模式
→ 3.5 日志文件直接分析

3.2 步骤二:节点/进程级致命错误排查

触发条件NODE_DOWN_COUNT > 0ERROR_MESSAGES 中出现 FATAL 级别(非 Client canceled 类)。

做什么:判断是进程崩溃、节点下线还是硬件问题。

第 3.2a 步:查看最近的 FATAL 详情

SELECT
    EVENT_TIMESTAMP,
    ERROR_CODE,
    MESSAGE,
    NODE_NAME,
    SESSION_ID,
    TRANSACTION_ID,
    USER_NAME
FROM v_monitor.ERROR_MESSAGES
WHERE ERROR_LEVEL = 'FATAL'
  AND EVENT_TIMESTAMP > CURRENT_TIMESTAMP - INTERVAL '1 hour'
  AND MESSAGE NOT ILIKE '%client canceled%'  -- 排除客户端主动断开,这不是真正的故障
ORDER BY EVENT_TIMESTAMP DESC
LIMIT 30;

如何解读

FATAL 模式 典型 MESSAGE 可能原因
VIAssert ... failed VIAssert(inProcessItems.count(ptr) == 0) failed 软件内部逻辑错误(bug),需升级
SIGSEGV / SIGABRT 内存违规访问 软件 bug 或硬件内存故障
Global Catalog X Lock Failure to acquire global catalog X lock for commit 某个节点夯死持有锁,导致所有节点 CommitTimeout
Could not create UDx side process failed to get UDx side process info from zygote UDx 进程资源不足或 zygote 进程异常
IOException while communicating 节点间通信异常 网络问题或某个节点进程停止响应

第 3.2b 步:检查 OOM Killer 痕迹(对无声宕机最关键)

如果 vertica 进程突然消失而 ERROR_MESSAGES 中没有对应 FATAL,极有可能是 OOM Killer:

dmesg -T | grep -i "killed process" | tail -10

# 同时检查 messages 日志
grep -i "out of memory" /var/log/messages | tail -10

如果确认是 OOM Killer,跳到 4.1 节的资源池内存调整方案。

第 3.2c 步:检查节点状态变更时间线

SELECT
    NODE_NAME,
    NODE_STATE,
    EVENT_TIMESTAMP
FROM v_monitor.NODE_STATES
WHERE EVENT_TIMESTAMP > CURRENT_TIMESTAMP - INTERVAL '24 hours'
ORDER BY EVENT_TIMESTAMP DESC;

如何解读:还原节点状态变更的精确时间线。如果看到 UP → DOWN → RECOVERING → UP 的序列,结合 vertica.log 中对应时间段的 ERROR 来定位根因。

3.3 步骤三:资源拒绝类错误排查

触发条件:错误消息中包含 RESOURCE_REJECTEDRejection,或 RESOURCE_REJECTIONS 表中 REJECTION_COUNT > 0

SELECT
    POOL_NAME,
    RESOURCE_TYPE,
    REASON,
    REJECTION_COUNT,
    FIRST_REJECTED_TIMESTAMP,
    LAST_REJECTED_TIMESTAMP,
    NODE_NAME
FROM v_monitor.RESOURCE_REJECTIONS
ORDER BY REJECTION_COUNT DESC;

如何解读

  • RESOURCE_TYPE = 'memory' + REASON = 'Query budget exceeded':查询需要的内存超过了 query_budget(= MEMORYSIZE / PLANNEDCONCURRENCY)。这是最常见的拒绝原因
  • RESOURCE_TYPE = 'memory' + REASON = 'Pool memory exhausted':整个资源池的内存用完了。检查是否有某个查询吃掉了大量内存,或资源池 MEMORYSIZE 设置过小
  • RESOURCE_TYPE = 'threads':CPU 线程资源不够,降低 EXECUTIONPARALLELISM 或扩大池的线程配额

详细处理方案见关联文章 Vertica 资源拒绝排查与资源池调优

3.4 步骤四:SQL 执行错误排查

触发条件:用户报告特定查询报错。

SELECT
    em.EVENT_TIMESTAMP,
    em.ERROR_CODE,
    em.ERROR_LEVEL,
    em.MESSAGE,
    em.DETAIL,
    em.HINT,
    em.NODE_NAME,
    em.SESSION_ID,
    qr.REQUEST AS query_text
FROM v_monitor.ERROR_MESSAGES em
LEFT JOIN v_monitor.QUERY_REQUESTS qr
    ON em.SESSION_ID = qr.SESSION_ID
   AND em.TRANSACTION_ID = qr.TRANSACTION_ID
WHERE em.SESSION_ID = ':session_id'    -- 替换为实际 session_id
  AND em.EVENT_TIMESTAMP > CURRENT_TIMESTAMP - INTERVAL '1 hour'
ORDER BY em.EVENT_TIMESTAMP DESC
LIMIT 50;

如何解读

  • HINT 列非空时:系统已经给出了修复建议,先按提示修改
  • ERROR_CODE = 50360452(列不存在):检查查询中引用的列名是否拼写正确,或者在当前表/投影中确实不存在该列
  • ERROR_CODE = 16932996(关系不存在):表或投影不存在,检查是否在使用错误的 schema 或表名
  • ERROR_CODE = 1088(不支持的查询模式):查询使用了 Vertica 不支持的 SQL 语法(如含聚合函数的关联子查询),需要改写

如果 HINT 为空且错误信息不够明确

  1. vertica.log 中按 SESSION_ID 搜索该会话的完整日志,通常比系统表包含更多上下文
  2. 查找该查询的 EXPLAIN 输出,看优化器是否做出了异常决策

3.5 步骤五:直接分析 vertica.log(当系统表信息不足时)

场景:Data Collector 有丢记录、错误是 PANIC 级别没有写入系统表(因为进程直接崩溃)、或者需要比系统表更详细的上下文信息。

vertica.log 的格式

YYYY-MM-DD HH:MM:SS.sss Thread:0x... [Module] <LEVEL> Message

例如:

2026-05-31 21:29:38.496 Init Session:0xfffed528a3c0 [Txn] <INFO> Commit Complete: Txn: a000000000da9f at epoch 0x7a

常用 grep 命令

# 1. 按错误级别筛选
grep -E '<ERROR>|<FATAL>|<PANIC>' /data/vmart3/v_vmart3_node0001_catalog/vertica.log | tail -50

# 2. 按事务 ID 追踪完整生命周期
grep 'a000000000da9f' /data/vmart3/v_vmart3_node0001_catalog/vertica.log

# 3. 按时间段提取(适合分析故障窗口)
grep '2026-05-31 10:0[0-9]' /data/vmart3/v_vmart3_node0001_catalog/vertica.log | grep -E '<ERROR>|<FATAL>|<PANIC>'

# 4. 统计各类错误的出现次数
grep -c '<ERROR>' /data/vmart3/v_vmart3_node0001_catalog/vertica.log
grep -c '<PANIC>' /data/vmart3/v_vmart3_node0001_catalog/vertica.log

注意:vertica.log 路径因数据库名和节点名不同而异。标准格式:/<数据目录>/<DB名>/v_<DB名>_node####_catalog/vertica.log。可以用以下命令找到确切路径:

find / -name "vertica.log" -type f 2>/dev/null

4. 解决方案:从快速见效到根本治理

4.1 内存相关错误的应对(OOM / RESOURCE_REJECTED)

立即措施(当天)

措施 方法 为什么
降低general资源池 MEMORYSIZE ALTER RESOURCE POOL general MEMORYSIZE '85%';
重启数据库生效
为操作系统留出更多内存,防止 OOM Killer。如果当前是 95%,降 5-10% 通常立竿见影
杀死内存大户查询 查找 execution_engine_profilesmemory reserved (bytes) 最大的查询,SELECT CLOSE_SESSION('session-id') 释放被占用的内存,恢复服务
临时限制并发 ALTER RESOURCE POOL general MAXCONCURRENCY 3; MAXCONCURRENCY 硬限制资源池内同时执行的查询数——从当前值缩小后,同时跑的查询减少,瞬时内存总消耗下降,为其他查询和 OS 留出空间

短期优化(当周)

措施 方法 为什么
按业务拆资源池 为 ETL 和查询分别创建资源池 隔离不同工作负载的内存竞争
设置 MAXQUERYMEMORYSIZE ALTER RESOURCE POOL general MAXQUERYMEMORYSIZE '20GB'; 防止单条异常查询吃掉整池内存
启用 QUEUETIMEOUT ALTER RESOURCE POOL general QUEUETIMEOUT 300; 避免查询无限排队,超时后拒绝而非堆积

详细方案见关联文章 Vertica 内存压力诊断与调优

4.2 锁超时与 Catalog 锁错误应对

典型场景:vertica.log 中出现 55V03/5157: Unavailable: X lock Global Catalog - timeout error

根本原因:Global Catalog X Lock 是集群级别的排他锁。当某个节点执行 DDL、Tuple Mover Mergeout、或 Commit 操作时持有此锁,其他节点必须等待。如果持有锁的节点故障(硬件夯死),锁永远释放不了,最终达到 CommitTimeout(默认 1800 秒),集群集体 PANIC。

立即措施:确认故障节点 → 修复硬件 → 跳过故障节点启动数据库 → 恢复节点。

长期措施

  • 监控节点硬件健康:某运营商 2024 年的案例中,一块故障阵列卡导致节点夯死、持有锁不释放,最终 CommitTimeout 触发全集群 PANIC。定期检查磁盘 SMART、内存 ECC、网卡状态,比事后分析锁超时有效得多
  • 清理无用表/投影,控制 Catalog 体积:Catalog 越大,Global Catalog X Lock 的持有时间越长,超时风险越高。某运营商的案例中,Catalog 从 30 GB 清理后,锁超时问题显著减少
  • 关注版本更新中的锁相关 bug 修复:某运营商的案例中,7.2.3-17 版本在节点恢复期间执行 COPY 会触发锁 PANIC——这是已知 bug,升级即修复
  • 增加分区粒度:让 Tuple Mover 的 Mergeout 操作范围更小,每次持有的锁时间更短

4.3 错误日志监控方案

方案一:利用 Vertica 内置 Monitoring Events + Notifier

Vertica 内置了事件系统,可以配置将严重事件推送到外部通道:

  1. 配置通知通道(如 SNMP、Syslog、Shell 脚本):通过 EVENT_CONFIGURATIONS
  2. 设置关键事件的严重级别阈值
  3. 配置自动化响应脚本

方案二:SQL + Cron 的轻量化监控

用以下 SQL 作为核心监控查询,通过 crontab 定时执行:

-- 关键指标汇总查询(可嵌入监控脚本)
SELECT
    'fatal_count' AS metric,
    COUNT(*)::VARCHAR AS value
FROM v_monitor.ERROR_MESSAGES
WHERE ERROR_LEVEL = 'FATAL'
  AND EVENT_TIMESTAMP > CURRENT_TIMESTAMP - INTERVAL '5 minutes'
UNION ALL
SELECT
    'error_count',
    COUNT(*)::VARCHAR
FROM v_monitor.ERROR_MESSAGES
WHERE ERROR_LEVEL = 'ERROR'
  AND EVENT_TIMESTAMP > CURRENT_TIMESTAMP - INTERVAL '5 minutes'
UNION ALL
SELECT
    'node_down',
    NODE_DOWN_COUNT::VARCHAR
FROM v_monitor.SYSTEM
UNION ALL
SELECT
    'active_critical_events',
    COUNT(*)::VARCHAR
FROM v_monitor.ACTIVE_EVENTS
WHERE EVENT_SEVERITY IN ('Critical', 'Warning');

将以上 SQL 嵌入一个 shell 脚本,在 crontab 中每 5 分钟执行一次,超过阈值时发邮件或调用告警接口。

方案三:日志聚合工具(适合大规模集群,外部方案)

⚠️ 以下方案使用的 Filebeat / ELK 为外部通用工具,vault 中暂无 Vertica 集成案例。

部署思路:在每个 Vertica 节点上安装 Filebeat,采集 vertica.log 并推送至集中式日志平台(Elasticsearch + Kibana 或 Loki + Grafana),在平台侧配置告警规则。

Filebeat 最小配置(/etc/filebeat/filebeat.yml):

filebeat.inputs:
  - type: log
    enabled: true
    paths:
      - /data/*/v_*_catalog/vertica.log
    multiline.pattern: '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}'
    multiline.negate: true
    multiline.match: after
    include_lines: ['<ERROR>|<FATAL>|<PANIC>']

output.elasticsearch:
  hosts: ["http://<elasticsearch_ip>:9200"]
  index: "vertica-error-%{+yyyy.MM.dd}"

关键配置说明:

  • paths:通配符匹配各数据库、各节点的 vertica.log 路径
  • multiline:Vertica 的错误消息可能跨多行,以时间戳 ^\d{4}-... 作为行首标记合并后续行
  • include_lines:只采集 ERROR/FATAL/PANIC 级别,避免 INFO/DEBUG 撑爆索引

告警规则示例(Elasticsearch Watcher 或 Grafana Alert):

  • 最近 5 分钟内 <PANIC> 条目数 > 0 → 立即通知
  • 最近 15 分钟内 <FATAL> 条目数 > 5 → 警告

4.4 Logrotate 确保日志不撑爆磁盘

Vertica 安装时会在 dbadmin 用户的 crontab 中自动配置日志轮转任务,无需手动创建:

$ crontab -l -u dbadmin
# Vertica administrator cron
   5  3  *  *  *   /opt/vertica/oss/python3/bin/python3 -m vertica.do_logrotate &> /dev/null

该任务每天凌晨 3:05 执行,读取各节点 /opt/vertica/config/logrotate/<数据库名> 下的配置文件进行轮转。默认策略(不同环境下策略可能不同)为:

  • 每周轮转weekly),保留 52 周
  • 日志超过 10 MB 触发轮转size 10M
  • 轮转后压缩compress
  • 不创建新空文件nocreate),而是通过 kill -USR1 信号通知 Vertica 进程重新打开日志句柄

磁盘一旦写满,Vertica 会拒绝写入操作。因此建议定期检查:

  1. dbadmin 的 crontab 是否存在且可正常执行
  2. 各节点 /opt/vertica/config/logrotate/ 下的配置文件是否存在、路径是否匹配本节点
  3. 如果某节点缺少配置文件,从正常节点复制后修改日志路径为本节点路径

4.5 Scrutinize:一键收集全部诊断信息

当需要向 Vertica 技术支持提交问题时,scrutinize 工具打包所有诊断数据:

/opt/vertica/bin/scrutinize -d vmart3 -P 'dbadmin_password' -o /tmp/diag -z 3

参数说明:

  • -d:数据库名
  • -P:dbadmin 密码
  • -o:输出目录
  • -z:收集最近 N 天的日志(减少打包体积)

收集内容包括:vertica.log、Data Collector 表数据、系统表快照、Catalog 对象信息、集群配置等。


5. 深入案例

> 📝 虚构案例一:凌晨 ETL 批量查询导致 RESOURCE_REJECTED

场景:某金融机构(20 节点,每节点 256 GB,Vertica 12.0.x)的 ETL 调度在每日凌晨 2:00 执行。最近 DBA 发现凌晨 2:00-2:30 期间大量查询返回 ERROR: Insufficient resources

诊断过程

-- Step 1: 查看资源拒绝概况
SELECT POOL_NAME, RESOURCE_TYPE, REASON, REJECTION_COUNT,
       FIRST_REJECTED_TIMESTAMP, LAST_REJECTED_TIMESTAMP
FROM v_monitor.RESOURCE_REJECTIONS
WHERE FIRST_REJECTED_TIMESTAMP > '2026-05-31 01:00:00'
ORDER BY REJECTION_COUNT DESC;

输出显示 general 池的 memory 拒绝次数为 347 次,集中在 2:00-2:30。

-- Step 2: 查看拒绝细节,关联到具体查询
SELECT rrd.REJECTED_TIMESTAMP, rrd.SESSION_ID, rrd.USER_NAME,
       rrd.POOL_NAME, qr.REQUEST
FROM v_monitor.RESOURCE_REJECTION_DETAILS rrd
LEFT JOIN v_monitor.QUERY_REQUESTS qr
  ON rrd.SESSION_ID = qr.SESSION_ID
 AND rrd.TRANSACTION_ID = qr.TRANSACTION_ID
WHERE rrd.REJECTED_TIMESTAMP > '2026-05-31 02:00:00'
  AND rrd.REJECTED_TIMESTAMP < '2026-05-31 02:30:00'
ORDER BY rrd.REJECTED_TIMESTAMP DESC
LIMIT 20;

根因分析:凌晨 2:00 同时启动了 12 条大型 INSERT...SELECT 语句(ETL 调度配置了并行度为 12)。每条查询需要约 22 GB 内存,12 条 × 22 GB = 264 GB,而 general 池只有 230 GB(每节点 256 GB 物理内存 × 90%)。约有 2-3 条查询被拒绝,加上重试,半小时间累计 347 次拒绝事件。

修复方案

  1. 将 ETL 查询从 general 池迁移到专用 etl_pool,分配 60% 总内存(~153 GB),隔离 ETL 与业务查询的内存竞争
  2. 调度器层面将同时启动的 ETL 作业数从 12 降为 4,与资源池容量匹配——原问题是调度器无节制地并行提交了 12 个独立 vsql 会话,远超池内存容量
  3. 对 etl_pool 设置 MAXCONCURRENCY = 4,作为第二道防线——即使调度器偶尔超发,资源池也会排队而非拒绝

效果对比

指标 修复前 修复后
每日 REJECTION_COUNT 347 0
ETL 完成时间 部分失败需重跑 ~45min 稳定 28min
general 池其他查询 凌晨受影响 不受影响

> 📝 虚构案例二:SQL 错误码 8912 — 数据库存储路径被 OS 自动清理

场景:某零售企业(3 节点,Vertica 24.1.x)的批处理程序在每月初执行时大量报错 ERROR 8912: FileColumnReader: unable to open position index

诊断过程

-- Step 1: 查看错误分布
SELECT ERROR_CODE, COUNT(*) AS cnt, NODE_NAME, MIN(EVENT_TIMESTAMP)
FROM v_monitor.ERROR_MESSAGES
WHERE EVENT_TIMESTAMP > '2026-05-01'
  AND ERROR_CODE = 8912
GROUP BY ERROR_CODE, NODE_NAME
ORDER BY cnt DESC;

发现所有 3 个节点都有此错误,说明是集群级别的问题。

-- Step 2: 查看存储位置配置
SELECT * FROM v_monitor.STORAGE_LOCATIONS;

发现 /tmp/rejects 路径被配置为 DATA,TEMP 用途——这是问题的根源。

根因分析:Linux 的 systemd-tmpfiles-clean 服务(或 tmpwatch)会定期清除 /tmp 下的旧文件,而 Vertica 的某些数据文件恰好在 /tmp/rejects 下。当文件被 OS 删除后,后续查询读取到不存在的文件句柄,抛出 ERROR 8912。

修复方案

  1. 立即移除:SELECT DROP_LOCATION('/tmp/rejects', '');
  2. /data 分区下创建专用路径:SELECT ADD_LOCATION('/data/rejects', '', 'DATA,TEMP');

教训永远不要将 Vertica 的数据存储路径放在 /tmp/tmp 是操作系统管理的临时目录,可能随时被清理。

> 📋 真实案例一:内部断言失败导致节点 PANIC

场景:某运营商(138 节点,Vertica 9.x)的一个节点突然 PANIC 宕机。

故障现象:vertica.log 中出现 PANIC 级别错误:

PANIC: VX001/5445: VIAssert(inProcessItems.count(ptr) == 0) failed
  File: /path/to/SomeFile.cpp
  Line: 1234

诊断步骤

  1. ERROR_MESSAGES 找到失败的事务 ID:
SELECT time, node_name, user_name, transaction_id, file_name, function_name, log_message
FROM dc_errors
WHERE time BETWEEN '2020-01-01 14:03:00' AND '2020-01-01 14:15:00'
  AND log_message ILIKE '%inProcessItems%'
ORDER BY time;
  1. 根据 transaction_id 找到出错的 SQL:
SELECT node_name, user_name, session_id, transaction_id, request
FROM query_requests
WHERE transaction_id = 58546795181444339 AND NOT success
ORDER BY start_timestamp;

根因VIAssert 失败是 Vertica 内部软件逻辑错误,即 bug(VER-70190)。触发条件是特定模式的查询在处理过程中出现内部数据结构不一致。

修复:升级 Vertica 版本以包含 bug 修复。短期措施:启用 coredump(ulimit -c unlimited),以便后续出现时能收集完整的崩溃文件送研发分析。

关键收获:当 ERROR_MESSAGES 中的错误是 VIAssert 或 SIGSEGV/SIGABRT 时,通常不是操作问题,而是需要升级到包含修复的版本。

> 📋 真实案例二:OOM Killer 导致单节点频繁宕机

场景:某制造企业(单节点,Vertica 9.x,K-safe=0)数据库频繁因 OOM Killer 宕机。

故障现象:数据库间歇性无响应,节点进程消失。vertica.log 中没有明确的 ERROR 或 PANIC(进程被 SIGKILL 杀死的瞬间来不及写日志)。但 MemoryReport.log 中记录了 RSS 从 83% 攀升至 99% 的过程。

诊断步骤

  1. 确认 OOM Killer:dmesg -T | grep "Killed process"
  2. 从 MemoryReport.log 追溯内存增长时间线,定位到一条特定的 SQL 消耗了 117 GB 内存
  3. 检查资源池配置:MAXMEMORYSIZE = 95%(在 256 GB 服务器上预留仅 12.8 GB 给 OS)

根因:K-safe=0 + 资源池内存设置过高(95%),单条异常 SQL 吃掉了几乎所有内存,Linux OOM Killer 直接终止了 Vertica 进程。

修复

  1. MAXMEMORYSIZE 从 95% 降至 90%(为 OS 预留 ~25 GB),调整 general 资源池 MAXMEMORYSIZE 设置需要重启数据库生效。
  2. 升级 K-safety 到 K=1(需要加节点)
  3. 为高内存消耗的 ETL SQL 添加优化(投影设计 + 统计信息收集)

效果:修复后再未发生 OOM 宕机。

关键收获:当 vertica.logERROR_MESSAGES 都无异常但进程突然消失时,90% 是 OOM Killer。/var/log/messages 是此场景的关键诊断入口。


6. 完整诊断流程实战

> 📝 虚构场景 · 完整演练

模拟场景:某个周一早上 9:00,DBA 接到用户电话:「昨天还好好的,今天所有查询都跑不了,一直报错。」

时间线

09:05 — 第一步:确认集群状态

SELECT NODE_DOWN_COUNT, NODE_COUNT, CURRENT_FAULT_TOLERANCE FROM v_monitor.SYSTEM;

输出:NODE_DOWN_COUNT = 1, NODE_COUNT = 5, CURRENT_FAULT_TOLERANCE = 1

判断:K-safety 正常(还有容错),但有一个节点宕机,需要立刻处理。

09:06 — 第二步:找到宕机节点和时间

SELECT NODE_NAME, NODE_STATE, EVENT_TIMESTAMP
FROM v_monitor.NODE_STATES
WHERE EVENT_TIMESTAMP > CURRENT_TIMESTAMP - INTERVAL '2 hours'
  AND NODE_STATE IN ('DOWN')
ORDER BY EVENT_TIMESTAMP DESC;

输出:v_mydb_node0004 于 08:47 DOWN。

09:08 — 第三步:查看节点宕机前后的错误

SELECT EVENT_TIMESTAMP, ERROR_CODE, ERROR_LEVEL, MESSAGE, NODE_NAME
FROM v_monitor.ERROR_MESSAGES
WHERE NODE_NAME = 'v_mydb_node0004'
  AND EVENT_TIMESTAMP BETWEEN '2026-05-31 08:40:00' AND '2026-05-31 08:55:00'
ORDER BY EVENT_TIMESTAMP DESC;

输出:发现 ERROR 4534: Receive on v_mydb_node0001: Message receipt from v_mydb_node0004 failed 出现在节点宕机时间附近。

09:10 — 第四步:SSH 到宕机节点检查 OS 层面

ssh root@node4 'dmesg -T | tail -50'

发现:Out of memory: Killed process 12345 (vertica) — OOM Killer 确认。

09:12 — 第五步:检查宕机节点在宕机前运行的查询

ERROR_MESSAGES 中的 SESSION_ID 追溯到 QUERY_REQUESTS,找到时段内运行过的 3 条查询。其中一条是用户早上 8:30 手动提交的 SELECT * FROM huge_table ORDER BY ...,这条查询需要全表排序。

09:15 — 根因分析完成

  • 某用户在单节点上执行了大排序查询,消耗了该节点大量内存
  • 该节点 OS 内存不足 → OOM Killer 杀掉 Vertica 进程
  • 节点宕机 → 其他节点与它的通信失败 → 产生 ERROR 4534

09:20 — 修复执行

  1. 重启宕机节点并等待恢复完成
  2. 临时将该用户的资源池 MAXQUERYMEMORYSIZE 限制为 8 GB
  3. 与该用户沟通,建议在 ORDER BY 大表时加上 LIMIT 或在离线批次处理

09:45 — 效果验证

SELECT NODE_DOWN_COUNT FROM v_monitor.SYSTEM;        -- 输出: 0

SELECT COUNT(*) FROM v_monitor.ACTIVE_EVENTS
WHERE EVENT_SEVERITY IN ('Critical', 'Warning');     -- 输出: 0(Low Disk Space 除外)

SELECT RECOVERY_PHASE, IS_RUNNING FROM v_monitor.RECOVERY_STATUS
WHERE NODE_NAME = 'v_mydb_node0004';                  -- 输出: Completed, false

恢复完成,服务正常。从用户报障到解决问题,总耗时 40 分钟。


7. 快速诊断 SQL 工具箱

诊断目标 SQL 说明
集群健康检查 SELECT NODE_DOWN_COUNT, CURRENT_FAULT_TOLERANCE FROM v_monitor.SYSTEM; 1 行,最快判断是否有节点宕机
最近 1 小时错误分布 SELECT ERROR_LEVEL, COUNT(*) FROM v_monitor.ERROR_MESSAGES WHERE EVENT_TIMESTAMP > CURRENT_TIMESTAMP - INTERVAL '1 hour' GROUP BY ERROR_LEVEL; 宏观了解错误态势
高频错误 Top 10 SELECT ERROR_CODE, ERROR_LEVEL, COUNT(*) AS cnt FROM v_monitor.ERROR_MESSAGES WHERE EVENT_TIMESTAMP > CURRENT_TIMESTAMP - INTERVAL '24 hours' AND ERROR_LEVEL IN ('ERROR','FATAL') GROUP BY ERROR_CODE, ERROR_LEVEL ORDER BY cnt DESC LIMIT 10; 找反复出现的错误
当前活跃严重事件 SELECT * FROM v_monitor.ACTIVE_EVENTS WHERE EVENT_SEVERITY IN ('Critical','Warning'); 待处理问题清单
Data Collector 丢数据检查 SELECT COMPONENT, LOST_RECORDS FROM v_monitor.DATA_COLLECTOR WHERE LOST_RECORDS > 0; 确认看到的错误是否完整
资源拒绝汇总 SELECT POOL_NAME, RESOURCE_TYPE, REASON, REJECTION_COUNT FROM v_monitor.RESOURCE_REJECTIONS ORDER BY REJECTION_COUNT DESC; 按拒绝次数排序
某会话的错误详情 SELECT * FROM v_monitor.ERROR_MESSAGES WHERE SESSION_ID = ':s_id' ORDER BY EVENT_TIMESTAMP DESC; 替换 :s_id 为实际会话 ID
登录失败分析 SELECT USER_NAME, CLIENT_HOSTNAME, REASON, COUNT(*) FROM v_monitor.LOGIN_FAILURES WHERE LOGIN_TIMESTAMP > CURRENT_TIMESTAMP - INTERVAL '1 hour' GROUP BY USER_NAME, CLIENT_HOSTNAME, REASON; 安全审计
节点状态变更历史 SELECT NODE_NAME, NODE_STATE, EVENT_TIMESTAMP FROM v_monitor.NODE_STATES WHERE EVENT_TIMESTAMP > CURRENT_TIMESTAMP - INTERVAL '1 day' ORDER BY EVENT_TIMESTAMP DESC; 重建宕机时间线
恢复进度检查 SELECT NODE_NAME, RECOVERY_PHASE, IS_RUNNING FROM v_monitor.RECOVERY_STATUS WHERE IS_RUNNING = TRUE; 确认恢复是否在进行
查询执行事件(含建议) SELECT EVENT_TIMESTAMP, EVENT_TYPE, SUGGESTED_ACTION, NODE_NAME FROM v_monitor.QUERY_EVENTS WHERE SUGGESTED_ACTION IS NOT NULL ORDER BY EVENT_TIMESTAMP DESC LIMIT 20; 系统给出的优化建议
OOM 检查(Linux) dmesg -T \| grep -i "out of memory" \| tail -10 确认是否有 OOM Killer
PANIC 检查(vertica.log) grep -c '<PANIC>' /data/*/v_*_catalog/vertica.log 统计 PANIC 次数
scrutinize 收集 /opt/vertica/bin/scrutinize -d <DB名> -P <密码> -o /tmp/diag -z 3 提交技术支持

8. 最佳实践清单(按投入产出比排序)

  1. 先看 v_monitor.SYSTEM,再看 ERROR_MESSAGES:如果 NODE_DOWN_COUNT > 0,先处理节点宕机,再处理报错——节点宕机可能是根因,报错只是症状。

  2. 确认 logrotate 正常工作,避免磁盘写满:Vertica 安装时已在 dbadmin 用户 crontab 中自动配置日志轮转(详见 4.4 节),但需定期确认该任务可正常执行、/opt/vertica/config/logrotate/ 下配置存在且路径匹配。磁盘写满后所有写入操作报错,后果远比一个 vertica.log 过大严重。

  3. MAXMEMORYSIZE 设为 ≤ 90% 而非 95%:多个真实 OOM 案例的共同根因是资源池占用太多内存(95%),操作系统只剩不到 5% 可用于文件缓存和内核。留 10% 给 OS 是对 OOM 最便宜的保险。

  4. ERROR_MESSAGES 设置监控告警:每 5 分钟查询一次 ERROR_MESSAGESERROR_LEVEL IN ('ERROR', 'FATAL') 的计数。如果最近 5 分钟 FATAL > 0 或 ERROR > 50,触发告警。

  5. 定期检查 DATA_COLLECTOR.LOST_RECORDS > 0:如果 Error 组件丢数据,你需要立刻切换到 vertica.log 分析模式。丢失错误记录的时间越长,越可能错过关键诊断信息。

  6. 不要将数据库存储路径放在 /tmp/tmp 由 OS 管理,随时可能被 tmpwatch/systemd-tmpfiles 清理。ERROR 8912 的根本原因通常是这个。

  7. 排查 OOM 时,先看 /var/log/messages 再看 ERROR_MESSAGES:OOM Killer 发送的是 SIGKILL,Vertica 进程无法捕获和记录,所以 ERROR_MESSAGES 中不会有对应条目。Linux 系统日志是唯一线索。

  8. Scrutinize 日志保留至少 3 天,最好 7 天:很多故障是在事后分析时才需要完整的上下文。如果 Data Collector 淘汰了关键记录,vertica.log 是最后的希望。

  9. 遇到 FATAL 先排除 Client canceled session:这类 FATAL 不是真正的故障,只是客户端断开了连接。过滤条件:MESSAGE NOT ILIKE '%client canceled%'

  10. 建立错误码与解决方案的知识库映射:每个 ERROR_CODE 在 vault 中都应该有一个对应的排查案例或说明。常见的代码如 4534(节点通信失败)、8912(文件访问失败)、5157(Catalog 锁超时)应该做到看到即知处理方案。


扩展阅读

总结:Vertica 错误日志分析的核心心法可以归纳为三句话:

先看系统表,再看日志文件。先排除节点宕机和 OOM,再排查具体错误。先解决 FATAL 和 ERROR,再关注 WARNING。

当你在凌晨三点收到告警、摸黑打开 vsql 的时候,打开本文第 7 节的工具箱表格,按行执行——这 14 条 SQL 和 2 条 Linux 命令覆盖了 95% 的故障场景。