感谢分享!
实践案例很有参考价值
OceanBase 生产:大量慢SQL + TPS暴跌 + 磁盘IO打满 完整排查方案
一、核心现象统一归因
三类现象是连锁反应:磁盘IO飙高是根因之一,IO等待导致SQL执行堆积、RT拉长,表现为大量慢查询;连接池打满、事务提交变慢,业务吞吐量TPS直接断崖下跌。
整体分四大类根因:存储合并Compaction异常、SQL执行引发IO风暴、数据倾斜/热点、集群资源故障。
二、全部可能根因分类
类别1:LSM-Tree合并异常(OB最高发,IO飙升头号元凶)
OB底层LSM架构,数据写入MemStore,转储生成SSTable;多层SSTable过多就会触发合并Compaction,大量磁盘读写。
-
Minor合并风暴
写入量突增,MemStore快速打满,频繁dump转储,产生海量小SSTable,持续触发小合并,随机IO打满磁盘。 -
Major大合并阻塞/堆积
- 长期未合并,SSTable层数超过阈值,强制大合并;
- 磁盘带宽不足、IO性能差,合并进度缓慢,大量IO占用;
- 业务高峰自动触发major,读写与合并争抢IO资源。
-
删除/更新堆积大量删除标记(Buffer表场景)
队列、临时缓冲表高频INSERT/DELETE,产生大量墓碑,每次查询扫描多层SSTable,读IO暴涨;同时后台合并清理墓碑加剧写IO。 - 分区转储均衡度差,少数Tablet集中触发dump,单点磁盘IO跑满。
类别2:SQL问题引发读写IO爆炸(慢查询同步爆发)
-
分区裁剪失效,全分区扫描
查询不带分区键、分区键函数包裹、隐式转换,SQL扫描全部分区,大量随机读IO。 -
优化器选错执行计划
无索引、全表扫描、笛卡尔积、未使用NLJ改用Hash Join,单次查询扫描几十万行数据,读IO持续走高。 -
冷热未隔离,大报表/离线分析混在线业务
统计类SQL长时间扫描历史冷分区,占用磁盘IO,挤压在线读写。 - 未使用绑定变量,高频硬解析+大量重复全表扫描SQL叠加。
- 大小账号数据倾斜:大账号SQL扫描超大分区,单Tablet IO打满。
类别3:数据/分区热点倾斜(单节点磁盘IO瓶颈)
- 分片键设计不合理,热点商户、热点日期全部落在同一个Tablet;该分区所有读写集中单台磁盘,IO打满,所有关联SQL变慢。
- 副本不均衡,多热点Tablet集中同一台OBServer,磁盘IO资源耗尽。
- 读写分离未开启,全部读请求压主副本,主盘IO过载。
类别4:集群/硬件/参数故障类
- 磁盘硬件故障、SSD掉速、raid卡异常,单次IO延迟大幅升高;少量请求就会IO等待堆积。
- 时钟偏移、网络波动,副本同步Clog日志积压,日志刷盘IO持续拉高。
- Memstore内存参数过小,频繁dump转储;
- ODP连接池配置不合理,并发堆积,大量SQL同时下发加剧IO竞争;
- 备份任务、数据校验、OMS迁移同步任务高峰抢占磁盘IO。
三、标准化排查步骤(从上到下,先定位再深挖)
步骤1:OCP大盘快速确认基础指标,锁定大方向
- 查看磁盘指标:磁盘IO util、读/写吞吐量、IO延迟、await(IO等待时间)
- await持续>20ms:磁盘IO饱和,所有SQL卡在IO等待;
- 观测租户指标:
MemStore水位、SSTable层数、合并次数、转储dump次数; - 业务指标:TPS/QPS下降曲线是否和IO飙升曲线完全重合;
- 慢SQL面板:导出Top耗时SQL,看特征(全表扫描、全分区扫描、大行数扫描);
- 节点负载:是否单台节点IO跑满(热点倾斜),还是所有节点同时冲高(全局合并风暴)。
步骤2:排查Compaction合并状态(OB特有优先查)
登录sys租户查询视图:
-- 查看所有分区SSTable层数、合并任务
SELECT zone, tablet_id, partition_id, sstable_count, minor_merge_cnt, major_merge_cnt
FROM oceanbase.gv$ob_tablet_meta;
-- 查询正在执行的合并任务
SELECT * FROM oceanbase.gv$ob_compaction_task WHERE status='RUNNING';
-- 查看转储dump统计
SELECT * FROM oceanbase.gv$ob_dump_stat;
判断:
- sstable_count普遍超过10:小文件过多,合并堆积;
- 大量RUNNING合并任务、持续新增dump任务 → 合并风暴。
步骤3:定位慢SQL,验证是否SQL导致IO上涨
- 抓取gv$ob_sql_audit中逻辑读/物理读极高的SQL(物理读=磁盘IO来源);
- EXPLAIN PARTITIONS 查看执行计划:
- 是否扫描全部分区(分区裁剪失效);
- 是否走全表扫描、缺失索引;
- 是否扫描百万级数据行;
- 区分两类慢查询:
离线报表SQL(定时执行、大批量读) / 在线业务SQL(高频短查询)。
步骤4:排查数据热点倾斜
-- 查看各分区行数,定位超大分区
SELECT partition_id, tablet_id, row_count
FROM oceanbase.gv$ob_partition_stat ORDER BY row_count DESC;
单分区行数远超其他分区 → 大小账号热点,单点IO瓶颈。
步骤5:排查后台抢占IO任务
- 查看备份任务是否正在执行;
- OMS数据迁移、回放校验任务是否高峰期运行;
- 是否手动执行过truncate、大批量delete触发大量墓碑合并。
步骤6:底层服务器硬件校验
- 服务器iostat查看%util、r_await/w_await;
- 检查SSD磁盘告警、磁盘坏道、raid告警;
- 网络流量:跨Zone同步流量是否打满,clog同步积压。
四、分场景解决方案(紧急止血 + 长期根治)
场景1:合并/转储风暴导致IO飙升(最常见)
紧急止血(立刻执行,快速恢复TPS)
- 手动限流写入:业务临时降峰,减少INSERT/UPDATE流量;
- 手动触发均衡Major合并,一次性清理多层SSTable:
ALTER SYSTEM MAJOR FREEZE TENANT tenant_name;
- 临时调大租户memstore内存,减少频繁dump转储;
- 临时调低合并并发参数,避免合并吃光磁盘IO:
_minor_merge_concurrent_num、_major_merge_concurrent_num。
长期优化
- 合理配置Unit内存,保证memstore充足;
- 错开Major合并时间,配置业务低峰期自动合并;
- Buffer队列表建表指定
TABLE_MODE='queuing',优化墓碑清理逻辑; - 分区拆分,单分区控制行数,避免单分区海量SSTable。
场景2:劣质SQL引发大量物理读、IO打满
紧急止血
- 临时kill超高物理读慢SQL,释放磁盘IO;
- 加Hint强制分区裁剪、强制走索引、限制并行度;
- 离线报表、统计SQL迁移至只读备副本,分离读写IO。
长期根治
- 改写SQL,WHERE条件带上原生分区键,保证分区裁剪生效;
- 缺失索引批量创建复合索引;
- 业务使用绑定变量,减少硬解析,缓存高效执行计划;
- 大查询增加资源组限流,避免抢占在线资源;
- 定时收集统计信息,防止优化器选错计划。
场景3:数据热点/大小账号倾斜,单节点磁盘IO跑满
紧急止血
- 读写分离,ODP配置读请求路由至备副本,分流主盘IO;
- 大账号SQL添加LOCAL HINT,减少跨节点IO交互;
- 手动触发rebalance,打散热点Tablet到多节点。
长期根治
- 优化分区键,采用复合分区键(商户ID+日期)拆分大账号数据;
- 热点大账号单独分表、分租户隔离资源;
- 扩容集群节点,提升整体磁盘IO带宽;
- 按业务冷热分区,冷数据归档降低扫描量。
场景4:后台任务抢占IO(备份/迁移/校验)
- 临时暂停备份、OMS同步、数据校验任务;
- 调整定时任务至凌晨低峰时段执行;
- 备份存储分离,不占用业务数据盘IO。
场景5:磁盘硬件性能不足/故障
- 故障磁盘立刻隔离,切换副本,迁移分区至正常节点;
- 升级高性能SSD,提升磁盘IO带宽;
- 优化系统磁盘参数:关闭atime、调整IO调度策略。
五、应急处理操作顺序(生产故障标准流程)
- 紧急Kill超高IO慢SQL,暂停抢占IO的后台任务,快速缓解磁盘压力;
- 判断是否合并风暴:是则手动major freeze合并,临时调大memstore;
- 观测TPS、IO指标是否恢复;
- 若单点IO跑满,开启读写分离分流读请求;
- 业务侧临时限流,降低写入吞吐量,给合并留出IO资源;
- 故障恢复后,定位根因输出优化方案,长期改造SQL、分区、参数。
六、预防手段(避免重复发生)
- OCP配置磁盘IO、慢SQL、合并任务告警,提前预警;
- 上线前流量回放验证,提前发现全扫描劣质SQL;
- 容量规划预留30%以上磁盘IO余量;
- 规范分区设计,避免超大热点分区;
- 区分在线业务与离线分析负载,资源物理隔离;
- 定期巡检SSTable层数、分区行数、慢SQL Top清单。
内容很好
宝贵的经验分享,谢谢!