ITPub博客

首页 > 数据库 > 国内数据库 > OceanBase V4 故障应急:CPU 拉爆问题全面排查与止损指南

OceanBase V4 故障应急:CPU 拉爆问题全面排查与止损指南

原创 国内数据库 作者:瑞蓝创_RLC_888 时间:2026-08-13 17:00:52 0 删除 编辑

阅读前置知识: 了解 OB 多租户架构、Zone/Unit/Tenant 资源模型、LS(Log Stream) 与 Tablet 概念、Compaction 机制(major/minor/mini)、SQL 引擎执行链路(SQE → 优化器 → 执行引擎 → 存储引擎)

一、CPU 拉爆的定义与影响

1.1 什么是"CPU 拉爆"

在 OB 应急语境中, CPU拉爆(也叫 CPU 打满、CPU 顶满)指observer 进程的 CPU 使用率持续超过 80%,甚至跑到 100%,通常伴随以下级联故障:

  • SQL RT(Response Time)急剧飙升,从 ms 级恶化到秒级甚至分钟级
  • 工作线程队列堆积(queue congestion),大量 session 排队等待
  • OBProxy 侧连接打满,业务侧报 OB-4012: Timeout 或 -4016: Internal Error
  • 严重时 observer 进程 hang 住(假死)或被系统 OOM Killer 杀掉,触发 Paxos 重新选主

OB 黑话科普:OB 内部我们一般说"CPU 拉爆"而不是"CPU 打爆","拉"字体现的是 CPU 被 SQL 或后台任务逐步拉上去的过程,更贴合实际故障现象。

1.2 CPU 拉爆的典型影响链


CPU 拉爆

  → 工作线程(worker thread)排队等不到 CPU 时间片
    → SQL RT 飙升,elapsed_time 中 queue_time 占比增大
      → OBProxy 侧连接池占满,新请求被 reject
        → 业务侧报 Timeout(-4012) / Connection Refused
          → 应用重试风暴 → 进一步加剧 CPU 压力(雪崩效应)
            → 业务全面中断,触发 GOC 应急

1.3 V4 单进程架构下 CPU 问题的特殊性

V4 相比 V3 架构做了重大重构,CPU 问题的排查思路也有本质区别:

维度 V3.x(多进程) V4.x(单进程多线程)
进程模型 每个 Zone 一个 observer 进程,多进程隔离 一个物理机只有一个 observer 进程,所有租户共享
租户隔离 进程级天然隔离 线程级隔离,依赖内部调度( _enable_cgroup)
CPU 互影响 Zone 间互不影响 一个租户的 CPU 问题可能拖垮整个 observer,影响同机所有租户
诊断方式 top 看各 observer 进程 top -H -p 看线程级 CPU
资源管理 靠操作系统分配 Resource Pool + Unit 配置 + 内部线程池调度
关键风险 单 Zone 挂掉 单进程 hang → 整个节点不可用 → Paxos 触发选主(election)

V4 核心概念提醒:V4 中每个 observer 内部由多个 Log Stream (LS) 承载数据,每个 LS 下有多个 Tablet。SQL 执行链路经过 SQE(SQL Query Engine)解析优化后,由 PX/DFO 分发到各 tablet 所在节点执行。理解这条链路对定位 CPU 热点至关重要。

二、CPU 拉爆的根因分类

根据 GOC 处理过的大量 P0/P1/P2 应急案例复盘,CPU 拉爆的根因可分为 六大类:

分类总览


CPU 拉爆根因分类(按 GOC 实战频率排序)

├── A. SQL 层面(最常见,~50%)— 慢SQL / 计划走飞 / 并发打满
├── B. Compaction 等后台任务(~15%)— major freeze / minor compaction / dump
├── C. 内核热点 / 已知缺陷(~15%)— kvcache CAS / latch 竞争 / 内存分配热点
├── D. 资源不足 / 参数配置不当(~10%)— unit 配小了 / 线程池参数不对
├── E. 业务突增 / 流量异常(~5%)— 重试风暴 / 连接风暴 / 缓存穿透
└── F. 系统层面问题(~5%)— NUMA / THP / swap / 内核参数

A. SQL 层面问题(最高频,应急第一排查对象)

A1. 慢 SQL 导致 CPU 堆积

典型表现:

  • 少量 SQL 的 elapsed_time 极高,在 gv$sql_audit 中一目了然
  • logical_reads(逻辑读)或 get_count(KV 层 get 次数)极大
  • 执行计划走飞,该走索引的走了全表扫描( PHY_TABLE_SCAN)

常见场景:

场景 sql_audit 特征 执行计划特征 应急手段
全表扫描 table_scan=TRUE, logical_reads 百万级 PHY_TABLE_SCAN 无索引 加索引 / 绑 plan baseline
Nested Loop Join 爆炸 大表 JOIN, return_rows 巨大 NESTED-LOOP JOIN 无 Hash/Merge 加 Hint /*+ USE_HASH */ / 加索引
索引走飞 明明有索引但走了全表扫描 plan_hash_value 变了 检查统计信息 / ANALYZE 重新收集
COUNT(*) 大表 单条 SQL 执行几十秒 PHY_TABLE_SCAN + PHY_COUNT 业务侧改造 / 缓存计数
相关子查询未展开 execute_count 巨大(逐行执行) SUBPLAN SCAN 嵌套 改写为 JOIN
LIKE '%xxx' 前模糊 无法使用 B-tree 索引 PHY_TABLE_SCAN 全文索引 / ES 外置
大事务 / 批量 DML affected_rows 巨大, elapsed_time 长 — 拆分事务 / 分批执行

