拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux进程管理与计划任务:从原理到实战排查指南

Linux进程管理与计划任务:从原理到实战排查指南

Linux 进程与计划任务,这俩词放在一起,几乎就是 Linux 运维日常工作的半壁江山。无论是刚入行的新人,还是写了几年脚本的老手,每天打交道最多的无非就是:这进程怎么又挂了、那个任务怎么到点没跑、后台服务怎么总被误杀。我最早接触 Linux 的时候,第一个折腾明白的概念就是进程,因为不理解进程,你连“为什么 kill 掉一个程序这么费劲”“为什么 ps 里能看到一堆同名的东西”都说不清楚。而计划任务,说白了就是让系统替你做那些重复性的脏活累活。

这篇文章我不打算讲什么高深内核源码,也不罗列所有命令参数,而是把“进程管理和计划任务”这两个主题串成一条线:先看进程是什么、怎么查、怎么管,再看计划任务怎么写、怎么排障,最后用我实际遇到过的问题来收尾。适合刚入门想系统理解 Linux 的人,也适合那些会用命令但说不清原理、遇到问题全靠试的运维伙伴。读完你会发现,很多“玄学”问题其实都是我们自己没搞懂底层逻辑。

1. 先把进程这东西看明白

1.1 进程和线程,别再傻傻分不清

很多人一上来就纠结进程和线程的区别,面试题里几乎必考。但我更愿意先用一句话点破:进程是操作系统分配资源(内存、文件描述符、CPU 时间片)的基本单位,线程则是 CPU 调度执行的基本单位。翻译成人话就是——进程像一个工厂,线程是工厂里的工人。工厂有自己独立的厂房(独立的内存空间),工人共享这个厂房和里面的机器(共享进程内存),但每个工人各干各的活(各自有栈和寄存器状态)。

从这个类比能推出几个关键结论:

  • 进程之间天然隔离,一个进程崩了不会直接拖垮另一个;而同一进程内的线程是兄弟,一个线程 segfault 往往整个进程崩掉。
  • 进程切换开销大,因为要切换内存地址空间、刷新各种缓存;线程切换只在进程内部进行,开销小得多。
  • 进程间通信(IPC)需要额外机制,比如管道、信号、共享内存;线程之间直接读写共享变量即可,但要注意同步问题。

但注意,Linux 的线程实现有点特殊,它通过 clone 系统调用创建,很多资源是共享的,所以线程在 ps 里看起来可能像进程,只是对内核来说都叫“任务”。这就是为什么你有时候 ps -ef 看到很多同名 java 进程,其实它们是同一个 JVM 进程里的线程,只是被展示出来了而已。理解这一点,排查“为什么 java 进程 CPU 占用从 100% 变成 300%”这类问题时就有方向了——别急着 kill,先看是不是多线程在跑。

1.2 进程的一生:从 fork 到 wait

进程是怎么诞生的?绝大多数不是凭空出现的,而是由一个已有进程通过 fork() 系统调用复制出来的。复制出来的那个叫子进程,原来的叫父进程。fork 有意思的地方在于,它会让子进程拥有一份父进程内存的拷贝,但之后两者就各过各的了。然后通常子进程会调用 exec 系列函数去加载新的程序,把自己替换成别的程序。这就是我们常说的“fork + exec”。

那进程怎么结束?正常退出时调用 exit(),把退出码返回给父进程;不正常退出则收到信号,比如段错误会收到 SIGSEGV。这里有个关键点:子进程退出后并不会立刻消失,它会变成一个“僵尸进程”,直到父进程调用 wait() 或 waitpid() 来回收它的退出状态。如果父进程一直不收尸,僵尸进程就留在进程表里,虽然不占 CPU 和内存,但它占着一个进程槽位,积累多了系统就创建不了新进程了。

我之前遇到过一个数据库容器,跑了几个月后突然报 “fork: Cannot allocate memory”,但 free 一看内存还有一大半。最后就是检查进程表,发现有几千个 僵尸进程。根因是父进程脚本写得不严谨,没有 wait 子进程的退出状态。所以看到这里你就明白,热搜里那个“进程等待 wait”其实就是这个含义——父进程必须处理子进程的退出,否则系统会被尸体填满。

1.3 常用命令三板斧:ps、top、htop

