基于湖库一体架构,统一管理结构化、半结构化与非结构化等多模态数据,一个系统承载事务处理、实时分析与 AI 工作负载。
smaps_rollup 信息导致 OBServer 进程内存分配操作卡顿
更新时间:2026-08-25 02:41
问题现象
在某客户的性能回归测试环境上,发现升级 OBServer 小版本后业务基准压测指标普遍出现了 10%~20% 的性能回退,同时在 observer.log 中出现大量的 OB_MALLOC COST TOO MUCH TIME 告警,该告警的含义是 observer 进程的实时内存分配操作过于缓慢:
[378757]OB_MALLOC COST TOO MUCH TIME, cost_time=119982, tenant_id=1, label=SqlExecutor, ctx_id=0, prio=0, size=245760,
[374291]OB_MALLOC COST TOO MUCH TIME, cost_time=887726, tenant_id=1001, label=CoStack, ctx_id=8, prio=1, size=638016, owner: ObMalloc, click_count: 2, time dist:[ALLOC_BLOCK#start=0, ALLOC_BLOCK#end=0], seq:[0, 1]
[374291]OB_MALLOC COST TOO MUCH TIME, cost_time=213386, tenant_id=1001, label=CoStack, ctx_id=8, prio=1, size=638208, owner: ALLOC_BLOCK, click_count: 1, time dist:[ALLOC_CHUNK_END=213381], seq:[0]
[374291]OB_MALLOC COST TOO MUCH TIME, cost_time=336210, tenant_id=1001, label=CoStack, ctx_id=8, prio=1, size=638016, owner: ObMalloc, click_count: 2, time dist:[ALLOC_BLOCK#start=0, ALLOC_BLOCK#end=213495], seq:[0, 1]
[386798]OB_MALLOC COST TOO MUCH TIME, cost_time=178243, tenant_id=1001, label=[T]MemoryContext, ctx_id=0, prio=0, size=24,
[373889]OB_MALLOC COST TOO MUCH TIME, cost_time=193289, tenant_id=500, label=CoStack, ctx_id=8, prio=1, size=638208, owner: ALLOC_BLOCK, click_count: 1, time dist:[ALLOC_CHUNK_END=193286], seq:[0]
[373889]OB_MALLOC COST TOO MUCH TIME, cost_time=193920, tenant_id=500, label=CoStack, ctx_id=8, prio=1, size=638016, owner: ObMalloc, click_count: 2, time dist:[ALLOC_BLOCK#start=0, ALLOC_BLOCK#end=193377], seq:[0, 1]
[378757]OB_MALLOC COST TOO MUCH TIME, cost_time=1054873, tenant_id=1, label=SqlExecutor, ctx_id=0, prio=0, size=245760,
[386803]OB_MALLOC COST TOO MUCH TIME, cost_time=527476, tenant_id=500, label=[T]MemoryContext, ctx_id=0, prio=0, size=24,
[386802]OB_MALLOC COST TOO MUCH TIME, cost_time=767643, tenant_id=1001, label=[T]MemoryContext, ctx_id=0, prio=0, size=24,
[374064]OB_MALLOC COST TOO MUCH TIME, cost_time=209409, tenant_id=1, label=CoStack, ctx_id=8, prio=1, size=638016, owner: ObMalloc, click_count: 2, time dist:[ALLOC_BLOCK#start=0, ALLOC_BLOCK#end=1], seq:[0, 1]
[374064]OB_MALLOC COST TOO MUCH TIME, cost_time=338136, tenant_id=1, label=CoStack, ctx_id=8, prio=1, size=638016, owner: ObMalloc, click_count: 2, time dist:[ALLOC_BLOCK#start=1, ALLOC_BLOCK#end=75734], seq:[0, 1]
进一步监控后发现,该告警的打印频率约为 30s/次。
问题原因
排查过程
依次排查 OBServer 服务器上的可疑服务和可疑进程后发现,将运行在该服务器上的 Prometheus 监控工具的 process_exporter 监控进程停掉后,observer.log 日志中 OB_MALLOC COST TOO MUCH TIME 告警不再打印。
根因分析
/proc/<pid>/smaps_rollup 是 Linux 内核提供的一个虚拟文件,用于以聚合形式展示进程的内存使用统计。它从 Linux 4.14 开始引入,位于每个进程的 /proc/<pid>/ 目录下,是 /proc/<pid>/smaps 文件的汇总版本。
该文件的主要作用如下:
- 快速获取进程整体内存统计:相比
/proc/<pid>/smaps会列出进程的每一个内存映射区域(如代码段、数据段、共享库、堆、栈等)的详细信息,smaps_rollup 将这些信息按字段相加汇总,直接给出整个进程的汇总值。 - 减少解析开销:在监控工具(如 top、ps、smem)或自动化脚本中,读取一个文件就能得到关键内存指标,无需遍历成百上千个映射条目。
当 Prometheus 监控工具的 process_exporter 监控进程读取 /proc/<pid>/smaps_rollup 时,内核需要:
- 获取目标进程的内存描述符(
mm_struct)的读锁(mmap_lock) - 遍历进程的所有虚拟内存区域(VMA),累加各区域的 RSS、PSS 等统计数据
- 释放锁,将聚合结果返回给用户
为了保证整个遍历过程的正确性,内核会持有该进程的内存管理锁(通常是 mmap_lock,即 mmap_sem)。该锁用于保护进程的 VMA 列表和页表。在锁被持有时,目标进程的任何需要修改 VMA 或页表的操作(如 mmap()、munmap()、mprotect()、缺页异常等)都会被阻塞,直到锁释放。
因此,取决于当前 observer 进程的虚拟内存(VIRT)和常驻物理内存(RSS)的大小,读取虚拟文件 /proc/<pid>/smaps_rollup 的耗时及相应的持锁时间为几毫秒到几秒不等。
在客户出现性能回退问题的环境上,cat /proc/$(pgrep observer)/smaps_rollup 命令耗时在 5s 以上,因此会导致 observer 进程的内存分配操作发生卡顿,进而影响到上层业务的 TPS/QPS。
测试验证
单节点 Oceanbase 集群当前的 observer 进程内存占用情况如下:
在左侧 Terminal 窗口手工执行命令 time cat /proc/$(pgrep observer)/smaps_rollup,同时在右侧 Terminal 窗口对该 OBServer 进程进行 sysbench 压测。
同一时刻对应 OBServer 节点上的 observer.log 日志中出现大量的 OB_MALLOC COST TOO MUCH TIME 告警。
问题的风险及影响
压测时 observer 内存分配操作过于缓慢,导致业务压测指标偏低。
适用版本
- Linux 4.14 及以上内核
- OBServer 所有版本
解决方法
方法一:彻底关闭并禁用 Prometheus 监控工具的 process_exporter 监控服务。
方法二:继续开启 Prometheus 监控工具的 process_exporter 监控服务,同时在监控对象中跳过收集 /proc/<pid>/smaps_rollup。