Linux Day33——定时任务+lvm


type: note

title: Linux:定时任务三层排查 + LVM 造卷/灌满/扩容

date: 2026-11-09~2026-11-10

description: 定时任务「写了不执行」分三层查:cron 活着没 / 这条被触发没 / 触发后成没成,证据是 journalctl -u cron 的 CRON 行与重定向 log;日期永不成立(2 月 31 日 / 4 月 31 日);x 位与 Permission denied;cron 环境(绝对路径、重定向);地基链盘→分区→格式化→挂载;LVM 三层 PV/VG/LV(砖/仓库/货位)与造卷七步;灌满 → 扩容两本账:lvextend 改 LVM、resize2fs 改文件系统,df 只读后者,顺序由因果定;ext2 家族与在线扩容限制;/dev 设备 vs /mnt 挂载点、dd 写设备会毁文件系统;附两道收尾面试题与答案要点

tags: Linux, crontab, journalctl, 权限, LVM, PV, VG, LV, lvextend, resize2fs, mkfs, mount, dd, ext4, 面试题, 试点


Linux:定时任务三层排查 + LVM 造卷/灌满/扩容(D4)

> 📌 GitHub:https://github.com/AR-firefly

笔记区

核心观点

**1. 「写了不执行」不是一种病,分三层查**

| 层 | 问什么 | 证据 |

| -- | ------ | ---- |

| ① cron 活着没 | 守护进程在不在(每分钟醒一次看表) | `systemctl status cron` 显示 `active (running)`;或心跳任务产物按分钟增长 |

| ② 这条被触发没 | 时间写法对不对、有没有到点 | `journalctl -u cron` 里的 `CRONpid: (用户) CMD (命令)` 行 |

| ③ 触发后成没成 | 命令本身跑成功没有 | 重定向的 log 原文、产物在不在、mtime 对不对 |

判据:`CMD` 行 **>0** = 触发过;**=0** = 从没触发(时间写法不成立、crontab 没装上、服务没起都归这层)。**触发过 ≠ 成功**。

**2. `crontab -l` 只能证明「写在表里」,证明不了「跑没跑」**------它列的是配置,不是执行结果。命令是 `crontab`(管任务表),不是 `cron`(守护进程名)。

**3. 「语法合法但日期永不成立」是第二层典型坑**:`0 2 31 2 *`(2 月 31 日)、`0 4 31 4 *`(4 月 31 日)都合法,但永不触发。

**4. `Permission denied` 拆三件事:谁 → 对什么 → 干什么**

`/bin/sh: 1: /home/.../backup.sh: Permission denied`:`/bin/sh` 以该用户身份、执行 `backup.sh`、被内核拒绝------因为文件没有 `x` 位。**root 也不能执行没有 x 的文件**,sudo 在这里没用。判据看 `ls -l` 第一列(三处都没有 `x`)。

**5. cron 的环境和终端不一样**:不读 `.bashrc`、PATH 更短 → 命令写绝对路径;没有终端 → 输出不重定向就丢(`>> 文件 2>&1`)。

**6. 地基:一块盘到能存文件 = 认设备 →(可选)分区 → 格式化 → 建挂载点 → 挂载**

  • 分区 = 在盘上划一段边界,得到 `/dev/sdb1` 这样的名字,再对**那一段**格式化

  • Windows 对照:「新建简单卷」= 分区,「格式化 NTFS」= `mkfs`,「分配盘符 D:」= **挂载到目录**(Linux 用目录代替盘符)

**7. LVM = 把「分区」换成可伸缩的一层**

| 层 | 是什么 | 记法 |

| -- | ------ | ---- |

| PV 物理卷 | 设备被登记进 LVM,切成固定 4M 小块(PE) | 砖 |

| VG 卷组 | 多个 PV 的块汇成一个池子,统一分配 | 仓库 |

| LV 逻辑卷 | 从池子里舀出一块,**这才是能格式化、能挂载的「分区」** | 货位 |

Windows 的「存储空间」是同一套:物理磁盘 → 存储池 → 虚拟磁盘。