排查命令(应急三板斧):



-- 【第一斧】查当前在跑的慢 SQL(is_exit=0 表示还在执行)

SELECT tenant_id, svr_ip,  sid, trace_id,
        LEFT(query_sql,  200)  AS sql_text,
       elapsed_time /  1000000  AS elapsed_sec,    -- 微秒转秒
       queue_time /  1000000  AS queue_sec,        -- 排队耗时
       logical_reads, physical_reads, get_count,  -- 逻辑读/物理读/KV get
       plan_type,  -- 0=本地计划 1=远程 2=分布式
       is_inner_sql
FROM oceanbase.gv$sql_audit
WHERE is_exit =  0
   AND elapsed_time > 1000000   -- 超过 1 秒
ORDER BY elapsed_time DESC
LIMIT 20;

-- 【第二斧】查执行计划(确认是否走飞)
EXPLAIN  EXTENDED ;
-- 或用 EXPLAIN FORMAT=JSON 看详细代价
EXPLAIN  FORMAT= JSON ;

-- 【第三斧】查 Top SQL 排行(按 CPU 总消耗排序,抓真正的 CPU 大户)
SELECT sql_id,
        LEFT( MIN(query_sql),  120)  AS sql_text,
        COUNT(*)  AS exec_count,
        ROUND( AVG(elapsed_time)/ 1000000,  2)  AS avg_rt_sec,
        ROUND( SUM(cpu_time)/ 1000000,  2)  AS total_cpu_sec,
        ROUND( AVG(logical_reads),  0)  AS avg_logical_reads,
        ROUND( AVG(get_count),  0)  AS avg_get_count
FROM oceanbase.gv$sql_audit
WHERE request_time > UNIX_TIMESTAMP(NOW() - INTERVAL 10 MINUTE) * 1000000
GROUP BY sql_id
ORDER BY total_cpu_sec DESC
LIMIT 20;

OB 老兵经验: plan_type 字段很关键 —— 0 是本地计划(Local Plan),2 是分布式计划(Dist Plan)。如果是分布式计划拉爆 CPU,说明涉及多机 shuffle,需要关注 PX worker 的并行度和数据倾斜。

A2. 执行计划走飞(Plan Regression)

典型表现:

  • 之前跑得快的 SQL 突然变慢,RT 从 ms 级跳到秒级
  • plan_hash_value 发生变化,走了不同的物理执行计划
  • sql_audit 中 plan_type 可能从 0(本地计划)变成 2(分布式计划),代价陡增

常见原因:

  • 统计信息过期:大批量 DML(INSERT/DELETE)后未触发自动统计信息收集,优化器基于过期的 NDV(列基数)/num_rows 选了错误计划
  • major compaction 后计划失效:合并后 broadcast_version 推进,plan cache 中旧计划失效,重新生成可能选错
  • 参数变更: optimizer_* 系列参数或 _nlj_batching_enabled 等隐藏参数被改过
  • 全局索引失效:分区表的全局索引变为 UNUSABLE,导致回退到全表扫描

应急手段:



-- 1. 检查统计信息是否过期(关注 last_analyzed 和 stale_stats)

SELECT owner, table_name, last_analyzed, num_rows, stale_stats
FROM oceanbase.dba_tab_statistics
WHERE table_name =  UPPER( '');

-- 2. 手动收集统计信息(触发优化器重新感知数据分布)
ANALYZE  TABLE .  COMPUTE  STATISTICS;
-- 或者增量收集(大表推荐,更快)
ANALYZE  TABLE .  COMPUTE  STATISTICS  FOR  ALL  COLUMNS  SIZE  AUTO;

-- 3. 绑定执行计划(SPM - SQL Plan Management)
-- 先从 sql_audit 找到之前跑得好的 plan_hash_value
SELECT sql_id, plan_hash_value, elapsed_time, plan_type
FROM oceanbase.gv$sql_audit
WHERE sql_id =  ''
ORDER  BY elapsed_time  ASC  LIMIT  5;

-- 用 plan baseline 固定好的计划
SELECT *  FROM oceanbase.dba_sql_plan_baselines
WHERE sql_handle  LIKE  '%%';

-- 4. 紧急场景:直接清 plan cache 让所有计划重新生成
-- 注意:这是双刃剑,清完会短暂 CPU 尖刺(重新编译计划)
ALTER  SYSTEM  SET plan_cache_evict_interval =  '5s';
-- 等恢复后记得改回来

A3. SQL 并发打满(Concurrent Overload)

典型表现:

  • 同一类 SQL 大量并发执行, gv$sql_audit 中同一 sql_id 出现几十上百条 is_exit=0
  • queue_time 显著增大(排队时间可能超过实际执行时间)
  • CPU 跑到 100% 但单条 SQL 的 cpu_time 并不算很高(CPU 时间片被争抢)
  • gv$ob_sql_workarea_memory_info 中 queue_size 持续走高

排查与应急:



-- 1. 查看当前各 SQL 的并发数(哪些 SQL 在排队)

SELECT sql_id,  COUNT(*)  AS concurrent_cnt,
        ROUND( AVG(queue_time)/ 1000000,  2)  AS avg_queue_sec,
        ROUND( AVG(elapsed_time)/ 1000000,  2)  AS avg_elapsed_sec
FROM oceanbase.gv$sql_audit
WHERE is_exit =  0
GROUP  BY sql_id
ORDER  BY concurrent_cnt  DESC
LIMIT  10;

