联系我们
18591797788
hubin@rlctech.com
北京市海淀区中关村南大街乙12号院天作国际B座1708室
18681942657
lvyuan@rlctech.com
上海市浦东新区商城路660号乐凯大厦26c-1
18049488781
xieyi@rlctech.com
广州市越秀区东风东路华宫大厦808号1608房
029-81109312
service@rlctech.com
西安市高新区天谷七路996号西安国家数字出版基地C座501
阅读前置知识: 了解 OB 多租户架构、Zone/Unit/Tenant 资源模型、LS(Log Stream) 与 Tablet 概念、Compaction 机制(major/minor/mini)、SQL 引擎执行链路(SQE → 优化器 → 执行引擎 → 存储引擎)
在 OB 应急语境中,CPU拉爆(也叫 CPU 打满、CPU 顶满)指observer 进程的 CPU 使用率持续超过 80%,甚至跑到 100%,通常伴随以下级联故障:
OB-4012: Timeout 或 -4016: Internal ErrorOB 黑话科普:OB 内部我们一般说"CPU 拉爆"而不是"CPU 打爆","拉"字体现的是 CPU 被 SQL 或后台任务逐步拉上去的过程,更贴合实际故障现象。
CPU 拉爆
→ 工作线程(worker thread)排队等不到 CPU 时间片
→ SQL RT 飙升,elapsed_time 中 queue_time 占比增大
→ OBProxy 侧连接池占满,新请求被 reject
→ 业务侧报 Timeout(-4012) / Connection Refused
→ 应用重试风暴 → 进一步加剧 CPU 压力(雪崩效应)
→ 业务全面中断,触发 GOC 应急
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 热点至关重要。
根据 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 / 内核参数
典型表现:
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 的并行度和数据倾斜。
典型表现:
plan_hash_value 发生变化,走了不同的物理执行计划sql_audit 中 plan_type 可能从 0(本地计划)变成 2(分布式计划),代价陡增常见原因:
broadcast_version 推进,plan cache 中旧计划失效,重新生成可能选错optimizer_* 系列参数或 _nlj_batching_enabled 等隐藏参数被改过应急手段:
-- 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';
-- 等恢复后记得改回来
典型表现:
gv$sql_audit 中同一 sql_id 出现几十上百条 is_exit=0queue_time 显著增大(排队时间可能超过实际执行时间)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 降下来再处理。
OB 背景知识:OB 存储引擎是 LSM-Tree 架构,数据先写 MemTable,达到阈值后 freeze → dump 成 mini SSTable,然后通过 mini compaction / minor compaction / major compaction 逐层合并。每一层 compaction 都会消耗 CPU + IO。
典型表现:
__all_virtual_zone_merge_info 中 major_compact_status = COMPACTING__all_virtual_tablet_compaction_progress 能看到大量 tablet 在合并排查与应对:
-- 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调小来降低合并并发。
典型表现:
__all_virtual_tablet_compaction_progress 中大量 mini/minor compaction 任务堆积应对:
-- 调整写入限速阈值(避免写入过快导致 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;
| 后台任务 | 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 尖峰 | 一般不需干预,频繁选举需检查网络 |
问题描述:
ref_cnt) 和序列号 (seq_num) 共用一个 int64dec_ref_cnt_and_inc_seq_num 函数占比显著(超过 5%)触发条件:
影响版本:V4.2.x BP 系列及更早版本,V4.3.5 已修复(重构了引用计数实现)
排查方法:
# 1. 抓取火焰图(perf,这是定位内核热点的核武器)perf record -g -p $(pgrep observer) -- sleep 30perf 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+ | 内核层面修复了引用计数实现 |
常见场景:
ob_malloc / ob_free 或 jemalloc 相关)排查:
# perf 抓取锁热点perf record -e cycles -g -p $(pgrep observer) -- sleep 10perf 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;
问题: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';
-- 恢复后改回默认
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,不超卖。
表现: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;
# 系统层面检查 swapfree -hvmstat 1 5# si/so 不为 0 → 说明在用 swap → observer 性能会严重下降
| 参数 | 默认值 | 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 的执行效率 |
典型场景:
应急手段:
-- 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. 业务侧配合:让应用侧临时停发请求 / 加指数退避
表现:短时间内大量新连接涌入,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;
OB 规范要求:observer 必须用
numactl --interleave=all启动,否则跨 NUMA 节点内存访问会导致 CPU 开销显著增加。
# 检查 NUMA 状态numactl --hardwarenumactl --show# 检查 observer 进程的 NUMA 策略cat /proc/$(pgrep observer)/numa_maps | head -5# 正确启动方式(必须在 observer 启动脚本中配置)numactl --interleave=all /home/admin/oceanbase/bin/observer
OB 规范要求:THP 必须关闭。THP 会导致内存分配时出现大页延迟,影响 observer 的 RT。
# 检查 THP 状态(应显示 [never])cat /sys/kernel/mm/transparent_hugepage/enabled# 关闭 THPecho never > /sys/kernel/mm/transparent_hugepage/enabledecho never > /sys/kernel/mm/transparent_hugepage/defrag
# OB 标准内核参数检查(与 obd 部署工具检查项对齐)sysctl vm.swappiness # 必须 = 0,禁止 swapsysctl vm.overcommit_memory # 建议 = 0sysctl net.core.somaxconn # 建议 >= 65535sysctl net.ipv4.tcp_tw_reuse # 建议 = 1sysctl fs.file-max # 建议 >= 655350# 检查 observer 文件描述符限制ulimit -n # 建议 >= 655350
[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 / 限流
# 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 crashdmesg | 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
-- 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;
# 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 30perf 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 = '';
| 级别 | 场景 | 止损措施 | 预期恢复时间 |
|---|---|---|---|
| P0-紧急 | 业务完全不可用,报 -4012/-4016 | Kill 问题 SQL + 扩 Unit + 切流 | 1-5 分钟 |
| P1-严重 | 业务严重降级,RT 恶化 10 倍+ | SUSPEND MERGE + 限流 + 加索引 | 5-15 分钟 |
| P2-一般 | 部分功能受影响 | 分析执行计划 + 加索引 + 绑 SPM | 15-60 分钟 |
| P3-观察 | CPU 偏高但未影响业务 | 收集 perf + sql_audit 数据 + 制定优化方案 | 计划性处理 |
# ===== 第一步:快速 Kill 慢 SQL =====# 通过 obclient 经 OBProxy 连接(也可以直接连 observer 的 2881 端口)obclient -h -P -u@# -p -D# 找到问题 SQL 的 sessionSELECT id, user, host, db, command, time, state, LEFT(info, 100) AS sql_textFROM information_schema.processlistWHERE time > 5 AND command != 'Sleep'ORDER BY time DESC;# Kill 对应 session(注意:先确认不是关键 DML 事务!)KILL ;# ===== 第二步:紧急扩 Unit CPU =====# 通过 OCP 操作更方便:租户管理 → 资源单元 → 修改# 或通过 SQLALTER 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# 重启前确认其他节点健康,避免多个节点同时不可用
-- 批量生成 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;
| 指标 | 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 |
stale_stats(是否有表统计信息过期)major_compact_status)row lock wait / SQL QUEUEING)freeze_trigger)log_archive_dest 是否正常)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 开销(压缩算法选型影响很大)
| 工具 | 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 |
# 一键性能诊断(分析 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、系统信息、火焰图等
gv$sql_audit + top -H 是应急双绝,精准定位高 CPU 线程和问题 SQL。| 踩坑 | 说明 | 正确做法 |
|---|---|---|
不看 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 系列版本。如有新的典型案例或解决方案,欢迎及时补充至知识库。