**8. 扩容是两本账,`df` 只读文件系统那本,顺序由因果定**

  • LVM 的账:这块地方多大(`lvs` 看)------ `lvextend` 改这本

  • 文件系统的账:ext4 在 `mkfs` 那一刻记下「我多少块」------ `resize2fs` 改这本

  • 只 `lvextend` 时 `df` **不变**(中间态,不是失败);`resize2fs` 之后才变

  • **顺序不能反**:文件系统扩容以「设备当前大小」为上限,设备没先变大,`resize2fs` 无处可扩 → 先 `lvextend`,后 `resize2fs`

**9. ext2 家族与命令命名**

  • ext2(无日志)→ ext3(+日志)→ ext4(+extents/大容量),同属 `e2fsprogs`,所以扩文件系统叫 `resize2fs`(`2fs` 来自 ext2 时代的工具名,ext4 也用它)

  • **ext2 不支持在线扩容**:`resize2fs` 报 `Kernel does not support online resizing`,必须先 `umount` → `resize2fs` → `mount`;ext3/ext4 可在挂载中扩

  • 命名规律:`<层><动作>`(`pvcreate`/`vgcreate`/`lvcreate`;`pvs`/`vgs`/`lvs` 是摘要列出,`pvdisplay` 是详细);「变大」各层办法不同:PV 用 `pvresize`、VG 用 `vgextend`、LV 用 `lvextend`

  • `mkfs` 与 `resize2fs` 不是一回事:mkfs **重铺**(清空)、resize2fs **改账本**(保留数据)

**10. `/dev` 是盘本身,`/mnt` 是打开后的文件夹**

  • `/dev/vg_d4/lv_d4`(=`/dev/mapper/vg_d4-lv_d4`)是**设备**:块设备文件(`ls -l` 第一列 `b`)

  • `/mnt/d4` 是**挂载点**:`mount` 把设备接到这个目录,之后看到的内容就是设备里的内容

  • `dd of=/dev/...` 直接写设备 = 绕过文件系统往盘面糊数据,把账本(超级块/inode 表)一起覆盖 → 文件系统坏(本次踩到,`df` 显示 `64Z`)

  • `dd of=/mnt/d4/fill` = 交文件系统分配空块、自己记账 → 正确用法;`of=` 指向目录报 `Is a directory`

关键方法/流程

**定时任务三层排查**

| 步 | 做什么 | 判据 |

| -- | ------ | ---- |

| 1 | `crontab -l` 看内容、五段、命令 | 只证明「写了」 |

| 2 | `systemctl status cron` | `active (running)` = 守护进程活着 |

| 3 | `journalctl -u cron --since "-20 min" \| grep 关键字`(或 `grep -c` 数条数) | >0 = 触发过;0 = 没触发 |

| 4 | 查命令绝对路径、脚本 x 位、输出重定向、cron 的 PATH | 缺 x → `Permission denied`;没重定向 → 报错没人收 |

| 5 | 修完:手动跑一次 → 等一次真实触发 → 看产物 mtime / 日志 | 产物 mtime = 触发时刻 = 真跑了 |

**LVM 建卷七步**

  1. 造假盘:`fallocate -l 512M ~/lab/d4r/disk.img`

  2. 挂成设备:`sudo losetup -f -P --show ~/lab/d4r/disk.img` → `/dev/loopN`(`-f` 找空闲、`-P` 扫分区表、`--show` 打印设备名)

  3. `sudo pvcreate -y /dev/loopN`

  4. `sudo vgcreate vg_d4 /dev/loopN`(第一个参数是卷组名,后面是 PV 设备)

  5. `sudo lvcreate -L 200M -n lv_d4 vg_d4`(`-L` 绝对大小、`-n` 名字、末尾是卷组)

  6. `sudo mkfs.ext4 -F /dev/vg_d4/lv_d4`(写在 LV 上,不是 loopN;`-F` 强制)

  7. `sudo mkdir -p /mnt/d4` → `sudo mount /dev/vg_d4/lv_d4 /mnt/d4` → `df -h /mnt/d4`

**扩容两步(顺序不能反)**

  1. 改 LVM 账:`sudo lvextend -L 400M /dev/vg_d4/lv_d4` → `lvs` 变,`df` 不变

  2. 改文件系统账:`sudo resize2fs /dev/vg_d4/lv_d4`(ext4 可在挂载中在线扩)→ `df` 变