排查进程最常用的就是 ps 和 top,虽然它们很基础,但很多人的用法其实是错的。先看 ps:

# 查看所有进程,显示完整命令 ps -ef # 查看所有进程,显示进程树关系 ps -ef --forest # 只查看某用户的进程 ps -u username # 过滤某个程序名 ps -ef | grep nginx

ps -ef 的字段从左到右分别是:UID(哪个用户的进程)、PID(进程号)、PPID(父进程号)、C(CPU占用)、STIME(开始时间)、TTY(所在终端)、TIME(累计占用CPU时间)、CMD(完整命令)。

这里有个细节:PID 和 PPID 一定要养成看的习惯。排查“某个服务怎么起不来”时,先确认是不是有一个父进程在循环拉起子进程,导致你 kill 完又活了。

top 是动态的,适合看实时状况。进去后按 P 按 CPU 排序,按 M 按内存排序,按 H 切换线程模式。这几个快捷键必须记住,比记 20 个参数有用得多。htop 是增强版,彩色,支持鼠标,但很多生产环境默认没装,所以我的建议是:ps 和 top 必须熟练到条件反射,htop 当作锦上添花。

2. 进程管理的进阶操作

2.1 守护进程与会话:让程序在后台稳住

“守护进程”这个词在热搜词里很显眼,因为它是后台服务的核心形态。普通进程和终端绑定,你关掉终端,进程收到 SIGHUP 信号就会退出。守护进程则脱离终端独立运行,生命周期从系统启动持续到关机或服务停止。

守护进程是怎么做到的?其实有三步:

  1. 调用 setsid() 创建新的会话,脱离控制终端。
  2. 忽略 SIGHUP 等与终端相关的信号。
  3. 把工作目录切换到根目录或其他固定目录,避免占用挂载点导致卸载失败。
  4. 把标准输入、输出、错误重定向到 /dev/null 或日志文件。

不过实际工作中,我们很少手写这么底层的逻辑。systemd 时代,通常就是写一个 service 单元文件,systemd 帮你把守护化过程处理好了。但你得知道原理,因为排查问题时需要判断:我的程序是不是被当作守护进程了?它当前属于哪个会话?可以用 pidstat 或者直接看 /proc/PID/stat 里的会话信息,也可以用 ps -o pid,ppid,sid,tty,cmd 来看。

我记得有次帮同事排查一个 Java 应用,他用 nohup 把进程放后台,结果过了两天进程莫名其妙没了。原因就是 nohup 只忽略 SIGHUP,但如果终端关闭导致进程变成孤儿后,某些情况下还是会因为资源限制被杀。真正想让服务 7x24 稳定跑,应该用 systemd 或 supervisor 这类进程守护工具,由它们负责拉起来、监控、重启。

2.2 给进程改名:修改进程名的正确姿势

热搜词里有一条很具体:“linux 修改进程名称 大于15个字符”。这确实是个常见需求——默认情况下,通过 exec 启动的程序,进程名就是程序名(在 /proc/PID/comm 里),而这个字段内核限制为 15 个字符。想改的话有几种思路:

最简单的做法是启动时用 bash 的 exec -a 参数:

exec -a my_custom_name /usr/bin/my_program

这在 Shell 层面设置了 argv[0],ps 看到的是自定义的名字。但注意,这种方式不影响 /proc/PID/comm 里的内核线程名,且长度仍受 argv 传递限制。

真正稳妥的办法是程序内部调用 prctl(PR_SET_NAME, "newname") 或者 pthread 里用 pthread_setname_np(),这能修改内核线程名。比如一个 Python 脚本,可以用 ctypes 调用 libc 的 prctl:

import ctypes libc = ctypes.CDLL("libc.so.6") libc.prctl(15, b"my_py_worker", 0, 0, 0)

那怎么让进程名超过 15 个字符?内核里 comm 字段就是 15 字节,这是硬限制,改不了。想显示更长的名称,只能在 /proc/PID/cmdline 上做文章,也就是 argv。比如你用/usr/bin/python3 /opt/myapp/worker.py --config /etc/worker.yml这种方式启动,ps 看到的其实是命令行,而命令行是没有长度限制的。所以实战中如果是脚本类程序,靠完整命令行就能区分不同实例;编译型程序才需要在代码层修改 comm 字段。

2.3 进程间通信 IPC:多条管道怎么连

