接到业务反馈"昨天下午服务好像断过一次",你登录服务器,第一件事该做什么?看监控?翻应用日志?其实最快的方式是先回答两个问题:这台机器上一次启动是什么时候,运行了多久。如果 uptime 显示已经连续运行 180 天,那么"重启导致中断"的假设可以直接排除;如果显示只运行了 2 小时,那就顺着重启记录去查是谁、什么原因触发的。查看系统启动时间与重启记录,是故障定位里成本最低、信息量最大的第一步,本文汇总 uptime、who、last、journalctl、systemd-analyze 等一整套命令,并说明每种方法在什么场景下最可靠。
一、uptime:一眼看运行多久、负载多高
uptime 是最常用的命令,不需要 root,任何用户都能执行。
# 基础用法 uptime # 只输出启动时刻(util-linux 2.28+ 支持 -s) uptime -s # 只输出运行时长的人类可读格式 uptime -p # 配合 w 命令,还能看到当前登录用户在干什么 w
典型输出与逐段解读:
14:32:10 up 87 days, 3:21, 2 users, load average: 0.15, 0.21, 0.18
- 14:32:10:当前系统时间。
- up 87 days, 3:21:连续运行 87 天 3 小时 21 分钟,这就是自上次启动以来的运行时长。如果显示 "up 2 min",说明刚重启过。
- 2 users:当前登录用户数。
- load average: 0.15, 0.21, 0.18:过去 1 分钟、5 分钟、15 分钟的系统平均负载(可运行态 + 不可中断睡眠态的进程数)。
负载怎么判断:把 1 分钟均值与 CPU 逻辑核数对比(nproc 查看核数)。长期高于核数说明 CPU 饱和;1 分钟值远高于 15 分钟值说明负载在快速上升;反过来则说明高峰已过。举例:4 核机器 load average 为 8.00、4.20、2.10,说明最近一分钟严重过载而整体趋势在回落。
需要注意的是:容器里的 uptime 显示的是宿主机的运行时长(因为 /proc/uptime 没有做命名空间隔离),所以不要用它判断容器何时启动。
二、查看"上次启动的具体时刻"
uptime 只给时长,要看具体时间点有四种方法,各有适用场景。
# 方法 1:最简洁,直接给出启动时间戳
uptime -s
# 输出示例:2024-06-15 09:11:03
# 方法 2:who -b,读取 /var/log/wtmp,几乎所有系统都支持
who -b
# 输出示例:system boot 2024-06-15 09:11
# 方法 3:从 /proc/uptime 自己算(适用于极简环境)
cat /proc/uptime
# 输出:7612345.67 7500123.45 (第一列=启动至今秒数,第二列=空闲时间累计秒数)
date -d "$(awk '{print $1}' /proc/uptime) seconds ago"
# 方法 4:systemd 系统专用
systemd-analyze
# 输出:Startup finished in 3.2s (kernel) + 12.8s (userspace) = 16.0s
/proc/uptime 的第二列是系统空闲时间累计(所有 CPU 的 idle 之和),在多核机器上它可能远大于第一列,这是正常的,别当成异常。用 awk 换算成天数的写法:awk '{printf "%d 天 %.1f 小时\n", $1/86400, ($1%86400)/3600}' /proc/uptime。
2.1 内核记录的 btime
# /proc/stat 中的 btime 是启动时刻的 Unix 时间戳 grep btime /proc/stat # 输出:btime 1718416263 date -d @1718416263 # 输出:2024年 06月 15日 星期六 09:11:03 CST
这是最"原始"的数据源,不依赖 wtmp 文件是否被轮转或清空,在审计场景下最可靠。
三、last:查重启与关机历史
last 命令读取 /var/log/wtmp,它是二进制文件,记录了所有登录、登出、系统启动与关机事件。查看重启记录是它的拿手好戏。
# 只看重启记录(最常用) last reboot # 同时看关机和重启(推荐,-x 显示系统状态变更) last -x reboot last -x | grep -E 'reboot|shutdown|system' # 只看最近 5 条 last -n 5 reboot # 指定时间范围 last -s 2024-06-01 -t 2024-06-30 reboot # 查看关机记录 last -x shutdown # 查看用户登录历史 last -n 20 last zhangsan # 查看失败登录尝试(读 /var/log/btmp) lastb -n 20 # 各用户最后登录时间 lastlog
典型输出解读:
reboot system boot 5.14.0-362.el9 Mon Jun 15 09:11 still running reboot system boot 5.14.0-284.el9 Wed Apr 3 22:07 - 09:09 (87+11:02) reboot system boot 5.14.0-284.el9 Fri Mar 15 03:41 - 22:05 (19+18:24)
- 第一行 still running:当前这次启动仍在运行,09:11 就是本次启动时刻。
- 其余行的时间段:形如
22:07 - 09:09 (87+11:02),表示该次启动从 4 月 3 日 22:07 持续到 6 月 15 日 09:09,共 87 天 11 小时 2 分钟。 - 内核版本列:这里能看到每次启动加载的内核版本,如果两次启动的内核版本不同,说明期间做过内核升级并重启,这对排查"升级后异常"非常有用。
注意:wtmp 文件会被 logrotate 轮转(通常保留一个月),所以 last reboot 只能看到有限的历史。如果文件被清空(> /var/log/wtmp)就什么都查不到了。需要长期留存建议把 wtmp 轮转周期调长,或把关键事件同步到远程日志服务器。
四、systemd 环境:更精细的启动分析
在使用 systemd 的发行版(CentOS 7+/Ubuntu 16.04+/Debian 8+)上,有一组专门工具可以看启动耗时、逐次启动日志。
# 总体启动耗时 systemd-analyze # 按耗时排序列出各单元(找出拖慢开机的服务) systemd-analyze blame | head -20 # 生成启动过程关键路径 systemd-analyze critical-chain # 列出所有启动序号及时间范围 journalctl --list-boots # 输出示例: # -2 8f3a... 一 2024-03-15 03:41:22 CST—五 2024-04-03 22:05:11 CST # -1 2b1c... 三 2024-04-03 22:07:03 CST—六 2024-06-15 09:09:58 CST # 0 9d7e... 六 2024-06-15 09:11:03 CST—六 2024-06-15 14:32:10 CST # 查看上一次启动的日志(-0 是本次,-1 是上次) journalctl -b -1 journalctl -b -1 -p err -n 100 # 查看上次启动结束前 10 分钟的日志(找宕机线索) journalctl -b -1 --until "2024-06-15 09:09" -n 200 # 只看本次启动以来的错误 journalctl -b -p err --no-pager
journalctl --list-boots 非常有用:0 表示当前这次启动,-1 是上一次,-2 是上上次。配合 journalctl -b -1 可以直接查看"上一台机器生命末期"发生了什么,比如 OOM killer 记录、文件系统错误、电源事件等。注意该功能依赖持久化的 journal(/var/log/journal 目录存在),否则重启后日志就丢了。
判断标准:systemd-analyze blame 里某个服务耗时超过 10 秒就值得关注(比如网络等待、NFS 挂载超时、DNS 解析卡住都会显著拖慢启动)。常见元凶是 systemd-networkd-wait-online.service,它在网卡拿不到地址时会等满默认 120 秒。
五、运行状态综合体检
确认了启动时间,通常还要看当前运行状态是否健康。一条命令组合可以给出完整快照。
# 主机名、内核、系统版本、启动时间一屏看完(systemd 专用) hostnamectl # 内核与发行版 uname -a cat /etc/os-release # CPU 概览 lscpu | grep -E 'Model name|^CPU\(s\)|Thread|Core|Socket' # 内存 free -h # 磁盘 df -hT -x tmpfs -x devtmpfs # 负载与进程 top -bn1 | head -20 # 系统活动统计(需安装 sysstat) sar -q 1 3 # 负载与队列 sar -r 1 3 # 内存 sar -n DEV 1 3 # 网卡流量
hostnamectl 的输出里会直接给出 Boot ID 与内核版本,配合 uptime 就足以写进巡检报告。sar 需要 sysstat 包并开启采集(systemctl enable --now sysstat),它提供历史数据,是"事后复盘昨天下午发生了什么"的关键工具。
六、常见场景速查表
| 需求 | 推荐命令 | 说明 |
|---|---|---|
| 运行了多久 + 当前负载 | uptime | 最快,无需 root |
| 具体启动时刻 | uptime -s 或 who -b | -s 需较新 util-linux |
| 历次重启记录 | last -x reboot | 读 /var/log/wtmp,受轮转限制 |
| 历次关机记录 | last -x shutdown | 区分正常关机与异常掉电 |
| 不依赖 wtmp 的启动时刻 | grep btime /proc/stat | 审计场景最可靠 |
| 启动耗时瓶颈 | systemd-analyze blame | 找出拖慢开机的服务 |
| 上一次启动的日志 | journalctl -b -1 | 追查上次宕机原因 |
| 所有启动序号清单 | journalctl --list-boots | 0=本次,-1=上次 |
| 失败登录尝试 | lastb | 读 /var/log/btmp,安全巡检用 |
| 用户最后登录时间 | lastlog | 排查僵尸账号 |
七、巡检步骤清单
- 先看运行时长:
uptime,判断是否近期重启过。若 uptime 远小于预期,说明发生过非计划重启,需要深挖原因。 - 取具体启动时刻:
uptime -s或who -b,与业务反馈的故障时间点比对。 - 看重启历史:
last -x reboot,观察重启频率是否异常(比如每周同一时间重启,很可能是定时任务或自动更新)。 - 对比内核版本:last 输出里相邻两次启动的内核版本不同,说明期间做过内核升级。
- 查上次生命末期日志:
journalctl --list-boots拿到序号后执行journalctl -b -1 -p err,重点找 OOM、I/O error、power 相关记录。 - 看异常情况:
last -x shutdown,如果没有对应的 shutdown 记录而直接出现新的 reboot,说明是非正常掉电或内核 panic(硬重启)。 - 评估当前状态:
hostnamectl+free -h+df -h+top -bn1,形成完整快照。 - 落库与告警:把 uptime 与 last reboot 纳入定期巡检脚本,并对"意外重启"配置告警(可对比 /proc/stat 的 btime 是否变化)。
小结
查看系统启动时间这件事,命令都很短,但组合起来信息量很大:uptime 看运行时长与负载、uptime -s 或 who -b 看启动时刻、last -x reboot 看重启历史、journalctl -b -1 看上一次生命末期的日志、systemd-analyze blame 看启动瓶颈。判断的关键在于"交叉验证"——如果 last 里有 shutdown 记录,说明是计划内关机;如果没有 shutdown 却出现 reboot,那就要按异常宕机去查电源、内核 panic 或 OOM。养成把 btime 与 uptime 写进巡检脚本的习惯,意外重启就能在第一时间被发现,而不是等业务投诉才后知后觉。
避坑清单
- 容器里 uptime 显示的是宿主机时长,判断容器启动时间要用
docker inspect --format '{{.State.StartedAt}}' 容器名或systemctl show -p ExecMainStartTimestamp。 - 别把 /proc/uptime 第二列当运行时长,它是所有 CPU 空闲时间累计,多核机器上会大于第一列。
- wtmp 会被轮转和清空,last 的历史不完整是常态;关键审计需求应依赖 journal 或远程日志。
- journalctl -b -1 需要持久化 journal,默认只在 /run 下时重启即丢,创建 /var/log/journal 目录并重启 systemd-journald 才能留存。
- 负载平均值包含不可中断睡眠(D 状态)进程,所以 I/O 卡死时 load 也会飙高,不要只盯着 CPU 使用率。
- uptime -s 在很老的发行版上不支持,此时用
who -b或date -d @$(awk '/btime/{print $2}' /proc/stat)替代。 - 虚拟机热迁移会导致 uptime 跳变,看到异常短的运行时长时先确认是否做过迁移或快照恢复。
企业QQ咨询