实战记录

**记录 1:三层判断在两条不同现场上都成立**

| 现场 | 心跳/同步 | 备份/同步 | 月报 | 结论 |

| ---- | --------- | --------- | ---- | ---- |

| 现场 A(`~/lab/d4`) | `d4/tick` 30 分钟内 29 条 | `d4/backup` 5 条(每 5 分钟)→ 触发了但失败 | `d4/monthly` 0 条(`0 2 31 2 *`) | 三条各归一类 |

| 现场 B(`~/lab/d4r`) | `beat.log` 每分钟一行且持续增长 | `sync` 每分钟有 `CMD` 行,`sync.log` 全是 `Permission denied` | `report` 搜不到 `CMD` 行、`report.log` 不存在(`0 4 31 4 *`) | 同上,证据齐 |

判据:journal 里 `CRONpid: (用户) CMD (...)` 行数 >0 只证明「启动过」;产物/日志才证明「成没成」。

**记录 2:两次 `x` 位修复,路径不同、判据一致**

```

cat ~/lab/d4/backup.log

/bin/sh: 1: /home/ar-26710/lab/d4/backup.sh: Permission denied (×8)

ls -l ~/lab/d4/backup.sh → -rw-r--r--(没有 x)

chmod u+x ~/lab/d4/backup.sh → -rwxr--r--

ls -l --time-style=+%T ~/lab/d4/backup/

src-latest.tar.gz 20:47:17 ← 手敲那次

src-latest.tar.gz 20:50:01 ← cron 自己跑的那次;backup.log 停在 8 行不再增长

```

重开那天同样:`ls -l ~/lab/d4r/sync.sh` → `-rw-r--r--`;`chmod u+x` 后 `-rwxr--r--`;`~/lab/d4r/sync.sh; echo $?` → `0`;此后 `sync.out` 按分钟增长、`sync.log` 停在旧行不再增。

**记录 3:造卷 → 挂载 → 灌满 → 扩容(主链)**

```

fallocate -l 512M ~/lab/d4r/disk.img

sudo losetup -f -P --show ~/lab/d4r/disk.img → /dev/loop2

sudo pvcreate -y /dev/loop2 → successfully created

sudo vgcreate vg_d4 /dev/loop2 → 508M(#PV 1, #LV 0)

sudo lvcreate -L 200M -n lv_d4 vg_d4 → 200M

sudo mkfs.ext4 -F /dev/vg_d4/lv_d4 → 51200 个 4k 块 / 51200 inode

sudo mount /dev/vg_d4/lv_d4 /mnt/d4

df -h /mnt/d4 → 172M(200M 扣掉日志 16M + inode 表)

sudo dd if=/dev/zero of=/mnt/d4/fill bs=1M → No space left on device

df -h /mnt/d4 → 172M, Used 168M, Avail 0, 100%

sudo lvextend -L 400M /dev/vg_d4/lv_d4 → 200.00 MiB (50 extents) → 400.00 MiB (100 extents)

df -h /mnt/d4 → 仍 172M / 100%(两本账不同步)

sudo resize2fs /dev/vg_d4/lv_d4 → now 102400 (4k) blocks long

df -h /mnt/d4 → 359M, Avail 174M, 50%

```

**踩坑记录**

| 坑 | 现象 | 原因 |

| -- | ---- | ---- |

| `dd if = /dev/zero`(`=` 带空格) | `Unrecognized operand 'if'` | shell 把 `if=` 按空格拆开 |

| `dd of=/mnt/d4`(写挂载点目录) | `Is a directory` | `of=` 是「往哪写数据」,不是「往哪个目录放」 |

| `dd of=/dev/vg_d4/lv_d4`(写设备) | 文件系统坏,`df` 显示 `64Z` | 绕过文件系统直接写盘面,账本一起被盖 |

| `lvextend -n ... bs=1M` | `Invalid path for Logical Volume` | 混进 `lvcreate`/`dd` 的参数;`lvextend` 只认「大小 + 卷设备」 |

| `mkfs` 不加 sudo | `Permission denied while trying to determine filesystem size` | 要 root |