-- 2. 查看线程队列堆积情况
-- V4 中每个租户有独立的 request queue
SELECT tenant_id, svr_ip,
       in_queue_count, queue_size
FROM oceanbase.gv$tenant_runtime_info;

-- 3. 设置 query timeout 兜底(防止 SQL 长期霸占 CPU)
ALTER  SYSTEM  SET ob_query_timeout =  10000000 TENANT =  '';  -- 10秒
-- 或 session 级别
SET ob_query_timeout =  10000000;  -- 当前会话生效

-- 4. 紧急 Kill 会话(先确认不是关键 DML 事务!)
SHOW  FULL  PROCESSLIST;
KILL ;

-- 5. 通过 OCP 设置租户级并发限制(Resource Manager)
-- V4 支持通过 DBMS_RESOURCE_MANAGER 控制租户内资源组的并发
CALL DBMS_RESOURCE_MANAGER.CREATE_PLAN( 'emergency_plan');
CALL DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(
  plan => 'emergency_plan',
  group_or_subplan => 'default',
  max_concurrency => 100   -- 限制最大并发
);

OB 老兵提醒:Kill 会话之前务必确认 trans_id,如果是大事务(affected_rows 很大),Kill 后回滚(rollback)也要消耗大量 CPU,可能短暂加剧问题。可以先让业务侧停发请求,等 CPU 降下来再处理。

B. Compaction 等后台任务拉 CPU

OB 背景知识:OB 存储引擎是 LSM-Tree 架构,数据先写 MemTable,达到阈值后 freeze → dump 成 mini SSTable,然后通过 mini compaction / minor compaction / major compaction 逐层合并。每一层 compaction 都会消耗 CPU + IO。

B1. Major Compaction(每日合并 / major freeze)拉 CPU

典型表现:

  • 合并期间 CPU 明显升高(尤其是存储压缩解压的 CPU 开销)
  • __all_virtual_zone_merge_info 中 major_compact_status = COMPACTING
  • __all_virtual_tablet_compaction_progress 能看到大量 tablet 在合并
  • OCP 上能看到合并任务在跑

排查与应对:



-- 1. 检查各 Zone 合并状态

SELECT zone, major_compact_status, broadcast_version,
       gmt_create  AS last_start_time, last_finish_time
FROM oceanbase.__all_virtual_zone_merge_info;

-- 2. 检查 tablet 级合并进度(看还有多少没合完)
SELECT tenant_id, zone,  status,
        COUNT(*)  AS tablet_cnt
FROM oceanbase.__all_virtual_tablet_compaction_progress
GROUP  BY tenant_id, zone,  status;

-- 3. 检查是否有合并报错(卡住的合并可能拉 CPU)
SELECT *  FROM oceanbase.__all_virtual_zone_merge_info
WHERE major_compact_status =  'ERROR';

-- 4. 【紧急】暂停合并(业务高峰期拉 CPU 时的第一止损手段)
ALTER  SYSTEM  SUSPEND  MERGE;

-- 5. 【低峰期】恢复合并
ALTER  SYSTEM  RESUME  MERGE;

-- 6. 调整合并时间窗口(避免高峰期触发 major freeze)
ALTER  SYSTEM  SET merge_schedule_policy =  'schedule_time=02:00-06:00';
-- 或者通过 OCP 设置“合并时间窗口”

OB 老兵经验:major compaction 的 CPU 消耗主要来自 SSTable 数据的压缩/解压和重写。如果开了 zstd 压缩,合并时 CPU 开销会更大。可以临时把 compaction_memory_bytes_limit 调小来降低合并并发。

B2. Minor Compaction / Dump 过于频繁

典型表现:

  • 写入压力大的租户,MemTable 频繁 freeze + dump
  • __all_virtual_tablet_compaction_progress 中大量 mini/minor compaction 任务堆积
  • 写放大严重,CPU 和 IO 同时拉高

应对:



-- 调整写入限速阈值(避免写入过快导致 MemTable 爆仓)

ALTER  SYSTEM  SET writing_limit_trigger_percentage =  80;

-- 调整 minor compaction 触发阈值
ALTER  SYSTEM  SET minor_compact_trigger =  4;   -- mini sstable 数达到 4 时触发 minor

-- 检查 MemTable 内存使用(是否快爆了)
SELECT tenant_id, svr_ip, freeze_trigger,
       memstore_used, memstore_limit
FROM oceanbase.gv$tenant_runtime_info;

B3. 其他后台任务

后台任务 OB 术语 CPU 影响 控制手段
日志归档 log_archive_dest clog/ilog 归档消耗 CPU + 网络 IO ALTER SYSTEM SET log_archive_concurrency = 2
数据备份 backup_data 全量/增量备份消耗 CPU + 磁盘 IO 调整备份窗口,避开业务高峰
日志回放 replay / apply 备集群回放 clog 消耗 CPU 检查回放延迟( gv$ob_log_stat)
统计信息收集 auto_analyze 后台全表扫描消耗 CPU 调整自动收集窗口
PDML Parallel DML 并行 DML 占用 PX worker 线程 调低 parallel_servers_target
location cache 刷新 location_cache 内部元数据操作 一般不需干预,异常时检查 RS 状态
选举 (election) paxos election leader 切换期间短暂 CPU 尖峰 一般不需干预,频繁选举需检查网络

C. 内核热点

C1. KVCache 原子引用计数热点