热搜词里“进程通信(ipc)”是高频,也是面试和实际开发中都绕不开的。进程间通信的武器库里有:管道(pipe)、命名管道(FIFO)、消息队列、共享内存、信号量、信号、套接字。你说系统为什么需要 IPC?因为进程之间是隔离的,不能直接访问对方内存,但现实场景又需要协作,比如 Web 服务器让 N 个 worker 进程共享一个监听端口,比如监控进程去读取目标进程的状态。

让我挑几个常用的说说:

  • 匿名管道:cmd1 | cmd2那种,管道连接的是父子进程或兄弟进程,是单向的,临时存在于内存。它的本质是内核里的一段缓冲区,写端写、读端读,如果读端没准备好,写端会阻塞。这个特性经常在 shell 脚本里产生“假死”现象——进程明明在跑,却卡住不动,很可能就是管道缓冲区满了。

  • 命名管道 FIFO:mkfifo /tmp/myfifo创建,不相关的进程也能通过同一个文件路径通信,适合简单的单向对接。需要注意:读端打开时会阻塞,直到有写端打开,反之亦然。

  • 共享内存:性能最好,适合大数据量场景。但要注意“可见性”和同步问题,通常会搭配信号量使用,否则可能出现读写竞争。

  • 信号:这里不是指 signal 库的“信号量”,而是 PID 级别的异步通知机制。最常见的用法是 kill -TERM、kill -HUP。进程可以捕获这些信号做自定义处理,比如 Nginx 收到 HUP 就重载配置,不中断服务。

我实际使用中,跨语言或跨进程的轻量通信更倾向于用 Unix socket 或 TCP socket,因为它们稳定、语义清晰,调试工具也多(ss、nc、socat)。共享内存我会谨慎用,因为一旦进程非正常退出,锁没释放,排查起来挺痛苦的。给你一个避坑心得:能用文件锁解决的别用共享内存,能用 socket 的别碰信号量,原则就是——简单可靠优先,极端性能再说。

2.4 进程池与并发:一次启动的学问

热搜词里还有“进程池”,这更多是开发层的概念。比如 Python 的 multiprocessing.Pool、Golang 的 goroutine 配合 GOMAXPROCS、Java 的线程池。但运维视角下的“进程池”往往指的是预创建一类 worker 进程,比如 PHP-FPM 的进程池、Nginx 的 worker_processes、Celery 的 worker 数量。为什么要池化?因为进程创建和销毁的开销大,提前准备好 N 个进程(或线程),请求来了直接分配,能显著降低响应延迟,也便于控制资源上限。

配置进程池数量是我见过最容易踩坑的地方。不是越多越好,因为:每个进程都占一定的内存(哪怕空闲),上下文切换要消耗 CPU,磁盘 IO 密集任务还可能互相争抢锁。以 PHP-FPM 为例,我曾经把进程数从 50 调到 200,本意是提升并发能力,结果内存直接爆掉,Swap 被疯狂占用,响应反而更慢了。后来根据 PM = dynamic,pm.max_children = (总内存 - 预留内存) / 单进程平均内存占用 来算,16G 的机器只给了 80 左右,问题迎刃而解。所以见到“进程池”关键词,不要只想到代码,更要想到系统资源预算。

3. 计划任务:让系统自己干活

3.1 cron 与 crontab:定时任务的老祖宗

计划任务的重头戏肯定是 cron。cron 是系统里的一个守护进程(cronie 或 vixie-cron),它每分钟醒来一次,检查是否有要执行的任务,有则通过 sh 执行。配置方式有两种:用户级 crontab 和系统级 crontab。

用户级用crontab -e编辑,格式是五个时间字段加一条命令:

分 时 日 月 周 命令

例如每天凌晨 3 点备份数据库:

0 3 * * * /usr/local/bin/backup_db.sh >> /var/log/backup_db.log 2>&1

字段从左到右依次是:分钟(0-59)、小时(0-23)、日(1-31)、月(1-12)、周(0-7,其中 0 和 7 都表示周日)。*表示任意,*/15表示每 15 分钟,1,15表示第 1 和第 15 分钟,2-6表示 2 到 6 的范围。

系统级 cron 任务放在 /etc/crontab 文件里,或者在 /etc/cron.d/ 目录下,文件格式里比用户级别多了一个“用户名”字段:

0 3 * * * root /usr/local/bin/cleanup.sh

我强烈建议,有日志有标准输出的脚本任务不要直接写裸命令,一定要写脚本文件。因为 crontab 环境变量非常精简,不加载 /etc/profile 和 ~/.bashrc,你平时能跑的命令,放到 cron 里可能就找不到环境变量、找不到 PATH 路径。所以脚本第一行建议写#!/bin/bash,第二行加载必要环境:source /etc/profile,然后所有路径用绝对路径。

3.2 一次性任务 at 与 loop:临时需求怎么办

cron 适合周期性任务,但“今天下午 4 点执行一次”“5 分钟后跑一个脚本”这种临时需求,用 at 更合适。我用一个真实例子:有一次线上数据库需要做表结构变更,DBA 评估后说凌晨 1 点做影响最小,但又不想改 crontab,于是我用了:

echo "mysql -u root -e 'ALTER TABLE ...'" | at 01:00

这样到了时间会自动执行,而且 at 会把任务挂到 atd 守护进程上,即使终端退出也不影响。查看任务列表用atq,删除任务用atrm 编号。

与之类似地,在较新的系统里也有 systemd-run 可以生成临时的一次性 timer,但 at 轻量、简单,仍然是我的首选。有一点要注意:at 默认是否被允许取决于 /etc/at.allow 或 /etc/at.deny 文件,有些最小化安装可能没启用 atd 服务。先systemctl status atd确认一下再使用。

3.3 systemd timer:新时代的定时器

如果你的系统是 CentOS 7+ 或 Ubuntu 16+,那么 systemd timer 是比 cron 更贴近现代系统的计划任务方案。它和 cron 的核心区别是:cron 只负责“到点了就执行命令”,而 systemd timer 可以绑定到某个 unit,还支持开机后延迟执行、错峰执行、依赖管理等。

写一个简单的 timer 需要两个文件。

首先是服务单元/etc/systemd/system/cleanup-task.service:

[Unit] Description=Cleanup temp files [Service] Type=oneshot ExecStart=/usr/local/bin/cleanup.sh

然后是定时器单元/etc/systemd/system/cleanup-task.timer:

[Unit] Description=Run cleanup every day at 2am [Timer] OnCalendar=daily Persistent=true [Install] WantedBy=timers.target

启用:

systemctl daemon-reload systemctl enable cleanup-task.timer --now systemctl list-timers

OnCalendar 的语法比 crontab 更灵活,比如OnCalendar=Mon..Fri *-*-* 09:00:00表示每周一到周五早上 9 点。Persistent=true的意思是:如果系统在计划时间点处于关机状态,下次开机后会补执行。这个特性是 cron 不具备的,很多备份任务因此强烈建议用 systemd timer 而不是 cron。

对了,关于热搜词里出现的“做快手星火计划任务”,那明显是和广告分发平台相关的任务系统,跟 Linux 系统计划任务不是一个东西,这里就不展开了,只是提醒大家搜索时要分辨语境。

3.4 任务被莫名禁用?backup scan 这类任务的排查思路

热搜词里有条 “backup scan计划任务怎么禁用”,这很典型——很多应用装的监控/备份组件会往 cron 里写一些定时任务,比如每天扫描、每天上报,用户觉得烦或觉得占资源,想禁掉。这种“系统里多出来的 cron 任务”要怎么找、怎么禁?我给出一个标准排查流程:

  1. 先把你自己的用户任务列出来:crontab -l。
  2. 再看系统级任务:cat /etc/crontab、ls /etc/cron.d/。
  3. 还有几个隐藏目录别漏:/etc/cron.hourly/、/etc/cron.daily/、/etc/cron.weekly/、/etc/cron.monthly/。某些安装包会往里面丢脚本。
  4. 检查所有用户的任务:grep -r "" /var/spool/cron/(具体路径因发行版而异,有的是 /var/spool/cron/,有的是 /var/spool/cron/crontabs/)。

找到目标后,确认它是否真的来自 backup scan 产品,方法很简单:看脚本内容,或者看脚本头部注释。如果是某个 rpm/deb 包带进来的,直接卸载那个包或者编辑/删除对应的 cron 文件即可。但我要提醒:不少“禁用方法”其实是把 cron 脚本里命令注释掉,但包升级时脚本会被还原。更彻底的办法是找到生成 cron 的配置文件,把相关开关关掉,或者干脆卸载不需要的组件。

