
服务器性能出问题的时候大多数人第一反应是跑一把top看一眼CPU是不是爆了然后就没有然后了。真正要定位一个问题光有这几秒的瞬时数据完全不够需要的是连续几个小时的监控曲线CPU到底在哪个时间点飙升内存是逐步被吃光还是突然跳变磁盘I/O高峰和业务高峰是否重叠。nmon这套工具恰恰就是为这种场景设计的而且它天生适合离线环境——单个可执行文件不依赖重型环境采集完的数据还能直接落成文件带回本地用Excel分析。这篇文章就完整走一遍在CentOS 7内网机器上离线安装nmon配置后台定时采集再把nmon数据转换成Excel能用的格式最后做成图表来定位性能瓶颈。基础判断先说一下这套方案适合谁搞运维的、做系统交付的、还有在做压测和性能调优的开发特别是那些服务器在隔离内网、既不能随便外联也没法用软件源的场景。看完这篇文章你至少能解决两件事一是知道怎么在没有网的环境里把nmon跑起来二是知道采集到的那些看起来乱糟糟的文本数据怎么变成一张直观的Excel图表。1. 方案选型与总体思路1.1 为什么偏偏选 nmon 而不是其它监控命令Linux下的性能监控命令不少top、vmstat、iostat、sar各个都能输出指标但它们在离线、需要长期采集的场景里各有各的别扭。top适合临时瞄一眼数据不落盘想回放历史趋势基本靠截图vmstat和iostat能看实时信息也可以定时输出但是指标维度偏单一CPU、内存、磁盘、网络要凑齐得同时开好几个终端还得自己手工对齐时间轴sar相对完整但默认依赖sysstat包离线环境下装依赖本身就是个麻烦事而且默认配置未必覆盖你要监控的维度。nmon不一样它在设计上就很贴合“一个工具管到底”的思路。安装包本身是一个二进制文件拷过去就能执行交互模式下按几个快捷键就能看到CPU、内存、磁盘、网络、进程等十几类信息采集模式下可以后台连续记录输出一个自描述格式的.nmon文件里面把每类指标按区块组织好后续拿到办公机上用表格软件打开或者交给第三方分析器全链路都是通的。我实测下来nmon的采集对系统本身的影响也比较小默认2秒一个采样点只增加极小的CPU开销在性能问题排查的场景下可以接受。我把常见的监控工具做了一个简单对比方便你判断自己的场景到底选谁。工具实时查看长期采集指标维度离线部署难度数据后续处理top强弱CPU、内存、进程为主低差vmstat中中CPU、内存、IO低中iostat中中磁盘IO低中sar中强覆盖面广高依赖sysstat中nmon强强CPU、内存、磁盘、网络、进程等极低强适合Excel如果你的需求是“某一个时间窗口内发生了什么、当时各维度资源是啥状态”nmon的综合成本最低。它不仅在采集阶段省心在数据分析阶段也少折腾这一点到后面讲Excel处理时体会会更明显。1.2 离线场景下的完整落地链路离线环境做监控最容易卡住的地方不是工具本身而是“怎么把工具弄进去”和“怎么把数据弄出来”。内网服务器出于安全考虑通常不开放外网访问也没有配可用的软件源镜像这时候直接执行yum install是不现实的你需要先在能联网的机器上把安装包准备好再通过运维通道传进去。整个方案的链路我分成五步第一步在联网主机上获取nmon的二进制包同时确认它依赖的动态库有哪些第二步把二进制包传到离线服务器的指定目录赋予可执行权限并做一次干净运行验证第三步根据监控需求计算采样间隔和采样次数用nmon的后台采集模式输出数据文件第四步把.nmon文件传回本地办公机做格式转换得到Excel可以直接识别的表格第五步在Excel里绘制趋势图结合业务时间点分析瓶颈。这里面每一步都有能踩的坑比如64位系统和32位二进制不兼容、缺少动态库导致执行时报错、crontab里写相对路径导致定时任务跑不起来、采集文件积攒太多把磁盘写满等等。文章主体部分我会把每一个环节的做法和替代方案都讲透尽量让你照着操作一遍就能完整跑通。2. 离线安装包准备与安装验证2.1 在联网主机上准备安装包nmon的发布形式有几种最常见的是直接提供各个平台编译好的二进制压缩包里面已经包含了多种CPU架构和系统版本对应的可执行文件另一种是打包成rpm适合通过包管理工具安装。离线环境下我更推荐直接拿二进制因为它不依赖系统的包管理数据库拷过去就能当绿色工具用rpm方式反而多一步依赖检查。在联通的临时主机上最简单的获取方式是用yumdownloader把rpm包拉下来。这个命令本身来自yum-utils如果机器上没有可以先装上然后执行下面这段yum install -y yum-utils mkdir -p /tmp/nmon_pkg yumdownloader nmon --resolve --destdir/tmp/nmon_pkg执行完以后/tmp/nmon_pkg目录下会出现nmon的rpm包以及它依赖的其它包比如ncurses-libs。--resolve这个参数很关键它会把nmon运行所需的动态库依赖一起拉下来省得你在离线服务器上装到一半发现缺库。如果机器能访问软件源里的所有扩展仓库也可以直接把整个依赖树打包。实际生产环境中大量服务器是连软件源都不通的。这种情况下我的做法是找一台和离线服务器操作系统版本相同、且能联机的跳板机在跳板机上执行上面的命令然后用scp把rpm包推到内网服务器上。操作系统版本尽量一致因为不同版本对glibc和ncurses的版本要求有差异跨大版本容易翻车。如果你拿到的不是rpm包而是一个zip格式的压缩包解压以后会看到一堆带系统后缀的二进制文件比如带_x86_64_centos7后缀的那个就是CentOS 7 64位对应的版本。选定的文件单独抽出来剩下的一概不管。2.2 上传、安装与快速验证先把准备好的二进制文件传到目标服务器。内网环境常见的通道是堡垒机加跳板或者直接通过运维网络传文件。上传完成后放到一个约定好的目录比如/opt/nmon方便统一管理。如果是rpm形式安装命令很简单rpm -ivh /tmp/nmon_pkg/nmon*.rpmrpm装完以后可执行文件一般会放到/usr/bin/nmon下面直接用nmon命令就能启动。如果是绿色二进制方式需要手动赋予执行权限chmod x /opt/nmon/nmon_x86_64_centos7 ln -s /opt/nmon/nmon_x86_64_centos7 /usr/bin/nmon做完软链接以后nmon命令在任何目录下都能直接调用后面写crontab也就省心。下一步做验证直接在终端敲nmon如果屏幕上出现了从上到下的实时数据面板说明二进制能跑动态库也都齐了。提示如果执行时提示找不到共享库文件最常见的原因是ncurses库缺失或版本不对。CentOS 7离线环境里可以先尝试rpm -qa | grep ncurses看看已安装的版本正常情况下系统自带的ncurses-libs就能满足要求只有那种被极度裁剪过的基础镜像才需要手动补装。验证结束时按q退出交互界面就能回到命令行。到这里离线安装环节就算收尾了后面要做的所有采集和分析都建立在这个能正常运行的二进制之上。3. nmon 数据采集实操3.1 交互模式快速查看系统状态启动nmon之后它是一个全屏交互界面底层按键控制显示哪些数据。刚进去默认只显示基础信息这时候可以按下面的常用键来切换视图按c显示CPU的每核心使用率以及整体汇总按m显示物理内存和交换分区的使用情况按d显示磁盘组的读写速率和繁忙度按n显示各网卡的收发包和速率按t显示系统最耗CPU的进程列表按V显示虚拟内存相关统计。交互模式适合在线排查比如接到报警说某台机器CPU满载登上去敲nmon按c和t一秒钟之内就能看到是哪个进程在吃CPU非常直接。不过它有一个局限一旦退出nmon数据就全没了没法回溯之前十分钟发生了什么。所以但凡要做周期性观测或者事后分析就必须切换到后台采集模式。真正到性能分析的时候我习惯的流程是先在交互模式下快速看一眼当前状态然后立刻启动后台采集让它连续记录一段时间这样既有现场快照又有完整曲线两边信息互相印证。3.2 后台采集模式的参数设计与原理解读nmon的后台采集模式核心就一句话定期把各项指标追加写入文件跑够指定次数后自动退出。命令格式如下nmon -f -s 5 -c 720 -m /var/log/nmon这里-f表示后台写文件模式输出文件会自动按主机名和时间戳命名比如xxx_220601_1530.nmon-s 5表示每5秒采集一次-c 720表示总共采集720次-m指定输出目录。5秒乘以720次正好是3600秒也就是一小时。如果你想要不同的采集时长记住这个公式采集间隔秒数乘以采集次数等于总时长秒数。参数选型没有绝对标准主要看你的分析粒度。如果是排查偶发性问题间隔定为10秒或30秒就够了太密的采样点除了让文件变大、分析时图表拥挤并没有额外价值如果是压测现场需要看秒级抖动那就用2到5秒的间隔。内存和磁盘这类指标变化相对平滑不需要过密采样而CPU占比突发性很强想抓住瞬态峰值就最好用5秒以内的间隔。实际使用中nmon采集进程会常驻在前台即使-f也不能真正后台化。如果你希望它完全脱离终端运行可以在命令前加nohup让它转向后台执行。现在的系统服务里很多人会把它做成systemd服务来托管但离线二进制配合nohup已经足够应付大多数临时采集需求不需要把复杂度提得太高。采集文件的大小也和采样频率成正比。按5秒间隔采集一天文件大概在几十MB上下按1秒间隔会大得多。对长期监控来说我的建议是先算一下磁盘余量再把输出目录挂到有独立空间的分区避免把根目录撑爆。3.3 定时采集与文件管理策略很多场景下监控不是一次性任务而是一天24小时、连续一周甚至更久的例行工作。比如你想观察业务高峰期的资源变化提前预判扩容时机就需要每天固定时段采集。这时候crontab是比手工执行更靠谱的选择。在crontab里加一行比如每天早8点开始采集8小时每10秒一个采样点0 8 * * * /usr/bin/nmon -f -s 10 -c 2880 -m /var/log/nmon /dev/null 2110秒乘以2880次就是28800秒正好8小时。注意crontab里的执行命令最好写绝对路径包括nmon路径和输出目录路径否则容易出现任务执行了但文件不知道写到哪去的情况这类问题一会儿到常见问题部分细说。长期跑下来/var/log/nmon目录会积累大量文件。我建议写一个简单的清理脚本配合crontab执行比如只保留最近30天的.nmon文件。脚本不复杂核心就是把超过保留天数的文件删掉find /var/log/nmon -name *.nmon -mtime 30 -delete运维实践里还有一个很多人忽略的点监控文件本身也要有统一的命名和归档习惯。nmon默认按主机名和时间命名如果你的服务器命名混乱建议在采集脚本里对生成文件做一次重命名加上环境和业务标签比如带上应用名缩写和内网IP的最后一段这样后续从几十台机器收集来的数据放到一起时一眼就能分辨出是哪台机器哪天的采集结果。4. nmon 数据解析与 Excel 化处理4.1 nmon 文件格式到底长什么样拿到.nmon文件以后直接用文本编辑器打开你会发现它不是二进制乱码而是结构化的文本里面每一行以AAA开头后面跟着指标区块名和数据。这种设计的精妙之处在于它把不同类型的数据用区块隔离开解析的时候只要按区块名取值就行后续无论是写脚本转换还是交给现成工具成本都很低。举个最典型的结构AAA,procx,Linux,221201,1530,09,3.10.0-957.el7.x86_64 AAA,CPU001,12,6,80,2 AAA,CPU_ALL,5,3,90,2 AAA,MEM,MemoryMB,2048000,2048000,0,0,0,0,1274374,... AAA,NET,eth0,0,0,0,0,0,0,0,0,... AAA,DISKBUSY,sda,12.5第一行是元数据包含主机名、系统版本、采集起始时间和内核版本CPU_ALL后面的数字分别是用户态占比、系统态占比、空闲占比等MEM后面是各种内存总量、可用量NET后面跟着收发包字节数DISKBUSY那类行则是磁盘繁忙度。字段顺序在不同版本的nmon里会有细微差异所以做转换脚本的时候不能硬编码列序号我后面给出的脚本会更稳健地按区块处理。用Excel直接打开这个文件不是不行但体验很差因为文本里大量元信息行、不同指标的列宽不齐而且时间戳格式对Excel不友好做图表时轴上的时间点会对不齐。所以中间必须经过一个转换环节。4.2 用脚本把 nmon 转成规整的 CSV转换的思路并不复杂读原始文件按行区分区块把每个区块内相同指标的行攒起来最后输出成若干列。为了实用性重点提取CPU_ALL、MEM、DISKBUSY、NET这几个最常见区块就够了其它细节指标可以按需扩展。下面这个脚本是我在实际项目中用过的简化版用Python3编写核心逻辑做了几处稳健性处理比如不管区块行首是否有空格都先strip把各种字段保留为文本防止Excel把前导零吞掉。import csv import sys def parse_nmon(path): # 收集各区块的全部行 blocks {} with open(path, r, encodingutf-8, errorsignore) as f: for line in f: line line.strip() if line.startswith(AAA): parts line.split(,) tag parts[1] blocks.setdefault(tag, []).append(parts) return blocks def convert(input_path, output_path): blocks parse_nmon(input_path) # 只处理关心的几个核心区块 wanted (CPU_ALL, MEM, DISKBUSY, NET) selected {tag: blocks[tag] for tag in wanted if tag in blocks} times [] col_data {} for tag, rows in selected.items(): for parts in rows: if len(parts) 5: continue ts parts[2] times.append(ts) col_data.setdefault(tag, []).append(parts[3:]) # 按时间点对齐输出 with open(output_path, w, newline) as f: w csv.writer(f) header [time] for tag in selected: sample_len len(col_data[tag][0]) if col_data[tag] else 0 header.extend([{}_{}.format(tag, idx) for idx in range(sample_len)]) w.writerow(header) row_count len(times) for i in range(row_count): row [times[i]] for tag in selected: if i len(col_data[tag]): row.extend(col_data[tag][i]) w.writerow(row) if __name__ __main__: source sys.argv[1] target source.replace(.nmon, .csv) convert(source, target)运行方式也很简单python3 nmon2csv.py server_221201_1530.nmon运行完以后Excel打开这个CSV就能看到规整的表第一列是时间后面每一列对应一个采集指标。如果觉得指标列还是太杂可以在脚本里把需要的列单独挑出来只留CPU用户态、系统态、空闲率、内存总量、可用量、磁盘总线忙绿比这些核心指标。注意如果.nmon文件是从Windows环境传输过来的文本行尾可能带了\r回车符打开前最好用dos2unix转换成LF否则CSV的表格会被弄出多余空行。站点上还有一些现成的第三方Excel分析宏原理上就是替你做了解析和制图导出的图表更丰富。但我个人体验是自己手握一个转换脚本更灵活起码可以按自己的口径去定义指标也不会被宏的安全设置卡住。5. Excel 图表制作与性能瓶颈分析5.1 核心指标怎么选才不会看花眼一个.nmon文件转换出来指标列可能有几十列如果全部丢进Excel做折线图结果就是一坨毛线什么也解读不出来。实际分析时我的习惯是先明确问题域再挑重点维度通常从四个方向入手。CPU维度只看两个指标CPU_ALL里的用户态占比和系统态占比。用户态高说明应用或者计算任务吃CPU系统态高往往意味着系统调用频繁、锁竞争或者内核态模块在消耗资源两类原因对应的排查方向完全不同。内存维度优先看可用内存的绝对值以及swap的读写量这两个指标能反映内存是否真的吃紧。磁盘维度看DISKBUSY的百分比配合CPU的等待占比能够区分磁盘I/O瓶颈和纯CPU计算瓶颈。网络维度看收发包速率和错误包数量判断是否存在流量异常。选指标时还有一个容易被忽略的地方字段单位。内存的原始值在nmon里是MB网络速率可能是KB/s如果混在一张图里数量级差着上千倍小块数据会被大块数据直接压成一条直线。遇到这种情况要么分开成两张图要么用Excel的次坐标轴让两条曲线各用各的刻度。5.2 Excel 折线图制作与坐标轴对齐技巧转换出来的CSV文件用Excel打开后做图表的步骤并不复杂。先选中时间列和你想看的指标列插入折线图然后调整X轴格式。这里有一个实战小技巧如果时间列是1530这种HHMMSS文本格式不要直接当坐标轴用先把它转成常规时间格式否则图表横轴要么出现1800这种超大的数要么被错误当作文本排序。最简单的处理方式是在CSV转换脚本里就把时间格式化成Excel认识的HH:MM:SS字符串再在Excel里把该列设置为时间格式。插入图表时横轴选择该列生成的折线就会按采集时间均匀铺开。如果中间有断点检查原始.nmon文件里是不是某一次采集没写进去这种断点往往对应操作系统负载过高导致nmon进程短暂卡死。多指标对比时建议先做一张“总览图”把CPU、内存、磁盘、网络的关键指标都放上去用次坐标轴区分量级发现哪个维度有异常趋势再单独抽出来做局部放大。分析长期数据的时候可以用数据透视表把小时数据聚合观察是否存在每天固定时间重复出现的高峰这比盯着原始秒级数据看更抓重点。5.3 从一个异常曲线反推瓶颈的分析方法有一次我处理过一个典型场景某个业务系统每天下午两点左右响应变慢应用日志里没有明显报错但用户端感觉明显延迟。运维同事在服务器上临时起了nmon采集频率30秒一次连续跑了三天。把Excel图表拉出来以后每天下午两点这条时间轴附近CPU的用户态占比并不高但等待占比从5%一下跳到40%以上对应的磁盘繁忙度也同步冲高到90%左右。这个匹配关系说明瓶颈不在CPU计算而在磁盘I/O。再往下深挖发现那个时间点正好是定时数据备份任务启动的窗口备份任务对大目录做全量扫描并写盘把I/O带宽基本吃满。后来把备份任务挪到业务低峰期响应时间的报警就消失了。这个过程里Excel图表的作用就是把三个独立的指标按照同一时间轴摆在一起让相关性一目了然。如果只看实时top或者分段日志很难把磁盘繁忙和系统卡顿这两件事关联起来。所以做分析的时候不要只画一张孤立的指标曲线而是尽量把CPU等待、磁盘IO、网络速率放在同一个时间窗口里对照这样才更容易找出真正的因果链。6. 常见问题与避坑指南6.1 现场高频问题速查表离线环境安装和后续采集踩坑的密集程度远比想象中高。下面这张表汇总了我见过的大多数问题每一行都对应一个真实发生过的场景。现象常见原因解决办法执行nmon提示Permission denied二进制文件没有可执行权限chmod x 对应二进制提示error while loading shared libraries: libncurses.so.5ncurses动态库缺失或版本不匹配检查ncurses-libs是否已安装rpm -q ncurses-libs界面能打开但数字不刷新终端类型不对部分SSH客户端对全屏刷新支持差换用标准终端或xterm重新连接后启动nmon找不到输出文件crontab看起来没执行cron环境变量PATH里没有nmon路径crontab中写完整路径 /usr/bin/nmon采集文件内容正常但Excel打开乱序文本行尾回车符来自Windows批量传输用dos2unix处理后再转换或改传输模式为binarynmon运行报date相关的错误服务器系统时间异常或时间同步服务未工作先校准系统时间再重启nmon采集采集文件越积越大磁盘空间告急没有配置清理策略用find按mtime定期清理并评估采集频率两个不同平台的二进制传错下载包里面对应的是另一个架构的版本确认uname -m结果选择匹配的二进制这张表里最容易被忽略的是crontab路径问题。crontab启动时加载的PATH很精简并不包含/opt/nmon这类自定义目录。之前有人把nmon放在/opt/nmon下crontab里只写了nmon -f -s 30 -c 120任务确实在跑但系统找不到命令文件一个都没有生成。改成写全绝对路径以后问题立刻解决。6.2 长期监控的几条实操心得在做长期nmon监控的时候我总结了几条经验未必在官方文档里看得到但实际帮过我不少忙。第一条正式部署前先做短周期小批量验证。不管你计划用30秒还是5秒的采样间隔先跑个两分钟的测试采集确认文件能正常生成再用Excel打开确认格式对最后才挂到crontab里长期跑。每次调整参数都这样来一遍能省掉大量来回排查的时间。第二条命名规范要提前定好。nmon默认的文件名带主机名但如果你的服务器命名没有业务含义数据混在一起根本分不清。我的做法是把采集脚本里加上环境名前缀比如在脚本里执行一次重命名把文件统一整理为app_web01_20220601.nmon这种格式这样后续归档和检索都高效。第三条采集目录要和系统根目录分离。长期监控必然产生文件如果/var/log所在分区本来就紧张监控数据会在不知不觉中把磁盘吃出一块隐患。把采集目录挂到独立分区或者至少给/var/log单独留足空间这是成本极低但收益明显的一条。第四条数据传回本地时尽量压缩传输。一个高频率采集的nmon文件可能几十MB如果每天都要从几十台服务器拉回来带宽开销不小。先gzip或使用压缩工具压一遍再传能减少大半体积本地解压后再分析流程完全不受影响。最后再说点实在的按上面这套流程走下来从离线安装到Excel图表分析工具链其实非常轻一个可执行文件、一个转换脚本、一个Excel模板就构成了一条完整的性能排查流水线。我个人在使用中的一个体会是nmon的价值不止在于“能看到实时状态”更在于“采集成本足够低、数据形态足够开放”让后续分析有充分的自由度。你完全可以先把这套流程跑通再根据自己服务器的实际情况去定义指标口径和制图模板时间长了甚至可以沉淀出一套适合自己团队的性能分析套路。真到了线上出故障、需要快速翻历史曲线的时候你会发现提前布置nmon绝对是一件高性价比的事。