一台跑了七八年甚至更久的小型机,半夜突然业务卡死,电话打过来第一句话通常是"机器是不是坏了"。等你远程登进去,uptime显示还在跑,业务进程也活着,那问题八成藏在日志里。这篇就以 HP-UX 小机的故障检测为切入点,专门聊 LOG 这一块:这台机器上到底有哪些日志、它们分别记什么、出问题时怎么在几分钟内从几十万行里捞出关键那几行、以及平时该怎么治理才不至于关键时刻日志断档。内容偏实操,适合刚接手 HP-UX 平台、又不想每次故障都靠重启和猜测过关的运维同行,也适合做了几年 Unix 但一直把日志当"出事了再 tail 一下"的读者。我不会只给你命令清单,重点讲清楚每条命令背后的假设,以及我踩过的那些坑。
1. 先把这台机器上的日志家底盘清楚
1.1 系统日志的三条主干线
很多人接手一台 HP-UX 小机,第一反应是cd /var/adm然后对着目录发呆。这个目录在老版本里是杂物间,在新版本里依然是。要快速建立地图感,抓住三条主干线就够了:内核与系统服务日志、登录与审计日志、硬件与平台事件日志。这三类日志的存放位置、格式、读取工具都不一样,混在一起看只会越看越乱。
第一条主干线是syslog体系,核心文件是/var/adm/syslog/syslog.log,滚动出来的旧文件通常叫OLDsyslog.log,配置文件在/etc/syslog.conf。内核打印、inetd、sshd、cron、nfs客户端、存储多路径、卷管理器的告警,绝大多数都会汇到这里。要注意一个历史差异:HP-UX 10.x 时代系统消息走的是/var/adm/messages,11i 之后才统一到syslog.log。如果接手的是非常老的机器,或者从别的平台迁过来的脚本还去读messages,会读到一个空文件然后误判"系统没有报错"。
第二条主干线是登录审计,/var/adm/wtmp记录成功登录和系统开关机事件,/var/adm/btmp记录失败登录,读取工具是last,失败记录用lastb或者在支持的环境下指定文件读取。这条线在排查"谁在故障时间点登过机器""是不是有人误操作"时非常关键,因为syslog.log里su和sshd的记录可能因为日志级别配置而缺失,但wtmp是登录框架自己写的,相对可靠。
第三条主干线是硬件与平台层,/var/adm/crash/放崩溃转储,/var/adm/ras/下有一堆名字很短的二进制或半文本文件,errdump与硬件错误相关,shutdownlog记录关机动作,还有 EMS 框架的事件日志落在/var/opt/resmon/log/下面。这条线是 HP-UX 相对其他 Unix 最有辨识度的部分,也是最容易被忽略的部分,因为不少同行习惯性地把它当成"惠普自己的东西,看不懂就不看了",结果硬件已经报了几天的磁盘预测故障,最后靠业务雪崩才发现。
1.2 每个文件该在什么时候看
盘清家底之后,更重要的是建立"什么症状看什么文件"的条件反射。我自己的习惯是按故障表现倒推,而不是按目录顺序遍历,这样能省掉大量无效阅读。下面这张表是我这些年最常用的对照关系,直接照着查能覆盖八成以上的现场。
| 故障表现 | 首选日志 | 辅助手段 |
|---|---|---|
| 系统莫名重启 | /var/adm/shutdownlog、syslog.log尾部 | who -b、uptime、crash 目录 |
| 业务进程被杀 | syslog.log中的out of memory、signal关键字 | dmesg输出、swapinfo |
| 文件系统只读或写入失败 | syslog.log中的vmunix行 | bdf、mount -p |
| 存储链路抖动 | syslog.log中的SCSI、lan、disk关键字 | ioscan -fnC disk、lanscan |
| 登录异常或账号锁定 | /var/adm/btmp、wtmp | last、lastb |
| 硬件风扇电源告警 | EMS 事件日志、errdump | cstm的sel、MP 事件日志 |
| 性能周期性劣化 | /var/adm/sa/下的sar数据 | sar -f回放、top |
注意表的最后一列。日志本身很少能单独定案,它提供的是时间点和现象,真正的结论要靠命令去现场验证。我见过太多人拿着一条SCSI: Queue full就断言磁盘要坏,实际是备份窗口把队列打满了。日志是线索,不是判决书,这个心态得先摆正。
1.3 那些容易被忽略的"半日志"
严格来说,/var/adm/sa/下的sar数据不算日志,是采样数据,但它在故障检测里的作用不亚于日志。系统默认通过cron里的sa1、sa2定时采集,文件名是saDD的格式,按日一个。故障时间点如果落在昨天,syslog.log里可能只有寥寥几行报错,但你用sar -f /var/adm/sa/sa12回放一下当天下午的 CPU、内存、磁盘、网络曲线,往往能看出异常是从几点几分开始爬升的。
还有/etc/rc.log,记录系统启动过程中每个启动脚本的执行情况。机器启动到一半卡住、某个服务没起来、文件系统检查耗时过长,这类问题在syslog.log里可能只有一句笼统的提示,但在rc.log里能看到具体卡在哪个环节。这个文件在故障复盘时价值很高,只是平时没人想起来看。
2. 日志系统的运行机制,决定了你能不能信它
2.1 syslog.conf 的匹配规则不是"从上到下"
/etc/syslog.conf的语法看起来很简单,facility.level加一个动作,中间用 Tab 分隔。问题在于很多人把它当成顺序执行的规则表,以为写了*.err /var/adm/syslog/syslog.log就只收 err 及以上。实际规则是:同一个 facility 的多个 selector 会叠加,同一行里用分号可以排除,而且默认的syslog.log配置往往写着*.notice;*.err之类看起来重复的写法。
举个我实际调整过的例子。默认配置里可能有一行*.notice;auth.debug /var/adm/syslog/syslog.log,意思是 notice 及以上全部记,同时 auth 相关连 debug 也记。为了排查某次登录问题,有人把auth.debug改成了*.debug,结果第二天/var分区直接打满,业务写文件报错,反而制造了一次故障。*.debug这种配置在测试环境试一下可以,生产上绝对不要随手放开,一个高频打印的守护进程能在几小时内写出几个 G。
改完配置之后必须重启或通知syslogd重读,命令是/sbin/init.d/syslogd restart,或者找到 pid 文件发HUP信号。这里有个细节:重启syslogd不会丢失已有的日志内容,但如果你在重启前把日志文件删了,syslogd会继续往那个已经不存在的 inode 里写,ls看不到任何新增,日志"凭空消失"。这个现象非常迷惑人,我第一次遇到时排查了很久,最后是lsof发现文件被占用但路径不存在才反应过来。正确做法是先停服务、或者用: > /var/adm/syslog/syslog.log清空内容而不是删除文件。
2.2 syslogd 挂了,日志就是一片安静
最可怕的不是日志里有报错,而是日志突然停止增长。业务在小规模报错,而syslog.log时间戳停在三天前,这通常意味着syslogd进程已经死了,或者它的写入目标出了问题。检查顺序建议是:先ps -ef | grep syslog确认进程在不在,再bdf /var/adm确认分区有没有满,最后ls -l看文件权限和属主有没有被人改过。
分区满是最常见的死因。/var或/var/adm单独划了分区且容量给得很小,是十几年前装机时的常见做法,放到今天根本不够用。分区满了之后,syslogd写不进去,某些版本会持续报错但继续运行,某些情况下会直接退出。更麻烦的是分区满会连带影响其他服务,比如cron写不了日志、inetd起不来、临时文件创建失败,最后表现为"一堆不相关的功能同时出问题",如果只盯着应用看,很容易误判成应用自身缺陷。
我的做法是在监控里对syslog.log的修改时间加一条告警,超过 15 分钟没有更新就报警。这条规则比监控进程是否存在更有效,因为进程活着但不写日志的情况太常见了。
2.3 时间基准不统一,日志就是废纸
跨设备排查最怕什么?最怕两台机器的时间差了几分钟。你在应用服务器上看到 14:03:12 开始报超时,在数据库小机上对应的日志时间却是 13:58:30,这时候你去grep "14:03",什么都抓不到,然后得出"小机侧没有异常"的错误结论。HP-UX 上时间同步依赖xntpd,配置在/etc/ntp.conf,启动脚本是/sbin/init.d/xntpd。
我建议在故障发生前就把时间这件事做扎实:用date和上游时间源比对一眼,偏差超过 30 秒就该处理。同时要接受一个现实——即使做了同步,日志里只有"月 日 时:分:秒",没有年份。跨年排查时,年初出问题去翻去年的日志,grep "Jan 3"会把两年前的记录一起翻出来。判断年份的办法是看文件本身的修改时间和轮转记录,或者干脆按文件切分,OLDsyslog.log一定比syslog.log早,逐层往前推。
还有个小坑:业务方给你的故障时间是"大概下午两点多",这个精度对日志排查毫无帮助。我通常会要求对方提供一个可锚定的动作,比如"两点十分重启过一次应用""两点半刷新页面开始报错",然后以这个动作在日志里的痕迹作为锚点,前后各扩展十分钟作为抓取窗口。窗口开得太大反而看不到重点。
3. 故障现场的标准排查动作
3.1 从时间锚点到关键行,五步收敛
现场只有几十万行日志、业务方催着要结论的情况下,必须有固定套路,否则很容易被日志牵着鼻子走。我自己的五步法是:定锚点、切窗口、抓异常、去噪声、做关联。
第一步定锚点,用业务动作或系统事件把时间锁定到分钟级,参考上一节说的方法。第二步切窗口,不要cat整个文件,直接用awk按时间字段过滤。这里要注意 HP-UX 日志的字段位置:多数 11i 版本的行格式是"月 日 时:分:秒 主机名 子系统[PID]: 消息",但也有早期版本或特定配置下省略主机名的情况,所以写脚本前先head -5看两眼,别想当然按固定列切。
第三步抓异常,用egrep把常见错误模式一次捞出来。第四步去噪声,把监控轮询、定时任务这类规律性的正常输出排除掉。第五步做关联,把日志时间点、sar曲线、ioscan现场状态三者对照,形成能自洽的解释。这五步里最容易跳过的是第五步,也是最容易出错的地方。
3.2 几条能直接抄走的命令
下面这些命令我在现场反复用过,改动量很小就能适配不同机器。先看时间窗提取,假设要抓 3 月 12 日下午 14:00 到 14:30 的内容:
# HP-UX 默认 sh 环境,避免使用 bash 特有语法 awk '$1=="Mar" && $2==12 && $3>="14:00:00" && $3<="14:30:00"' \ /var/adm/syslog/syslog.log > /tmp/win_0312_1400.log注意字符串比较在这里是可行的,因为时:分:秒是定长格式,补零之后字典序和时间序一致。但如果你的日志格式里日字段是空格补齐而不是零补齐(像Mar 2),字符串比较依然能用,只是要注意$2的值是2而不是02,条件里别写错。
抓异常关键字的写法:
egrep -i 'error|fail|panic|timeout|reset|offline|full|denied|scsi|lan[0-9]' \ /tmp/win_0312_1400.log | egrep -v 'monitor|heartbeat' \ > /tmp/win_0312_1400_err.log-i不能省,HP-UX 上不同子系统的大小写习惯不一致,有的是全小写,有的是首字母大写,漏掉一种就漏掉一半线索。egrep -v那一步是去噪声,实际用的时候噪声词要根据自己环境补,有的环境是备份软件的轮询,有的是集群心跳,不排掉的话真正的错误会被埋掉。
去重统计能让异常模式快速浮现:
awk '{for(i=5;i<=NF;i++) printf "%s ", $i; print ""}' /tmp/win_0312_1400_err.log \ | sed 's/[0-9]\{1,\}/N/g' | sort | uniq -c | sort -rn | head -30这段的作用是把消息体里的数字统一替换成N,再去重计数,这样"同一个错误重复了几百次"和"同一类错误变了几十个不同参数"就能区分开。前者往往指向持续性资源问题,后者往往指向批量对象出错。这个技巧不是 HP-UX 专属,但在这类小机上特别好用,因为它们的日志量级刚好卡在"人工看得累、又不至于必须上专业平台"的区间。
3.3 五类典型故障的日志指纹
故障检测的难点不在于会不会用grep,而在于看到某几行时能不能立刻联想到根因。我按经验整理了几类高频故障在 HP-UX 日志里的"指纹",命中之后可以直接往对应方向深挖。
第一类是内存耗尽。日志里会出现内核杀进程的记录,或者应用侧报Cannot allocate memory、out of memory。这时候要立刻swapinfo -tam看交换区使用率,再用sar -w回放故障时间段的换页情况。要注意 HP-UX 的交换策略和 Linux 差异较大,早期版本对交换空间的管理更保守,内存超配的容忍度低,业务量涨一点就可能在日志里冒出一堆分配失败,而top里看 CPU 还很闲,容易误判成应用 bug。
第二类是文件系统写满或只读。指纹是vmunix前缀的行里出现file system full、no space、read-only。这类故障有一个很讨厌的连锁反应:日志自己也在被写的分区里,分区一满,后续日志全丢,你在日志里看到的最后一条恰好是"空间不足",然后就没有然后了。所以遇到这类情况,先把bdf的输出完整存一份,再动手清理,别一边清一边丢证据。
第三类是存储链路问题。指纹包括SCSI、disk、device、offline、path这些词。HP-UX 上多路径和卷管理器的日志比较散,可能在syslog.log,也可能在硬件事件日志里。出现这类记录时要配合ioscan -fnC disk看设备状态,用vgdisplay -v看卷组里有没有 PV 掉线。我遇到过一次日志里反复出现某块盘的重试记录,但业务无感,三天后这块盘彻底掉线,卷组降级,业务才开始报错。如果当时看了日志,提前换盘就没这回事。
第四类是网络异常。指纹是网卡名加link、down、up、reset,还有NFS server not responding。这里要提醒一句:NFS卡住时应用表现出的现象是"进程 D 状态、不可中断",ps看得见但不干活,很容易被当成应用死锁。实际根因在网络或存储侧,日志里的 NFS 超时记录才是关键线索。
第五类是异常重启。shutdownlog里能看出是不是有人手工关机,who -b能确认最近一次启动时间,如果两者对不上,或者日志在某个时间点突然从头开始,就要去/var/adm/crash/看有没有崩溃转储。有转储说明是内核级故障,没有转储但确实重启了,可能是电源或硬件层面的事件,这时候要去看 MP 的事件日志。
4. 日志容量治理,别等出事才想起分区
4.1 分区打满的连锁反应比想象中严重
前面提过分区满是syslogd的头号杀手,这里展开说连锁反应,因为很多人对"满"的严重性估计不足。/var满之后,第一个受影响的是日志写入,第二个是临时文件和锁文件,第三个是某些服务启动时需要的状态文件。业务侧可能表现出"登录不上""命令执行报错但看不出原因""服务起不来但没有任何日志"。
排查这种局面的顺序是:bdf看所有分区使用率,du -kx /var/adm | sort -rn | head -20找目录级的大户,再用find定位大文件。这里有个 HP-UX 特有的细节必须说清楚:老版本find的-size参数单位是 512 字节的块,且不支持+50M这种带单位的写法。写脚本时如果用 Linux 上的习惯,会得到一个完全错误的结果,要么找不到文件,要么找出海量小文件。
# HP-UX 老版本 find:-size 单位是 512 字节块 # 找大于 50MB 的文件:50*1024*1024/512 = 102400 find /var/adm -type f -size +102400 -exec ls -l {} \;这个单位换算我建议直接记下来,+102400对应 50MB。如果机器是较新的 11i v3,find可能支持后缀写法,但为了脚本能在所有机器上跑,用块数最保险。
4.2 轮转策略要按"故障窗口"倒推
很多人做日志轮转是拍脑袋定个大小,比如 100MB 就切。我建议反过来算:你的故障从发生到被发现,平均间隔多长?如果是核心交易系统,几分钟就有人报障,那日志保留三天就够;如果是内部支撑系统,可能一周后才有人反馈"上周三有点慢",那你的日志必须能覆盖两周以上。
按这个思路倒推,我一般给syslog.log设的阈值是 200MB 到 500MB,保留四到八份滚动文件,同时保留至少一个月的归档压缩包。归档目录单独放,不要和活动日志挤在同一个分区,否则归档本身又成了空间隐患。
轮转脚本要注意三件事:一是切换过程不能让syslogd写丢,正确姿势是先mv再给syslogd发信号让它重建文件,或者干脆重启服务;二是滚动文件要有明确的命名和排序规则,方便脚本按时间倒序清理;三是脚本本身要有日志,记录"什么时候切了多大文件",否则哪天轮转失败你都不知道。
也可以用系统自带的logrotate,部分版本是预装的,用which logrotate确认一下。有就用它,配置比手写脚本清晰;没有就别硬装,一条cron加二十行sh足够解决问题。HP-UX 上装第三方包要走swinstall,为了一个轮转功能去折腾软件仓库,性价比不高。
# 简易轮转脚本示例,放在 cron 里每小时跑一次 LOG=/var/adm/syslog/syslog.log MAXSIZE=209715200 # 200MB,单位字节 if [ -f "$LOG" ]; then SIZE=`ls -l $LOG | awk '{print $5}'` if [ "$SIZE" -gt "$MAXSIZE" ]; then STAMP=`date +%Y%m%d%H%M` mv $LOG /var/adm/syslog/syslog.log.$STAMP /sbin/init.d/syslogd restart gzip /var/adm/syslog/syslog.log.$STAMP fi fi这段脚本在 POSIXsh下能跑,注意别改成bash语法,HP-UX 默认 shell 未必有bash。另外ls -l取文件大小在文件名有空格时会出问题,日志文件名是固定的,所以这里安全,但如果你改成通用的,记得加引号。
4.3 远程汇聚:单机日志的最大价值在"活得比机器久"
单机日志有个根本缺陷:机器一旦宕机或者磁盘损坏,日志跟着一起没了。而最有价值的故障复盘,恰恰是"机器为什么会宕机"。所以我一般会给关键小机配一条syslog转发,把*.err及以上级别的日志同步到一台日志收集机上。配置就是在/etc/syslog.conf里加一行,指向收集机的地址,然后重启syslogd。
这件事的价值在于,崩溃前的最后几条记录会留在远端。本地日志因为写入缓冲或者磁盘故障丢掉了,远端往往还留着。我经历过一次电源相关的意外停机,本地syslog.log最后一行是半小时前的正常记录,远端收集机上却有停机前 30 秒内的几条硬件告警,直接锁定了方向。就凭这一次,后面所有关键机器我都加了转发。
要注意两点:转发只发 err 以上级别,别把 debug 也转过去,否则网络和收集端都扛不住;另外转发是尽力而为的 UDP,不保证到达,别把它当审计合规手段,它的定位是"多一份现场记录"。
5. 常见问题与踩坑实录
5.1 日志缺失排查速查表
日志类问题最让人抓狂的不是内容看不懂,而是"该有的没有"。下面这张表是我遇到过的日志缺失场景和对应处理,按发生频率排序。
| 现象 | 可能原因 | 验证与处理 |
|---|---|---|
| 日志停止增长 | syslogd退出 | ps -ef确认,重启服务 |
| 日志停止增长 | 分区满 | bdf确认,清理后重启服务 |
| 删除后无新日志 | 文件被进程占用,写入已删除 inode | 重启syslogd,用清空代替删除 |
| 某类日志完全没有 | syslog.conf级别未放开 | 核对 selector,改后重启服务 |
| 登录记录缺失 | wtmp被清理或轮转 | 检查last输出,确认轮转脚本 |
| 硬件告警查不到 | 未启用 EMS 或日志已滚动 | 检查/var/opt/resmon/log/目录 |
| 崩溃无转储 | 转储区未配置或空间不足 | 检查转储配置与目标分区容量 |
表格里第三行值得单独说。用rm删日志文件,是新手最容易犯的错,因为在很多场景下删了就删了,看起来没问题,但syslogd还握着旧的文件描述符,后续写入全部进了"已删除但被占用"的空间,bdf上甚至看不出空间释放。正确做法是: > /var/adm/syslog/syslog.log,用重定向清空内容,文件 inode 不变,服务无感。
5.2 几个只有踩过才知道的细节
第一个细节:syslog.log里的时间没有年份,跨年排查会翻出陈年旧账。我现在的习惯是每次重大故障后,把抓取窗口的日志另存一份到归档目录,文件名带上完整日期,这样以后复盘时不用再去猜年份。
第二个细节:grep关键字要留余量。搜磁盘问题别只搜disk,还要搜SCSI、device、path、offline;搜网络别只搜lan,还要搜网卡实例名和link。不同版本的固件和驱动打印的措辞不一样,同一类问题在两台机器上的日志文本可能完全不同。我的做法是先攒一个关键字库,每次新遇到一种措辞就补进去,久而久之命中率会明显上升。
第三个细节:cstm和 MP 的用法在不同机型、不同固件版本上差异不小。cstm是字符界面的硬件诊断工具,进去之后可用的子命令取决于平台,Integrity 系列上常见的是用sel读系统事件日志;MP 的命令行里sl看事件日志、lc清日志,但具体命令集合以he帮助输出为准,别照着旧笔记硬敲。硬件日志的读取我一般只做两件事:确认是否有电源、风扇、温度、磁盘预测故障这几类记录,然后把原始输出整段保存下来交给硬件侧判断,不自己下结论。
第四个细节:不要在生产机上随手tail -f一个大日志然后放着不管。看着无害,实际上长时间挂着会占住文件描述符,有些环境里还会因为终端会话超时导致进程残留。用完就 Ctrl-C,或者用tail -n 500一次性看。
第五个细节:日志里有敏感信息。登录失败记录可能包含用户名,业务日志可能带内部地址和参数,别随手贴到公开渠道去问问题。要贴就把主机名、地址、账号名替换掉,这个习惯得养成。
接手一台陌生的小机,我做的第一件事往往不是看业务,而是花二十分钟把日志体系摸一遍:syslog.conf里配了什么、日志分区多大、轮转有没有做、EMS 有没有启用、sar数据在不在。这二十分钟的投入,在第一次半夜故障时会连本带利还回来。日志这东西平时看不出价值,出事的时候它就是唯一还愿意跟你说实话的东西,前提是你得让它一直在写、写下来的东西还留得住。