| `mkfs` 在挂载中 | `is mounted; will not make a filesystem here!` | 挂载中不许重铺;要重铺先 `umount`(这是保护,不是故障) |

| 改完 LV 不 `resize2fs` | `df` 不变 | 文件系统账没改 |

| ext2 上在线扩 | `Kernel does not support online resizing` | ext2 不支持在线扩,必须 `umount` 后扩 |


线索区(学完后合上材料,自问自答)

**Q: 一条定时任务没跑,第一步查什么?**

A: 分三层:cron 活着没 / 这条被触发没 / 触发后成没成。证据分别是 `systemctl status cron`、journal 的 `CRONpid: CMD` 行、重定向的 log 与产物。

**Q: `crontab -l` 能看到任务,能不能说明它跑过?**

A: 不能。只证明写在表里;跑没跑要看 journal 的 CMD 行。

**Q: `0 2 31 2 *` / `0 4 31 4 *` 为什么永远不跑?**

A: 语法合法但日期永不成立(2 月/4 月没有 31 日),属于「从不触发」。

**Q: 脚本报 `Permission denied`,加 sudo 有用吗?**

A: 没用。缺的是文件的 `x` 位,root 也不能执行没有 x 的文件;判据看 `ls -l` 第一列。

**Q: cron 里命令为什么必须写绝对路径?**

A: cron 不读 `.bashrc`,PATH 比终端短,相对路径找不到命令。

**Q: 一块新盘到能存文件,要几步?**

A: 认设备 →(可选)分区 → `mkfs` 格式化 → 建挂载点 → `mount`。

**Q: PV / VG / LV 各是什么?**

A: PV = 设备切成 4M 小块的砖;VG = 砖汇成的池子;LV = 从池子舀出的一块,能格式化、能挂载的「分区」。

**Q: 为什么 `lvextend` 完 `df` 还是旧的?**

A: `df` 读文件系统自己记的大小,那个数在 `mkfs` 时就写定了;`lvextend` 只改 LVM 记的大小,要 `resize2fs` 改文件系统的账。

**Q: 为什么必须先 `lvextend` 再 `resize2fs`?**

A: 文件系统扩容以「设备当前大小」为上限;设备没变大,`resize2fs` 无处可扩。

**Q: ext2 能在线扩容吗?**

A: 不能,报 `Kernel does not support online resizing`,必须先 `umount`;ext3/ext4 才能在线扩。

**Q: `mkfs` 和 `resize2fs` 的区别?**

A: mkfs 重新铺文件系统(会清空数据);resize2fs 只改已有文件系统的大小(保留数据)。

**Q: `dd of=/dev/vg_d4/lv_d4` 和 `dd of=/mnt/d4/fill` 差在哪?**

A: 前者绕过文件系统直接写盘面(账本一起被覆盖,fs 坏);后者由文件系统分配空块、自己记账。


总结(50字以内)

定时任务不跑分三层查(cron 活着 / 触发没 / 执行成没),各拿证据;LVM 走 PV→VG→LV→mkfs→mount,扩容两本账:先 lvextend 改 LVM,再 resize2fs 改文件系统。


复习卡片

| 概念 | 必学/了解 | 一句话 | 场景 |

| ---- | --------- | ------ | ---- |

| 三层判断(cron / 触发 / 执行) | 必学 | 写了不执行先分层,各层各有证据 | 任何定时任务不跑 |

| `journalctl -u cron` | 必学 | `-u` 按服务;触发留 `CRONpid: (用户) CMD (命令)` | 判有没有被触发 |

| `grep -c` | 必学 | 只输出匹配行数,不打印内容 | 数触发次数 |

| `crontab -l / -e / -r` | 必学 | list 读 / edit 改 / remove 全删;命令是 crontab 不是 cron | 管任务 |

| `systemctl status cron` | 必学 | `active (running)` = 守护进程活着 | 三层第一层 |

| cron 环境(PATH、重定向) | 必学 | 不读 `.bashrc`、绝对路径、`>> log 2>&1` | 排查执行失败 |

| `x` 位与 `Permission denied` | 必学 | 缺 x 位谁都不能执行;判据 `ls -l` 第一列 | 脚本跑不起来 |

