面试 · 概念解释型
考察目标:用自己的话讲清楚核心概念 24 题
题目1:什么是 inode?删文件为什么不等于删数据?#
参考答案:
inode 是 Linux 文件系统的"身份证",存储文件的元数据(权限、大小、时间戳、数据块指针),不存文件名。文件名存于目录项中,目录项指向 inode。
删文件的本质是删除目录项(文件名),不是删除 inode。只有当 inode 的硬链接计数降为 0 且没有进程打开文件时,内核才真正释放数据块。
这在运维中常引发一个现象:df -h 显示磁盘满,但 du -sh 加起来远小于磁盘容量——因为有进程持有已删除文件的句柄,用 lsof | grep deleted 可以找到这些"幽灵文件"。
题目2:软链接和硬链接有什么区别?#
| 维度 | 软链接 (symlink) | 硬链接 (hard link) |
|---|---|---|
| 本质 | 一个独立的文件,内容是目标路径 | 同一个 inode 的多个目录项 |
| 跨文件系统 | 支持 | 不支持 |
| 链接目录 | 支持 | 不支持(防止环路) |
| 删源文件后 | 链接失效(断链) | 不受影响,数据仍存在 |
| inode | 独立 inode | 共享 inode |
| 链计数 | 不影响 | 每次 +1 |
运维中软链接常用于 /usr/bin/python → /usr/bin/python3、/etc/nginx/sites-enabled/ → sites-available/ 等场景。硬链接较少手工创建,常见于 rsync --link-dest 做增量备份。
完整对比表见「对比辨析型 题目1」,底层实现(
i_nlink/S_IFLNK/ 为何硬链接不能跨文件系统、不能链目录)见「原理追问型 题目6」。
题目3:SUID、SGID、Sticky bit 分别是什么意思?#
参考答案:
| 特殊权限 | 数字 | 文件 | 目录 |
|---|---|---|---|
| SUID | 4 | 以文件属主权限执行 | 无意义 |
| SGID | 2 | 以文件属组权限执行 | 新建文件继承目录属组 |
| Sticky | 1 | 无意义 | 只有属主能删自己的文件 |
典型例子:/usr/bin/passwd 有 SUID(属主 root),普通用户执行时以 root 权限修改 /etc/shadow。/tmp 有 Sticky bit(1777),任何人都可写但只能删自己的文件。SGID 目录常用于团队共享目录(/var/www 设 SGID,新建文件自动归属 www-data 组)。
高频易错点:SUID 对脚本无效——Linux 内核出于安全(解释器竞态、注入风险)忽略脚本文件的 SUID 位,只对编译型二进制生效。想让脚本以高权限运行,用 sudo 规则或 capabilities(见题目23),而不是给脚本 chmod u+s。
题目4:Linux 进程状态 R/S/D/Z/T 各是什么?D 状态为什么 kill -9 也杀不掉?#
参考答案:
| 状态 | 含义 | 典型原因 |
|---|---|---|
| R | Running/就绪 | 正在 CPU 或等待 CPU |
| S | Interruptible Sleep | 等待事件(IO/信号),可被中断 |
| D | Uninterruptible Sleep | 等待内核 IO 完成,不可中断 |
| Z | Zombie | 进程已退出,父进程未回收 |
| T | Stopped | 被 SIGSTOP/Ctrl+Z 暂停 |
D 状态不可 kill:进程正在内核态等待 IO 完成(如 NFS 无响应、磁盘故障),信号被挂起直到 IO 完成才处理。kill -9 的原理是发信号,而 D 状态的进程不处理任何信号。只能等 IO 超时(通常 120 秒)或重启节点。K8s 中 NFS PV 挂载故障常导致 Pod 卡在 Terminating 就是这个原因。
题目5:Linux 内存管理中 Buffer 和 Cache 有什么区别?#
参考答案:
- Buffer(缓冲区):缓存块设备的元数据(inode、目录项),解决写操作的缓冲问题
- Cache(页缓存):缓存文件内容,解决读操作的加速问题
用 free -h 看到的 buff/cache 是两者之和。关键认知:Linux 会主动用空闲内存做缓存,available 内存才是真正可用的(available ≈ free + 可回收 buff/cache)。echo 3 > /proc/sys/vm/drop_caches 可手动释放(生产慎用)。
题目6:什么是 Swap?什么时候该用什么时候不该用?#
参考答案:
Swap 是磁盘上的"虚拟内存",当物理内存不足时内核将不活跃的内存页换出到磁盘。如果物理内存充足,Swap 用作安全余量;如果内存紧张但程序必须运行,Swap 让系统不会立即 OOM Kill。
该用的场景:小内存机器跑非延迟敏感服务、数据库等有突发内存需求的服务。 不该用的场景:高性能计算/GPU 训练(Swap 严重拖慢速度)、对延迟敏感的服务。
生产建议:普通服务器不必彻底关 Swap,调 vm.swappiness=1 让内核尽量不用它。但 K8s 有坑:kubelet 默认 failSwapOn=true,节点上开着 Swap 会直接拒绝启动;Swap 支持从 1.22 alpha、1.28 beta 起才逐步可用,需显式 failSwapOn: false + NodeSwap 特性开关(1.34 已 GA/stable,LimitedSwap 模式)。所以传统 K8s 节点的标准做法仍是关 Swap,别想当然给它留 Swap。
题目7:systemd 替代 SysV init 解决了什么问题?#
参考答案:
SysV init 的问题:
- 串行启动:按
/etc/rc.d/rcX.d/S##name顺序逐个启动,几百个服务按顺序等,启动极慢 - 无依赖管理:只能人工保证启动顺序,没有自动依赖解析
- 进程管理弱:服务 fork 后 init 不知道它在哪,状态跟踪困难
- 日志分散:每个服务各自写
/var/log/xxx.log
systemd 的改进:
- 并行启动:自动解析依赖 DAG,无依赖的服务同时启动
- cgroup 集成:每个 service 一个 cgroup,进程绝不逃脱跟踪
- 统一日志:journalctl 统一管理所有服务日志
- socket/timer/dbus 激活:按需启动,不用开机全拉起来
题目8:Linux 启动过程是怎样的?#
参考答案:
BIOS/UEFI → Bootloader(GRUB) → Kernel 加载 → initramfs → systemd(pid=1) → 启动服务关键阶段:
- BIOS/UEFI:硬件自检,找到引导设备
- GRUB:加载内核映像 + initramfs 到内存
- Kernel:初始化驱动、挂载根文件系统(先只读)
- initramfs:临时的根文件系统,包含必需驱动(如 RAID/LVM 模块),帮助挂载真正的根文件系统
- systemd:作为 PID=1 启动,并行启动所有 target 依赖的服务
排查启动问题时常用 systemd-analyze blame 看服务耗时排序,dmesg 看内核阶段日志。
题目9:什么是 /proc 文件系统?列出 3 个你常用的 /proc 文件#
参考答案:
/proc 是伪文件系统(pseudo filesystem),不占磁盘,内容由内核动态生成,是内核与用户空间的信息接口。
常用文件:
/proc/cpuinfo— CPU 型号/核心数/缓存/proc/meminfo— 内存详细信息(比 free 更细)/proc/<pid>/status— 进程状态/内存/VmRSS/proc/<pid>/oom_score和oom_score_adj— OOM 优先级/proc/sys/net/ipv4/tcp_tw_reuse等 — 内核参数调优/proc/mounts— 当前挂载表
运维常用场景:查看容器内 CPU 核数 → nproc(实际读 /proc/cpuinfo),查进程 OOM 风险 → cat /proc/<pid>/oom_score。
题目10:硬链接创建/删除时 inode 链接计数怎么变?#
参考答案:
硬链接每 ln 一次,inode 的链接计数(i_nlink)+1;ls -l 第二列、stat 的 Links 就是它。rm 本质是 unlink(),让计数 -1;当计数降为 0 且无进程打开该文件时,内核才回收 inode 和数据块(这正是「删了大文件空间没释放」的成因,见「场景排查型 题目8」)。软链接是独立 inode,不触碰目标的链接计数,删源文件后变断链。
验证:
touch a; stat -c %h a # 1
ln a b; stat -c %h a # 2(同一 inode 多了个名字)
rm b; stat -c %h a # 1软/硬链接的完整对比见「对比辨析型 题目1」,底层实现见「原理追问型 题目6」。
题目11:Linux 的 IO 调度算法有哪些?什么时候用哪个?#
| 算法 | 原理 | 适用场景 |
|---|---|---|
| none (noop) | FIFO 简单队列 | SSD/NVMe,硬件自己调度 |
| mq-deadline | 读写分开 + 截止时间 | 混合负载 SATA SSD |
| bfq | 按 cgroup 公平分配带宽 | 多租户/桌面系统 |
| kyber | 基于延迟目标的调度 | 低延迟敏感 |
cat /sys/block/sda/queue/scheduler 查看当前调度器。NVMe 盘建议 none(内核 5.0+ 对 NVMe 默认无调度器)。
题目12:什么是 cgroup?v1 和 v2 的主要区别?#
参考答案:
cgroup(Control Group)是 Linux 内核的资源限制/隔离机制,用于限制进程组的 CPU、内存、IO 等资源。容器(Docker/K8s)的底层资源隔离依赖 cgroup。
v1 vs v2:
- v1:每个资源控制器(CPU/memory/blkio)独立的层级树,互不感知,存在"no internal process"限制
- v2:单一统一层级树,所有控制器共享,支持 cgroup 线程模式,内存控制器增强(PSI 压力通知)
cgroup v2 在 K8s 1.25 GA(成为标准路径,但不是强制——v1 仍受支持);v1 已在 1.31 进入维护模式、并计划在 1.36 彻底移除(届时仍用 v1 的节点 kubelet 将无法启动)。查看当前版本:stat -fc %T /sys/fs/cgroup(cgroup2fs=v2),或 mount | grep cgroup2(有输出即 v2)。
题目13:Linux 的实际内存和虚拟内存分别是什么?#
参考答案:
实际内存(RSS, Resident Set Size):进程实际占用的物理内存页。ps aux 的 RSS 列或 /proc/<pid>/status 的 VmRSS。
虚拟内存(VSZ, Virtual Size):进程"认为自己可以用的"地址空间,包括映射的共享库、mmap、堆和栈。通常 VSZ >> RSS。
K8s 中的 OOMKill 基于容器 cgroup 的实际内存使用量(不是 RSS),超过 Limit 就杀。cat /sys/fs/cgroup/memory/memory.usage_in_bytes 可查看。
题目14:什么是内核参数 sysctl?常调哪些?#
参考答案:
sysctl 是运行时修改内核参数的工具,对应 /proc/sys/ 下的文件。永久生效写 /etc/sysctl.conf 或 /etc/sysctl.d/。
常用调优:
| 参数 | 作用 | 值 |
|---|---|---|
net.ipv4.tcp_tw_reuse | TIME_WAIT 连接复用 | 1 |
net.core.somaxconn | listen 全连接队列(accept 队列)上限;半连接队列由 tcp_max_syn_backlog 管 | 65535 |
vm.swappiness | 倾向使用 Swap 的程度 | 1-10 |
vm.max_map_count | mmap 数量上限(ES 需要) | 262144 |
fs.file-max | 系统级文件描述符上限 | 6553500 |
fs.inotify.max_user_watches | 文件监控数限制 | 524288 |
应用方式:sysctl -w net.ipv4.tcp_tw_reuse=1(临时)或 echo "net.ipv4.tcp_tw_reuse=1" >> /etc/sysctl.conf && sysctl -p(永久)。
题目15:Linux 文件系统 ext4 和 xfs 的区别?什么时候选哪个?#
| 维度 | ext4 | xfs |
|---|---|---|
| 最大文件系统 | 1EB | 8EB |
| 最大文件 | 16TB | 8EB |
| 在线扩容 | ✅ resize2fs | ✅ xfs_growfs |
| 缩容 | ✅ 但须卸载离线用 resize2fs 缩小 | ❌ 完全不支持缩小(只能备份重建) |
| 性能 | 小文件好 | 大文件/高并发好 |
| 碎片 | 更少 | 更多 |
| 推荐 | 通用场景 | 大文件(数据库/日志/对象存储) |
创建:mkfs.ext4 / mkfs.xfs。关键差异:xfs 只能扩不能缩(xfs_growfs);ext4 更灵活(resize2fs 在线扩、离线缩)。默认文件系统:RHEL/Rocky/Alma 8·9、AWS AL2 默认 xfs(注意 CentOS 7 已于 2024-06-30 EOL,别再当"当前主流")。选盘时若预期可能要缩容,选 ext4。
题目16:什么是信号?列出 5 个常用信号及其含义#
参考答案:
| 信号 | 编号 | 含义 | 能否捕获 |
|---|---|---|---|
| SIGTERM | 15 | 终止进程(优雅退出),默认 | 能 |
| SIGKILL | 9 | 强制终止,不可捕获 | 否 |
| SIGHUP | 1 | 挂断,常用于重载配置 | 能 |
| SIGINT | 2 | Ctrl+C 中断 | 能 |
| SIGQUIT | 3 | Ctrl+\ core dump 退出 | 能 |
| SIGSTOP | 19 | 暂停进程 | 否 |
| SIGCONT | 18 | 继续暂停的进程 | 能 |
kill <pid> 不带参数默认发的就是 SIGTERM(不是 SIGKILL)。K8s 中 Pod 终止流程:先发 SIGTERM,等 terminationGracePeriodSeconds(默认 30s),超时后发 SIGKILL。应用需要在代码中捕获 SIGTERM 做 graceful shutdown。
进程被信号杀死的退出码约定 128+信号号(137=128+9 被 KILL、143=128+15 被 TERM、130=128+2 Ctrl+C),详见「原理追问型 题目8」。
题目17:什么是 Runlevel?target 和 runlevel 的对应关系?#
参考答案:
Runlevel 是 SysV init 的系统运行级别(0-6),systemd 用 target 替代:
| Runlevel | target | 含义 |
|---|---|---|
| 0 | poweroff.target | 关机 |
| 1 | rescue.target | 单用户救援模式 |
| 3 | multi-user.target | 多用户命令行 |
| 5 | graphical.target | 多用户图形界面 |
| 6 | reboot.target | 重启 |
systemctl get-default 查看默认 target,systemctl set-default multi-user.target 设置为命令行启动。
题目18:什么是 umask?为什么新建文件默认 644、目录 755?#
参考答案:
umask 是"权限遮罩"——它是按位清除(最终权限 = 默认权限 AND (NOT umask)),不是算术减法。默认权限:文件 666、目录 777(文件天生不给 x 位,安全考虑)。umask=022 时:
- 文件 666 & ~022 = 666 & 755 → 644(rw-r--r--)
- 目录 777 & ~022 = 777 & 755 → 755(rwxr-xr-x)
为什么必须强调"按位"而非"相减":022 这种"干净"掩码下两种算法结果碰巧相同,换成 umask 023 就露馅:
- 按位(正确):文件 666 & ~023 = 644
- 相减(错误):666 − 023 = 643(rw-r---wx,凭空算出个 x 位,荒谬)
umask(无参)看当前值,umask 027 临时设置;系统默认在 /etc/login.defs 的 UMASK、/etc/profile 或 PAM 的 pam_umask 中配置。
题目19:什么是 SSH 免密登录?ssh-keygen 做了什么?#
参考答案:
SSH 免密登录基于非对称加密:用户生成公钥/私钥对,公钥放在远程服务器的 ~/.ssh/authorized_keys,连接时客户端用私钥签名,服务器用公钥验证。
过程:
ssh-keygen -t ed25519生成密钥对(推荐 ed25519,比 RSA 更安全更快)ssh-copy-id user@host将公钥追加到远端 authorized_keys- 之后的 ssh 连接用私钥认证,不再需要密码
运维场景:免密登录用于 Ansible、rsync 备份、Git SSH 拉取。私钥权限必须为 600(chmod 600 ~/.ssh/id_ed25519)。
题目20:文件描述符是什么?为什么 Linux 说"一切皆文件"?#
参考答案:
文件描述符(File Descriptor, FD)是内核为每个进程维护的打开文件的整数索引。0=stdin、1=stdout、2=stderr(这三个标准 FD)。
"一切皆文件"意味着 Linux 把网络连接(socket)、管道(pipe)、设备(/dev/sda)、进程信息(/proc)都抽象为文件描述符,可以用统一的 read()/write()/close() 系统调用操作。
运维影响:ulimit -n 限制进程最大文件描述符数(含 socket 连接),当达到上限时出现 "Too many open files"。K8s 中 NOFILE 需要调大(如 1048576)。cat /proc/<pid>/limits 查看进程限制。
题目21:Linux 怎么添加到开机自启动?#
参考答案:
systemd 时代的标准方法:
# 1. 创建 service unit 文件
sudo vim /etc/systemd/system/myapp.service
# 2. 重载 systemd
sudo systemctl daemon-reload
# 3. 设为开机自启
sudo systemctl enable myapp非 systemd 方式(备用):
crontab -e加@reboot /path/to/script/etc/rc.local(需chmod +x)
K8s 中开机自启由 kubelet 实现——节点启动后 kubelet 自动拉取并运行 DaemonSet、Deployment。
题目22:/etc/fstab 是什么?格式怎么读?#
参考答案:
/etc/fstab 是文件系统挂载表,定义开机自动挂载的设备和选项。格式:设备 挂载点 文件系统 选项 dump pass
UUID=xxx / xfs defaults 0 1
UUID=yyy /data ext4 defaults,noatime 0 2
192.168.1.1:/nfs /mnt/nfs nfs defaults 0 0pass 字段:1=根分区先检查,2=其他分区,0=不检查。生产注意:NFS/CIFS 网络挂载应加 _netdev,noauto 避免网络不可达时阻塞启动。
题目23:ugo 权限不够用时,ACL 和 capabilities 各解决什么问题?#
参考答案:
传统 ugo(属主/属组/其他)只能表达三类主体,粒度太粗。两个"超越 ugo"的机制:
1. ACL(访问控制列表)——给单个用户/组单独授权,突破"一个文件只能属一个组"的限制。
setfacl -m u:alice:rw file # 单独给 alice 读写
setfacl -m g:dev:rx dir # 给 dev 组读+执行
getfacl file # 查看;ls -l 权限位末尾带 + 号即表示有 ACL
setfacl -d -m u:alice:rw dir # default ACL:目录内新建文件自动继承需文件系统挂载支持 acl(ext4/xfs 现代默认已开)。
2. capabilities(能力)——把 root 的"全能"拆成约 40 个细粒度能力,让程序只拿它需要的那一点特权,替代危险的 SUID-root。
setcap 'cap_net_bind_service=+ep' /usr/sbin/nginx # 不用 root 就能监听 80/443
getcap /usr/sbin/nginx常见能力:CAP_NET_BIND_SERVICE(绑 <1024 端口)、CAP_NET_RAW(ping/抓包)、CAP_DAC_OVERRIDE(无视文件权限)、CAP_SYS_ADMIN("新 root",最危险)。
面试点:题目3 讲过 SUID 对脚本无效、且 SUID-root 是"全有或全无"的巨大攻击面;capabilities 只授予二进制真正需要的那一个能力,是更安全的替代。容器安全里 securityContext.capabilities.drop: ["ALL"] 再按需 add 就是这个思路。
题目24:systemd 的 unit 有哪些类型?enable 和 start 什么区别?journalctl 日志怎么持久化?#
参考答案:
unit 类型(按后缀):.service(守护进程)、.socket(套接字激活)、.timer(定时任务,替代 cron)、.mount/.automount(挂载)、.target(一组 unit 的集合,替代 runlevel)、.path(路径变化触发)、.device、.slice(cgroup 资源分片)。
enable vs start(高频混淆):
systemctl start:立即启动,重启后不保留systemctl enable:创建开机自启软链接(写入*.wants/),不影响当前是否在跑- 两者都要 →
systemctl enable --now myapp
daemon-reload:改了 unit 文件后必须 systemctl daemon-reload 让 systemd 重读,否则用的还是旧配置(改完直接 restart 却没生效,多半是漏了这步)。
journalctl 持久化:默认 Storage=auto——若 /var/log/journal/ 目录不存在,日志只存内存(/run/log/journal),重启即丢。开启持久化:
mkdir -p /var/log/journal
systemctl restart systemd-journald # 或在 journald.conf 里设 Storage=persistent
journalctl --list-boots # 能看到历史 boot 才算持久化成功
journalctl -u myapp -b -1 # 看上一次开机时该服务的日志小结#
概念解释型题目重在"说清楚本质 + 给实际例子"。Linux 核心概念(inode/进程状态/信号/cgroup/文件描述符)承载了容器、K8s、可观测性等上层技术的基础理解,面试中能讲清楚这些说明基础扎实。