负责地建议:如果 backup scan 是某个商业备份软件的组件,最好在官网文档里查“disable scheduled scan”之类的关键词,不要粗暴删除脚本。我见过有人删了 cron 文件后备份软件的控制台一直报错,连手动备份都起不来。正确路径通常是停服务 -> 禁用定时器 -> 卸载组件,而不是只删 cron 条目。

4. 实战排障与避坑指南

4.1 cron 任务就是不执行?先查这几个地方

这是我被问得最多的问题:cron 明明配置了,但任务没跑。按经验,按顺序排查:

  1. cron 服务是否在运行。systemctl status crond(CentOS)或systemctl status cron(Ubuntu)。我见过有人改了 crontab 但服务没起来,任务当然不跑。
  2. 时间字段写错。最容易错的是“周与日”同时指定时的 OR 逻辑。cron 里日月和周是“或”关系,比如0 0 1 * 0表示每月 1 日或每周日执行,而不是 1 日且周日执行。这条规则颠覆直觉,坑过无数人。
  3. 环境变量问题。cron 的 PATH 通常只有/usr/bin:/bin。脚本里用了 /usr/local/bin 下的程序,在交互 shell 没问题,但 cron 里找不到,表现为“任务日志不报错,脚本没跑”。解决:脚本开头 export PATH。
  4. 日志没输出。很多人的 cron 脚本没有重定向输出,导致执行失败时看不见任何错误。最直接的做法是在命令后面加>> /var/log/mytask.log 2>&1,然后记录执行日志。
  5. 权限问题。如果脚本没有执行权限(没 chmod +x),cron 会静默失败,检查 /var/log/cron 可以看到 “Permission denied”。
  6. 任务执行时间太短导致没日志。如果脚本只执行了 1 秒,根本来不及落盘。可以用CONTINUE_ON_IO_ERROR或者给 sleep 缓冲,不过一般不会这么极端——先看 cron 日志最直接。

cron 日志位置因发行版而异:CentOS/RHEL 是 /var/log/cron,Debian/Ubuntu 大多看 /var/log/syslog。用journalctl -u crond -f也能实时观察任务触发过程。

4.2 java 进程 OOM 排查实录

热搜词里有一条特别具体:“idea 编译时,进程堆大小调整为8000,还是报错 java.lang.OutOfMemoryError”。这其实是两个层面的问题,如果是对 Java 应用服务器(生产环境)调堆,那是 -Xmx 参数的问题;如果是 IDEA 编译时的进程,那它可能是前台的编译守护进程崩了,也可能是 Gradle/Maven 的 worker 进程内存不够。

先说生产环境。Java 进程 OOM 有很多种表现:堆内存溢出(Java heap space)、栈溢出(StackOverflowError)、Metaspace 溢出、或者干脆是无法分配本地内存。热搜里 “进程堆大小调整为 8000” 就是把 -Xmx 调成 8G,但仍然报错。遇到这种情况,我建议先别急着加大堆,因为:如果物理内存或容器限额不够,你调大 -Xmx 反而可能导致系统 OOM Killer 直接杀掉进程(而不是 JVM 正常抛出 OOM)。

正确的排查顺序:

# 1. 确认当前 JVM 参数 jps -l jinfo -flag MaxHeapSize PID # 2. 观察进程实际内存占用 top -p PID ps -o pid,rss,vsz,cmd -p PID # 3. 看 GC 日志和堆直方图 jstat -gcutil PID 1000 jmap -histo PID | head -30

如果是编译环境的报错,那就是另一个套路了。IDEA 的编译进程默认配置在 Help -> Change Memory Settings 里,或者通过自定义 VM options 调整。但注意,编译进程启动时 -Xmx 如果已经给了 8G,仍然报错,很可能是Metaspace或**直接内存(Direct Memory)**不足,而不是堆不够。编译大量代码时,注解处理器和编译器会加载大量 Class 元数据到 Metaspace,默认-XX:MaxMetaspaceSize可能偏小。排查时可以同时调大:

-Xmx8192m -XX:MaxMetaspaceSize=2048m