| 盘→分区→格式化→挂载 | 必学 | 分区划边界、mkfs 铺账本、mount 接目录 | 任意新盘 |

| `mkfs.ext4` | 必学 | 写超级块 + inode 表 + 块位图;与 resize2fs 区别看数据保不保 | 格式化 |

| PV / VG / LV | 必学 | 砖 / 仓库 / 货位;LV 才是「分区」 | LVM 三层 |

| `pvcreate` / `vgcreate` / `lvcreate` | 必学 | 层+动作;vgcreate 第一个参数是卷组名,lvcreate 用 `-n 名字 -L 大小` | 建卷 |

| `pvs` / `vgs` / `lvs` | 必学 | 三层各一张摘要清单;要 sudo 才读得到元数据 | 查看 |

| `lvextend` | 必学 | 改 LVM 账;`-L 400M` 目标、`-L +200M` 增量;没有 `-n` | 扩容第一步 |

| `resize2fs` | 必学 | 改 ext 家族文件系统账;ext2 要离线,ext4 可在线 | 扩容第二步 |

| ext2 / ext3 / ext4 | 必学 | 无日志 / 加日志 / 加 extents 与更大容量 | 选文件系统 |

| `df -h` | 必学 | 读文件系统那本账,不是设备的账 | 验证扩容 |

| `/dev` 设备 vs `/mnt` 挂载点 | 必学 | `/dev` 是盘本身,`/mnt` 是打开后的文件夹 | 写文件、dd |

| `dd if=... of=... bs=1M` | 必学 | 灌满用;`of=` 是「往哪写数据」,不能写目录、不能写设备(会毁 fs) | 造满盘 |

| `mount` / `umount` | 必学 | mount 接线到目录;umount 断开(可给目录或设备);成功时都不打印 | 挂载 |

| `fallocate` / `losetup` / `fdisk` | 了解 | 查 `man 1 fallocate` / `man 8 losetup` / `man 8 fdisk` | 造盘、分区 |


流程附加段

旧知识回收

| 概念 | 一句话 | 出处 |

| ---- | ------ | ---- |

| 盘→分区→格式化→挂载 这条链 | 一条盘到能存文件的四步说不全 | 教学诊断 |

| ext2/ext3/ext4 家族 | 各自多了什么说不清;`resize2fs` 的 `2fs` 来历不明 | 补讲 |

| PV / VG / LV | 三层关系与「LV 才相当于分区」讲不清 | 补讲 |

| 命令名与动作的对应 | 「挂载」想不起是 `mount`;给动作报不出命令;`cron -l` 不是命令 | 反复出现 |

| `dd` 的 `if=` / `of=` | `if=/dev/null` 读 0 字节灌不满;`of=` 指目录报 `Is a directory`;`of=` 指设备盖坏文件系统 | 踩到 |

| 整机 CPU 百分比口径 | 20 核单核满 = 5%;8 核 2 核满 = 200/800 = 25%(分母 = 核数×100%) | 复习时踩到 |

| 用户级 vs root 权限 | `/mnt/d4` 属主 root,普通用户不能写;LVM 命令要 sudo | 踩到 |

| `lvextend` 没有 `-n` | `-n` 是 `lvcreate` 的参数,扩容只要「大小 + 卷设备」 | 踩到 |

| 判据数字 | 200M LV 可用 172M(不是 197M);400M 可用 359M(不是 380M) | 验证校正 |

今日产出验收

| 产出条 | 证据 | 结果 |

| ------ | ---- | ---- |

| 定时任务三层各自的证据 | 29/5/0 三个数;`beat.log` 增长;`sync.log` 的 `Permission denied`;`report.log` 不存在 | 过 |

| LVM 造卷挂载 | `pvcreate/vgcreate/lvcreate/mkfs/mount` 全流程输出 | 过 |

| 灌满 → 扩容 → `df` 证明 | 100% → `lvextend` 后仍 172M → `resize2fs` 后 359M | 过 |

| 独立做成(自己写全链) | 第 3 段两条命令由 AI 示范;2026-11-11 用户拍板改判全过 | 过(按用户拍板) |

| 复盘(为什么先 lvextend 再 resize2fs) | 补讲后重考答对 | 过 |