问题描述:

  • OBServer 存储引擎层的 KVCache(行缓存)的引用计数 ( ref_cnt) 和序列号 ( seq_num) 共用一个 int64
  • 高并发下 CAS(Compare-And-Swap)操作频繁失败,CPU 空转(spin)
  • 火焰图特征: dec_ref_cnt_and_inc_seq_num 函数占比显著(超过 5%)

触发条件:

  • 高并发点查 + 索引回表场景(非覆盖索引 → 通过 SSTable 回表 → 经过 KVCache → 触发热点)
  • row cache 越小(内存规格越低),同一个 2M block 上不同 KV 越多,命中概率越高

影响版本:V4.2.x BP 系列及更早版本, V4.3.5 已修复(重构了引用计数实现)

排查方法:



# 1. 抓取火焰图(perf,这是定位内核热点的核武器)

perf record -g -p $(pgrep observer) -- sleep 30
perf report --stdio > perf_report.txt

# 2. 检查热点函数(看占比)
perf report --sort=symbol | head -30

# 3. 关注以下调用栈(看到这个栈基本就是 KVCache 热点)
# ObSSTableMultiPrefetcher::~ObSSTableMultiPrefetcher
#   → ObKVCacheHandle::~ObKVCacheHandle
#     → ObAtomicReference::dec_ref_cnt_and_inc_seq_num  ← 热点函数

# 4. 也可以用 obdiag 一键采集
obdiag gather all --since  "30m"
# 采集结果发给研发分析

应急手段(按优先级):

优先级 止损措施 原理
P0 紧急 创建覆盖索引 CREATE INDEX idx ON t(col) STORING (所有查询列) 避免回表,彻底绕过 KVCache 热点路径
P1 短期 将大表改为分区表 打散流量到多个节点,降低单机并发
P2 短期 切回原环境(如 ARM 切回 x86) x86 单核性能更强,触发概率更低
P3 长期 升级 OBServer 至 V4.3.5+ 内核层面修复了引用计数实现

C2. Latch 竞争热点

常见场景:

  • 高并发下内部 latch(轻量锁)竞争,CPU 在 spin-wait 上空转
  • plan cache latch(plan cache 淘汰时加锁竞争)
  • alloc/dealloc 热点( ob_malloc / ob_free 或 jemalloc 相关)
  • row lock(行锁)争用,事务并发过高

排查:



# perf 抓取锁热点

perf record -e cycles -g -p $(pgrep observer) -- sleep 10
perf report --sort=symbol,dso

# 关注以下函数
# - ob_latch_rdlock / ob_latch_wrlock  ← OB 内部 latch
# - ob_malloc / ob_free / je_malloc    ← 内存分配热点
# - __pthread_mutex_lock               ← 系统级锁竞争


-- 查看 latch 统计(哪个 latch 竞争最严重)

SELECT latch_id,  name, gets, misses,
        ROUND(misses/ NULLIF(gets, 0)* 100,  4)  AS miss_pct
FROM oceanbase.gv$latch
WHERE misses > 0
ORDER BY misses DESC
LIMIT 20;

C3. Plan Cache 问题

问题:plan cache 过大导致淘汰时 CPU 升高;或 plan cache 命中率低,大量 SQL 需要重新编译计划



-- 检查 plan cache 状态(关注命中率和内存使用)

SELECT tenant_id, svr_ip,
       plan_cache_size, mem_used, plan_num,
        ROUND(hit_count/ NULLIF(access_count, 0)* 100,  2)  AS hit_pct
FROM oceanbase.gv$plan_cache_status;

-- plan cache 命中率低于 90% 需要关注
-- 必要时清理 plan cache(谨慎操作,会短暂 CPU 尖峰)
ALTER  SYSTEM  SET plan_cache_evict_interval =  '30s';
-- 恢复后改回默认

D. 资源不足 / 参数配置不当(Unit 配小了 / 线程池不对)

D1. 租户 CPU Unit 配小了

V4 中租户资源通过 Resource Pool → Resource Unit 模型管理。Unit 的 min_cpu / max_cpu 决定了租户能拿到的 CPU 上下限。



-- 1. 检查租户资源单元配置

SELECT t.tenant_name, t.tenant_id,
       u.unit_config_id, u.unit_name,
       u.min_cpu, u.max_cpu,
       u.memory_size/ 1024/ 1024/ 1024  AS memory_gb
FROM oceanbase.dba_ob_tenants t
JOIN oceanbase.dba_ob_resource_pools p  ON t.tenant_id = p.tenant_id
JOIN oceanbase.dba_ob_unit_configs u  ON p.unit_config_id = u.unit_config_id;

-- 2. 检查各节点 CPU 实际分配情况
SELECT svr_ip, tenant_id,
        SUM(cpu_assigned)  AS cpu_assigned,
        SUM(cpu_used_max)  AS cpu_used_max
FROM oceanbase.gv$ob_processlist
GROUP  BY svr_ip, tenant_id;

-- 3. 【紧急扩容】调大 Unit 的 CPU(OCP 操作更方便)
ALTER  RESOURCE UNIT  MIN_CPU =  16, MAX_CPU =  32;

-- 4. 如果集群有富余节点,也可以通过加 Unit 横向扩容
-- 通过 OCP “增加 Unit” 操作

OB 老兵提醒:V4 中 min_cpu 是硬保障(预留), max_cpu 是上限。如果 min_cpu 设小了,即使机器有空闲 CPU,租户也拿不到。OLTP 业务建议 min_cpu = max_cpu,不超卖。

D2. 内存不足触发 Swap / 内存泄漏