还要检查是不是同时启动了多个 Gradle/IDEA 编译守护进程,每个都占一堆内存。jps能列出现有 Java 进程,把多余守护进程停掉再编译,往往就正常了。总之,Java OOM 不能无脑加堆,得先分清是“堆不够”还是“整体内存不够”还是“元空间不够”。

4.3 僵尸进程与孤儿进程:处理不当的后果

前面讲 wait 的时候提过僵尸进程,这里展开说。僵尸进程就是已经退出但还没被父进程 wait 回收的进程,在 ps 里显示为<defunct>。之所以叫“僵尸”,是因为它已经死了,但进程表里的僵尸条目还在。它不消耗 CPU 和内存,但消耗 PID 资源,量大了会阻塞操作系统创建新进程。

和僵尸容易混淆的是“孤儿进程”:父进程先退出了,子进程就成了孤儿,被 PID 1(systemd)收养。这其实不是坏事,很多守护化操作就是依赖这一点让子进程脱离原父进程的。但如果父进程反复 fork 而不 wait,子进程退出便堆积僵尸,这才是问题。

处理僵尸进程的标准姿势:

# 找到僵尸进程 ps -eo pid,ppid,stat,cmd | grep defunct # 看它的父进程是谁 ps -o pid,ppid,cmd -p 父进程PID # 杀掉父进程,让僵尸被 systemd 回收 kill 父进程PID

杀父进程要谨慎,尤其当它承载了关键服务时。更好的做法是在代码层面让父进程正确 wait 所有子进程的退出码,脚本场景可以用wait命令,后台任务可以用 trap 'wait' EXIT 之类的技巧。如果父进程是 Java/Python 写的非托管程序,且已经无法修改代码,那就只能临时重启该父进程来清理僵尸池。

4.4 一套顺手好用的巡检脚本

最后,把我日常高频使用的进程+计划任务巡检命令整合成一个脚本,虽然不算复杂,但能让你在面试或汇报时拿得出手,也能实实在在节省时间:

#!/bin/bash echo "===== 系统运行时间与负载 =====" uptime echo "===== 内存使用 TOP10 =====" ps -eo pmem,pid,comm --sort=-pmem | head -11 echo "===== CPU 使用 TOP10 =====" ps -eo pcpu,pid,comm --sort=-pcpu | head -11 echo "===== 僵尸进程数量 =====" ps -eo stat | grep -c defunct echo "===== 当前所有用户的 crontab =====" for user in $(cut -f1 -d: /etc/passwd); do crontab -l -u "$user" 2>/dev/null && echo "--- $user ---" done echo "===== 系统级 cron 任务 =====" ls -la /etc/cron.d/ /etc/cron.hourly/ /etc/cron.daily/ 2>/dev/null echo "===== systemd timers =====" systemctl list-timers --all --no-pager

这段脚本看起来平平无奇,但实际能一句话看出系统是否有隐蔽的异常。有一次我就是通过“僵尸进程数量”发现某个老旧 PHP 长驻进程在持续泄漏任务,进而在巡检工具中连一条异常告警都没触发的情况下提前暴露问题。建议你把它放进 cron 里每天跑一次,输出重定向到日志,再配合简单的 grep 告警规则,基本就是一个小型的健康检查系统了。

关于计划任务还有一个值得养成的习惯:给任务加 LOCK 防止重入。比如一个脚本可能要跑 10 分钟,但 cron 每 5 分钟触发一次,就会造成两个实例同时运行,轻则资源竞争、重则数据错乱。用 flock 能优雅解决:

#!/bin/bash exec 9>/var/run/mytask.lock flock -n 9 || exit 1 # 业务代码...

另外,cron 脚本的执行结果建议推送到集中告警通道,比如写入数据库,或者调用 webhook。否则任务失败了,日志躺在服务器角落,只有事后翻才看到,就等于没有计划任务。

我个人在实际操作中的体会是:进程管理和计划任务,看着都是命令行的基本功,但它们才是 Linux 运维的“地基”。地基松了,上面无论是 Docker、Kubernetes 还是大数据框架,都会在你最意想不到的时候给你上一课。最后再分享一个小技巧:排查任何进程或任务问题,第一步永远是date看时间、uptime看负载、df -h看磁盘,因为这三样过不去,后面全白折腾。记住这个顺序,能少熬很多夜。

返回列表