| 收尾面试题 | 两道题 + 答案要点见下节 | 已入笔记 |


面试题(两块内容各一道)

一、cron 任务不执行(Adaface 第 9 题)

> 出处:Adaface --- 98 Linux Interview Questions(https://www.adaface.com/blog/linux-troubleshooting-interview-questions/) 高级组第 9 题

**题面**

> A scheduled cron job is failing to execute as expected. What steps would you take to determine the cause of the failure and ensure the job runs successfully?

中文:一个定时任务没有按预期执行,你会怎么确定原因、并确保它跑起来?

说人话:cron 任务该跑没跑,你按什么顺序查、拿什么证据、修完怎么确认。

**答案要点(三层判断 + 修完验证)**

  1. **第一层:cron 活着没**------`systemctl status cron` 看 `active (running)`;或心跳任务产物按分钟增长。服务没起时后面日志全空,会误判成「时间写错」。

  2. **第二层:这条被触发没**------`journalctl -u cron | grep 关键字`,数 `CRONpid: (用户) CMD (命令)` 行:**>0 = 触发过;=0 = 从没触发**(时间写法不成立、`2 月 31 日` 这种、crontab 没装上,都归这层)。

  3. **第三层:触发后成没成**------看重定向 log 原文、产物在不在、mtime 对不对;常见坑:相对路径 / cron 的 PATH 更短、脚本没 `x` 位、输出没重定向。

  4. **修完怎么确保它跑起来**------手动跑一次 → 等一次真实触发 → 看产物 mtime 是否等于触发时刻;不能凭「我改完了」宣布解决。

> 最常见答错点:拿 `crontab -l` 当「跑过」的证据------它只证明写在表里。

二、自定义脚本执行失败(Adaface 第 28 题)

> 出处:同上,第 28 题

**题面**

> Explain how you would identify and resolve a situation where a custom script is failing to execute properly on a Linux server.

中文:一台 Linux 服务器上,一个自定义脚本无法正常执行,你会怎么定位并解决?

说人话:脚本该跑,但跑不起来或跑不对,你按什么顺序查、怎么确认修好了。

**答案要点(按顺序)**

  1. **先分现象**:是「根本没跑」还是「跑了但结果不对」------手动执行一次,`echo $?` 看退出码;非 0 就读 stderr。

  2. **看执行权限与解释器**:`ls -l 脚本` 看 `x` 位;`file 脚本` 或首行 shebang 看解释器;`bash -x 脚本`(或 `sh -x`)逐行看执行到哪。

  3. **看「谁在跑」和「环境差」**:手动能跑、cron/服务里不跑 → PATH 更短、相对路径、cwd 不同、不读 `.bashrc`、没有终端;对应写绝对路径、`>> log 2>&1` 接住输出。

  4. **看日志与产物**:重定向的 log、`journalctl -u <服务>`、产物在不在、mtime 对不对。

  5. **修完验证**:手动跑一次 → 等一次真实触发 → 看产物 mtime / 日志不再新增报错。

相关推荐
墨痕诉清风2 小时前
SSRF漏洞实战记录+OSS桶命令执行+MCP漏洞
linux·服务器·数据库
byte轻骑兵2 小时前
实战 4:BlueZ 源码中添加自定义设备过滤规则
linux·物联网·bluez·电脑蓝牙·嵌入式蓝牙
润滑卫士2 小时前
液压系统工作粘度窗口等级选型:泵允许粘度范围与油温-粘度匹配计算
运维
瓦瓦gogo3 小时前
从一个 TypeScript 函数开始理解 MCP 协议
linux·ubuntu·typescript
鱼听禅4 小时前
Ubuntu安装YOLOv8进行菌落识别训练
linux·python·yolo·ubuntu
测试界的小码农4 小时前
【Linux 命令实战(04):文件内容查看,掌握 cat、less、head、tail】
linux·服务器·less
每月一号准时摆烂5 小时前
服务器运维笔记(一)——使用shell编写实时查看BMC功率的脚本
运维·服务器·笔记
CodeYp20195 小时前
第13讲:HTTPS 协议原理
linux·https
时间售卖铺6 小时前
Chrony与SSH实战:精准时间同步与安全远程登录
运维·安全·云原生·ssh