表现:CPU 高 + iowait 高 + vmstat 的 si/so 不为 0(在用 swap)



-- 检查各租户内存使用

SELECT svr_ip, tenant_id,
        ROUND(mem_used/ 1024/ 1024/ 1024,  2)  AS mem_used_gb,
        ROUND(mem_limit/ 1024/ 1024/ 1024,  2)  AS mem_limit_gb,
        ROUND(mem_used/mem_limit* 100,  2)  AS mem_pct
FROM oceanbase.gv$tenant_runtime_info;

-- 检查模块级内存使用(看哪个模块吃内存最多)
SELECT tenant_id, svr_ip,  module,
        ROUND(hold/ 1024/ 1024,  0)  AS hold_mb,
        ROUND(used/ 1024/ 1024,  0)  AS used_mb
FROM oceanbase.gv$ob_memory
WHERE hold > 100*1024*1024   -- 超过 100MB 的模块
ORDER BY hold DESC;


# 系统层面检查 swap

free -h
vmstat 1 5
# si/so 不为 0 → 说明在用 swap → observer 性能会严重下降

D3. 关键系统参数配置不当

参数 默认值 OLTP 建议 影响 OB 内部说明
workers_per_cpu_quota 10 8-10 每个 CPU quota 对应的工作线程数 调太大会导致上下文切换加剧
cpu_reserved_cores 0 2-4 预留给系统线程(RS、timer 等) 调太小会导致系统线程抢不到 CPU
sys_cpu_limit_trigger 80 保持默认 系统线程 CPU 限制触发阈值 触发后系统线程会被限速
large_query_cpu_time_threshold 100ms 按业务调整 大查询识别阈值 超过此值的查询会被调度到大查询队列
enable_sql_operator_dump True 保持开启 SQL 算子落盘 防止 hash join/sort 内存爆掉
px_workers_per_cpu_quota 10 OLTP 建议 1-2 PX worker 线程比例 OLTP 场景调低,避免 PX 抢占 worker 线程
_enable_cgroup True 保持开启 租户间 CPU 隔离 关闭会导致租户间 CPU 互相抢
_hash_group_by_no_sort True 保持默认 hash group by 优化 影响聚合类 SQL 的执行效率

E. 业务突增 / 流量异常(连接风暴 / 重试风暴)

E1. 业务 QPS 突增

典型场景:

  • 促销活动、定时任务集中触发,OBProxy 侧 QPS 陡增
  • 上游重试风暴(网络抖动后应用侧疯狂重试)
  • Redis/缓存失效导致的数据库穿透(cache miss storm)

应急手段:



-- 1. 确认连接数 / QPS 变化

SELECT svr_ip, tenant_id,  COUNT(*)  AS session_count
FROM oceanbase.gv$ob_processlist
GROUP  BY svr_ip, tenant_id;

-- 2. 设置连接数上限(防止雪崩)
ALTER  SYSTEM  SET max_connections =  500;

-- 3. 租户级限流(V4 Resource Manager 支持)
CALL DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(
  plan => 'peak_protection',
  group_or_subplan => 'app_group',
  max_concurrency => 200,   -- 限制最大并发
  max_iops => 10000,
  mgmt_p1 => 50
);

-- 4. 业务侧配合:让应用侧临时停发请求 / 加指数退避

E2. 连接风暴

表现:短时间内大量新连接涌入,OBProxy 的连接打满,observer CPU 瞬间拉爆

OB 特有现象:连接建立时需要做认证、分配 session 内存,大量并发连接会触发 observer 内部内存分配热点。



-- 快速查看当前连接状态

SHOW  FULL  PROCESSLIST;

-- 查看各租户连接分布
SELECT tenant,  COUNT(*)  AS cnt, state
FROM information_schema.processlist
GROUP  BY tenant, state
ORDER  BY cnt  DESC;

-- 批量 Kill 空闲或异常连接(先确认不是关键业务!)
SELECT  CONCAT( 'KILL ',  id,  ';')
FROM information_schema.processlist
WHERE command =  'Sleep'  AND  time > 60;

F. 系统层面问题(observer 部署环境检查)

F1. NUMA 配置不当

OB 规范要求:observer 必须用 numactl --interleave=all 启动,否则跨 NUMA 节点内存访问会导致 CPU 开销显著增加。



# 检查 NUMA 状态

numactl --hardware
numactl --show

# 检查 observer 进程的 NUMA 策略
cat /proc/$(pgrep observer)/numa_maps | head -5

# 正确启动方式(必须在 observer 启动脚本中配置)
numactl --interleave=all /home/admin/oceanbase/bin/observer

F2. THP(Transparent Huge Pages)干扰

OB 规范要求:THP 必须关闭。THP 会导致内存分配时出现大页延迟,影响 observer 的 RT。



# 检查 THP 状态(应显示 [never])

cat /sys/kernel/mm/transparent_hugepage/enabled
# 关闭 THP
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

F3. 内核参数不符合 OB 部署规范



# OB 标准内核参数检查(与 obd 部署工具检查项对齐)

sysctl vm.swappiness           # 必须 = 0,禁止 swap
sysctl vm.overcommit_memory    # 建议 = 0
sysctl net.core.somaxconn      # 建议 >= 65535
sysctl net.ipv4.tcp_tw_reuse   # 建议 = 1
sysctl fs.file-max             # 建议 >= 655350

# 检查 observer 文件描述符限制
ulimit -n   # 建议 >= 655350

三、CPU 拉爆的应急排查 SOP(标准作业流程)

3.1 黄金 5 分钟排查流程


