一台 uptime 显示跑了 400 多天的服务器,是运维的骄傲还是隐患?两种说法都有道理:长时间不重启说明系统稳定,但也意味着这台机器上的启动配置从未被真正验证过——你改过的 fstab、装过的新内核、调过的 GRUB 参数,全都没有经历过一次真实的开机检验。真到某天意外断电,它可能就起不来了。本文讨论的不是"要不要定期重启"这种伪命题,而是:什么情况下必须重启、什么情况下不必、以及如何把重启这件事做得可控。
一、长时间运行真正会带来哪些风险
| 风险 | 成因 | 如何观测 | 是否必须重启 |
|---|---|---|---|
| 内核补丁未生效 | 新内核已安装但仍在跑旧内核 | uname -r 与 /boot 下最新内核不一致;/var/run/reboot-required 存在 | 是(或使用热补丁) |
| 库升级未生效 | glibc、OpenSSL 等被替换,老进程仍持有旧版本内存映像 | needrestart、dnf needs-restarting | 需重启相关服务,不必整机重启 |
| 内存与句柄缓慢泄漏 | 应用或内核模块未释放资源 | RSS 单调上升、fd 数持续增加 | 重启服务即可 |
| 启动配置从未验证 | fstab、GRUB、网卡配置改过却没重启过 | 只有重启才能暴露 | 是(这是最被低估的理由) |
| 文件系统错误累积 | 在线无法做完整的 fsck | tune2fs -l 的挂载次数与检查间隔 | 建议在维护窗口内重启并检查 |
| 内核软锁死/挂起任务 | 驱动缺陷、硬件异常 | dmesg 中的 soft lockup、hung task | 是,且要尽快 |
| 时钟漂移 | 长期未校时或 NTP 服务失效 | timedatectl、chronyc tracking | 不必,修 NTP 即可 |
其中最容易被忽略的是第四项。一台三年没重启的机器,它的 /etc/fstab 可能在两年前加过一块数据盘、网卡配置换过一次 netplan 文件、GRUB 参数改过一次——这些改动全都是"未验证状态"。一旦因停电或硬件故障意外重启,多个未验证项会同时爆发,而此时你既没有准备也没有窗口。相比之下,一次计划内的重启能提前把这些雷排掉。
二、判断:这台机器到底有没有"欠重启"
# 1. 开机时长与上次启动时间
uptime
uptime -s
who -b
last -x reboot | head -10
awk '{printf "%.1f 天\n", $1/86400}' /proc/uptime
# 2. Debian/Ubuntu:apt 会在需要重启时留下标记文件
ls -l /var/run/reboot-required 2>/dev/null && cat /var/run/reboot-required.pkgs
# 3. 当前内核 vs 已安装的最新内核
uname -r
ls -1 /boot/vmlinuz-* | sort -V | tail -1
dpkg -l | grep -E 'linux-image-[0-9]' | awk '{print $2, $3}' # Debian/Ubuntu
# rpm -qa | sort | grep '^kernel-' # RHEL 系
# 4. 哪些进程还在使用已删除的旧库文件
sudo needrestart -k # Debian/Ubuntu,需安装 needrestart
sudo checkrestart -v # 需安装 debian-goodies
sudo dnf needs-restarting -r # RHEL 8/9 系
# 5. 内核级别的异常记录
dmesg -T | grep -iE 'soft lockup|hung task|call trace|mce|hardware error|out of memory'
journalctl -k -p err --no-pager | tail -30
# 6. 开机耗时与启动次数(评估启动健康度)
systemd-analyze
journalctl --list-boots | wc -l
2.1 三类场景的判定
| 判定 | 典型条件 | 建议动作 |
|---|---|---|
| 必须重启 | 存在 /var/run/reboot-required;当前内核落后于已安装内核;出现 soft lockup / hung task / MCE 硬件错误;更换过硬件或磁盘 | 尽快排入维护窗口,先做快照 |
| 可延后重启 | 只有库(glibc/OpenSSL)更新需要生效;单纯的运行时间长但各项指标平稳 | 逐个重启受影响的服务;整机重启排进季度维护窗口 |
| 不必重启 | 仅日志、临时文件堆积;NTP 失效;配置已通过其他方式生效 | 做清理与校时即可,不用付重启的中断代价 |
关于"运行时间长"本身:Linux 内核并没有一个"必须重启的时间上限"。跑几百天本身不代表有问题,关键是上面这些可观测指标是否健康。把"uptime 数字大"当作重启理由是错误的,把"数字大所以不敢重启"当作不重启的理由同样错误。
三、能不重启就解决的部分
很多"重启一下就好了"的问题,其实有更精准的解法,代价小得多。
3.1 内核热补丁(Livepatch)
如果重启的唯一理由是"内核安全补丁没生效",可以考虑热补丁方案:Canonical Livepatch(需配合 Ubuntu Pro 订阅使用,具体适用范围以官方说明为准)、RHEL 的 kpatch、以及第三方商业热补丁服务。它们只对部分CVE 生效,不能替代常规维护窗口,但能显著推迟重启时间。
# Ubuntu 查看与启用(需先完成 Ubuntu Pro 绑定) pro status sudo pro enable livepatch # canonical-livepatch status sudo canonical-livepatch status
3.2 systemd 自身升级后不必重启
sudo systemctl daemon-reexec # 重新执行 systemd 自身,无需重启整机 systemctl --version sudo systemctl daemon-reload # 只重载单元文件配置,不替换 systemd 二进制
3.3 只重启受影响的服务
# 找出哪些服务在用被替换的库 sudo needrestart -k -l # 逐个优雅重启(注意先摘流量、确认有副本) sudo systemctl restart nginx sudo systemctl restart php-fpm # 确认重启后版本的确变了 systemctl show -p ExecMainStartTimestamp nginx
3.4 清理类操作不必重启
# journald 日志限容(避免长期运行把 /var 撑满) sudo journalctl --vacuum-size=1G sudo journalctl --vacuum-time=30d journalctl --disk-usage # 临时文件清理(按 /usr/lib/tmpfiles.d 与 /etc/tmpfiles.d 的策略) sudo systemd-tmpfiles --clean sudo du -sh /tmp /var/tmp # 日志轮转(先做干跑验证) sudo logrotate -d /etc/logrotate.conf sudo logrotate -f /etc/logrotate.d/nginx # 回收页缓存(仅临时缓解,不是"优化",不要写进定时任务) sudo sync echo 3 | sudo tee /proc/sys/vm/drop_caches
关于 drop_caches:它只能释放可回收的 page cache,不能解决内存泄漏,而且会立刻让后续的文件访问变慢。把它当"定期维护手段"是典型误区。
四、重启前的检查清单
- 确认有回退路径:云盘快照或系统快照已创建,并且验证过可恢复。这一步几十秒,是重启操作里最重要的保险。
- 核对启动配置:
/etc/fstab用 UUID、非关键挂载点带nofail;update-grub已执行过;GRUB 默认启动项是你要的那个内核。长期未重启的机器,这一步必须做。 - 确认当前内核能启动:
uname -r所指的内核文件在/boot下确实存在,且对应的 initramfs 也已生成完整。若/boot曾经写满过,务必先执行update-initramfs -u -k all再重启。 - 确认数据已落盘:数据库执行过 checkpoint/刷盘,消息队列消费积压已清空,缓存有副本或可接受冷启动。
- 集群场景逐个来:不要同时重启多个节点。先重启一台观察 10~15 分钟,确认能正常加入集群再继续下一台。
- 确认监控能感知:告警规则、健康检查、看门狗都在线,别在监控盲区里重启。
- 通知与时间选择:避开业务高峰,提前通知相关方,用
wall或shutdown的广播提醒当前登录用户。
4.1 计划重启的执行方式
# 定时重启并广播通知(+5 表示 5 分钟后,也可写绝对时间 02:00) sudo shutdown -r +5 "计划维护重启,请保存工作" # 取消 sudo shutdown -c # 提前广播一条消息给所有登录用户 sudo wall "本服务器将在 5 分钟后重启" # 重启后核对:是不是真的起来了新的内核 uptime -s uname -r systemctl --failed journalctl -b -p err --no-pager | head -30 # 快速回看上一次开机耗时 systemd-analyze systemd-analyze blame | head -10
五、让"必须重启"这件事变少:稳定性优化
重启只是兜底。真正决定机器能连续稳定跑多久的,是下面这些日常配置。
| 优化项 | 做法 | 监控阈值建议 |
|---|---|---|
| 服务自愈 | 关键服务配置 Restart=on-failure、RestartSec=5s,并显式调大 StartLimitBurst(默认仅 5) | 监控 NRestarts,1 小时内 >3 次告警 |
| 内存泄漏 | 采集 RSS 趋势(sar -r 或 PSI),定期对比 | RSS 7 天上涨 >30% 且无回落即排查 |
| 句柄泄漏 | 采样 ls /proc/PID/fd | wc -l | 达到 LimitNOFILE 的 80% 即告警 |
| 日志容量 | journald 配 SystemMaxUse;应用日志用 logrotate 切割 | /var 使用率 >80% 告警 |
| 内核异常处理 | 设置 kernel.panic=10,panic 后 10 秒自动重启(默认 0 = 永不自动重启) | 重启事件本身告警 |
| 看门狗 | 启用硬件看门狗或 systemd 的 RuntimeWatchdogSec | 看门狗触发即最高级告警 |
| 配置一致性 | 用 Ansible/Salt 管理配置,保证重启后不会"回到出厂设置" | 定期跑 --check 巡检 |
| 变更可验证 | 任何影响启动的改动(fstab/grub/内核)都在测试机先走一遍 | 变更单记录验证结果 |
5.1 让机器"自己知道该重启了"
# 内核 panic 后自动重启(默认 kernel.panic=0 表示卡死不重启) echo 'kernel.panic = 10' | sudo tee /etc/sysctl.d/99-panic.conf echo 'kernel.panic_on_oops = 1' | sudo tee -a /etc/sysctl.d/99-panic.conf sudo sysctl --system # systemd 看门狗(60 秒内未被喂狗则强制重启) sudo systemctl edit --force --full /etc/systemd/system.conf.d/10-watchdog.conf # [Manager] # RuntimeWatchdogSec=60 # RebootWatchdogSec=10min sudo systemctl daemon-reexec systemctl show | grep -i watchdog # 确认硬件看门狗设备 wdctl 2>/dev/null || ls -l /dev/watchdog
5.2 建立重启记录与例行窗口
# 查看历史重启记录,区分计划内与意外 last -x reboot shutdown | head -20 journalctl --list-boots | tail -10 # 意外断电/异常关机的迹象(正常关机应有对应的 shutdown 记录) last -x | grep -E 'reboot|shutdown' | head -20 journalctl -b -1 -p err --no-pager | tail -20
建议做法:与其纠结"要不要定期重启",不如设定固定维护窗口(例如每季度或跟随内核安全补丁节奏),把内核升级、fsck、配置验证、快照一起做掉。这样重启变成一件可预期、有准备的事,而不是救火。
六、一次健康的重启该长什么样
- 提前 24 小时完成快照,并确认快照可用。
- 提前执行
update-initramfs -u -k all与update-grub,确认/boot有余量、内核文件完整。 - 逐节点执行:摘流量 → 确认无新请求 →
shutdown -r→ 等待启动完成。 - 启动后立即核对四项:
uname -r、systemctl --failed、ss -lntp端口是否齐全、业务健康检查是否通过。 - 观察 10~15 分钟无异常后,再放开流量并处理下一个节点。
- 记录本次重启的耗时、异常项与结论,作为下次维护窗口的输入。
小结
结论可以压缩成三句话:运行时间长本身不是重启的理由,但"启动配置从未验证"和"内核补丁未生效"是;能只重启服务就别重启整机;重启的价值来自计划性,而不是频率。
避坑建议:
- 不要因为
uptime数字大就重启,也不要因为数字大就不敢重启。判断依据是uname -r、/var/run/reboot-required、内核异常日志这些可观测指标。 - 重启前必做快照,且必须确认启动相关配置(fstab 用 UUID、GRUB 默认项正确、initramfs 完整)。长期未重启的机器最容易在这一步翻车。
/boot曾经写满过的机器,重启前一定执行update-initramfs -u -k all,否则很可能停在 initramfs 提示符。- 集群务必滚动重启,间隔观察 10~15 分钟,绝不并行重启多个节点。
- 不要把
drop_caches写进定时任务,它解决不了内存泄漏,只会掩盖问题并制造性能抖动。 - 把
kernel.panic设置成 10(默认 0 表示 panic 后永不自动重启),让机器在极端情况下能自己恢复。 - 库升级(glibc/OpenSSL)后优先用
needrestart精准重启受影响服务,不要动不动整机重启。 - 维护窗口要形成记录:本次做了什么、耗时多久、有什么异常。这些记录是把"重启"从应急变成例行的关键。
稳定运行的服务器不是"从来不重启"的服务器,而是"随时可以安全重启"的服务器。把可重启性做扎实,比纠结 uptime 数字有意义得多。
企业QQ咨询




