首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
OSWatcher性能排查:从操作系统指标定位数据库瓶颈
📅 2026/10/31 11:46:48
✍️ 爱科研究院
👁 阅读 3,247
凌晨两点多被电话叫起来处理一套交易库的性能问题是很多做数据库运维的人共同的记忆。到了现场你会发现数据库层面看起来一切正常AWR 里的 Top SQL 排第一的语句执行时间也就几十毫秒等待事件里 db file sequential read 占比不算离谱连接数也在正常范围。但业务方咬死说系统慢页面转圈转了十几秒。这种时候问题往往不在数据库里面而在它脚下那台机器上——CPU 被别的进程抢了、内存开始换页、磁盘队列排到了几十米开外。OSWatcher全称 OSWatcher Black Box下面统一简称 OSW就是专门用来回答“机器当时到底在干什么”这个问题的一套工具。它本身不复杂几个 shell 脚本加一堆 .dat 文本文件但它解决的是数据库自带诊断能力覆盖不到的那一层。这篇内容面向已经会写 SQL、会用 AWR 报表但对操作系统层指标还没形成体系认知的同行也适合需要给性能问题留下可复盘证据的团队参考。1. 数据库变慢时为什么我第一个动作是去看操作系统数据库的自己诊断能力是有盲区的这一点很多人是在踩过坑之后才彻底接受的。AWR 告诉你“这个 SQL 花了 3 秒”ASH 告诉你“会话在等 db file sequential read”但这两个结论都在默认一个前提操作系统层面的资源是充足且公平分配的。这个前提一旦不成立AWR 里所有的数字都会变形而且变形的方式很隐蔽——它会让你以为是数据库内部慢了实际上是整个进程在排队。1.1 AWR 报表现象和操作系统真实状态之间的偏差举个具体的偏差。某套系统在业务高峰期出现大量 latch free 和 cursor: pin S wait on X 等待从 AWR 看像是共享池配置有问题于是有人去调 _shared_pool_size调完之后更慢了。后来翻操作系统数据才发现那段时间 CPU 的 run queue 排到了 30 多机器只有 8 个物理核。真实的因果是 CPU 严重不足导致持有 latch 的会话得不到调度等 latch 的会话自然越积越多。你看AWR 记录的是结果操作系统记录的是原因两者的因果方向经常被搞反。还有一种更常见的偏差来自内存。数据库进程的 RSS 在缓慢增长AWR 里的 buffer cache 命中率一切正常但机器已经开始用 swap 了。这时候数据库每一次读文件都会触发一次换页响应时间从 0.5 毫秒跳到 20 毫秒而 AWR 只会告诉你“IO 变慢了”它不知道是物理磁盘慢还是内存换页导致的额外开销。这类问题如果只看数据库内部的报表能查一周也查不出所以然。我自己的习惯是任何超过 30% 的性能回退先不打开 AWR先去翻 OSW 的归档目录把问题时间段内 CPU、内存、IO、网络四类数据扫一遍。这个过程通常十几分钟就能完成而它能帮你排除掉一大半“伪数据库问题”。顺序反过来做代价是可能在错误的方向上花掉几个小时。提示OSW 的价值不在于它有多少指标而在于它在你需要的时候“刚好有”。它的采集是常驻的不依赖问题发生时才去抓现场——这一点决定了它和事后用 top、vmstat 手动抓数据完全是两回事。1.2 OSW 到底采集了什么一份清单和它的取舍OSW 的原理说破了很简单它用一层 shell 循环按固定间隔调用操作系统上已有的性能命令把输出按时间戳写成文本文件。它不是监控系统没有数据库没有前端没有告警就是一堆带时间的文本。正因为简单它几乎没有资源开销可以在生产环境长期跑着。它默认采集的项目大致分这么几类我把用途也一并写上方便你在排查时知道该翻哪个目录采集目录底层命令主要用途oswvmstatvmstatCPU 队列、上下文切换、换页、IO 等待oswtoptop单进程级别的 CPU 和内存占用排序oswiostatiostat -x每块磁盘的利用率、响应时间、队列深度oswmpstatmpstat每个 CPU 核的使用分布看是否单核打满oswmeminfo/proc/meminfo内存构成区分 cache 和真实占用oswpsps进程快照看进程数是否异常膨胀oswslabinfo/proc/slabinfo内核对象缓存排查内核态内存泄漏oswnetstatnetstat连接数、重传、网络队列oswprvtnet/proc/net私网相关的网络统计这份清单有个很明显的特点它关心的都是“进程外部”的资源。数据库自己有多少 session、执行了多少次逻辑读这些它一概不管那是 AWR 的活。所以两者天然互补谁也不替代谁。需要说明的是OSW 的采集项是可以在启动时通过采集器目录做裁剪的。有些人为了“采得全”把能开的都开了结果 top 和 ps 这两个采集器在进程数上万的主机上单个周期要跑一两秒采集频率一高就形成了自己拖慢自己的局面。我的建议是默认项全开但采集间隔不要低于 30 秒进程数特别多的高并发主机可以考虑关掉 oswps需要的时候再单独抓。2. 部署看起来只是解压加启动真正的难点在参数和空间OSW 的安装过程用一句话就能说完解压压缩包、改环境变量、跑启动脚本。听起来五分钟的事但我在实际环境中见过因为目录规划不当跑到第三天后磁盘写满把整个主机带崩的情况。所以这一段重点讲参数而不是讲命令。2.1 采集间隔和保留天数怎么折算成磁盘占用这两件事是强关联的必须先算清楚再启动。OSW 有两个核心参数-i是采集间隔秒-f是归档保留时长小时。默认值通常是 30 秒和 48 小时。磁盘占用的估算方法很朴素单个采集周期的文件体积基本固定采集频率决定了每天写多少个周期两者相乘就是日增量。以一套中等规模的主机为例全部采集器开启、间隔 30 秒的情况下日增量大概在几百兆这个量级如果主机上有几百个磁盘设备iostat 的文件会显著变大日增量翻倍也很正常。所以我的做法是启动前先做一次小规模试跑用 30 秒间隔跑 10 分钟然后du -sh看一下归档目录体积乘以 144 得到每日增量再乘以想保留的天数就是需要的空间。这个动作耗时十分钟但能避免后面所有麻烦。保留时长怎么定取决于你的问题发现周期。如果团队的问题通常在业务方投诉后才被发现那保留 48 小时往往不够——周末出的问题周一才发现数据早就被滚动覆盖了。这种场景我一般会配到 96 小时甚至 168 小时前提是磁盘空间算得过来。反过来如果已经有一套实时监控能在分钟级发现问题48 小时完全够用因为数据只是用来复盘那一段的细节。2.2 启动脚本的参数与开机自启的实际做法启动脚本的参数不多但每个都值得说清楚-i采集间隔单位秒不建议低于 15 秒低于这个值采集本身的开销就不可忽略了-f归档保留小时数按上面算出来的值填-l日志目录建议和归档目录分开避免日志把归档区写满-t归档目录这个参数最容易被忽略也最容易出事如果不指定默认会写到脚本所在目录下很多人解压到家目录就启动了结果系统盘被写满-a采集器目录用于自定义采集项关于开机自启我的经验是不要图省事直接塞进 rc.local。原因是 rc.local 在很多发行版上默认不启用而且执行时机在部分服务启动之前OSW 依赖的一些命令可能还没就绪会导致采集文件里出现大量空输出。更稳妥的做法是写一个独立的 systemd 单元或者用 crontab 的reboot前者更好管理状态后者更简单。用 crontab 的做法大概是这样前提是脚本里的相对路径都改成了绝对路径reboot /opt/oswbb/startOSWbb.sh 30 96 /opt/oswbb/log /opt/oswbb/archive # 每十分钟检查一次进程不在就拉起来 */10 * * * * if [ ! -f /opt/oswbb/oswbb.pid ]; then /opt/oswbb/startOSWbb.sh 30 96 /opt/oswbb/log /opt/oswbb/archive; fi注意检查进程是否存活要用 pid 文件而不是ps | grep。用过 grep 的人都知道grep 自己那一行经常会匹配到关键字导致判断永远为真进程死了也拉不起来。这个坑我看过太多次了。2.3 装在数据库主机上还是单独一台监控机这是个需要认真权衡的决策两条路各有代价。装在数据库主机上的好处是数据最真实任何资源争抢都能直接反映出来而且不依赖网络。坏处有两个一是主机彻底挂掉的时候最后那几秒的数据也一起没了而恰恰是那几秒最有价值二是它和数据库抢同一份资源虽然开销极小但在资源已经极度紧张的场景下任何额外负担都会被放大。装在一台独立监控机上通过远程方式采集好处是主机宕机时数据仍然保留且零侵入。代价是需要额外的网络和认证配置采集到的是“从外面看到的”指标某些内核态细节拿不到。我个人的取舍是核心生产库用独立监控机普通业务库直接装在本地。理由很简单核心库最怕的就是“出事时没有现场”而普通库的问题多半是资源争抢型本地采最准。3. 归档目录里那些 dat 文件怎么读出门道很多人拿到 OSW 的数据之后第一反应是找工具看图其实在图上看到之前用几个命令扫一遍文本文件往往更快。文本文件的好处是你能看到原始值不会被图表的采样聚合和缩放误导。3.1 文件命名规则与时间段对齐的方法OSW 的文件命名是固定格式采集器名_年.月.日.时.分.dat比如oswvmstat_24.05.12.14.30.dat表示这个文件从 24 年 5 月 12 日 14 点 30 分开始写。注意是开始时间不是文件名里那个时间段的数据。一个文件里通常包含很多个采集周期具体多少取决于文件大小上限。文件内部每个采集周期之间用一行固定的分隔标记隔开形如zzz ***Sun May 12 14:30:05 CST 2024。这个分隔行是整个 OSW 数据里最重要的一个东西因为它是你定位时间点的唯一抓手。想找某个具体时间点的数据直接grep -n zzz \*\*\*Sun May 12 14:35 oswvmstat_24.05.12.14.30.dat拿到行号之后用 sed 取那一段就能得到那个时刻的完整快照。这个技巧比打开图表拖时间轴精确得多尤其是在排查持续几秒钟的瞬时抖动时。对齐时间这件事本身有个坑数据库服务器和你的工作站可能不在同一时区OSW 写的时间戳用的是主机本地时间而数据库 AWR 里的时间可能是数据库时区。两者相差 8 小时的情况下你会对着完全错位的数据分析半天。我的习惯是每次分析前先用date命令确认一次主机时间并且在笔记里记录时区偏移。3.2 三类高频信号在文本里的典型形态不用图表也能看出来的问题主要有这么三类它们的特征形态很有辨识度。第一类是 CPU 饱和。打开 vmstat 文件关注r列运行队列长度和ussy两列之和。健康状态下r应该长期小于 CPU 核数如果持续出现 r 值超过核数 2 倍以上同时 ussy 接近 100那就是明确的 CPU 饥饿。这时候再去看 oswtop就能找到是哪个进程在吃 CPU——注意不一定是数据库进程。第二类是 IO 瓶颈。iostat 输出里重点看两列%util和await。%util 接近 100 说明磁盘设备一直忙await 是这个设备上请求的平均响应时间毫秒。这两个要一起看%util 高但 await 低说明磁盘忙但响应正常问题不大%util 不高但 await 很高说明请求在排队但队列不深往往是单块盘性能下降或者存储侧的问题。这种“两个指标打架”的情况正是需要 OSW 原始数据而不是聚合图表的地方。第三类是内存压力。看 vmstat 的si和so两列每秒换入换出页数。只要这两列长期不为零就说明系统在真的换页这时候数据库的性能一定受影响不管 AWR 怎么说。同时看 /proc/meminfo 的 available 字段而不是 free 字段——Linux 上 free 把 cache 也算成已用看起来永远紧张实际可用的是 available。3.3 用分析器出图的完整流程和常见卡点OSW 配套有一个分析器OSWbba是一个 Java 程序输入归档目录输出图表和 HTML 报告。流程大概是# 1. 确认 Java 可用版本不能太低 java -version # 2. 进入分析器目录指定归档目录启动 java -jar oswbba.jar -i /opt/oswbb/archive # 3. 交互式输入起止时间格式是 MM/dd/yy HH:mm # 4. 选择要生成的内容一般选生成图表和数据文件常见的卡点有三个。一是 Java 版本分析器对 JDK 版本有要求太新的 JDK 可能跑不起来太旧的也不行遇到报错先看是不是这个原因。二是内存图表生成阶段对堆内存有要求归档目录特别大的时候需要加大-Xmx否则会抛内存溢出。三是时间格式这个输入框非常严格少一位数或者用错分隔符都会失败而且报错信息不友好容易让人以为是数据损坏。还有一点值得说分析器生成图片时如果用了无图形界面的模式某些配置下会报找不到显示设备的错误这个和 Java 的图形库有关加-Djava.awt.headlesstrue通常能绕过。4. 三个现象的完整排查链路还原理论讲完了这一段用三个模拟场景把排查过程串起来重点不是结论而是每一步为什么这么走。4.1 CPU 长期高位但业务方说速度正常现象是监控平台对某套系统报 CPU 使用率超过 85%持续了两小时但业务方反馈一切正常。这时候最容易犯的错误是直接让开发去优化 SQL。第一步应该看 mpstat判断是全核均匀还是单核打满。如果所有核的 us 都接近 90%那是真的算力不足如果只有一两个核接近 100其他核闲置那要怀疑是不是某个单线程进程在做密集计算或者中断集中在某个核上。这一步花不到一分钟但方向完全不同。第二步看 oswtop找到占用最高的进程。如果头部不是数据库进程而是某个备份程序、日志采集程序或者定时任务那答案就很清楚了。实际环境中“数据库 CPU 高”这个说法十有八九是误判数据库往往只是一堆进程中占得比较多的那个但绝对值并不高。第三步才是回到数据库看这个时间段内的活跃会话数。如果会话数很低说明数据库其实很闲CPU 消耗来自后台进程比如并行查询、归档、统计信息收集。到这一步结论已经很明确了。这条链路的关键在于先用操作系统数据把“谁的 CPU”这个问题回答清楚再决定要不要进数据库内部。跳过第一步直接进数据库是绝大多数误判的起点。4.2 数据库报 IO 等待磁盘却显示很闲置这个现象我第一次遇到的时候困惑了很久。AWR 里 db file sequential read 的平均等待时间到了 20 毫秒以上而 iostat 显示那块盘的 %util 只有 20% 出头。第一个要排除的是 iostat 的统计对象对不对。数据库的数据文件在哪个挂载点、底层对应哪些物理设备这个映射关系经常被搞错。用 lsblk 或者多路径工具确认一遍很可能你看着闲的那块盘根本不是你该看的那块。这个错误比想象中普遍尤其在存储做过卷管理、多路径、条带化的环境里。第二个要排除的是缓存层的干扰。存储侧如果有一层很大的写缓存iostat 看到的响应时间是设备驱动层的不代表请求真正落盘的耗时。这种情况下磁盘看起来闲但数据库的等待时间是真的长问题在存储侧而不是主机侧。第三个才是考虑单块盘性能退化。这种情况下 %util 不会很高但 await 明显偏高同时队列深度上不去。判断方法是看这块盘的历史基线如果它比一个月前的响应时间翻了一倍那就是硬件层面在变差。这条链路的经验是iostat 的数字必须建立在“设备映射正确”这个前提上否则所有的分析都是对着别人家的数据做推理。4.3 可用内存持续下降但进程本身没占多少现象是 free 出来的 available 值在几天内从 60% 掉到 10%但 top 排序看下来没有任何进程的 RSS 明显增长。这种情况很容易被当成内存泄漏上报然后进入漫长的排查。第一步应该看 /proc/meminfo 的构成。如果下降的部分是被 Slab 或者 PageTables 拿走的那就和用户态进程无关是内核层面的对象缓存。oswslabinfo 就是为这个准备的看哪个 slab 对象在持续增长通常能定位到具体的内核子系统。第二步看是不是文件缓存没有被正确统计。有些环境里大量文件读写会把 page cache 撑得很大available 会相应变小但这些缓存是可回收的不代表内存紧张。判断标准是看有没有换页si/so 为零就不算真紧张。第三步才考虑数据库自己的内存管理。数据库的共享内存通常在启动时就分配固定大小不会持续增长但 PGA 这类按需分配的部分会随着并发上升而涨。这个可以从 oswps 里的进程 RSS 变化趋势看出来。这条链路的重点是“内存不够”这个结论必须由换页行为来支撑而不是由 free 的数字来支撑。只看 free 就下结论是新手最常见的误判。5. 数据收集齐了之后怎么让第二个人也能看懂性能排查很少有一个人从头干到尾的情况数据往往要在运维、DBA、开发、厂商之间流转。这时候数据的可读性和上下文完整性比数据本身的精度更重要。5.1 抓取时间段的选择比打包工具重要我见过很多次把整个归档目录原样打包发出去的情况几十个 G 的包对方下载要半天打开之后发现 99% 的数据和问题无关。正确做法是先做时间窗口裁剪原则是“问题开始前 15 分钟到问题结束后 15 分钟”。为什么要有前置窗口因为问题的根因往往发生在现象出现之前。比如内存泄漏是在凌晨三点开始积累的业务投诉是早上九点你只抓九点那段看到的只是一个已经满了的结果看不到增长过程。前置窗口给的就是这个增长曲线的起点。为什么要有后置窗口为了确认恢复动作的效果。你调整了参数或者重启了服务恢复的那一瞬间各指标怎么变化的这个信息对判断根因极有价值。很多人抓完问题点就收工等别人问“你改完之后好没好”的时候答不上来。裁剪可以用脚本按文件名批量筛因为文件名本身就带起始时间按时间排序取区间内的文件就行。这个过程要小心的是跨零点的文件需要按文件名时间有序合并之后再切。5.2 交付之前必须补的三样东西纯粹的数据包是没有分析价值的交付时至少补齐这三样一是时间范围的明确说明包括时区。写成“5 月 12 日 14:00 到 16:00主机本地时间UTC8”不要只写“下午两点到四点”。二是指标的对应关系。主机上有几块盘、数据库的数据文件在哪个挂载点、哪个进程是数据库主进程这些信息在原始数据里是看不出来的但对方分析时必须知道。我一般会附一个简单的说明表。三是已知的业务背景。那个时间段有没有做大促、有没有跑批量任务、有没有做过发布这些外部事件对解读数据至关重要。少写这一句对方可能会花几个小时去研究一个由批量任务引起的 CPU 峰值。提示如果数据要交给外部支持团队主机名、IP、路径里的敏感信息需要提前处理。别等着对方问你要提前做好比事后补更省事。6. 长期跑着不管早晚会出的几个问题OSW 因为太简单很容易被装完之后遗忘。但它在生产环境里是要长期跑的放着不管会积累出一堆毛病。6.1 归档被覆盖、脚本被误删、时区被改归档被覆盖是所有问题的头号来源而且往往在你最需要数据的时候才发现。表现是打开目录一看最早的文件是昨天下午的而你要查的是前天晚上的事。防范办法很简单就是把保留时长的实际占用算出来并且在监控里加一条对归档目录大小的监控。空间不够的时候宁可拉长采集间隔也不要缩短保留时长——间隔拉长只是精度下降保留时长缩短是直接把数据弄丢了。脚本被误删的问题多半发生在系统清理或者目录迁移的时候。OSW 的脚本都是明文 shell改过参数之后如果没备份重新部署一遍还得重新配。我的做法是把整个目录做一次 baseline 打包放在另一个路径下出问题直接解压回来。时区被改的影响比较隐蔽。如果主机时区调整过OSW 之前写的数据用的是旧时区之后的是新时区同一个目录里的文件时间轴会错位。排查时如果不注意这一点会得出“某时刻数据缺失”的错误结论。所以每次分析前先确认那段时间内主机有没有做过时间同步或者时区调整。6.2 用一个简单的健康检查脚本兜住长期运行与其依赖人记得检查不如让系统自己检查。除了前面提到的用 pid 文件做进程拉起之外我还建议加两个检查一是每天检查一次最新文件的时间戳如果超过采集间隔的 3 倍还没更新说明采集卡住了二是每周检查一次归档目录的体积增长趋势如果某天突然暴涨多半是采集器或者设备数量发生了变化。#!/bin/bash ARCHIVE/opt/oswbb/archive LATEST$(find $ARCHIVE -name *.dat -printf %T\n | sort -n | tail -1 | cut -d. -f1) NOW$(date %s) GAP$(( (NOW - LATEST) / 60 )) if [ $GAP -gt 5 ]; then echo OSW 采集可能已停止最后更新在 ${GAP} 分钟前 # 这里接告警通知 fi这个脚本不复杂但它能把“数据悄悄没了”这种最难发现的问题变成一条告警。我在实际运维里的体会是监控工具本身也需要被监控尤其是那种“装完之后就不用管”的工具恰恰是最容易失效的。最后分享一个小习惯每次做完一次没有找到根因的排查我都会在归档目录旁边留一个文本文件写上这次排查的时间范围、已经排除了哪些方向、还剩下哪些怀疑点。下一次问题复发的时候这份笔记比任何图表都值钱因为它省掉的是重复劳动。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/31 11:46:48
MySQL实训通关指南:建表约束、查询连接与存储过程全解析
2026/10/31 11:46:48
Git修改已推送Commit的实践与风险控制
2026/10/31 11:46:48
Go语言实现公链转账功能的核心技术与实践
2026/10/31 12:42:20
金蝶KIS跨版本升级实战:账套迁移、精度处理与数据安全避坑指南
2026/10/31 12:42:20
分布式事务原理与主流实现方案解析
2026/10/31 12:42:20
高通NPU端侧大模型推理框架调研:QNN、ONNX Runtime与llama.cpp适配对比
2026/10/31 12:42:20
程序员专属云笔记:命令行驱动的可检索知识操作系统
2026/10/31 12:42:19
Docker部署Nacos服务注册与配置中心实战
2026/10/31 12:37:19
改进麻雀搜索算法在CCHP微网优化调度中的应用
2026/10/31 0:00:18
猫狗目标检测数据集:VOC/COCO/YOLO三格式一体化实战包
2026/10/31 0:00:18
HDU2017多校标程复现:算法竞赛工程化真题沙盒
2026/10/31 0:00:18
Codex Sandbox 隔离环境拆解:AI Agent 的临时实验室如何运作
2026/10/31 0:57:03
全国计算机二级C语言真题PDF高效刷题指南
2026/10/31 0:56:56
requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南
2026/10/30 21:48:31
递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现
2026/10/30 3:44:27
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/30 3:44:25
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/30 3:44:29
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)