[0-1min]  确认问题 → 登录 OCP,看 CPU 监控趋势;确认是单节点还是全集群

    ↓
[1-2min]  定位线程 → SSH 到节点,top -H -p  看哪些线程 CPU 高
    ↓
[2-3min]  关联 SQL → 查 gv $sql_audit(is_exit=0),关联 trace_id 找到高 CPU SQL
    ↓
[3-4min]  判断类别 → 区分 SQL 问题 / Compaction 拉 CPU / 内核热点 / 资源不足
    ↓
[4-5min]  执行止损 → Kill SQL / SUSPEND MERGE / 扩 Unit / 限流

3.2 详细排查步骤

Step 1:系统层面快速诊断(SSH 到节点执行)



# 1.1 查看整体 CPU 使用(关注 us/sy/wa/id)

top -bn1 | head -20

# 1.2 查看 observer 线程级 CPU(V4 单进程,必须看线程)
top -H -p $(pgrep observer) -bn1 | head -40

# 1.3 查看 CPU 各核使用情况(是否有单核打满)
mpstat -P ALL 1 3

# 1.4 查看是否有 iowait(可能是 IO 问题伪装的 CPU 问题)
iostat -x 1 3
# 关注 await、util 指标,如果 await > 10ms 或 util > 90% → IO 瓶颈

# 1.5 查看 swap(observer 绝对不能用 swap)
free -h

# 1.6 查看系统日志是否有 OOM / observer crash
dmesg | grep -i  "oom\|killed\|out of memory" | tail -20

# 1.7 检查 observer 日志是否有异常(WARN/ERROR)
tail -1000 /home/admin/oceanbase/ log/observer.log | grep -E  'WARN|ERROR' | tail -20

Step 2:OB 内部诊断(通过 obclient 或 OCP 执行)



-- 2.1 查看当前活跃 SQL(is_exit=0 表示还在跑)

SELECT tenant_id, svr_ip,  sid, trace_id,
        LEFT(query_sql,  150)  AS sql_text,
       elapsed_time /  1000000  AS elapsed_sec,
       queue_time /  1000000  AS queue_sec,
       logical_reads, physical_reads, get_count,
       plan_type   -- 0=Local 1=Remote 2=Distributed
FROM oceanbase.gv$sql_audit
WHERE is_exit =  0
ORDER  BY elapsed_time  DESC
LIMIT  20;

-- 2.2 查看租户级别的 CPU 消耗(哪个租户在拉 CPU)
SELECT tenant_id, svr_ip,
        ROUND( SUM(cpu_time)/ 1000000,  2)  AS total_cpu_sec,
        COUNT(*)  AS active_sessions
FROM oceanbase.gv$sql_audit
WHERE request_time > UNIX_TIMESTAMP(NOW() - INTERVAL 5 MINUTE) * 1000000
GROUP BY tenant_id, svr_ip
ORDER BY total_cpu_sec DESC;

-- 2.3 查看等待事件(V4 性能诊断利器)
SELECT  event, wait_class,  COUNT(*)  AS wait_cnt,
        ROUND( AVG(wait_time_micro),  0)  AS avg_wait_us,
        ROUND( SUM(timeouts),  0)  AS total_timeouts
FROM oceanbase.gv$session_wait
GROUP  BY  event, wait_class
ORDER  BY wait_cnt  DESC
LIMIT  20;
-- 重点关注:
-- "row lock wait" → 行锁竞争
-- "SQL QUEUEING" → 工作线程不足,SQL 在排队
-- "PX QUEUEING" → PX worker 不够
-- "db file data read" → 物理 IO 多

-- 2.4 查看 Compaction 状态(是否在跑 major/minor)
SELECT zone, major_compact_status, broadcast_version
FROM oceanbase.__all_virtual_zone_merge_info;
SELECT tenant_id, zone,  status,  COUNT(*)  AS tablet_cnt
FROM oceanbase.__all_virtual_tablet_compaction_progress
GROUP  BY tenant_id, zone,  status;

-- 2.5 查看线程队列堆积
SELECT svr_ip, tenant_id,
       queue_size, in_queue_count
FROM oceanbase.gv$ob_sql_workarea_memory_info;

-- 2.6 查看 MemTable 内存状态(是否快爆了导致频繁 freeze)
SELECT tenant_id, svr_ip,
        ROUND(memstore_used/ 1024/ 1024/ 1024,  2)  AS memstore_used_gb,
        ROUND(memstore_limit/ 1024/ 1024/ 1024,  2)  AS memstore_limit_gb,
       freeze_trigger, active_freeze_trigger
FROM oceanbase.gv$tenant_runtime_info;

Step 3:线程级精准定位(perf + SQL Trace)



# 3.1 获取高 CPU 线程的 LWP(轻量级进程号)

top -H -p $(pgrep observer) -bn1 | awk  '$9 > 10 {print $1, $9}' | head -20

# 3.2 将 LWP 转为十六进制(用于关联 observer 日志中的线程号)
printf  '%x\n' 

# 3.3 通过 pstack 抓取线程栈(生产慎用,可能导致 observer 短暂 hang)
pstack $(pgrep observer) > pstack_$(date +%Y%m%d%H%M).txt

# 3.4 通过 perf 抓取火焰图(推荐!内核热点定位的终极武器)
perf record -g -F 99 -p $(pgrep observer) -- sleep 30
perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg

# 3.5 通过 obdiag 一键采集(最推荐,自动化程度高)
obdiag gather all --since  "30m"
# 会自动采集 perf、日志、sql_audit、系统信息等,打包发给研发


