
一、故障现象:毫无征兆的磁盘危机
某日,我们的 OceanBase 集群某节点毫无征兆地爆发磁盘危机——短短 3 小时内,该节点磁盘占用从 6T 一路飙到 17T。没有任何前期征兆,也没有批量数据导入之类的"常规嫌疑人",空间就像被一只看不见的手迅速掏空。
这种"凭空消失"的磁盘空间,第一时间让我们把目光投向了临时文件:在 OceanBase 中,临时文件类似于 Oracle 的临时表空间,用于存放 HASH 计算、排序等算子的中间数据。当 SQL 执行产生大量中间结果时,临时文件会迅速膨胀。
二、排查过程
第 1 步:分析 observer 日志
我们用关键字 mark_and_sweep 过滤 observer 日志。该关键字会周期性打印磁盘使用情况,是定位"空间被谁吃了"的第一现场。
在 14:05:36 的日志中,我们看到这样一行关键数据:
tmp_file_count=4790388
这是临时文件的宏块数。OceanBase 中每个宏块为 2M,因此:
4790388 × 2M ≈ 9356G ≈ 9.14T
数字对上了——磁盘空间的膨胀,正是来自临时文件的疯狂写入。
第 2 步:查看 TOP-SQL
回到问题时段,我们在 OCP 的 TOP-SQL 中发现了一条异常 SQL:它的执行耗时高达 3 小时,与"数据膨胀到报错"的时长完全吻合。时间线对上了,嫌疑 SQL 锁定。
第 3 步:分析 ASH 视图
为了看清这条 SQL 慢在哪里,我们查询了 ASH(Active Session History)视图:
select sql_id, trace_id, sql_plan_line_id, count(*) * 10 cnt
from dba_wr_active_session_history
where sql_id = 'A77650731411859E9886898E9122759D'
group by sql_id, trace_id, sql_plan_line_id
order by sql_id, trace_id, cnt;
结果显示,这条 SQL 主要消耗在执行计划的第 0 步——也就是最底层的扫描/关联阶段。问题不在某个深层算子,而在一开始的数据膨胀。
第 4 步:剖析问题 SQL 文本
问题 SQL 的核心逻辑如下(已脱敏):
WITH T2 AS (
SELECT col1 as col1id, CURRENTSTEPSEQ, SGESTEPSEQ, TXNTIME
FROM (
SELECT col1, CURRENTSTEPSEQ, SGESTEPSEQ, TXNTIME,
ROW_NUMBER() OVER(PARTITION BY col1 ORDER BY TXNTIME DESC) as rn
FROM T1
WHERE col1 = 'xxxxxx'
AND TXNTIME BETWEEN '20260519160000' AND '20260520120000'
)
WHERE rn = 1 AND CURRENTSTEPSEQ IS NOT NULL AND SGESTEPSEQ IS NOT NULL
),
step_positions AS (
SELECT STEPSEQ, ROW_NUMBER() OVER(ORDER BY STEPSEQ) as step_row_num
FROM T3
WHERE STEPSEQ IN (SELECT CURRENTSTEPSEQ FROM T2 UNION SELECT SGESTEPSEQ FROM T2)
)
SELECT a.col1id, a.CURRENTSTEPSEQ, a.SGESTEPSEQ, a.TXNTIME,
cs.step_row_num as current_step_row,
ss.step_row_num as sge_step_row,
-(ss.step_row_num - cs.step_row_num) as THEORETICAL_VALUE
FROM T2 a
JOIN step_positions cs ON cs.STEPSEQ = a.CURRENTSTEPSEQ
JOIN step_positions ss ON ss.STEPSEQ = a.SGESTEPSEQ;
第 5 步:分析 SQL 逻辑——近乎笛卡尔积的膨胀
问题的根源在最后一段:step_positions 这个派生表被关联了两次(分别与 CURRENTSTEPSEQ、SGESTEPSEQ 做 JOIN)。而 STEPSEQ 字段对应的行数越多,返回行数就呈2 次方膨胀。
· 测试取 30000 行,最终返回约 10 亿行(近笛卡尔积效果);
· STEPSEQ 取值最多的记录高达 200 万行;
· 若实际取到 50 万行记录,最终将返回约 2500 亿行。
一条本应返回少量结果的查询,因表被反复关联,瞬间放大成天文数字,临时文件随之被写到约 10T。
第 6 步:OceanBase 临时文件限制机制
为什么能写到 10T 而没提前拦住?这涉及 OB 的临时文件管控机制:
· V4.2 及之前:临时文件上限采用固定算法,基本可达约 100T,等于"无限制";
· V4.3 / V4.4:改为由参数 temporary_file_max_disk_size 控制总大小,但默认值 0,同样等于无限制。
也就是说,产研把"设不设限、设多少"的选择权交给了使用者——默认情况下,临时文件可以一路狂奔到把磁盘写满。
三、总结建议
根因:问题 SQL 存在逻辑缺陷(同一张派生表被多次关联,产生近笛卡尔积效果),在 3 小时内生成约 10T 临时文件;同时 OceanBase V4.3/V4.4 虽有参数可控,但默认无限制。
运维建议:
1. 规范参数:V4.3+ 环境建议将 temporary_file_max_disk_size 纳入规范参数模板,并按业务类型设值,避免空间暴增;
2. 预留空间:为临时文件长期预留独立空间,防止波及数据盘;
3. 排查三步法(详见下方):
· ① 日志:grep mark_and_sweep observer.log 看磁盘使用;
· ② 视图:select sum(data_bytes/1024/1024) from dba_ob_temp_files;
· ③ 设限:alter system set temporary_file_max_disk_size = '2T';
北京新浦金350vip安图科技股份有限公司(简称"新浦金350vip有限公司",股票代码 301208)是国内领先的第三方 IT 基础架构服务与产品提供商。公司具备全栈服务能力,可为全周期、全行业的客户提供数据库运维、性能优化、故障排查等全方位服务。数据库运维是公司最具技术含量的优势项之一,但公司的能力远不止于此——全栈、全周期、全行业,才是新浦金350vip有限公司的底色。