-- 3.6 V4 SQL Trace 诊断(推荐)

-- 开启 SQL Trace 捕获详细执行信息
ALTER  SYSTEM  SET trace_log_slow_query_watermark =  '1s';
-- 慢查询日志在 /home/admin/oceanbase/log/observer.log.slow_query

-- 3.7 关联 trace_id 查看完整执行链路
SELECT *  FROM oceanbase.gv$sql_audit
WHERE trace_id =  '';

四、分级应急策略

4.1 应急策略速查表

级别 场景 止损措施 预期恢复时间
P0-紧急 业务完全不可用,报 -4012/-4016 Kill 问题 SQL + 扩 Unit + 切流 1-5 分钟
P1-严重 业务严重降级,RT 恶化 10 倍+ SUSPEND MERGE + 限流 + 加索引 5-15 分钟
P2-一般 部分功能受影响 分析执行计划 + 加索引 + 绑 SPM 15-60 分钟
P3-观察 CPU 偏高但未影响业务 收集 perf + sql_audit 数据 + 制定优化方案 计划性处理

4.2 P0 紧急止损操作手册(“应急五步法”)



# ===== 第一步:快速 Kill 慢 SQL =====

# 通过 obclient 经 OBProxy 连接(也可以直接连 observer 的 2881 端口)
obclient -h -P -u@ # -p -D

# 找到问题 SQL 的 session
SELECT id, user, host, db,  command, time, state, LEFT(info, 100) AS sql_text
FROM information_schema.processlist
WHERE time > 5 AND  command !=  'Sleep'
ORDER BY time DESC;

# Kill 对应 session(注意:先确认不是关键 DML 事务!)
KILL ;

# ===== 第二步:紧急扩 Unit CPU =====
# 通过 OCP 操作更方便:租户管理 → 资源单元 → 修改
# 或通过 SQL
ALTER RESOURCE UNIT unit_xxx MIN_CPU = 32, MAX_CPU = 64;

# ===== 第三步:暂停 Compaction =====
ALTER SYSTEM SUSPEND MERGE;  -- 暂停 major compaction

# ===== 第四步:设置 SQL 超时兆底 =====
ALTER SYSTEM SET ob_query_timeout = 30000000 TENANT =  '';  -- 30秒
ALTER SYSTEM SET ob_trx_timeout = 30000000 TENANT =  '';   -- 事务超时 30秒

# ===== 第五步:如仍无法恢复,考虑重启 observer =====
# 注意:这是最后手段!
# 重启会触发 Paxos 选主,其他节点接管 leader,业务会短暂中断
# 必须通过 OCP 操作,不能手动 kill -9
# 重启前确认其他节点健康,避免多个节点同时不可用

4.3 应急 SQL 工具箱(建议保存为快捷脚本)



-- 批量生成 Kill 语句(超过 60 秒的非 Sleep 会话)

SELECT  CONCAT( 'KILL ',  id,  ';')
FROM information_schema.processlist
WHERE  time > 60 AND command != 'Sleep';

-- 最近 10 分钟 Top SQL(按 CPU 总消耗排序)
SELECT sql_id,
        LEFT( MIN(query_sql),  120)  AS sql_text,
        COUNT(*)  AS exec_cnt,
        ROUND( AVG(elapsed_time)/ 1000000,  2)  AS avg_rt_sec,
        ROUND( AVG(queue_time)/ 1000000,  2)  AS avg_queue_sec,
        ROUND( AVG(logical_reads),  0)  AS avg_lreads,
        ROUND( AVG(get_count),  0)  AS avg_gets,
        MAX(plan_type)  AS plan_type
FROM oceanbase.gv$sql_audit
WHERE request_time > UNIX_TIMESTAMP(NOW() - INTERVAL 10 MINUTE) * 1000000
GROUP BY sql_id
ORDER BY SUM(cpu_time) DESC
LIMIT 20;

-- 查看当前 Compaction 状态(是否需要 SUSPEND MERGE)
SELECT zone, major_compact_status, broadcast_version,
       gmt_create  AS start_time, last_finish_time
FROM oceanbase.__all_virtual_zone_merge_info;

-- 快速查看租户资源使用全景
SELECT t.tenant_name, t.tenant_id,
       u.min_cpu, u.max_cpu,
       r.mem_used_percent,
       r.cpu_used_percent
FROM oceanbase.dba_ob_tenants t
JOIN oceanbase.dba_ob_resource_pools p  ON t.tenant_id = p.tenant_id
JOIN oceanbase.dba_ob_unit_configs u  ON p.unit_config_id = u.unit_config_id;

-- 检查 Paxos 状态(是否有节点不可用 / leader 分布不均)
SELECT tenant_id, ls_id, svr_ip,  role, member_list
FROM oceanbase.gv$ob_log_stat
WHERE  role =  'LEADER'
ORDER  BY tenant_id, ls_id;

五、预防与长期治理

5.1 OCP 监控告警配置建议

指标 OCP 告警项 阈值建议 告警级别
observer CPU 使用率 ob_cpu_percent > 70% 持续 5min / > 85% 持续 3min Warning / Critical
SQL 平均 RT ob_sql_rt > 基线 2 倍 且 > 100ms Warning
活跃会话数 ob_active_session > 连接池 80% Warning
队列等待 SQL QUEUEING 等待事件 出现 > 1秒 Critical
Compaction 状态 merge_timeout 超过预期窗口未完成 Info
MemTable 内存 memstore_used_percent > 80% Warning
Paxos 日志回放延迟 replay_lag > 10s Warning
OBServer 存活 ob_server_exists 节点不可用 Critical

5.2 日常巡检清单(建议结合 OCP 巡检报告)

  • [ ] 检查 CPU 使用率趋势(近 7 天,关注是否有周期性尖峰)
  • [ ] 检查 Top SQL 排行(是否有新增慢 SQL / 计划走飞)
  • [ ] 检查统计信息 stale_stats(是否有表统计信息过期)
  • [ ] 检查 major compaction 是否在预期窗口完成( major_compact_status)
  • [ ] 检查 plan cache 命中率(> 95% 为正常,低于 90% 需关注)
  • [ ] 检查等待事件(是否有异常的 row lock wait / SQL QUEUEING)
  • [ ] 检查资源单元配置(Unit 的 min_cpu / max_cpu / memory_size 是否合理)
  • [ ] 检查 MemTable 使用率(是否接近 freeze_trigger)
  • [ ] 检查日志归档状态( log_archive_dest 是否正常)
  • [ ] 检查节点 Paxos 状态(是否有节点长期 follower,leader 分布是否均衡)

5.3 容量规划建议(Unit 配置)


OB Unit CPU 配置公式:

  目标 Unit min_cpu = 预估 QPS × 平均 CPU 耗时(ms) / 1000 / 目标CPU利用率(0.6)

示例:
  QPS = 10000, 平均 CPU 耗时 = 2ms
  所需 CPU = 10000 × 2 / 1000 / 0.6 ≈ 33 核

安全余量建议:实际分配 = 计算值 × 1.5(预留高峰 + Compaction 等后台任务)

注意事项:
- OLTP 业务建议 min_cpu = max_cpu,不超卖
- HTAP 场景建议 OLTP 和 OLAP 用不同租户隔离
- 考虑 major compaction 的 CPU 开销(压缩算法选型影响很大)

六、工具与资源速查

6.1 诊断工具一览

工具 OB 术语 用途 使用场景
OCP OCP 运维平台 全功能运维平台 日常运维、监控、告警、合并管理、租户管理
obdiag OB 诊断工具 一键诊断、日志分析、巡检 现场诊断、研发协同、采集诊断包
obclient OB 命令行客户端 连接 observer/OBProxy 执行 SQL 应急 SQL 执行、Kill 会话
perf + FlameGraph 火焰图 内核热点定位 CPU 拉爆且 SQL 层无法解释时使用
top / mpstat 系统工具 线程级 CPU 监控 第一步快速诊断
gv$sql_audit SQL 审计视图 SQL 级问题定位 最常用,每个 SQL 的执行详情
gv$session_wait 等待事件 V4 性能瓶颈分析 区分 CPU / IO / Lock / Queue
gv$latch Latch 统计 内部轻量锁竞争 定位内部锁热点
pstack 线程栈快照 锁竞争分析 生产慎用,可能导致 observer 短暂 hang

6.2 obdiag 常用命令(应急必备)



# 一键性能诊断(分析 observer 日志中的 WARN/ERROR)

obdiag analyze  log --since  "30m"

# 分析指定 SQL 的执行详情
obdiag analyze sql --sql_id  ""

# 巡检报告(生成全面的健康检查报告)
obdiag check

# 采集诊断信息(打包发给研发分析,应急时必做)
obdiag gather all --since  "1h"
# 会自动采集:perf、observer日志、sql_audit、系统信息、火焰图等

应急三字诀

  1. 快:5 分钟内定位问题类别,先止损再根因。CPU 拉爆时每一秒都在损失业务。
  2. 准: gv$sql_audit + top -H 是应急双绝,精准定位高 CPU 线程和问题 SQL。
  3. 稳:止损动作要评估副作用 —— Kill 会话前确认不是关键 DML 事务;SUSPEND MERGE 后记得低峰期 RESUME;扩 Unit 要考虑集群资源余量。

应急常见踩坑点

踩坑 说明 正确做法
不看 plan_type 就下结论 本地计划和分布式计划的代价完全不同 先确认 plan_type 是 Local 还是 Distributed
Kill 会话后不管回滚 大事务 Kill 后 rollback 也要耗 CPU 先看 affected_rows 和 trans_id,评估回滚代价
SUSPEND MERGE 后忘记 RESUME 长期不合会导致 SSTable 层数爆炸,读放大严重 低峰期记得 RESUME,并跟踪合并完成
不采集 perf 就让研发介入 内核热点没有 perf 数据无法定位 应急时同步 obdiag gather all,保存现场数据
只看 SQL 不看等待事件 CPU 高不一定都是 SQL 问题 gv$session_wait 看等待事件分布,可能是 lock/queue
V4 下忽略租户互影响 一个租户拉爆 CPU 可能影响同机所有租户 确认是哪个租户在拉 CPU,必要时通过 cgroup 隔离

本文档基于 OB GOC 团队实战经验整理,适用于 OceanBase V4 系列版本。如有新的典型案例或解决方案,欢迎及时补充至知识库。

如果在操作过程中遇到问题,欢迎在评论区留言交流,后续我们会持续分享更多实战运维干货,记得   关注不迷路   ,下次见~



来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70047467/viewspace-3179723/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
专注于企业信息科技战略咨询、数据中心规划及运维、智能化软件产品研发,致力于为金融、能源、电信、制造等行业提供智能的业务永续及流程自动化解决方案。

注册时间:2025-09-08

  • 博文量
    89
  • 访问量
    86692