<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Shirone</title><description>A Material 3 anime blog</description><link>https://blog-l7wd3.pages.dev/</link><language>zh_CN</language><item><title>一文讲通 LVM 与传统扩容的异同</title><link>https://blog-l7wd3.pages.dev/posts/lvm/</link><guid isPermaLink="true">https://blog-l7wd3.pages.dev/posts/lvm/</guid><description>从分区与文件系统的职责划分讲清 LVM 与传统分区的差异，并给出新增磁盘、在线扩容的完整流程、命令与常见坑。</description><pubDate>Fri, 11 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;本文思维链：理解分区职能 → 拆开传统分区的两个角色 → 看清 LVM 的三层抽象 → 落到扩容流程与常见坑&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;基本概念&lt;/h2&gt;
&lt;p&gt;Linux 的存储从上到下是一条链：&lt;strong&gt;物理磁盘 → 分区表 → 分区 / PV → （VG）→ 文件系统 → 挂载点&lt;/strong&gt;。
日常最容易混淆的是&quot;分区&quot;和&quot;文件系统&quot;——把它们分开看，后面所有扩容操作才讲得通。&lt;/p&gt;
&lt;h3&gt;分区概念&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;分区不是一块独立的设备&lt;/strong&gt;，它只是分区表里的一条记录：「从第 X 个扇区开始，共 Y 个扇区」。内核读到这条记录后，生成一个块设备 &lt;code&gt;/dev/sdb1&lt;/code&gt;，上层就能像读写整盘一样读写这段地址范围。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;分区表&lt;/strong&gt;写在磁盘最前面，常见两种：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;类型&lt;/th&gt;
&lt;th&gt;位置&lt;/th&gt;
&lt;th&gt;分区数上限&lt;/th&gt;
&lt;th&gt;容量上限&lt;/th&gt;
&lt;th&gt;特点&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MBR&lt;/td&gt;
&lt;td&gt;第 0 扇区（512 B）&lt;/td&gt;
&lt;td&gt;4 个主分区（或 3 主 + 1 扩展）&lt;/td&gt;
&lt;td&gt;2 TiB&lt;/td&gt;
&lt;td&gt;老、兼容性好，改完需重读&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT&lt;/td&gt;
&lt;td&gt;头部 + 尾部各一份，带 CRC 校验&lt;/td&gt;
&lt;td&gt;默认 128 个&lt;/td&gt;
&lt;td&gt;远超 2 TiB&lt;/td&gt;
&lt;td&gt;自带备份表，主表损坏可恢复&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;分区与文件系统的分工&lt;/strong&gt;：&lt;code&gt;mkfs.xfs /dev/sdb1&lt;/code&gt; 是把文件系统的超级块、空闲块位图、inode 表&lt;strong&gt;写进分区覆盖的地址范围&lt;/strong&gt;。也就是说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;分区&lt;/strong&gt;决定「文件系统能用多大」——地址范围写在分区表里，建好即固定；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文件系统&lt;/strong&gt;决定「这些空间怎么组织数据」——元数据写在分区内部。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两边互不知情，所以扩容时要&lt;strong&gt;拆成两次扩&lt;/strong&gt;：先改分区表/LV 映射让块设备变大，再通知文件系统吃满新空间。这是全文最关键的一句话。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;flowchart TD
    A[物理磁盘 /dev/sdb] --&amp;gt; B[分区表 MBR / GPT]
    B --&amp;gt; C[分区 /dev/sdb1]
    C --&amp;gt; D[文件系统 XFS / EXT4]
    D --&amp;gt; E[挂载点 /data]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;查看命令&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lsblk -f                              # 树形展示：磁盘→分区→文件系统→挂载点
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT
blkid                                 # 查看 UUID / 文件系统类型
fdisk -l /dev/sdb                     # 查看分区表
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;LVM概念&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;LVM（Logical Volume Manager）&lt;/strong&gt; 是架在 &lt;code&gt;device-mapper&lt;/code&gt;（dm）之上的卷管理层：它把「物理空间」和「逻辑空间」解耦，用一张可动态修改的&lt;strong&gt;映射表&lt;/strong&gt;取代固定地址。&lt;/p&gt;
&lt;p&gt;层次结构：物理磁盘/分区 → &lt;strong&gt;PV&lt;/strong&gt; → &lt;strong&gt;VG&lt;/strong&gt; → &lt;strong&gt;LV&lt;/strong&gt; → 文件系统&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;层&lt;/th&gt;
&lt;th&gt;全称&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;th&gt;关键命令&lt;/th&gt;
&lt;th&gt;类比&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PV&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Physical Volume&lt;/td&gt;
&lt;td&gt;被 LVM 纳管的块设备；空间切成固定大小的 PE（默认 4 MiB），头部写入 LVM 元数据&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pvcreate&lt;/code&gt; / &lt;code&gt;pvs&lt;/code&gt; / &lt;code&gt;pvdisplay&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;砖头&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VG&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Volume Group&lt;/td&gt;
&lt;td&gt;把一个或多个 PV 汇总成存储池，池内空间以 PE 为单位统一编号&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vgcreate&lt;/code&gt; / &lt;code&gt;vgextend&lt;/code&gt; / &lt;code&gt;vgs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;砖堆&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LV&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Logical Volume&lt;/td&gt;
&lt;td&gt;从 VG 里切出一段空间，由若干 LE 组成，与 PE 一一映射&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lvcreate&lt;/code&gt; / &lt;code&gt;lvextend&lt;/code&gt; / &lt;code&gt;lvs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;砌好的墙&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PE / LE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Physical / Logical Extent&lt;/td&gt;
&lt;td&gt;分配的最小粒度：PE 在 PV 上，LE 在 LV 上，默认 4 MiB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pvcreate -s&lt;/code&gt; / &lt;code&gt;lvcreate -l&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;砖的单位&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;映射是怎么实现的&lt;/strong&gt;：LV 并不是&quot;把某块盘的一部分划出来&quot;，而是 dm 里的一张 &lt;code&gt;linear&lt;/code&gt; 映射表——「LV 的第 0 ~ 10239 个 LE → /dev/sdb 上第 0 ~ 10239 个 PE」。由此得到三个直接结论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个 LV 可以&lt;strong&gt;横跨多块 PV&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;扩容只是&lt;strong&gt;往映射表尾部追加条目&lt;/strong&gt;，已有条目的地址不动，所以不需要搬数据；&lt;/li&gt;
&lt;li&gt;设备节点其实是 &lt;code&gt;/dev/mapper/vg_data-lv_data&lt;/code&gt;，&lt;code&gt;/dev/vg_data/lv_data&lt;/code&gt; 只是 udev 生成的软链接，两者是同一个设备。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;元数据存在哪&lt;/strong&gt;：LVM 自己的元数据（PV/VG/LV 结构、PE 分配表）有两份——磁盘上每个 PV 头部的 label + metadata area，以及 &lt;code&gt;/etc/lvm/backup/&lt;/code&gt;、&lt;code&gt;/etc/lvm/archive/&lt;/code&gt; 里的文本备份，必要时可用 &lt;code&gt;vgcfgrestore&lt;/code&gt; 回滚。这也是 LVM 比裸分区&quot;更好救&quot;的原因之一。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pvs                 # PV 清单
vgs                 # VG 清单（重点看 VFree：还剩多少可分配）
lvs -o +devices     # LV 清单，+devices 可看到它落在哪些 PV 上
pvdisplay -m        # 展开 PE → LE 的映射关系
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;两者关系&lt;/h3&gt;
&lt;p&gt;传统分区 &lt;code&gt;/dev/sdb1&lt;/code&gt; 同时干了两件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;划分物理边界&lt;/strong&gt;：把一块物理磁盘切成一段一段的存储区域&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;作为文件系统的载体&lt;/strong&gt;：&lt;code&gt;mkfs /dev/sdb1&lt;/code&gt;，文件系统直接建在分区上&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而 LVM 把这两个角色&lt;strong&gt;拆开&lt;/strong&gt;了：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;角色&lt;/th&gt;
&lt;th&gt;传统&lt;/th&gt;
&lt;th&gt;LVM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;划分物理边界&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;分区（fdisk）&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;PV&lt;/strong&gt;（pvcreate，切成 PE）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;池化/合并空间&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;不存在&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VG&lt;/strong&gt;（vgextend 加入新 PV）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;作为文件系统载体&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;分区（sdb1）&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LV&lt;/strong&gt;（lvcreate）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;容量调整粒度&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;整块磁盘的空闲区域&lt;/td&gt;
&lt;td&gt;VG 中任意可用 PE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;注：&lt;strong&gt;VG&lt;/strong&gt; ≈ 传统里没有的中间池化层（把多个物理范围合并成一个可分配空间）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;两者区别&lt;/h3&gt;
&lt;h4&gt;分区大小&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;LV 的物理边界不是固定的&lt;/strong&gt;，而传统分区大小固定：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;传统 &lt;code&gt;/dev/sdb1&lt;/code&gt; 建好后，物理位置和大小就钉死了。&lt;/li&gt;
&lt;li&gt;LVM 的 &lt;code&gt;/dev/vg_data/lv_data&lt;/code&gt; 逻辑上 50G，但底层可能横跨 &lt;code&gt;/dev/sda3&lt;/code&gt; 和 &lt;code&gt;/dev/sdb&lt;/code&gt; 两块盘，扩容后可以变成 150G。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;也就是说，&lt;strong&gt;LV 只保留&quot;文件系统载体&quot;这个角色，丢掉了&quot;固定物理边界&quot;这个角色&lt;/strong&gt;——物理边界被 PV/VG 接管了。这正是 LVM 灵活性的来源。&lt;/p&gt;
&lt;h4&gt;在线扩容&lt;/h4&gt;
&lt;p&gt;传统分区必须挂载新目录或调整分区，LVM 可通过 LV 实现逻辑上的扩展：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PV 层面&lt;/strong&gt;：&lt;code&gt;pvcreate /dev/sdb&lt;/code&gt; 只是初始化磁盘元数据，不涉及已挂载的磁盘。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VG 层面&lt;/strong&gt;：&lt;code&gt;vgextend vg_data /dev/sdb&lt;/code&gt; 只是在卷组里新增一个物理存储池成员，不影响现有 LV 的数据分布。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LV 层面&lt;/strong&gt;：&lt;code&gt;lvextend -l +100%FREE /dev/vg_data/lv_data&lt;/code&gt; 是逻辑上的扩展，内核支持动态调整映射表。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文件系统层面&lt;/strong&gt;：&lt;code&gt;xfs_growfs /data&lt;/code&gt; 或 &lt;code&gt;resize2fs&lt;/code&gt; 专门设计为&lt;strong&gt;在线扩展&lt;/strong&gt;，底层文件系统会动态分配新空间到已有目录中。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;整个过程业务进程无需重启，正在读写的文件不受影响（因为扩展的是空闲区域，不移动已有数据）。&lt;/p&gt;
&lt;h4&gt;扩容能力的边界&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;场景&lt;/th&gt;
&lt;th&gt;传统分区&lt;/th&gt;
&lt;th&gt;LVM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;同一块盘有&lt;strong&gt;紧邻&lt;/strong&gt;空闲空间时扩容&lt;/td&gt;
&lt;td&gt;可以（改分区表 + 重读 + resize2fs）&lt;/td&gt;
&lt;td&gt;可以&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;跨磁盘扩大同一个目录&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;不可能&lt;/strong&gt;，分区不能跨盘&lt;/td&gt;
&lt;td&gt;可以（vgextend + lvextend）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;在线扩容（不 umount、不停业务）&lt;/td&gt;
&lt;td&gt;受盘内空间与内核重读分区表限制&lt;/td&gt;
&lt;td&gt;可以&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;缩容&lt;/td&gt;
&lt;td&gt;ext4 需 umount + e2fsck；XFS 完全不支持&lt;/td&gt;
&lt;td&gt;同样受限，&lt;code&gt;lvreduce&lt;/code&gt; 必须离线且风险极高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;秒级快照 / 克隆&lt;/td&gt;
&lt;td&gt;不支持&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lvcreate -s&lt;/code&gt; 支持&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;结论：LVM 换来灵活性，代价是多一层抽象（多一份要维护的元数据、多一处可能敲错的地方）。缩容不是它的强项，&lt;strong&gt;扩容才是它的主场&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;扩容流程&lt;/h2&gt;
&lt;p&gt;扩容要先分清诉求，两种诉求的代价完全不同：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A. 新增挂载点&lt;/strong&gt;：磁盘满了，加一块盘，把新盘挂到新目录（如 &lt;code&gt;/data2&lt;/code&gt;）——不需要停机。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B. 扩大已有目录&lt;/strong&gt;：磁盘满了，但业务路径不能改，必须让 &lt;code&gt;/data&lt;/code&gt; 本身变大——这才是考验底层方案的地方。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;新增磁盘（传统 &amp;amp; LVM）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;场景1&lt;/strong&gt;：为新磁盘新建分区（或 LV）并挂载到&lt;strong&gt;新目录&lt;/strong&gt;，即上面的诉求 A。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;传统流程&lt;/strong&gt;：OS 层执行 rescan → 确认 lsblk → fdisk 分区 → mkfs 格式化 → mount 挂载 → df 验证→ fstab 永久挂载 → mount -a 验证&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# OS层发现新设备
echo &quot;- - -&quot; &amp;gt; /sys/class/scsi_host/host0/scan
lsblk                        # 确认新容量已识别
fdisk /dev/sdb               # 分区
mkfs.xfs /dev/sdb1           # 格式化
mount /dev/sdb1 /mnt/data    # 挂载
df -h                        # 验证
# 永久挂载：获取UUID → 写入 /etc/fstab
blkid /dev/sdb1				 # 获取UUID
blkid /dev/sdb1 | grep -o &apos; UUID=&quot;[^&quot;]*&apos; | cut -d&apos;&quot;&apos; -f2	# 获取纯UUID字段
vim /etc/fstab				 # vim 手动加一行或用 echo 追加
echo &apos;UUID=&amp;lt;UUID&amp;gt; /mnt/data xfs defaults 0 0&apos; &amp;gt;&amp;gt; /etc/fstab
mount -a -v					 # 用 mount -a 测试 fstab 是否正确
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;LVM 流程&lt;/strong&gt;：OS 层执行 rescan → 确认 lsblk → PV/VG/LV 操作 → mkfs → mount → df 验证 → fstab 永久挂载 → mount -a 验证&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo &quot;- - -&quot; &amp;gt; /sys/class/scsi_host/host0/scan
lsblk
pvcreate /dev/sdb                    # 相当于分区中的初始化物理边界
vgcreate vg_data /dev/sdb            # 建存储池（传统没有这层）
lvcreate -L 50G -n lv_data vg_data   # 相当于&quot;切出分区&quot;
mkfs.xfs /dev/vg_data/lv_data        # 格式化
mount /dev/vg_data/lv_data /mnt/data # 挂载
df -h
blkid /dev/sdb1
vim /etc/fstab
mount -a -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;场景2&lt;/strong&gt;：为新磁盘新建分区（或 LV）并挂载到&lt;strong&gt;已有目录&lt;/strong&gt;，即上面的诉求 B。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;流程&lt;/strong&gt;：停业务 → 搬运现有业务数据 → 识别新容量 → umount → 其余流程&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么该流程要停止业务/不支持在线操作？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&quot;新盘 + 新挂载点&quot;这套流程本身不需要停机&lt;/strong&gt;。&lt;code&gt;mkfs&lt;/code&gt; 和 &lt;code&gt;mount&lt;/code&gt; 只作用于新的块设备与新的空目录，完全不碰正在服务的文件系统。真正要停机的，是「&lt;strong&gt;想把新盘并进已有目录&lt;/strong&gt;」（诉求 B）——传统分区方案做不到，只能停机搬数据。&lt;/p&gt;
&lt;p&gt;拆开看，原因有三层：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;分区是固定地址，且不能跨盘&lt;/strong&gt;：&lt;code&gt;/dev/sda1&lt;/code&gt; 的边界写死在分区表里，&lt;code&gt;/dev/sdb1&lt;/code&gt; 是另一段独立地址。&quot;把 sdb 的空间追加给 sda1 上的文件系统&quot;在传统分区里根本不存在对应操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;同一块盘内扩容也有限制&lt;/strong&gt;：只有当盘上存在&lt;strong&gt;紧邻分区尾部&lt;/strong&gt;的空闲空间时才能扩（&lt;code&gt;growpart&lt;/code&gt; / &lt;code&gt;parted resizepart&lt;/code&gt; → &lt;code&gt;resize2fs&lt;/code&gt;）；改完分区表还要让内核重读（&lt;code&gt;partprobe&lt;/code&gt; / &lt;code&gt;partx -u&lt;/code&gt;），而分区正被挂载占用时，旧内核会直接拒绝重读，只能 umount。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;做不到就只能搬数据&lt;/strong&gt;：换新盘意味着 &lt;code&gt;rsync&lt;/code&gt; 全量搬运 → umount → 重新分区、&lt;code&gt;mkfs&lt;/code&gt; → 改 &lt;code&gt;/etc/fstab&lt;/code&gt; → 重新 mount。停机时间和数据量成正比，且搬运期间的新写入无法保证一致，业务必须停。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;另外，&lt;code&gt;mkfs&lt;/code&gt; 这个动作&lt;strong&gt;永远不可能在线做&lt;/strong&gt;：它是&quot;在块设备上从零构建文件系统元数据&quot;的&lt;strong&gt;破坏性&lt;/strong&gt;操作，等于把原有超级块、inode 表、位图全部重建。这和&quot;扩容文件系统（在原有结构上变大、保留数据）&quot;是两件完全不同的事。&lt;/p&gt;
&lt;h3&gt;LVM 在线扩容&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;生产环境中的最佳实践&lt;/strong&gt;。不动现有磁盘/分区，而是把新磁盘加入卷组，再扩展 LV，让文件系统直接使用新空间。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;流程&lt;/strong&gt;：OS 层执行 rescan → 确认 lsblk → PV/VG/LV 操作 → xfs_growfs/resize2fs → df 验证&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo &quot;- - -&quot; &amp;gt; /sys/class/scsi_host/host0/scan
lsblk
pvcreate /dev/sdb                             # 新盘纳入 LVM
vgextend vg_data /dev/sdb                     # 加入卷组，VG 变大
lvextend -l +100%FREE /dev/vg_data/lv_data    # LV 变大（也可以 -L +50G 指定增量）
# 扩容文件系统，通知文件系统用满新空间
xfs_growfs /data                 # XFS：接挂载点
resize2fs /dev/vg_data/lv_data   # EXT4：接设备
# 检查
df -h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::tip
想少敲一条命令，可以在扩 LV 时直接加 &lt;code&gt;-r&lt;/code&gt;（等价于 &lt;code&gt;--resizefs&lt;/code&gt;）：&lt;code&gt;lvextend -r -l +100%FREE /dev/vg_data/lv_data&lt;/code&gt;，LVM 会顺带调用文件系统的扩容工具。
:::&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么扩容流程中没有格式化/挂载操作？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;格式化（mkfs）&lt;strong&gt;是对整个块设备&quot;从无到有&quot;&lt;strong&gt;创建文件系统&lt;/strong&gt;的操作，只能做一次；而扩容是&lt;/strong&gt;扩展文件系统&lt;/strong&gt;（在原有基础上变大、保留数据），走的是另一条代码路径。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;挂载（mount）&lt;strong&gt;只在&lt;/strong&gt;全新磁盘 / 全新 LV 第一次投入使用&lt;/strong&gt;时做一次，作用是把文件系统接入目录树；扩容是对&lt;strong&gt;已挂载&lt;/strong&gt;的对象操作，属于两个不同阶段。&lt;/li&gt;
&lt;li&gt;扩容其实是&quot;拆成两次扩&quot;：&lt;code&gt;lvextend&lt;/code&gt; 让&lt;strong&gt;块设备&lt;/strong&gt;变大（改 dm 映射表），&lt;code&gt;xfs_growfs&lt;/code&gt; / &lt;code&gt;resize2fs&lt;/code&gt; 让&lt;strong&gt;文件系统&lt;/strong&gt;用满新空间。少做后一步，&lt;code&gt;lsblk&lt;/code&gt; 已经变大而 &lt;code&gt;df -h&lt;/code&gt; 毫无变化。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;常见坑&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;只扩了 LV，忘了扩文件系统&lt;/strong&gt;：补一条 &lt;code&gt;xfs_growfs /data&lt;/code&gt;（XFS）或 &lt;code&gt;resize2fs /dev/vg_data/lv_data&lt;/code&gt;（EXT4）即可，对已挂载的文件系统是安全的（XFS 只支持扩、不支持缩）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数搞反&lt;/strong&gt;：&lt;code&gt;xfs_growfs&lt;/code&gt; 接&lt;strong&gt;挂载点&lt;/strong&gt;，&lt;code&gt;resize2fs&lt;/code&gt; 接&lt;strong&gt;设备&lt;/strong&gt;；&lt;code&gt;lvextend&lt;/code&gt; 接 LV 路径，&lt;code&gt;vgextend&lt;/code&gt; 接 &lt;strong&gt;VG 名 + 新 PV&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对已有数据的盘执行 &lt;code&gt;pvcreate&lt;/code&gt;&lt;/strong&gt;：会覆盖磁盘头部（含分区表），旧数据事实不可见。新盘整盘使用没问题；复用旧盘前务必确认盘上没有要保留的数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;整盘做 PV 还是分区做 PV&lt;/strong&gt;：&lt;code&gt;pvcreate /dev/sdb&lt;/code&gt; 最省事；若这块盘还要分给别的用途、或需要保留分区表结构，就先建一个类型为 &lt;code&gt;8e&lt;/code&gt;（Linux LVM）的分区，再 &lt;code&gt;pvcreate /dev/sdb1&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;虚拟机扩完盘系统没识别&lt;/strong&gt;：SCSI 用 &lt;code&gt;echo &quot;- - -&quot; &amp;gt; /sys/class/scsi_host/host0/scan&lt;/code&gt;；NVMe 用 &lt;code&gt;echo 1 &amp;gt; /sys/class/nvme/nvme0/rescan_controller&lt;/code&gt;；只改了分区表则用 &lt;code&gt;partprobe /dev/sdb&lt;/code&gt; 或 &lt;code&gt;partx -u /dev/sdb&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缩容是另一回事&lt;/strong&gt;：ext4 缩容要先 &lt;code&gt;umount&lt;/code&gt; + &lt;code&gt;e2fsck -f&lt;/code&gt; + &lt;code&gt;resize2fs&lt;/code&gt;，顺序错一步就丢数据；XFS 根本不支持缩容。生产上想&quot;腾出空间&quot;，通常是新建 LV、迁移数据、再删旧 LV。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;变更前留后路&lt;/strong&gt;：动 LV 之前可以先 &lt;code&gt;lvcreate -s&lt;/code&gt; 打个快照，或确认有可用备份，扩容失败时可回滚。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;小结&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;问题&lt;/th&gt;
&lt;th&gt;一句话答案&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;分区和文件系统有什么区别？&lt;/td&gt;
&lt;td&gt;分区是「地址范围」（写在分区表里），文件系统是「数据的组织方式」（写在分区内部），扩容要分别扩两次。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LVM 比传统分区多了什么？&lt;/td&gt;
&lt;td&gt;多了 &lt;strong&gt;VG 池化层&lt;/strong&gt;和一张可动态修改的&lt;strong&gt;映射表&lt;/strong&gt;，所以空间能跨盘拼、容量能在线追加。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;为什么还要执行 &lt;code&gt;xfs_growfs&lt;/code&gt; / &lt;code&gt;resize2fs&lt;/code&gt;？&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lvextend&lt;/code&gt; 只改块设备大小，文件系统必须被显式通知才能用满新空间。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;为什么扩容不需要 mkfs / mount？&lt;/td&gt;
&lt;td&gt;格式化是&quot;从无到有创建&quot;，扩容是&quot;在原有基础上变大&quot;；挂载只在对象第一次投入使用时做一次。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;传统方案什么时候必须停机？&lt;/td&gt;
&lt;td&gt;当诉求是&quot;扩大已有目录&quot;，且可用空间不在同一块盘的紧邻位置时——只能停机搬数据，这正是 LVM 存在的理由。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>Kubernetes 八股</title><link>https://blog-l7wd3.pages.dev/posts/interview/k8s/</link><guid isPermaLink="true">https://blog-l7wd3.pages.dev/posts/interview/k8s/</guid><description>速记版 Kubernetes 八股</description><pubDate>Fri, 21 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;架构与组件&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Kubernetes 核心组件有哪些？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Master（控制平面）&lt;/strong&gt;：kube-apiserver（API 入口）、etcd（配置存储）、kube-scheduler（调度）、kube-controller-manager（控制器）、cloud-controller-manager（云厂商控制器，可选）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Node（工作节点）&lt;/strong&gt;：kubelet（Pod 生命周期）、kube-proxy（网络代理/负载均衡）、containerd（容器运行时）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;kube-apiserver 的作用？&lt;/strong&gt;
集群统一 API 入口，所有组件通过它通信。它是唯一直接读写 etcd 的组件，负责认证（Authentication）、鉴权（Authorization）、准入控制（Admission）、校验与持久化，并提供 Watch 机制供其他组件监听资源变化。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;etcd 的作用？&lt;/strong&gt;
分布式 KV 存储，保存集群所有配置和状态数据。基于 Raft 协议保证强一致性，因此生产环境推荐 3/5 个奇数节点做高可用；它是集群的&lt;strong&gt;唯一真实数据源&lt;/strong&gt;，备份 etcd 就等于备份整个集群。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;kube-scheduler 如何调度 Pod？&lt;/strong&gt;
过滤（Filtering）→ 打分（Scoring）→ 绑定（Binding）。过滤阶段剔除不满足条件的节点（资源不足、污点不容忍、端口冲突、亲和性不符）；打分阶段按优先级函数（资源均衡、亲和性权重等）排序选出最优节点；最后把结果写入 Pod 的 &lt;code&gt;nodeName&lt;/code&gt;（Binding）。调度考虑资源、亲和性、污点容忍、拓扑分布等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;kube-controller-manager 的作用？&lt;/strong&gt;
运行一系列控制循环（Reconcile Loop），让实际状态不断逼近期望状态。常见控制器：Deployment、ReplicaSet、StatefulSet、DaemonSet、Node、Job、EndpointSlice、ServiceAccount 等。多个控制器共享同一进程以减少复杂度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;kubelet 的作用？&lt;/strong&gt;
每个节点上的代理，负责 Pod 生命周期管理（创建、监控、销毁）。它监听 API Server 上属于自己的 Pod，通过 CRI 调用容器运行时拉起容器，并上报节点与 Pod 状态；&lt;strong&gt;它不管理非本节点创建的静态 Pod 之外的容器&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;kube-proxy 的 iptables 和 IPVS 模式区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;iptables：基于规则链线性匹配，规则数量随 Service 数量增长而膨胀，适合小规模集群；随机负载均衡。&lt;/li&gt;
&lt;li&gt;IPVS：基于哈希表，性能高、支持 rr/wrr/lc/sh 等多种负载均衡算法与会话保持，适合大规模集群。&lt;/li&gt;
&lt;li&gt;两者都只做&lt;strong&gt;四层转发&lt;/strong&gt;，都从 EndpointSlice 获取后端地址。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;一个 Pod 从创建到运行的完整流程？&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;kubectl 提交 YAML → apiserver 认证、鉴权、准入（Mutating/Validating）→ 写入 etcd。&lt;/li&gt;
&lt;li&gt;controller-manager 中的 Deployment/ReplicaSet 控制器发现后创建对应的 Pod 对象。&lt;/li&gt;
&lt;li&gt;scheduler 监听到未绑定的 Pod，筛选节点后写入 &lt;code&gt;nodeName&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;目标节点的 kubelet watch 到该 Pod，调用 CRI 拉镜像、先跑 Init 容器、再按顺序启动业务容器；调用 CNI 分配 IP、挂载 Volume。&lt;/li&gt;
&lt;li&gt;kubelet 上报状态，EndpointSlice 控制器把就绪 Pod 写入 Service 后端，CoreDNS 提供域名解析。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Pod&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Pod 是什么？&lt;/strong&gt;
Kubernetes 最小调度单元，一组容器的集合，共享网络（同一 Network Namespace 与 IP）和存储（Volume），可共享 UTS/IPC。每个 Pod 都有一个 &lt;code&gt;pause&lt;/code&gt; 容器（Infra 容器）持有网络命名空间，业务容器加入其中。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么 Pod 是 K8s 调度的最小单元？&lt;/strong&gt;
调度、网络、存储和资源配额都以 Pod 为粒度：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;网络、存储和资源配额&lt;/strong&gt;：容器只是进程的封装，如果容器需要&lt;strong&gt;共享 Network/UTS/IPC 命名空间与 Volume&lt;/strong&gt;，必须被调度到同一节点，单独调度无法保证共置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调度&lt;/strong&gt;：资源 requests/limits、QoS 等级、亲和性与污点容忍都定义在 Pod 级别（容器级别只是求和）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生命周期&lt;/strong&gt;：Pod 是原子生命周期单位，副本数、滚动更新、扩缩容的计数对象都是 Pod。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Pod 的生命周期状态有哪些？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pending（等待调度/拉镜像）&lt;/li&gt;
&lt;li&gt;Running（至少一个容器运行中）&lt;/li&gt;
&lt;li&gt;Succeeded（全部容器成功退出且不会重启）&lt;/li&gt;
&lt;li&gt;Failed（至少一个容器异常退出且不会重启）&lt;/li&gt;
&lt;li&gt;Unknown（与节点失联）&lt;/li&gt;
&lt;li&gt;容器自身的状态则为 Waiting、Running、Terminated。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Init 容器的作用？&lt;/strong&gt;
在主容器启动前串行执行、必须成功退出，常用于等待依赖服务就绪、初始化配置、修改数据卷权限；与普通容器不同的还有：不支持探针、不计入 QoS 计算。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pod 与 Deployment 的区别？&lt;/strong&gt;
Pod 是单个调度单元，生命周期短暂，重启/迁移后 IP 变化；Deployment 通过 ReplicaSet 管理 Pod 副本，提供声明式副本数、滚动更新和回滚。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pod 健康检查的探针有哪些？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;三种探针：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Liveness Probe（存活探针，失败则按 restartPolicy 重启容器）&lt;/li&gt;
&lt;li&gt;Readiness Probe（就绪探针，失败则从 Service 后端摘除、不转发流量）&lt;/li&gt;
&lt;li&gt;Startup Probe（启动探针，成功前抑制其他探针，适合慢启动应用）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实现方式：&lt;code&gt;exec&lt;/code&gt;（执行命令）、&lt;code&gt;httpGet&lt;/code&gt;、&lt;code&gt;tcpSocket&lt;/code&gt;、&lt;code&gt;grpc&lt;/code&gt;。参数有 initialDelaySeconds、periodSeconds、timeoutSeconds、failureThreshold。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;讲一下Pod重启，restartPolicy 有哪些？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;重启是重启容器而不是重建 Pod，所以 Pod IP 不变，但重启间隔会指数退避（10s→20s→40s…上限 5min），这就是 CrashLoopBackOff。&lt;/li&gt;
&lt;li&gt;重启策略：Always（默认，Deployment 用）、OnFailure、Never（Job 常用）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Pod 处于 CrashLoopBackOff / ImagePullBackOff 怎么办？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CrashLoopBackOff：&lt;code&gt;kubectl logs --previous&lt;/code&gt; 看上次崩溃日志，常见原因有配置错误、依赖服务不可用、探针配置过严、OOMKilled（&lt;code&gt;kubectl describe pod&lt;/code&gt; 看 Last State）。&lt;/li&gt;
&lt;li&gt;ImagePullBackOff：镜像名/标签错误、私有仓库缺少 &lt;code&gt;imagePullSecrets&lt;/code&gt;、节点网络不通。&lt;/li&gt;
&lt;li&gt;Pending：资源不足、没有可调度节点、PVC 未绑定。&lt;/li&gt;
&lt;li&gt;Terminating 卡住：finalizer 未清理或节点失联。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Pod 的 QoS 等级？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Guaranteed（所有容器都设了 requests == limits）&lt;/li&gt;
&lt;li&gt;Burstable（设了部分 requests，不满足 Guaranteed）&lt;/li&gt;
&lt;li&gt;BestEffort（完全没设）&lt;/li&gt;
&lt;li&gt;节点内存不足时按 BestEffort → Burstable → Guaranteed 的顺序驱逐&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Service 与网络&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Service 的类型有哪些？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ClusterIP（默认，仅集群内访问，虚拟 IP）；&lt;/li&gt;
&lt;li&gt;NodePort（每个节点开放 30000-32767 端口映射）；&lt;/li&gt;
&lt;li&gt;LoadBalancer（调用云厂商 LB，通常是 NodePort 的超集）；&lt;/li&gt;
&lt;li&gt;ExternalName（CNAME/DNS 别名，不转发流量）；&lt;/li&gt;
&lt;li&gt;另外还有无头服务 Headless Service（&lt;code&gt;clusterIP: None&lt;/code&gt;，直接返回 Pod IP，供 StatefulSet 使用）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Service 的实现原理？&lt;/strong&gt;
Service 只是一组 iptables/IPVS 规则的抽象：apiserver 分配 ClusterIP 后，kube-proxy 监听 Service 与 EndpointSlice 变化并下发规则，把访问 ClusterIP 的流量 DNAT 到某个就绪 Pod 的 IP:Port；CoreDNS 把 &lt;code&gt;svc.namespace.svc.cluster.local&lt;/code&gt; 解析为 ClusterIP。三层结构 = DNS 名称 → ClusterIP → Pod IP。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ingress 是什么？与 Service 的关系？&lt;/strong&gt;
Ingress 提供集群外部到 Service 的 HTTP/HTTPS 路由规则集合（基于 Host/Path 转发、TLS 终止），本身只是一份配置，必须由 Ingress Controller（Nginx Ingress、Traefik、Higress 等）解析并生效。流量路径为：客户端 → Ingress Controller → Service → Pod。Ingress 是七层，Service 是四层。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CNI 是什么？常见实现？&lt;/strong&gt;
Container Network Interface，容器网络插件标准（负责给 Pod 分配 IP、配置路由与网卡）。常见：Flannel（Overlay 网络，VXLAN/host-gw，简单但无 NetworkPolicy）、Calico（BGP 三层网络或 IPIP，性能好且支持 NetworkPolicy）、Cilium（eBPF，性能和可观测性更强）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;K8s 如何实现负载均衡？&lt;/strong&gt;
分层次实现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;四层（Service）&lt;/strong&gt;：kube-proxy 通过 iptables/IPVS 把 ClusterIP 的流量随机/轮询转发到后端 Pod，可用 &lt;code&gt;sessionAffinity: ClientIP&lt;/code&gt; 做会话保持。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;七层（Ingress / Gateway API）&lt;/strong&gt;：按域名、路径、Header、权重做路由。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;外部入口&lt;/strong&gt;：LoadBalancer 类型 Service 或云厂商 SLB/Nginx 做最外层负载均衡。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;客户端侧&lt;/strong&gt;：无头 Service + 客户端自行负载均衡（gRPC 常用）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Pod 之间如何通信？跨节点呢？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同一 Pod 内通过 localhost；&lt;/li&gt;
&lt;li&gt;同节点不同 Pod 通过 CNI 创建的 veth/bridge 通信；&lt;/li&gt;
&lt;li&gt;跨节点由 CNI 路由（Flannel VXLAN 封装、Calico BGP 路由）完成，要求满足 K8s 网络模型：每个 Pod 一个 IP，Pod 间可直接通信无需 NAT。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Service 访问不通怎么排查？&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;kubectl get endpointslices&lt;/code&gt; 确认后端是否有就绪 Pod（没有则检查探针/标签选择器）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl exec&lt;/code&gt; 进 Pod 测 &lt;code&gt;nslookup&lt;/code&gt; 与 &lt;code&gt;curl ClusterIP&lt;/code&gt;，定位是 DNS 还是转发问题。&lt;/li&gt;
&lt;li&gt;检查 &lt;code&gt;targetPort&lt;/code&gt; 与容器实际监听端口是否一致。&lt;/li&gt;
&lt;li&gt;检查 NetworkPolicy 是否拦截流量。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;存储&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;PV、PVC、StorageClass 的关系？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PV（PersistentVolume）：集群级存储资源，由管理员静态创建或由 provisioner 动态创建。&lt;/li&gt;
&lt;li&gt;PVC（PersistentVolumeClaim）：用户存储申请（容量、accessMode、storageClassName），绑定到某个 PV。&lt;/li&gt;
&lt;li&gt;StorageClass：动态存储供给配置，声明 provisioner 与参数（如 &lt;code&gt;reclaimPolicy&lt;/code&gt;、磁盘类型），PVC 引用它即可自动创建 PV。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;访问模式 accessMode 有哪些？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ReadWriteOnce（RWO，单节点读写，最常见）&lt;/li&gt;
&lt;li&gt;ReadOnlyMany（ROX）&lt;/li&gt;
&lt;li&gt;ReadWriteMany（RWX，需 NFS/CephFS 等支持）&lt;/li&gt;
&lt;li&gt;ReadWriteOncePod&lt;/li&gt;
&lt;li&gt;回收策略有 Retain / Delete / Recycle&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;PVC 处于 Pending 状态的可能原因？&lt;/strong&gt;
没有匹配的 PV（容量 / accessMode / storageClassName / 标签选择器不匹配）；StorageClass 不存在或 provisioner 故障；WaitForFirstConsumer 模式下还没有 Pod 使用它。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何配置持久化存储？&lt;/strong&gt;
三步：创建 StorageClass（或管理员静态建 PV）→ 创建 PVC 申请 → Pod 通过 &lt;code&gt;volumes&lt;/code&gt; 引用 PVC。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast
provisioner: kubernetes.io/aws-ebs   # 或 csi 驱动
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data
spec:
  storageClassName: fast
  accessModes: [&quot;ReadWriteOnce&quot;]
  resources:
    requests:
      storage: 10Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: app
      image: nginx
      volumeMounts:
        - name: data
          mountPath: /data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;emptyDir、hostPath 与 PVC 的区别？&lt;/strong&gt;
emptyDir 生命周期与 Pod 相同（Pod 删除即清空），适合缓存与容器间共享；hostPath 挂载宿主机目录，Pod 漂移后数据仍在但强绑定节点，仅适合特殊场景（日志采集）；PVC 才是真正的持久化、与 Pod 解耦的存储。&lt;/p&gt;
&lt;h2&gt;配置与安全&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;ConfigMap 和 Secret 的区别？&lt;/strong&gt;
ConfigMap 存明文非敏感配置；Secret 存敏感信息，值以 &lt;strong&gt;base64 编码&lt;/strong&gt;存储（并非加密），可限制为 &lt;code&gt;type: Opaque&lt;/code&gt; 或 dockerconfigjson 等。使用时都可以通过环境变量或 Volume 挂载注入。
&lt;strong&gt;注意：base64 是可逆编码不是加密&lt;/strong&gt;，要真正安全需开启 etcd 静态加密、RBAC 限制读取、或使用外部密钥管理（Vault/KMS）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;更新 ConfigMap/Secret 后 Pod 会立即生效吗？&lt;/strong&gt;
环境变量方式注入的&lt;strong&gt;不会&lt;/strong&gt;生效，必须重建 Pod（Deployment 可用 &lt;code&gt;kubectl rollout restart&lt;/code&gt;）；以 Volume 挂载方式的最终会更新（kubelet 周期同步，约 1 分钟），但应用需自行 reload。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RBAC 中 Role 和 ClusterRole 的区别？&lt;/strong&gt;
Role 作用于单个 Namespace；ClusterRole 作用于整个集群（或用于跨 Namespace 复用与集群级资源如 Node、PV）。通过 RoleBinding 绑定 Role/ClusterRole（限定在某 Namespace），通过 ClusterRoleBinding 绑定 ClusterRole（全集群生效）。RBAC 是&lt;strong&gt;纯允许模型&lt;/strong&gt;，没有拒绝规则。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ServiceAccount 的作用？&lt;/strong&gt;
Pod 访问 API Server 时的身份标识，未指定则使用 default。Token 会自动挂载到 &lt;code&gt;/var/run/secrets/kubernetes.io/serviceaccount&lt;/code&gt;，配合 RoleBinding 即可实现 Pod 级别最小权限。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pod 安全限制有哪些手段？&lt;/strong&gt;
SecurityContext（runAsUser、readOnlyRootFilesystem、capabilities、privileged）、Pod Security Admission（baseline/restricted）、NetworkPolicy（网络隔离）、ResourceQuota/LimitRange（资源约束）。&lt;/p&gt;
&lt;h2&gt;高级资源&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;StatefulSet 和 Deployment 的区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deployment 用于无状态应用，Pod 完全等价、可随意替换；&lt;/li&gt;
&lt;li&gt;StatefulSet 用于有状态应用，常用于数据库、消息队列、ZooKeeper 等，提供：
&lt;ul&gt;
&lt;li&gt;稳定的网络标识（&lt;code&gt;pod-name-0.svc&lt;/code&gt; 依赖 Headless Service）&lt;/li&gt;
&lt;li&gt;稳定的独立存储（volumeClaimTemplates）&lt;/li&gt;
&lt;li&gt;有序的创建/删除/滚动（0→N创建，逆序删除）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;DaemonSet 的典型应用场景？&lt;/strong&gt;
每个（或指定的）节点运行一个 Pod，如日志收集（Fluentd/Filebeat）、节点监控（Node Exporter）、CNI 组件、kube-proxy。新节点加入时会自动部署。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HPA 是什么？&lt;/strong&gt;
Horizontal Pod Autoscaler，基于 CPU/内存或自定义指标自动扩缩容 Pod 副本数。默认每 15s 采集一次指标（依赖 Metrics Server），按 &lt;code&gt;期望副本数 = 当前副本数 × 当前指标 / 目标指标&lt;/code&gt; 计算并受 tolerance 与扩缩容冷却时间限制。配套还有 VPA（垂直调资源）与 Cluster Autoscaler（扩节点）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Job 和 CronJob 的区别？&lt;/strong&gt;
Job 运行一次性任务直到成功（可设 completions/parallelism、backoffLimit）；CronJob 按 cron 表达式周期性创建 Job，支持 concurrencyPolicy 与历史保留数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何限制 Pod 资源使用？&lt;/strong&gt;
在 Pod 的 &lt;code&gt;resources&lt;/code&gt; 字段定义 &lt;code&gt;requests&lt;/code&gt;（调度依据，保证下限）和 &lt;code&gt;limits&lt;/code&gt;（运行时上限，超出内存会被 OOMKilled、超出 CPU 会被限流）。命名空间级别可用 LimitRange 设默认值与上下限，用 ResourceQuota 限制总量。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;节点亲和性与污点容忍的区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;亲和性是 Pod 主动选择节点（吸引，支持 requiredDuringScheduling 硬性 与 preferredDuringScheduling 软性、nodeAffinity/podAffinity/podAntiAffinity）；&lt;/li&gt;
&lt;li&gt;污点容忍是 Pod 被动适应节点（排斥），节点打污点排斥 Pod，Pod 加容忍才能调度上去。污点效果有 NoSchedule、PreferNoSchedule、NoExecute（NoExecute 还会驱逐不容忍的存量 Pod）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;包管理&lt;/h2&gt;
&lt;h3&gt;Helm&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Helm 是什么？&lt;/strong&gt;
Kubernetes 的包管理器，把一组 YAML 抽象成可参数化、可版本化、可复用的 Chart。三个核心概念：Chart（模板包）、Release（Chart 的一次部署实例）、Repository（Chart 仓库）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;常用命令？&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;helm repo add bitnami https://charts.bitnami.com/bitnami
helm search repo nginx
helm install my-nginx bitnami/nginx -n web --create-namespace -f values.yaml
helm upgrade my-nginx bitnami/nginx --set replicaCount=3
helm rollback my-nginx 1        # 回滚到指定 revision
helm history my-nginx
helm uninstall my-nginx -n web
helm template ./chart           # 本地渲染，不部署
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Helm 的目录结构？&lt;/strong&gt;
&lt;code&gt;Chart.yaml&lt;/code&gt;（元数据）、&lt;code&gt;values.yaml&lt;/code&gt;（默认值）、&lt;code&gt;templates/&lt;/code&gt;（Go Template 模板 YAML）、&lt;code&gt;charts/&lt;/code&gt;（子 Chart 依赖）。升级/回滚依赖 release 的 revision 记录（存在 Secret 中）。&lt;/p&gt;
&lt;h3&gt;kustomize&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;kustomize 是什么？&lt;/strong&gt;
K8s 原生命令（&lt;code&gt;kubectl apply -k&lt;/code&gt;）的配置定制工具。&lt;strong&gt;不用模板&lt;/strong&gt;，而是通过 base + overlay 的叠加（patch）方式复用同一份基础 YAML，适配不同环境。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;典型目录结构？&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;base/
  kustomization.yaml     # resources: [deployment.yaml, service.yaml]
  deployment.yaml
overlays/
  dev/kustomization.yaml # resources: [../../base]; replicas/patch 覆盖
  prod/kustomization.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;kustomize 常用能力？&lt;/strong&gt;
&lt;code&gt;resources&lt;/code&gt; 引入基础资源、&lt;code&gt;patchesStrategicMerge&lt;/code&gt;/&lt;code&gt;patches&lt;/code&gt; 覆盖字段、&lt;code&gt;replicas&lt;/code&gt; 改副本数、&lt;code&gt;images&lt;/code&gt; 改镜像 tag、&lt;code&gt;namePrefix&lt;/code&gt;/&lt;code&gt;commonLabels&lt;/code&gt; 统一前缀与标签、&lt;code&gt;configMapGenerator&lt;/code&gt; 自动生成配置并触发滚动更新。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Helm 与 kustomize 怎么选？&lt;/strong&gt;
Helm 适合对外分发、需要参数化与版本管理的场景；kustomize 适合内部多环境、以 patch 为主、不想维护模板语法的场景。两者常组合使用（Helm 渲染 base + kustomize 做 overlay patch）。&lt;/p&gt;
&lt;h2&gt;更新与发布&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;什么是滚动更新？如何实现滚动更新与回滚？（命令）&lt;/strong&gt;
滚动更新（RollingUpdate）是 Deployment 的默认策略：新建一个 ReplicaSet，逐步增加新 Pod 副本、同时减少旧 Pod 副本，过程中始终有可用实例，实现零中断发布。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl set image deploy/app app=nginx:1.25      # 触发更新
kubectl rollout status deploy/app                # 观察进度
kubectl rollout history deploy/app               # 查看历史版本
kubectl rollout undo deploy/app --to-revision=2  # 回滚
kubectl rollout pause/resume deploy/app          # 暂停/继续
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;滚动更新涉及哪些组件？如何控制？&lt;/strong&gt;
链路是 Deployment → ReplicaSet → Pod：Deployment 控制器发现 Pod 模板变更后创建新的 ReplicaSet 并扩缩两个 RS 的副本数，kubelet 负责实际起停容器。控制参数在 &lt;code&gt;strategy.rollingUpdate&lt;/code&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;maxSurge&lt;/code&gt;：更新过程中最多超出期望副本数的 Pod 数（默认 25%）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maxUnavailable&lt;/code&gt;：最多不可用的 Pod 数（默认 25%，设为 0 即&quot;先扩后缩&quot;的零中断更新）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;minReadySeconds&lt;/code&gt;：Pod 就绪后多久才认为可用；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;progressDeadlineSeconds&lt;/code&gt;：超时未完成则标记为失败。
滚动更新不丢请求的前提是配置了 &lt;strong&gt;Readiness 探针&lt;/strong&gt;与优雅退出（preStop + terminationGracePeriodSeconds）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;什么是 Recreate 策略？&lt;/strong&gt;
&lt;code&gt;Recreate&lt;/code&gt; 是一种用于更新应用的 Deployment 策略。它通过&lt;strong&gt;先终止所有旧的 Pod，再创建新的 Pod&lt;/strong&gt;来完成更新。存在停机时间。适合不能同时运行多个版本的应用（如数据库迁移）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;什么是灰度发布 / 金丝雀发布？如何实现？&lt;/strong&gt;
灰度（金丝雀）发布指先让一小部分流量进入新版本，观察指标正常后再逐步放量到 100%。实现方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;副本比例&lt;/strong&gt;：新旧两个 Deployment 共用同一个 Service 的标签，靠调节副本数比例分流（最粗糙，比例受 Pod 数限制）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ingress 注解&lt;/strong&gt;：Nginx Ingress 的 &lt;code&gt;nginx.ingress.kubernetes.io/canary: &quot;true&quot;&lt;/code&gt; + &lt;code&gt;canary-weight: 10&lt;/code&gt; / canary-by-header 精确切流。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务网格&lt;/strong&gt;：Istio VirtualService 按权重/Header/用户维度切流，粒度最细。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;渐进式交付工具&lt;/strong&gt;：Argo Rollouts、Flagger，支持自动分析指标并自动回滚。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;滚动更新、蓝绿、金丝雀的区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;滚动更新：逐个替换实例，资源占用小，回滚快，但新旧版本会短暂共存。&lt;/li&gt;
&lt;li&gt;蓝绿发布：同时部署完整的新旧两套环境，切流量即完成发布/回滚，需要双倍资源，回滚最快。&lt;/li&gt;
&lt;li&gt;金丝雀发布：按比例放量，风险最小，需要完善的监控与流量控制能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;其他&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;K8s 为何要关闭 Swap？&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;资源确定性被破坏&lt;/strong&gt;：K8s 依赖 &lt;strong&gt;cgroups&lt;/strong&gt; 严格限制 Pod 的内存上限（limits）。如果开启 Swap，Pod 写数据可能被换出到磁盘，导致 &lt;code&gt;cgroups&lt;/code&gt; 统计的内存使用量不准确，容器无法精准判断自己是否达到内存限制。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能不可控&lt;/strong&gt;：Swap 依赖磁盘 I/O，速度比内存慢几个数量级。一旦发生大量换页，Pod 响应延迟会急剧飙升，且这种抖动毫无预兆，破坏了 Kubernetes 承诺的 &lt;strong&gt;服务质量（QoS）&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调度误判&lt;/strong&gt;：Kubelet 根据节点上的内存容量进行 Pod 调度，如果 Swap 被占用，实际可用内存被稀释，容易产生节点资源枯竭但调度器不知情的情况。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;K8s 节点上只有 containerd 而没有 Docker，如何构建镜像？&lt;/strong&gt;
Docker 和 containerd 都是运行时，构建镜像需要单独的构建器：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;nerdctl + BuildKit&lt;/strong&gt;：&lt;code&gt;nerdctl&lt;/code&gt; 是兼容 Docker CLI 的 containerd 客户端，&lt;code&gt;nerdctl build&lt;/code&gt; 依赖 &lt;code&gt;buildkitd&lt;/code&gt;（需单独部署，&lt;code&gt;buildkitd --oci-worker-no-process-sandbox&lt;/code&gt;），也支持 &lt;code&gt;nerdctl compose&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;buildctl + buildkitd&lt;/strong&gt;：直接用 BuildKit 原生客户端，支持多平台构建与缓存导入导出。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;在集群内构建&lt;/strong&gt;：Kaniko（无需特权，在 Pod 内构建）、Buildpacks、或 Tekton/Argo Workflows 流水线。&lt;/li&gt;
&lt;li&gt;生产实践通常是 CI 里用 Docker/BuildKit 构建并推送镜像，节点只负责拉取运行。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;K8s 与 Docker 的关系？&lt;/strong&gt;
Docker 是容器技术的早期实现（CLI + daemon + 运行时 + 镜像格式）；K8s 是容器编排系统。早期 K8s 通过 dockershim 调用 Docker，1.24 起移除 dockershim，直接使用 CRI 对接 containerd/CRI-O，因此“K8s 弃用 Docker”弃用的是 dockershim 这层适配，镜像（OCI 标准）依然通用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;常用排错命令？&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get pod -A -o wide                 # 全量 Pod 与所在节点
kubectl describe pod &amp;lt;pod&amp;gt;                 # 事件、探针、调度失败原因
kubectl logs &amp;lt;pod&amp;gt; -c &amp;lt;container&amp;gt; -f       # 日志（--previous 看上次崩溃）
kubectl exec -it &amp;lt;pod&amp;gt; -- sh
kubectl top node / pod                     # 资源使用（依赖 metrics-server）
kubectl get events --sort-by=.lastTimestamp
kubectl get pod &amp;lt;pod&amp;gt; -o yaml              # 看最终生效的 spec
kubectl auth can-i get pods --as=system:serviceaccount:default:default
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Docker 八股</title><link>https://blog-l7wd3.pages.dev/posts/interview/docker/</link><guid isPermaLink="true">https://blog-l7wd3.pages.dev/posts/interview/docker/</guid><description>速记版 Docker 八股</description><pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;基础概念&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Docker 是什么？&lt;/strong&gt;
容器化平台，将应用及其依赖打包成轻量级、可移植的容器，实现操作系统级虚拟化。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么容器被称为&quot;一次构建，到处运行&quot;？&lt;/strong&gt;
镜像把应用和它的所有依赖（库、运行时、配置）一起打包，容器运行时只依赖宿主机内核，因此只要内核兼容，任何装了 Docker 的机器行为都一致，消除了&quot;环境不一致&quot;问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Docker 镜像与容器的关系？&lt;/strong&gt;
镜像是只读模板（代码+依赖+环境），容器是镜像的运行实例（可读写层）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Docker 的三大核心是什么？&lt;/strong&gt;
镜像（Image）、容器（Container）、仓库（Repository）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Docker 工作原理是什么？&lt;/strong&gt;
Docker 使用客户端-服务器架构。Docker 客户端与 Docker 守护进程通信，后者负责构建、运行和分发 Docker 容器的繁重工作。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Docker 组成部分？&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;docker client / CLI，客户端/命令行工具，为用户提供一系列可执行命令，用户用这些命令实现跟 docker daemon 交互；&lt;/li&gt;
&lt;li&gt;docker daemon，守护进程，在宿主主机后台运行，等待接收来自客户端的请求消息；&lt;/li&gt;
&lt;li&gt;docker build，用于构建镜像，使用 &lt;strong&gt;BuildKit&lt;/strong&gt; 作为构建器；&lt;/li&gt;
&lt;li&gt;docker container，容器，一个系统级别的服务，拥有自己的 ip 和系统目录结构。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Docker 容器与虚拟机的本质区别？&lt;/strong&gt;
虚拟机通过 Hypervisor 虚拟化硬件，每个 VM 运行独立 Guest OS（GB 级、分钟级启动）；Docker 共享宿主机内核，进程级隔离（MB 级、秒级启动）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;容器是一种轻量级虚拟机吗？&lt;/strong&gt;
不是。容器本质就是&lt;strong&gt;宿主机上被 namespace 隔离、被 cgroup 限流的普通进程&lt;/strong&gt;，与宿主共享同一个内核，所以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优势是启动快、开销小、密度高；&lt;/li&gt;
&lt;li&gt;代价是隔离性弱于虚拟机，内核漏洞会影响所有容器，且无法运行不同内核版本（如 Linux 上跑 Windows 容器）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Dockerfile / 镜像构建&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Dockerfile 中常用指令？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FROM（基础镜像）&lt;/li&gt;
&lt;li&gt;COPY/ADD（复制文件）&lt;/li&gt;
&lt;li&gt;RUN（构建时执行）&lt;/li&gt;
&lt;li&gt;CMD（默认命令）&lt;/li&gt;
&lt;li&gt;ENTRYPOINT（入口点）&lt;/li&gt;
&lt;li&gt;EXPOSE（声明端口，仅文档作用）&lt;/li&gt;
&lt;li&gt;WORKDIR（工作目录）&lt;/li&gt;
&lt;li&gt;ENV（环境变量）&lt;/li&gt;
&lt;li&gt;ARG（构建参数，构建后可丢弃）&lt;/li&gt;
&lt;li&gt;USER（运行用户）&lt;/li&gt;
&lt;li&gt;VOLUME（声明匿名卷）&lt;/li&gt;
&lt;li&gt;LABEL（元数据）&lt;/li&gt;
&lt;li&gt;HEALTHCHECK（健康检查）&lt;/li&gt;
&lt;li&gt;ONBUILD（被继承时触发）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;CMD 和 ENTRYPOINT 的区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CMD 可被 &lt;code&gt;docker run&lt;/code&gt; 命令覆盖；&lt;/li&gt;
&lt;li&gt;ENTRYPOINT 不可覆盖，适合固定执行程序。&lt;/li&gt;
&lt;li&gt;两者可组合使用：ENTRYPOINT 定可执行文件，CMD 提供默认参数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;ADD 和 COPY 的区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;COPY 只复制本地文件；&lt;/li&gt;
&lt;li&gt;ADD 支持自动解压 tar 和远程 URL 下载。&lt;/li&gt;
&lt;li&gt;官方推荐用 COPY（行为更可预期）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;RUN、CMD、ENTRYPOINT 的区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RUN 在&lt;strong&gt;构建时&lt;/strong&gt;执行并把结果固化进镜像层；&lt;/li&gt;
&lt;li&gt;CMD/ENTRYPOINT 在&lt;strong&gt;容器启动时&lt;/strong&gt;执行，写进镜像元数据，只有最后一条生效。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;RUN 命令 shell 形式和 exec 形式的区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RUN apt-get update&lt;/code&gt;（shell）等价于 &lt;code&gt;/bin/sh -c &quot;...&quot;&lt;/code&gt;，能使用变量和管道，但会多一层 shell 进程；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RUN [&quot;apt-get&quot;,&quot;update&quot;]&lt;/code&gt;（exec）直接执行，&lt;strong&gt;PID 1 就是目标进程&lt;/strong&gt;，能正确接收信号。&lt;/li&gt;
&lt;li&gt;CMD/ENTRYPOINT &lt;strong&gt;推荐用 exec 形式&lt;/strong&gt;，否则 &lt;code&gt;docker stop&lt;/code&gt; 的 SIGTERM 会被 sh 吞掉，导致容器等 10 秒后被杀（退出码 137）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;ARG 和 ENV 的区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ARG 只在构建期有效，容器运行时拿不到（可用 &lt;code&gt;--build-arg&lt;/code&gt; 传入，不应放敏感信息，&lt;code&gt;docker history&lt;/code&gt; 能看到）；&lt;/li&gt;
&lt;li&gt;ENV 会写入镜像元数据，构建期和运行期都可见。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;如何减小 Docker 镜像体积 / 加速镜像构建？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;.dockerignore 排除非必要文件（&lt;code&gt;.git&lt;/code&gt;、&lt;code&gt;node_modules&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;使用轻量级基础镜像（如 alpine/slim、distroless）；&lt;/li&gt;
&lt;li&gt;编译型语言采用多阶段构建；&lt;/li&gt;
&lt;li&gt;合并 RUN 命令减少层数；&lt;/li&gt;
&lt;li&gt;清理 apt/pip/npm 缓存（且必须与安装写在同一层，否则删除只是标记，体积不减）；&lt;/li&gt;
&lt;li&gt;把变化频率低的指令放前面，充分利用层缓存；&lt;/li&gt;
&lt;li&gt;BuildKit 的 &lt;code&gt;--mount=type=cache&lt;/code&gt; 缓存包管理器目录。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;多阶段构建的好处？&lt;/strong&gt;
最终镜像只保留运行时所需文件，不包含编译工具和中间产物，大幅减小镜像体积，同时降低攻击面（工具链不进生产镜像）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;镜像分层存储的好处？&lt;/strong&gt;
共享和缓存——多个镜像共享同一基础层只存一份；构建时缓存不变层，加快构建速度。写时容器只在其上叠加一个可写层（Copy-on-Write），多个容器可共享同一个只读镜像层。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;镜像构建缓存机制？&lt;/strong&gt;
Docker 逐条指令比对缓存，某条指令的&lt;strong&gt;命令文本、父层、以及 COPY/ADD 的文件内容校验和&lt;/strong&gt;任一变化，该层及其后续所有层缓存全部失效，需要重新构建。所以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先把 &lt;code&gt;package.json&lt;/code&gt; 复制进去装依赖，再复制源码，改动代码时不会重装依赖；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--no-cache&lt;/code&gt; 强制不用缓存，&lt;code&gt;--cache-from&lt;/code&gt; 复用 CI 中拉取的镜像缓存。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;HEALTHCHECK 的作用？&lt;/strong&gt;
在容器内定时执行命令检查应用是否健康（&lt;code&gt;docker ps&lt;/code&gt; 显示 healthy/unhealthy），仅状态标记，&lt;strong&gt;Docker 本身不会自动重启 unhealthy 容器&lt;/strong&gt;（这正是 K8s 探针要解决的问题）。&lt;/p&gt;
&lt;h2&gt;网络与存储&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;如何让容器随 Docker 服务自动重启？&lt;/strong&gt;
&lt;code&gt;--restart=always&lt;/code&gt; 或 &lt;code&gt;--restart=unless-stopped&lt;/code&gt;，还有 &lt;code&gt;on-failure[:max-retries]&lt;/code&gt;。注意 &lt;code&gt;docker stop&lt;/code&gt; 手动停止的容器在 always 下仍会随 daemon 启动。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Docker 数据持久化方式？&lt;/strong&gt;
Volume（&lt;code&gt;docker volume create&lt;/code&gt;）、Bind Mount（挂载宿主机目录）、tmpfs（内存中）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Volume 和 Bind Mount 的区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Volume：由 Docker 管理，存放在 &lt;code&gt;/var/lib/docker/volumes/&lt;/code&gt;，跨平台、可备份/迁移、可用 volume driver 接 NFS；适合生产数据。&lt;/li&gt;
&lt;li&gt;Bind Mount：直接映射宿主机任意路径，路径依赖宿主机结构，权限与 SELinux 容易出问题；适合开发时挂代码、挂配置文件。&lt;/li&gt;
&lt;li&gt;两者用 &lt;code&gt;docker inspect&lt;/code&gt; 的 Mounts 字段区分（Type 为 volume 或 bind）。&lt;/li&gt;
&lt;li&gt;容器内数据不持久化的场景：不挂载时数据留在容器可写层，&lt;strong&gt;容器删除即丢失&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;容器网络隔离方式？&lt;/strong&gt;
存在以下网络模式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bridge 模式：默认模式，容器通过虚拟网桥 docker0 通信，拥有独立的网络命名空间。&lt;/li&gt;
&lt;li&gt;Host 模式：容器与宿主机共享网络命名空间，直接使用宿主机的 IP 和端口，性能较高但缺乏隔离。&lt;/li&gt;
&lt;li&gt;None 模式：容器没有网络配置，适用于无需网络的场景。&lt;/li&gt;
&lt;li&gt;Container 模式：多个容器共享一个网络命名空间，适合需要紧密协作的容器。&lt;/li&gt;
&lt;li&gt;Overlay / Macvlan：跨主机通信（Swarm）或让容器直接获得物理网段 IP。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;容器之间如何互相通信？&lt;/strong&gt;
默认 bridge 网络下只能用 IP 互访，且&lt;strong&gt;没有 DNS 解析&lt;/strong&gt;。推荐自定义 bridge 网络：&lt;code&gt;docker network create app-net&lt;/code&gt;，加入同一网络的容器可直接用&lt;strong&gt;容器名 / &lt;code&gt;--network-alias&lt;/code&gt;&lt;/strong&gt; 作为主机名互访（Docker 内置 DNS 127.0.0.11）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;端口映射的原理？&lt;/strong&gt;
&lt;code&gt;-p 8080:80&lt;/code&gt; 由 docker-proxy 与 iptables 的 DNAT 规则实现，把宿主机 8080 的流量转发到容器 IP 的 80 端口。&lt;code&gt;-P&lt;/code&gt; 随机映射所有 EXPOSE 端口，&lt;code&gt;-p 127.0.0.1:8080:80&lt;/code&gt; 只监听本机。&lt;/p&gt;
&lt;h2&gt;容器&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;如何进入容器？&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker exec -it &amp;lt;容器&amp;gt; /bin/sh        # 推荐：新开一个进程进入
docker attach &amp;lt;容器&amp;gt;                  # 进入主进程的标准输入输出（Ctrl+C 会杀掉容器）
docker exec -it -u root &amp;lt;容器&amp;gt; bash   # 指定用户
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;exec&lt;/code&gt; 会在容器内新起一个进程（需镜像里有 shell，distroless 镜像没有）；调试特权容器还可用 &lt;code&gt;nsenter -t &amp;lt;PID&amp;gt; -a&lt;/code&gt; 直接进入其命名空间（宿主机上无需容器内有工具）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;exec 和 attach 的区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;exec 启动一个新的进程，退出不影响主进程；&lt;/li&gt;
&lt;li&gt;attach 接管容器 PID 1 的标准流，退出（Ctrl+C）可能终止容器，且多个 attach 会共享输出。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;如何查看容器日志？&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker logs -f --tail 100 &amp;lt;容器&amp;gt;      # 实时跟踪最近 100 行（-f 实时跟踪）
docker logs --since 10m &amp;lt;容器&amp;gt;        # 最近 10 分钟
docker logs --timestamps &amp;lt;容器&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;日志来自容器主进程的 stdout/stderr，由 json-file 日志驱动落盘到 &lt;code&gt;/var/lib/docker/containers/&amp;lt;id&amp;gt;/*-json.log&lt;/code&gt;。&lt;strong&gt;默认无大小限制&lt;/strong&gt;，容易把磁盘写满，需配置 &lt;code&gt;--log-opt max-size=10m --log-opt max-file=3&lt;/code&gt;（可在 &lt;code&gt;/etc/docker/daemon.json&lt;/code&gt; 全局设置）。应用应把日志打到前台而不是文件里，这是容器的最佳实践。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何查看容器信息与资源占用？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker ps -a&lt;/code&gt;（状态与端口）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker inspect&lt;/code&gt;（完整 JSON，含 IP、挂载、退出码）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker stats&lt;/code&gt;（实时 CPU/内存/网络）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker top&lt;/code&gt;（容器内进程）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker diff&lt;/code&gt;（可写层的文件变更）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;容器退出码代表什么？&lt;/strong&gt;
0 正常退出；1 应用错误；126/127 命令不可执行/不存在；137 = 128+9 被 SIGKILL（OOM 或 &lt;code&gt;docker kill&lt;/code&gt;）；143 = 128+15 被 SIGTERM（&lt;code&gt;docker stop&lt;/code&gt; 优雅停止）。&lt;/p&gt;
&lt;h2&gt;镜像仓库&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;如何推送镜像到仓库？&lt;/strong&gt;
&lt;code&gt;docker login&lt;/code&gt; → &lt;code&gt;docker tag app:1.0 registry.example.com/ns/app:1.0&lt;/code&gt;（必须带仓库地址前缀）→ &lt;code&gt;docker push&lt;/code&gt;。拉取时同理，私有仓库需先登录或配置凭证。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;镜像的命名规则？&lt;/strong&gt;
&lt;code&gt;[registry/][namespace/]repository[:tag][@digest]&lt;/code&gt;，tag 默认 &lt;code&gt;latest&lt;/code&gt;。生产&lt;strong&gt;禁止依赖 latest&lt;/strong&gt;，因为它是可变的，不同节点可能拉到不同版本；用不可变 tag（版本号或 commit id）或 digest 保证一致性。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何减小镜像拉取时间？&lt;/strong&gt;
使用更小的基础镜像、减少层数、把 registry 部署在内网、开启镜像加速器、使用 P2P 分发（Dragonfly）或按需拉取（懒加载）。&lt;/p&gt;
&lt;h2&gt;Docker Compose&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Docker Compose 是什么？&lt;/strong&gt;
单机多容器编排工具，用一个 &lt;code&gt;docker-compose.yml&lt;/code&gt; 声明多个服务、网络、卷和依赖关系，一条 &lt;code&gt;docker compose up -d&lt;/code&gt; 全部拉起。适合本地开发与小型部署；跨主机的生产编排应使用 Kubernetes/Swarm。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compose 常用命令？&lt;/strong&gt;
&lt;code&gt;up -d&lt;/code&gt;（后台启动）、&lt;code&gt;down&lt;/code&gt;（停止并删除）、&lt;code&gt;ps&lt;/code&gt;、&lt;code&gt;logs -f&lt;/code&gt;、&lt;code&gt;exec&lt;/code&gt;、&lt;code&gt;build&lt;/code&gt;、&lt;code&gt;restart&lt;/code&gt;、&lt;code&gt;config&lt;/code&gt;（校验并渲染最终配置）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compose 中 &lt;code&gt;depends_on&lt;/code&gt; 能保证依赖服务就绪吗？&lt;/strong&gt;
不能，它只保证&lt;strong&gt;启动顺序&lt;/strong&gt;。要等待服务真正可用需配合 healthcheck + &lt;code&gt;condition: service_healthy&lt;/code&gt;，或在应用内做重试。&lt;/p&gt;
&lt;h2&gt;常用命令&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# 镜像
docker build -t app:1.0 .            # 构建
docker images / docker image prune   # 列出 / 清理悬空镜像
docker tag / push / pull             # 打标签与仓库交互

# 容器
docker run -d --name web -p 8080:80 -v data:/usr/share/nginx/html nginx
docker ps -a / start / stop / restart / rm
docker cp file.txt web:/tmp/         # 与容器互拷文件
docker commit web web:snapshot       # 把容器存成镜像（不推荐，应用 Dockerfile）

# 清理
docker system df                     # 查看磁盘占用
docker system prune -a --volumes     # 清理未使用镜像/网络/卷
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;docker run 常用参数？&lt;/strong&gt;
&lt;code&gt;-d&lt;/code&gt; 后台运行、&lt;code&gt;-it&lt;/code&gt; 交互式 TTY、&lt;code&gt;--name&lt;/code&gt; 命名、&lt;code&gt;-p&lt;/code&gt; 端口映射、&lt;code&gt;-v&lt;/code&gt; 挂载、&lt;code&gt;-e&lt;/code&gt; 环境变量、&lt;code&gt;--network&lt;/code&gt; 网络、&lt;code&gt;--restart&lt;/code&gt; 重启策略、&lt;code&gt;--rm&lt;/code&gt; 退出即删除、&lt;code&gt;--memory/--cpus&lt;/code&gt; 资源限制、&lt;code&gt;--privileged&lt;/code&gt; 特权、&lt;code&gt;-w&lt;/code&gt; 工作目录、&lt;code&gt;--entrypoint&lt;/code&gt; 覆盖入口。&lt;/p&gt;
&lt;h2&gt;底层原理&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Docker 使用的底层技术？&lt;/strong&gt;
Namespaces（隔离：PID、NET、IPC、UTS、MNT、USER）、Cgroups（资源限制：CPU、内存）、UnionFS（分层存储）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;各个 Namespace 隔离了什么？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PID：进程号，容器内 PID 1 是应用进程；&lt;/li&gt;
&lt;li&gt;NET：网卡、IP、端口、路由表；&lt;/li&gt;
&lt;li&gt;IPC：信号量、共享内存；&lt;/li&gt;
&lt;li&gt;UTS：主机名与域名；&lt;/li&gt;
&lt;li&gt;MNT：挂载点与文件系统视图；&lt;/li&gt;
&lt;li&gt;USER：用户与 UID 映射；&lt;/li&gt;
&lt;li&gt;Cgroup：cgroup 视图（较新）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cgroups 的作用？&lt;/strong&gt;
限制、统计和隔离进程组的资源使用（CPU、内存、IO、PID 数量）。CPU 用 quota/period（&lt;code&gt;--cpus&lt;/code&gt;）或 shares（&lt;code&gt;--cpu-shares&lt;/code&gt; 相对权重）；内存超限触发 OOM Killer，容器退出码 137。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Docker 的分层架构（与 containerd / runc / OCI 的关系）？&lt;/strong&gt;
&lt;code&gt;dockerd&lt;/code&gt;（接收 CLI 请求、构建、镜像管理）→ &lt;code&gt;containerd&lt;/code&gt;（容器生命周期管理，K8s 也直接用它）→ &lt;code&gt;runc&lt;/code&gt;（真正调用 Linux namespace/cgroup 创建进程）。镜像格式遵循 OCI Image Spec，运行时遵循 OCI Runtime Spec，因此 Docker 构建的镜像可以被 containerd、CRI-O、Podman 通用。&lt;strong&gt;Docker 1.24 之后 K8s 抛弃的是 dockershim 适配层，不是容器本身。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UnionFS 是如何工作的？&lt;/strong&gt;
采用&lt;strong&gt;写时复制（CoW）&lt;/strong&gt;：镜像由多个只读层叠加而成，容器启动时在最上面追加一个可写层；读文件时从上层往下找，修改文件时先把文件复制到可写层再改，因此&lt;strong&gt;多个容器共享一份只读镜像层&lt;/strong&gt;，启动快、占用小。Docker 默认存储驱动为 overlay2。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;容器的 1 号进程与信号处理？&lt;/strong&gt;
容器 PID 1 就是应用进程（exec 形式时），它需要负责回收僵尸进程、处理 SIGTERM 优雅退出。若应用不处理信号或使用 shell 形式启动，&lt;code&gt;Ctrl+C&lt;/code&gt;/&lt;code&gt;docker stop&lt;/code&gt; 会失效或超时后被 SIGKILL（10 秒 grace period 可用 &lt;code&gt;--stop-timeout&lt;/code&gt; 调整）。&lt;/p&gt;
&lt;h2&gt;安全与排错&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;容器为什么不安全？如何加固？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;共享内核：内核漏洞可逃逸；应保持内核与 Docker 版本更新。&lt;/li&gt;
&lt;li&gt;默认 root 运行：用 &lt;code&gt;USER&lt;/code&gt; 指定非 root、&lt;code&gt;--user&lt;/code&gt; 覆盖、开启 user namespace。&lt;/li&gt;
&lt;li&gt;权限：避免 &lt;code&gt;--privileged&lt;/code&gt;，按需 &lt;code&gt;--cap-drop=ALL --cap-add=NET_BIND_SERVICE&lt;/code&gt;，使用 &lt;code&gt;--security-opt no-new-privileges&lt;/code&gt;、只读根文件系统 &lt;code&gt;--read-only&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;敏感信息：不要把密钥写进镜像层（&lt;code&gt;docker history&lt;/code&gt; 可见），用环境变量、secret 文件或外部密钥管理。&lt;/li&gt;
&lt;li&gt;其他：AppArmor/SELinux 配置、限制资源防 DoS、镜像扫描（Trivy）与最小化基础镜像。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;容器启动失败怎么排查？&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;docker ps -a&lt;/code&gt; 看状态与退出码，&lt;code&gt;docker logs&lt;/code&gt; 看应用日志；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker inspect&lt;/code&gt; 看 State.Error、OOMKilled、挂载与端口；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker run -it --entrypoint /bin/sh image&lt;/code&gt; 进镜像手工验证命令与文件是否存在；&lt;/li&gt;
&lt;li&gt;端口冲突（&lt;code&gt;netstat -tulnp&lt;/code&gt;）、磁盘满（&lt;code&gt;docker system df&lt;/code&gt;）、权限问题（挂载目录 SELinux 需 &lt;code&gt;:z&lt;/code&gt;）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;常见问题：磁盘被容器占满怎么办？&lt;/strong&gt;
先 &lt;code&gt;docker system df -v&lt;/code&gt; 定位，再清理：&lt;code&gt;docker container prune&lt;/code&gt;、&lt;code&gt;docker image prune -a&lt;/code&gt;、&lt;code&gt;docker volume prune&lt;/code&gt;、&lt;code&gt;docker builder prune&lt;/code&gt;；同时配置日志 max-size、给容器日志与数据盘单独分区。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么容器里不能用 systemd / systemctl？&lt;/strong&gt;
容器只运行一个前台进程，没有 init 系统；应把每个服务拆成独立容器，或用 supervisor 管理多进程（不推荐），确需时用 &lt;code&gt;--privileged&lt;/code&gt; + systemd 镜像（脏且不安全）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Docker 与 Kubernetes 的关系？&lt;/strong&gt;
Docker 是单机容器引擎，K8s 是集群编排系统；K8s 早期通过 dockershim 调用 Docker，1.24 起改为直接用 CRI 对接 containerd/CRI-O，镜像标准（OCI）保持通用。&lt;/p&gt;
</content:encoded></item><item><title>Shell 三剑客八股</title><link>https://blog-l7wd3.pages.dev/posts/interview/shell-three/</link><guid isPermaLink="true">https://blog-l7wd3.pages.dev/posts/interview/shell-three/</guid><description>详细版 grep/sed/awk 八股</description><pubDate>Wed, 12 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;一、三剑客总览与选型&lt;/h2&gt;
&lt;p&gt;面试官常问“三者的区别是什么”或“什么场景用谁”。记住一个口诀：&lt;strong&gt;grep 负责“查”，sed 负责“改”，awk 负责“算”和“格式化”&lt;/strong&gt;。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;工具&lt;/th&gt;
&lt;th&gt;核心职责&lt;/th&gt;
&lt;th&gt;一句话选型&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;grep&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;文本&lt;strong&gt;过滤&lt;/strong&gt;与&lt;strong&gt;搜索&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;仅需&lt;strong&gt;查找&lt;/strong&gt;、&lt;strong&gt;计数&lt;/strong&gt;或&lt;strong&gt;筛选&lt;/strong&gt;行，就用 grep。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;sed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;文本&lt;strong&gt;编辑&lt;/strong&gt;与&lt;strong&gt;替换&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;需要&lt;strong&gt;替换&lt;/strong&gt;、&lt;strong&gt;删除&lt;/strong&gt;、&lt;strong&gt;插入&lt;/strong&gt;文本行，就用 sed。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;awk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;文本&lt;strong&gt;格式化&lt;/strong&gt;与&lt;strong&gt;分析&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;需要&lt;strong&gt;按列处理&lt;/strong&gt;、&lt;strong&gt;统计计算&lt;/strong&gt;、&lt;strong&gt;生成报告&lt;/strong&gt;，就用 awk。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;二、grep（文本搜索器）&lt;/h2&gt;
&lt;h3&gt;1. 核心功能&lt;/h3&gt;
&lt;p&gt;在文件或输入流中，根据&lt;strong&gt;正则表达式&lt;/strong&gt;搜索文本，并打印匹配的行。&lt;/p&gt;
&lt;h3&gt;2. 高频选项&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;选项&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-i&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;忽略大小写&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-v&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;反向匹配&lt;/strong&gt;，显示不包含模式的行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-n&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;显示匹配行的&lt;strong&gt;行号&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;只输出&lt;strong&gt;匹配行的总数&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-l&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;只输出&lt;strong&gt;包含匹配内容的文件名&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-r&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;递归搜索&lt;/strong&gt;目录下的所有文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-E&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;使用&lt;strong&gt;扩展正则表达式&lt;/strong&gt;（支持&lt;code&gt;+&lt;/code&gt;、&lt;code&gt;?&lt;/code&gt;、`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-o&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;只输出&lt;strong&gt;匹配到的部分&lt;/strong&gt;，而不是整行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-A n&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;显示匹配行及其&lt;strong&gt;后 n 行&lt;/strong&gt;（After）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-B n&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;显示匹配行及其&lt;strong&gt;前 n 行&lt;/strong&gt;（Before）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-C n&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;显示匹配行及其&lt;strong&gt;前后各 n 行&lt;/strong&gt;（Context）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--include&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;仅在&lt;strong&gt;指定类型&lt;/strong&gt;的文件中搜索&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-m n&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配 &lt;strong&gt;n 次后停止&lt;/strong&gt;读取&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;3. 典型面试题&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;题目&lt;/th&gt;
&lt;th&gt;命令示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;显示匹配行及其后2行&lt;/td&gt;
&lt;td&gt;&lt;code&gt;grep -A 2 &quot;pattern&quot; file.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;在&lt;code&gt;file.txt&lt;/code&gt;中查找包含&quot;error&quot;或&quot;fail&quot;的行并显示行号&lt;/td&gt;
&lt;td&gt;grep -n -E &quot;error|fail&quot; file.txt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;统计&lt;code&gt;file.txt&lt;/code&gt;中&quot;error&quot;出现的总次数&lt;/td&gt;
&lt;td&gt;grep -o &quot;error&quot; file.txt | wc -l&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;过滤掉文件中的空行和注释行（以&lt;code&gt;#&lt;/code&gt;开头）&lt;/td&gt;
&lt;td&gt;grep -vE &apos;^#|^$&apos; file.txt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;递归查找&lt;code&gt;/etc/&lt;/code&gt;下所有&lt;code&gt;.conf&lt;/code&gt;文件中包含&quot;port&quot;的行&lt;/td&gt;
&lt;td&gt;&lt;code&gt;grep -r --include=&quot;*.conf&quot; &quot;port&quot; /etc/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;找出当前目录下包含&quot;127.0.0.1&quot;的文件&lt;/td&gt;
&lt;td&gt;&lt;code&gt;grep &quot;127.0.0.1&quot; \&lt;/code&gt;find -type f``&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;匹配以数字开头的行&lt;/td&gt;
&lt;td&gt;&lt;code&gt;grep &quot;^[0-9]&quot; file.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;匹配IPv4地址&lt;/td&gt;
&lt;td&gt;&lt;code&gt;grep -E &quot;([0-9]{1,3}\.){3}[0-9]{1,3}&quot; file.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;4. 进阶考点：正则表达式引擎&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;grep&lt;/code&gt;默认使用&lt;strong&gt;NFA（非确定性有限自动机）引擎&lt;/strong&gt;。需注意**灾难性回溯（Catastrophic Backtracking）**问题，例如模式&lt;code&gt;(a+)+b&lt;/code&gt;匹配一长串&lt;code&gt;a&lt;/code&gt;会消耗极长时间。生产环境中，对超大文件使用&lt;code&gt;-m&lt;/code&gt;参数限制匹配次数是常见的优化手段。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;三、sed（流编辑器）&lt;/h2&gt;
&lt;h3&gt;1. 核心功能&lt;/h3&gt;
&lt;p&gt;非交互式地&lt;strong&gt;编辑文本流&lt;/strong&gt;，主要进行“取行、删除、替换、插入”等操作。&lt;/p&gt;
&lt;h3&gt;2. 高频选项与命令&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;选项/命令&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-n&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;安静模式&lt;/strong&gt;，仅显示被&lt;code&gt;p&lt;/code&gt;命令处理的行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-i&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;直接修改&lt;/strong&gt;原文件（非常危险，生产环境慎用）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-E&lt;/code&gt; / &lt;code&gt;-r&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;使用&lt;strong&gt;扩展正则表达式&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;追加&lt;/strong&gt;，在指定行后添加新行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;删除&lt;/strong&gt;指定行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;打印&lt;/strong&gt;指定行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;s/old/new/g&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;替换&lt;/strong&gt;，&lt;code&gt;g&lt;/code&gt;可选，表示全局替换&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/pattern/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;模式匹配&lt;/strong&gt;，可包含正则，&lt;code&gt;/&lt;/code&gt; 需要转义 &lt;code&gt;\/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a,b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;多行&lt;/strong&gt;，从第 a 行到第 b 行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/pattern1/,/pattern2/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;按范围匹配&lt;/strong&gt;，表示从匹配 pattern1 的行到匹配 pattern2 的行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/pattern1/,//&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;按范围匹配&lt;/strong&gt;，表示从匹配 pattern1 的行到下次匹配相同的行&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;3. 典型面试题&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;题目&lt;/th&gt;
&lt;th&gt;命令示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;将文件中所有&lt;code&gt;apple&lt;/code&gt;替换为&lt;code&gt;orange&lt;/code&gt;并直接修改文件&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sed -i &apos;s/apple/orange/g&apos; file.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;删除文件的第5到第10行&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sed &apos;5,10d&apos; file.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;显示文件的第3到第10行&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sed -n &apos;3,10p&apos; file.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;删除文件中的所有空行&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sed &apos;/^$/d&apos; file.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;删除所有以&lt;code&gt;#&lt;/code&gt;或&lt;code&gt;//&lt;/code&gt;开头的注释行&lt;/td&gt;
&lt;td&gt;sed &apos;/^#|^///d&apos; file.txt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;在文件末尾追加一行&quot;END OF FILE&quot;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sed &apos;$a END OF FILE&apos; file.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;将&lt;code&gt;/etc/passwd&lt;/code&gt;中所有&lt;code&gt;nologin&lt;/code&gt;替换为&lt;code&gt;bash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sed -i &apos;s/nologin/bash/g&apos; /etc/passwd&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;4. 进阶考点：定址与分组&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定址（Addressing）&lt;/strong&gt;：可以指定操作的行范围，如&lt;code&gt;&apos;10,20d&apos;&lt;/code&gt;删除10到20行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分组（Grouping）&lt;/strong&gt;：替换时使用&lt;code&gt;(...)&lt;/code&gt;分组，并用&lt;code&gt;\1&lt;/code&gt;、&lt;code&gt;\2&lt;/code&gt;引用。例如&lt;code&gt;sed -r &apos;s#(^[^:]+):.*#\1#g&apos;&lt;/code&gt;可以提取&lt;code&gt;/etc/passwd&lt;/code&gt;中的用户名。（实际取列推荐下面的&lt;code&gt;cut -d: -f1,2,...&lt;/code&gt;，-d 指定分隔符，-f 跟提取第几列，提取多列用逗号分隔）&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;正则&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;s#...#...#g&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;替换命令，用 &lt;code&gt;#&lt;/code&gt; 作分隔符（避免和内容里的 &lt;code&gt;/&lt;/code&gt; 冲突）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(^[^:]+)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;第 1 个捕获组：行首开始，一个或多个&lt;strong&gt;非冒号&lt;/strong&gt;字符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配一个冒号&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配冒号后面的所有内容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;替换为第 1 个捕获组的内容&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;四、awk（文本分析器）&lt;/h2&gt;
&lt;h3&gt;1. 核心功能&lt;/h3&gt;
&lt;p&gt;一种强大的&lt;strong&gt;文本分析&lt;/strong&gt;和&lt;strong&gt;格式化输出&lt;/strong&gt;编程语言，以&lt;strong&gt;行&lt;/strong&gt;为单位，默认以&lt;strong&gt;空白符&lt;/strong&gt;为分隔符将行切分为&lt;strong&gt;字段&lt;/strong&gt;。&lt;/p&gt;
&lt;h3&gt;2. 高频内置变量&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;变量&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;整行内容&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$1, $2, ...&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;第1、2...个字段&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NF&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;当前行的字段总数&lt;/strong&gt;（Number of Fields）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NR&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;当前行的行号&lt;/strong&gt;（Number of Records）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;输入字段分隔符&lt;/strong&gt;，默认为空白符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OFS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;输出字段分隔符&lt;/strong&gt;，默认为空白符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;输入记录分隔符&lt;/strong&gt;，默认为换行符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ORS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;输出记录分隔符&lt;/strong&gt;，默认为换行符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FILENAME&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;当前正在处理的&lt;strong&gt;文件名&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;3. 高频选项与模式&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;选项/模式&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-F&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;指定&lt;strong&gt;输入字段分隔符&lt;/strong&gt;，如&lt;code&gt;-F:&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BEGIN{...}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;在&lt;strong&gt;处理第一行文本之前&lt;/strong&gt;执行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;END{...}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;在&lt;strong&gt;处理完所有文本之后&lt;/strong&gt;执行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/pattern/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;匹配&lt;/strong&gt;正则表达式的行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;! /pattern/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;不匹配&lt;/strong&gt;正则表达式的行&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;4. 典型面试题&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;题目&lt;/th&gt;
&lt;th&gt;命令示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;取出&lt;code&gt;/etc/passwd&lt;/code&gt;的第一列（用户名）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;awk -F: &apos;{print $1}&apos; /etc/passwd&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;打印文件&lt;code&gt;file.txt&lt;/code&gt;的&lt;strong&gt;行号&lt;/strong&gt;和&lt;strong&gt;整行内容&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;awk &apos;{print NR, $0}&apos; file.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;打印每行的&lt;strong&gt;字段总数&lt;/strong&gt;（&lt;code&gt;NF&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;awk &apos;{print NF}&apos; file.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;统计&lt;code&gt;/etc/passwd&lt;/code&gt;中&lt;strong&gt;用户总数&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;awk -F: &apos;END{print NR}&apos; /etc/passwd&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;过滤出&lt;strong&gt;奇数行&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;awk &apos;NR%2==1&apos; file.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;提取网卡IP地址（多种实现）&lt;/td&gt;
&lt;td&gt;ip a | awk &apos;/([0-9]{1,3}.){3}[0-9]{1,3}/{print $2}&apos;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;统计Nginx日志中&lt;strong&gt;独立IP数&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;awk &apos;{dic[$1]++}END{for(i in dic) print i}&apos; access.log&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;求第二列和&lt;/td&gt;
&lt;td&gt;&lt;code&gt;awk &apos;{sum+=$2} END{print sum}&apos; 1.log&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;查空行&lt;/td&gt;
&lt;td&gt;&lt;code&gt;awk &apos;/^$/{print NR}&apos; file1.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;5. 进阶考点：BEGIN与END&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;awk&lt;/code&gt;脚本可以包含&lt;code&gt;BEGIN&lt;/code&gt;和&lt;code&gt;END&lt;/code&gt;代码块，分别用于&lt;strong&gt;初始化和汇总&lt;/strong&gt;。例如，在&lt;code&gt;BEGIN&lt;/code&gt;中设置分隔符&lt;code&gt;FS=&quot;:&quot;&lt;/code&gt;，在&lt;code&gt;END&lt;/code&gt;中打印统计总数，是极其常见的用法。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;五、综合对比与常见组合&lt;/h2&gt;
&lt;h3&gt;1. 三剑客对比总结&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;工具&lt;/th&gt;
&lt;th&gt;核心优势&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;grep&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;速度最快&lt;/strong&gt;，简单查找&lt;/td&gt;
&lt;td&gt;日志过滤、内容搜索&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;sed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;行编辑&lt;/strong&gt;能力最强&lt;/td&gt;
&lt;td&gt;批量替换、文本格式化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;awk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;列处理&lt;/strong&gt;和&lt;strong&gt;统计&lt;/strong&gt;能力最强&lt;/td&gt;
&lt;td&gt;日志分析、数据报告&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;2. 经典组合用法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;grep&lt;/code&gt; + &lt;code&gt;awk&lt;/code&gt;&lt;/strong&gt;：先用&lt;code&gt;grep&lt;/code&gt;粗筛，再用&lt;code&gt;awk&lt;/code&gt;精处理。
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;grep &quot;ERROR&quot; app.log | awk &apos;{print $1, $NF}&apos;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;统计&lt;code&gt;php.ini&lt;/code&gt;中&lt;strong&gt;每个单词出现次数&lt;/strong&gt;：&lt;code&gt;grep -oE &apos;[a-zA-Z]+&apos; php.ini | awk &apos;{dic[$0]++}END{for(i in dic) print i, dic[i]}&apos;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;find&lt;/code&gt; + &lt;code&gt;xargs&lt;/code&gt; + &lt;code&gt;grep&lt;/code&gt;&lt;/strong&gt;：在大量文件中搜索内容。例如：&lt;code&gt;find . -name &quot;*.log&quot; | xargs grep &quot;timeout&quot;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;grep&lt;/code&gt; + &lt;code&gt;sed&lt;/code&gt;&lt;/strong&gt;：查找并替换。例如：&lt;code&gt;grep -l &quot;old&quot; *.txt | xargs sed -i &apos;s/old/new/g&apos;&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;六、其他文本处理命令&lt;/h2&gt;
&lt;h3&gt;1. 命令&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;cut&lt;/code&gt;&lt;/strong&gt;：按列切分，&lt;code&gt;cut -d: -f1 /etc/passwd&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;sort&lt;/code&gt;&lt;/strong&gt;：排序，&lt;code&gt;-n&lt;/code&gt;（数字）、&lt;code&gt;-r&lt;/code&gt;（逆序）、&lt;code&gt;-k&lt;/code&gt;（指定列）、&lt;code&gt;-t&lt;/code&gt;（指定分隔符）、&lt;code&gt;-u&lt;/code&gt;（去重，等价于&lt;code&gt;sort &apos;filename&apos; | uniq&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;uniq&lt;/code&gt;&lt;/strong&gt;：去重（&lt;strong&gt;必须配合 &lt;code&gt;sort&lt;/code&gt; 使用，仅去除相邻重复行&lt;/strong&gt;）。常用 &lt;code&gt;sort | uniq -c&lt;/code&gt; 统计次数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;tr&lt;/code&gt;&lt;/strong&gt;：字符替换/删除，&lt;code&gt;tr &apos;A-Z&apos; &apos;a-z&apos;&lt;/code&gt;（大小写转换）、&lt;code&gt;tr -d &apos;\r&apos;&lt;/code&gt;（删除回车）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;xargs&lt;/code&gt;&lt;/strong&gt;：将标准输入转为命令行参数。&lt;code&gt;find . -name &quot;*.log&quot; | xargs rm -f&lt;/code&gt;（解决参数过长问题）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 经典组合用法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;查找当前目录所有包含有字符”123”的文件名称：&lt;code&gt;grep -r &quot;123&quot; /root | cut -d: -f1 | sort -u&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;七、正则表达式规则&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;基础正则表达式（BRE）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;^ / $&lt;/strong&gt;：匹配行首、行尾&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;.&lt;/strong&gt;：匹配除换行符外的任意单字符&lt;/li&gt;
&lt;li&gt;*：匹配前一字符 0 次或多次&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[list] / [^list]&lt;/strong&gt;：匹配列表内或不在列表内的任意字符&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;{n}, {n,}, {n,m}&lt;/strong&gt;：匹配前一字符的固定或范围次数（需转义 &lt;code&gt;\{ \}&lt;/code&gt; ）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;扩展正则表达式（ERE）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;+&lt;/strong&gt;：匹配前一字符 1 次或多次&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;?&lt;/strong&gt;：匹配前一字符 0 次或 1 次&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;()&lt;/strong&gt;：分组，将括号内模式视为整体&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;|&lt;/strong&gt;：逻辑或，匹配任一模式&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;{n}, {n,}, {n,m}&lt;/strong&gt;：次数匹配（无需转义）&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Shell 八股</title><link>https://blog-l7wd3.pages.dev/posts/interview/shell/</link><guid isPermaLink="true">https://blog-l7wd3.pages.dev/posts/interview/shell/</guid><description>速记版 Shell 八股</description><pubDate>Mon, 10 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;基础语法&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Shell脚本第一行是什么？为什么重要？&lt;/strong&gt;
&lt;code&gt;#!/bin/bash&lt;/code&gt;（shebang），指定脚本解释器。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;变量赋值为什么报错&lt;code&gt;command not found&lt;/code&gt;？&lt;/strong&gt;
等号两边不能有空格——&lt;code&gt;name = &quot;Alice&quot;&lt;/code&gt;会被解析为命令，正确写法&lt;code&gt;name=&quot;Alice&quot;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何定义只读变量？&lt;/strong&gt;
&lt;code&gt;readonly var&lt;/code&gt; 或 &lt;code&gt;declare -r var&lt;/code&gt;，后续无法修改。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何撤销变量？&lt;/strong&gt;
&lt;code&gt;unset var&lt;/code&gt;（不能撤销只读变量）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;[ ]&lt;/code&gt;vs&lt;code&gt;[[ ]]&lt;/code&gt;vs&lt;code&gt;(())&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;语法&lt;/th&gt;
&lt;th&gt;类型&lt;/th&gt;
&lt;th&gt;支持逻辑运算符&lt;/th&gt;
&lt;th&gt;支持正则/通配符&lt;/th&gt;
&lt;th&gt;空变量安全性&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[ ]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;POSIX 通用&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-a&lt;/code&gt;（与）、&lt;code&gt;-o&lt;/code&gt;（或）&lt;/td&gt;
&lt;td&gt;不支持&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;变量必须加双引号&lt;/strong&gt;，否则报错&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[ ]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bash 特有&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;、||、&lt;code&gt;!&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;支持 &lt;code&gt;=~&lt;/code&gt;（正则）和 &lt;code&gt;==&lt;/code&gt;（通配符）&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;变量无需加引号&lt;/strong&gt;，自动处理空值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(( ))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bash 特有&lt;/td&gt;
&lt;td&gt;数学比较（&lt;code&gt;&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;&lt;/code&gt;、&lt;code&gt;&amp;gt;=&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;专用于数值计算&lt;/td&gt;
&lt;td&gt;专用于 &lt;code&gt;C&lt;/code&gt; 风格循环和数值判断&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;判断文件是否存在且为普通文件&lt;/strong&gt;
&lt;code&gt;[ -f &quot;$file&quot; ]&lt;/code&gt; 或 &lt;code&gt;[[ -f $file ]]&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;数值计算&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;$((...))&lt;/code&gt;&lt;/strong&gt;（最推荐，纯 Bash 内建，速度最快）：&lt;code&gt;sum=$((a + b))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;let&lt;/code&gt; 命令&lt;/strong&gt;：&lt;code&gt;let sum=a+b&lt;/code&gt;（无需 &lt;code&gt;$&lt;/code&gt; 前缀）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;expr&lt;/code&gt; 外部命令&lt;/strong&gt;（慢，过时）：&lt;code&gt;sum=$(expr $a + $b)&lt;/code&gt;（注意加号两侧必须有空格）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;浮点数运算&lt;/strong&gt;：必须借助 &lt;code&gt;bc&lt;/code&gt; 或 &lt;code&gt;awk&lt;/code&gt;，如 &lt;code&gt;echo &quot;scale=2; 5/3&quot; | bc&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;exit和return的区别？&lt;/strong&gt;
&lt;code&gt;exit N&lt;/code&gt;终止整个脚本；&lt;code&gt;return N&lt;/code&gt;从函数返回。0表示成功，非0表示失败。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;位置参数&lt;code&gt;$0&lt;/code&gt;、&lt;code&gt;$1&lt;/code&gt;、&lt;code&gt;$#&lt;/code&gt;、&lt;code&gt;$?&lt;/code&gt;、&lt;code&gt;$$&lt;/code&gt;、&lt;code&gt;$@&lt;/code&gt;的含义？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$0&lt;/code&gt;：脚本名，&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$1&lt;/code&gt;：第一个参数，&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$#&lt;/code&gt;：传递给脚本的参数个数，&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$?&lt;/code&gt;：上条命令退出码。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$$&lt;/code&gt;：当前Shell进程的 &lt;strong&gt;PID&lt;/strong&gt;（常用于生成临时唯一文件名，如 &lt;code&gt;/tmp/a_$$&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$!&lt;/code&gt;：后台&lt;strong&gt;最后一个进程&lt;/strong&gt;的 PID（配合 &lt;code&gt;wait $!&lt;/code&gt; 使用）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$@&lt;/code&gt;：所有参数（带引号保留空格），&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;什么是IFS？&lt;code&gt;&quot;$*&quot;&lt;/code&gt; 和 &lt;code&gt;&quot;$@&quot;&lt;/code&gt; 区别？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Internal Field Separator（内部字段分隔符），是 Shell 中的一个特殊环境变量，用来决定 &lt;strong&gt;Shell 在哪些字符处把一个字符串拆分成多个单词（字段）&lt;/strong&gt;。默认值是：空格 + 制表符 + 换行符&lt;/p&gt;
&lt;p&gt;假设这样调用：&lt;code&gt;./test.sh &quot;a b&quot; c d&lt;/code&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;写法&lt;/th&gt;
&lt;th&gt;是否保留每个参数的独立性&lt;/th&gt;
&lt;th&gt;是否受 &lt;code&gt;IFS&lt;/code&gt; 影响&lt;/th&gt;
&lt;th&gt;结果&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$@&lt;/code&gt; / &lt;code&gt;$*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌ 会重新分词&lt;/td&gt;
&lt;td&gt;✅ 受影响&lt;/td&gt;
&lt;td&gt;&quot;a&quot; &quot;b&quot; &quot;c&quot; &quot;d&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&quot;$@&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ 每个参数独立&lt;/td&gt;
&lt;td&gt;❌ 不受影响&lt;/td&gt;
&lt;td&gt;&quot;a b&quot; &quot;c&quot; &quot;d&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&quot;$*&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌ 合并成一个字符串&lt;/td&gt;
&lt;td&gt;✅ 受影响（用 IFS 连接）&lt;/td&gt;
&lt;td&gt;&quot;a b c d&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;重定向&lt;/h2&gt;
&lt;p&gt;用于改变命令的输入来源或输出目的地，替代默认的 &lt;strong&gt;键盘输入(stdin)&lt;/strong&gt; 和 &lt;strong&gt;屏幕输出(stdout/stderr)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;常用语法&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;输出覆盖&lt;/strong&gt;：&lt;code&gt;command &amp;gt; file&lt;/code&gt;（覆盖写入）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;输出追加&lt;/strong&gt;：&lt;code&gt;command &amp;gt;&amp;gt; file&lt;/code&gt;（追加写入）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;输入重定向&lt;/strong&gt;：&lt;code&gt;command &amp;lt; file&lt;/code&gt;（从文件读取输入）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误输出&lt;/strong&gt;：&lt;code&gt;command 2&amp;gt; file&lt;/code&gt;（仅错误信息）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;合并输出&lt;/strong&gt;：&lt;code&gt;command &amp;gt; file 2&amp;gt;&amp;amp;1&lt;/code&gt;（stdout 和 stderr 合并）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Here Document&lt;/strong&gt;：&lt;code&gt;command &amp;lt;&amp;lt; EOF ... EOF&lt;/code&gt;（内联多行输入），常用生成配置文件。
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;-&lt;/code&gt; 可以忽略前导 Tab（缩进友好）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Here String&lt;/strong&gt;：&lt;code&gt;command &amp;lt;&amp;lt;&amp;lt; &quot;string&quot;&lt;/code&gt;（单行字符串作为标准输入）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt; 必须放在哪？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;功能&lt;/strong&gt;：将标准错误（2）重定向到标准输出（1）所在的地方。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;正确写法&lt;/strong&gt;：&lt;code&gt;command &amp;gt; file 2&amp;gt;&amp;amp;1&lt;/code&gt;（先让标准输出去file，再把错误也指向file）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误写法&lt;/strong&gt;：&lt;code&gt;command 2&amp;gt;&amp;amp;1 &amp;gt; file&lt;/code&gt;（错误先指向了当前终端的标准输出，随后标准输出才去file，导致错误依然打印在屏幕上）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;简写&lt;/strong&gt;：&lt;code&gt;command &amp;amp;&amp;gt; file&lt;/code&gt; 等效于上面正确的写法。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;作用域&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;子 Shell 与大括号 &lt;code&gt;{}&lt;/code&gt; 的区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;小括号 &lt;code&gt;( ... )&lt;/code&gt;&lt;/strong&gt;：在&lt;strong&gt;子 Shell&lt;/strong&gt; 中执行，内部变量修改不影响父 Shell。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;大括号 &lt;code&gt;{ ... }&lt;/code&gt;&lt;/strong&gt;：在&lt;strong&gt;当前 Shell&lt;/strong&gt; 中执行，内部变量修改会影响父 Shell。&lt;strong&gt;注意大括号内部左侧必须有空格&lt;/strong&gt;，且命令结尾必须加分号 &lt;code&gt;;&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;进程替换（&lt;code&gt;&amp;lt;()&lt;/code&gt;）与管道（&lt;code&gt;|&lt;/code&gt;）的本质区别&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;管道 &lt;code&gt;|&lt;/code&gt;&lt;/strong&gt;：会创建&lt;strong&gt;子 Shell&lt;/strong&gt;，导致父 Shell 变量无法被子进程修改。&lt;code&gt;a=1; echo &quot;2&quot; | read a; echo $a&lt;/code&gt; 依然输出 1。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;进程替换 &lt;code&gt;&amp;lt;()&lt;/code&gt;&lt;/strong&gt;：不会引入子 Shell 的副作用，相当于把命令输出伪装成文件。&lt;code&gt;while read line; do ...; done &amp;lt; &amp;lt;(cat file)&lt;/code&gt; 可以在当前 Shell 中执行循环（规避管道变零）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;export 变量和无export区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;有 &lt;code&gt;export&lt;/code&gt;&lt;/strong&gt;：变量会传递给&lt;strong&gt;所有子进程&lt;/strong&gt;（子Shell、外部命令、脚本等），称为&lt;strong&gt;环境变量&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无 &lt;code&gt;export&lt;/code&gt;&lt;/strong&gt;：变量仅在&lt;strong&gt;当前Shell进程&lt;/strong&gt;中有效，子进程不可见，称为&lt;strong&gt;局部变量&lt;/strong&gt;（或Shell变量）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;source/bash script.sh 和 ./script.sh 和 exec ./mod.sh的区别？&lt;/strong&gt;
&lt;code&gt;source&lt;/code&gt;在当前Shell执行，变量和环境变量保留；&lt;code&gt;./script.sh&lt;/code&gt;在子Shell执行，变量不保留。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;执行方式&lt;/th&gt;
&lt;th&gt;执行环境&lt;/th&gt;
&lt;th&gt;变量继承&lt;/th&gt;
&lt;th&gt;是否影响当前环境&lt;/th&gt;
&lt;th&gt;权限&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;source 或 . script.sh&lt;/td&gt;
&lt;td&gt;当前Shell&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;r&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bash script.sh&lt;/td&gt;
&lt;td&gt;子Shell&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;r&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;./script.sh&lt;/td&gt;
&lt;td&gt;子Shell&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;rx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;exec script.sh&lt;/td&gt;
&lt;td&gt;脚本覆盖当前Shell&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;rx&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;综合上面两个：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash
export PATH=&quot;aaa&quot;
cd bbb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;记上述脚本为&lt;code&gt;mod.sh&lt;/code&gt;，问：&lt;strong&gt;&lt;code&gt;source/bash mod.sh&lt;/code&gt; 和 &lt;code&gt;exec ./mod.sh&lt;/code&gt; 父 Shell 的 PATH 和当前目录怎么变化？为什么？&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;执行方式&lt;/th&gt;
&lt;th&gt;父Shell的 &lt;code&gt;PATH&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;父Shell的PWD&lt;/th&gt;
&lt;th&gt;脚本运行结束后&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;source mod.sh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aaa&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bbb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;变量和目录变更&lt;strong&gt;永久保留&lt;/strong&gt;在父Shell中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bash mod.sh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;不变&lt;/td&gt;
&lt;td&gt;不变&lt;/td&gt;
&lt;td&gt;脚本在子Shell中运行，父Shell毫无影响&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;exec ./mod.sh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;消失&lt;/td&gt;
&lt;td&gt;消失&lt;/td&gt;
&lt;td&gt;父Shell&lt;strong&gt;被脚本替换&lt;/strong&gt;，进程随脚本结束而退出&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;进阶与陷阱&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;如何安全地逐行读取文件？&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;while IFS= read -r line; do
    echo &quot;$line&quot;
done &amp;lt; file
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用&lt;code&gt;IFS=&lt;/code&gt;将IFS设置为一个空字符串，以确保读取的行不会因为空格或制表符被截断，&lt;code&gt;-r&lt;/code&gt;防止反斜杠转义。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;set -e的作用？&lt;/strong&gt;
set命令用于显示或设置 Shell 的特性和变量，&lt;code&gt;-e&lt;/code&gt; 遇到非零退出码立即退出脚本。
注意：管道中命令失败不一定触发（需配合&lt;code&gt;set -o pipefail&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;set -euxo pipefail&lt;/code&gt; 各参数含义？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-e&lt;/code&gt;：脚本中任何命令失败（非0退出码）立即&lt;strong&gt;终止退出&lt;/strong&gt;（防止错误蔓延）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-u&lt;/code&gt;：引用&lt;strong&gt;未定义变量&lt;/strong&gt;时报错退出（防止空变量酿成事故）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-x&lt;/code&gt;：&lt;strong&gt;调试模式&lt;/strong&gt;，执行前把每条命令打印到终端（用于排错）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o pipefail&lt;/code&gt;：管道中&lt;strong&gt;任何一个&lt;/strong&gt;子命令失败，整个管道就算失败（弥补 &lt;code&gt;-e&lt;/code&gt; 只管管道最后一条命令的缺陷）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt;：仅&lt;strong&gt;语法检查&lt;/strong&gt;，不执行（可用于排错）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt;：打印读取到的&lt;strong&gt;原始输入行&lt;/strong&gt;（与 &lt;code&gt;-x&lt;/code&gt; 不同，&lt;code&gt;-x&lt;/code&gt; 打印展开后的命令）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;如何避免&lt;code&gt;rm -rf&lt;/code&gt;误删？&lt;/strong&gt;
先&lt;code&gt;ls&lt;/code&gt;确认再执行；用&lt;code&gt;rm -i&lt;/code&gt;交互确认；关键操作前备份；脚本中用&lt;code&gt;set -u&lt;/code&gt;防止空变量。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shell脚本中如何捕获信号并做清理？&lt;/strong&gt;
&lt;code&gt;trap &apos;cleanup; exit&apos; INT TERM&lt;/code&gt; 捕获中断和终止信号。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;信号捕获与后台控制&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;trap&lt;/code&gt;&lt;/strong&gt;：捕获信号并执行自定义操作。常用于脚本退出时清理临时文件。
&lt;ul&gt;
&lt;li&gt;语法：&lt;code&gt;trap &quot;rm -f /tmp/temp_$$&quot; EXIT&lt;/code&gt;（脚本无论正常/异常退出都会触发）。&lt;/li&gt;
&lt;li&gt;常见信号：&lt;code&gt;INT&lt;/code&gt;（Ctrl+C）、&lt;code&gt;TERM&lt;/code&gt;、&lt;code&gt;EXIT&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;wait&lt;/code&gt;&lt;/strong&gt;：阻塞等待后台进程结束。&lt;code&gt;wait $pid&lt;/code&gt; 等待指定进程，无参则等待所有后台子进程。
&lt;ul&gt;
&lt;li&gt;面试题：&lt;code&gt;sleep 3 &amp;amp; wait&lt;/code&gt; 会等待 &lt;code&gt;sleep&lt;/code&gt; 结束再继续。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;如何用Shell实现并发控制？&lt;/strong&gt;
使用&lt;code&gt;&amp;amp;&lt;/code&gt;后台执行 + &lt;code&gt;wait&lt;/code&gt;等待，或用&lt;code&gt;xargs -P N&lt;/code&gt;、&lt;code&gt;GNU parallel&lt;/code&gt;控制并发数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;后台运行 &lt;code&gt;&amp;amp;&lt;/code&gt;  vs &lt;code&gt;nohup&lt;/code&gt; 的区别&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;command &amp;amp;&lt;/code&gt;：放入&lt;strong&gt;后台&lt;/strong&gt;运行，但进程依然属于当前终端（Shell）的子进程。&lt;strong&gt;终端关闭&lt;/strong&gt;（收到 SIGHUP 信号），进程会&lt;strong&gt;随之消亡&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nohup command &amp;amp;&lt;/code&gt;：让进程&lt;strong&gt;忽略 SIGHUP 信号（1信号）&lt;/strong&gt;，同时默认将输出重定向到 &lt;code&gt;nohup.out&lt;/code&gt;。&lt;strong&gt;终端关闭后，进程依然存活&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;最佳实践&lt;/strong&gt;：想退出终端后服务不挂，必须用 &lt;code&gt;nohup&lt;/code&gt; + &lt;code&gt;&amp;amp;&lt;/code&gt;（或用 &lt;code&gt;screen&lt;/code&gt;/&lt;code&gt;tmux&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;如何定义函数并获取返回值？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt;：&lt;code&gt;function func_name() { ... }&lt;/code&gt; 或 &lt;code&gt;func_name() { ... }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;局部变量&lt;/strong&gt;：必须用 &lt;code&gt;local&lt;/code&gt; 声明，否则默认全局污染。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回值（数字）&lt;/strong&gt;：&lt;code&gt;return 0&lt;/code&gt;（成功）或 &lt;code&gt;return 1&lt;/code&gt;（失败），通过 &lt;code&gt;$?&lt;/code&gt; 接收。&lt;strong&gt;但 &lt;code&gt;return&lt;/code&gt; 只能返回 0-255 的状态码&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回字符串&lt;/strong&gt;：不能用 &lt;code&gt;return&lt;/code&gt;，必须用 &lt;code&gt;echo&lt;/code&gt; 输出，调用方用 &lt;code&gt;$(func)&lt;/code&gt; 接收。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;单引号 &lt;code&gt;&apos;&lt;/code&gt;、双引号 &lt;code&gt;&quot;&lt;/code&gt;、反引号 ``和 &lt;code&gt;$()&lt;/code&gt; 的区别&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;单引号 &lt;code&gt;&apos;&apos;&lt;/code&gt;&lt;/strong&gt;：&lt;strong&gt;所见即所得&lt;/strong&gt;，完全保留字面意思，无视所有变量和转义符。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;双引号 &lt;code&gt;&quot;&quot;&lt;/code&gt;&lt;/strong&gt;：&lt;strong&gt;部分保留&lt;/strong&gt;，允许变量展开 &lt;code&gt;$var&lt;/code&gt; 和命令替换 &lt;code&gt;$()&lt;/code&gt;，但会阻止通配符 &lt;code&gt;*&lt;/code&gt; 展开。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;反引号 ``与 &lt;code&gt;$()&lt;/code&gt;&lt;/strong&gt;：均为&lt;strong&gt;命令替换&lt;/strong&gt;（先执行内部命令）。&lt;strong&gt;强烈推荐 &lt;code&gt;$()&lt;/code&gt;&lt;/strong&gt;，\支持嵌套（如 &lt;code&gt;$(grep $(whoami) file)&lt;/code&gt;）且引号处理更清晰。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;登录Shell vs 非登录Shell 与 &lt;code&gt;.bashrc&lt;/code&gt;/&lt;code&gt;.bash_profile&lt;/code&gt; 加载逻辑&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;登录Shell&lt;/strong&gt;（如 &lt;code&gt;su -&lt;/code&gt;、SSH登录）：先读 &lt;code&gt;/etc/profile&lt;/code&gt;，再找 &lt;code&gt;~/.bash_profile&lt;/code&gt;（或 &lt;code&gt;~/.bash_login&lt;/code&gt;、&lt;code&gt;~/.profile&lt;/code&gt;），&lt;strong&gt;通常不读&lt;/strong&gt; &lt;code&gt;~/.bashrc&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;非登录Shell&lt;/strong&gt;（如手动敲 &lt;code&gt;bash&lt;/code&gt;）：只读 &lt;code&gt;~/.bashrc&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决痛点&lt;/strong&gt;：为了登录Shell也能加载别名，通常在 &lt;code&gt;~/.bash_profile&lt;/code&gt; 里强制写入 &lt;code&gt;source ~/.bashrc&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;其他&lt;/h2&gt;
&lt;h3&gt;命令连接符/逻辑判断：&lt;code&gt;;&lt;/code&gt; 、&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; 与 &lt;code&gt;||&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;;&lt;/code&gt;：&lt;strong&gt;无视成败&lt;/strong&gt;，前面命令执行完（无论对错），&lt;strong&gt;无条件&lt;/strong&gt;执行后面的命令。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;：&lt;strong&gt;短路与&lt;/strong&gt;，前面命令执行&lt;strong&gt;成功&lt;/strong&gt;（&lt;code&gt;$?=0&lt;/code&gt;）才执行后面的。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;||&lt;/code&gt;：&lt;strong&gt;短路或&lt;/strong&gt;，前面命令执行&lt;strong&gt;失败&lt;/strong&gt;（&lt;code&gt;$?≠0&lt;/code&gt;）才执行后面的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;经典组合&lt;/strong&gt;：&lt;code&gt;make &amp;amp;&amp;amp; make install || echo &quot;Failed&quot;&lt;/code&gt;（编译成功才安装，任一失败则报错）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;分支与循环结构速记&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;结构&lt;/th&gt;
&lt;th&gt;语法要点&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;if-then-else&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;if [ condition ]; then ...; elif [ cond2 ]; then ...; else ...; fi&lt;/code&gt;（&lt;strong&gt;分号和 &lt;code&gt;then&lt;/code&gt; 同行&lt;/strong&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;case&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;适合字符串匹配，支持 &lt;code&gt;*&lt;/code&gt; 通配符。末尾 &lt;code&gt;;;&lt;/code&gt; 跳出，&lt;code&gt;*)&lt;/code&gt; 为默认&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;for&lt;/code&gt; 循环&lt;/td&gt;
&lt;td&gt;&lt;code&gt;for i in {1..10}; do ...; done&lt;/code&gt;（序列） &lt;code&gt;for ((i=0; i&amp;lt;10; i++)); do ...; done&lt;/code&gt;（C风格）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;while&lt;/code&gt; 循环&lt;/td&gt;
&lt;td&gt;&lt;code&gt;while read line; do ...; done &amp;lt; file&lt;/code&gt;（&lt;strong&gt;逐行读文件标准做法&lt;/strong&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;until&lt;/code&gt; 循环&lt;/td&gt;
&lt;td&gt;条件为假时执行，与 &lt;code&gt;while&lt;/code&gt; 相反&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;数组操作（Bash 特有）&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;操作&lt;/th&gt;
&lt;th&gt;语法&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;定义索引数组&lt;/td&gt;
&lt;td&gt;&lt;code&gt;arr=(a b c)&lt;/code&gt; 或 &lt;code&gt;arr[0]=&quot;a&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;定义关联数组（类似Map）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;declare -A map; map[&quot;key&quot;]=&quot;value&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;获取所有元素&lt;/td&gt;
&lt;td&gt;&lt;code&gt;${arr[@]}&lt;/code&gt;（独立参数） vs &lt;code&gt;${arr[*]}&lt;/code&gt;（单字符串，类似于 &lt;code&gt;&quot;$@&quot;&lt;/code&gt; vs &lt;code&gt;&quot;$*&quot;&lt;/code&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;获取数组长度&lt;/td&gt;
&lt;td&gt;&lt;code&gt;${#arr[@]}&lt;/code&gt; 或 &lt;code&gt;${#arr[*]}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;获取索引列表&lt;/td&gt;
&lt;td&gt;&lt;code&gt;${!arr[@]}&lt;/code&gt;（关联数组常用）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;切片&lt;/td&gt;
&lt;td&gt;&lt;code&gt;${arr[@]:1:2}&lt;/code&gt;（从下标1取2个）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>Linux 场景题</title><link>https://blog-l7wd3.pages.dev/posts/interview/linux-scene/</link><guid isPermaLink="true">https://blog-l7wd3.pages.dev/posts/interview/linux-scene/</guid><description>详细版 Linux 场景题</description><pubDate>Wed, 05 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;CPU / 内存&lt;/h2&gt;
&lt;h3&gt;内存泄漏如何排查？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;：遵循 &lt;strong&gt;“自上而下+工具链”&lt;/strong&gt; 的思路&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;确认现象&lt;/strong&gt;：用 &lt;code&gt;free -h&lt;/code&gt; 看 &lt;code&gt;available&lt;/code&gt; 是否持续走低，用 &lt;code&gt;vmstat 1&lt;/code&gt; 看 &lt;code&gt;si&lt;/code&gt;/&lt;code&gt;so&lt;/code&gt; 是否频繁交换。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定位进程&lt;/strong&gt;：用 &lt;code&gt;ps aux --sort=-%mem | head -n 10&lt;/code&gt; 或 &lt;code&gt;top&lt;/code&gt; 按 &lt;code&gt;M&lt;/code&gt; 排序，找到内存占用最高的 PID。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;深入分析（按语言选工具）&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Java 应用&lt;/strong&gt;：用 &lt;code&gt;jmap -dump&lt;/code&gt; 导出堆转储，配合 MAT 分析支配树和 GC Roots 引用链，定位泄漏对象。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C/C++ 应用&lt;/strong&gt;：可用 &lt;code&gt;memleak&lt;/code&gt; (eBPF) 追踪未释放的分配调用栈，或 &lt;code&gt;valgrind&lt;/code&gt; 在测试环境分析。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;判断类型&lt;/strong&gt;：结合 GC 日志判断是堆内存泄漏、元空间泄漏还是直接内存泄漏，再针对性修复&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;服务器CPU使用率飙升，如何排查？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;：遵循 &lt;strong&gt;“自上而下+工具链”&lt;/strong&gt; 的思路&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;标准排查流程：系统级/进程→线程→栈→系统调用&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;系统级分析&lt;/strong&gt;： &lt;code&gt;top&lt;/code&gt;按 &lt;code&gt;P&lt;/code&gt; 排序，或&lt;code&gt;ps aux --sort=-%cpu | head -n 10&lt;/code&gt;，找到 &lt;code&gt;%CPU&lt;/code&gt; 最高的异常进程 PID。
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;vmstat 1&lt;/code&gt; 观察 &lt;code&gt;r&lt;/code&gt;（运行队列）是否长时间大于CPU核数，若 &lt;code&gt;sy&lt;/code&gt;（内核态占用）飙升，可能是有频繁的上下文切换或中断。&lt;/li&gt;
&lt;li&gt;排查是否遭受了 &lt;strong&gt;DDoS/恶意攻击&lt;/strong&gt;（大量握手请求占满CPU软中断 &lt;code&gt;si&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;转为线程级分析&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;执行 &lt;code&gt;top -H -p [PID]&lt;/code&gt; 找出该进程内最耗CPU的线程ID（十进制）。（-H 显示详细线程，-p 指定PID）&lt;/li&gt;
&lt;li&gt;将线程ID转换为16进制：&lt;code&gt;printf &quot;%x\n&quot; [线程ID]&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;抓线程栈&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JAVA&lt;/strong&gt;：使用 &lt;code&gt;jstack [PID] | grep -A 20 [16进制线程ID]&lt;/code&gt; 直接查看该线程正在执行的代码堆栈，定位到具体类和方法。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;perf top -p [PID]&lt;/code&gt; 查看 CPU 在执行哪些内核/用户态函数，精细定位热点函数（如垃圾回收GC线程，或者正则计算）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;系统调用&lt;/strong&gt;：如果栈显示卡在 &lt;code&gt;read&lt;/code&gt;/&lt;code&gt;write&lt;/code&gt;/&lt;code&gt;futex&lt;/code&gt; 等，使用 &lt;code&gt;strace -p [PID]&lt;/code&gt; 跟踪进程的系统调用，看是否卡在某个内核调用上（如不断重复读写文件）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;服务器频繁发生 OOM Kill，但业务进程内存占用并不高，如何排查？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;根因&lt;/strong&gt;：通常是 &lt;strong&gt;内核 slab 内存（内核缓存）暴涨&lt;/strong&gt; 或 &lt;strong&gt;某个进程疯狂申请匿名内存页（如内存泄漏）但被漏看&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;dmesg -T | grep -i &quot;Out of memory&quot;&lt;/code&gt; 查看 OOM 发生时被杀的进程名和 &lt;code&gt;oom_score&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;查看系统内存细分：&lt;code&gt;cat /proc/meminfo&lt;/code&gt; 关注 &lt;code&gt;Slab&lt;/code&gt;、&lt;code&gt;SReclaimable&lt;/code&gt;、&lt;code&gt;KernelStack&lt;/code&gt;。若 &lt;code&gt;Slab&lt;/code&gt; 异常大，用 &lt;code&gt;slabtop&lt;/code&gt; 看是哪个内核对象占用（如 &lt;code&gt;dentry&lt;/code&gt;、&lt;code&gt;inode_cache&lt;/code&gt; 暴涨，说明文件句柄泄露）。&lt;/li&gt;
&lt;li&gt;统计所有进程实际占用总和：&lt;code&gt;ps aux | awk &apos;{sum+=$6} END {print sum/1024 &quot; MB&quot;}&apos;&lt;/code&gt;（单位 KB），若总和远小于总内存，差值就是内核占用了。&lt;/li&gt;
&lt;li&gt;检查是否有 &lt;strong&gt;内存超卖&lt;/strong&gt; 情况（如 K8s Pod 的 limits 设置过小，虽然物理内存够，但 cgroup 限制内 OOM）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vmstat -s&lt;/code&gt; 查看 &lt;code&gt;pages paged in/out&lt;/code&gt;，确认是否有频繁换页加剧内存压力。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;服务器负载（Load Average）飙升，但 CPU 使用率很低，什么原因？如何排查？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：&lt;code&gt;top&lt;/code&gt; 看 &lt;code&gt;load average&lt;/code&gt; 高达几十，但 &lt;code&gt;%us&lt;/code&gt; 和 &lt;code&gt;%sy&lt;/code&gt; 都很低。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;根因&lt;/strong&gt;：&lt;strong&gt;大量进程处于不可中断睡眠状态（D 状态）&lt;/strong&gt;，通常是因为 I/O 阻塞（磁盘/网络/外部设备）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;top&lt;/code&gt; 按 &lt;code&gt;D&lt;/code&gt; 键排序，查看处于 &lt;code&gt;D&lt;/code&gt; 状态的进程数量。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ps aux | awk &apos;$8==&quot;D&quot; {print $2,$NF}&apos;&lt;/code&gt; 列出所有 D 状态进程。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;strace -p [PID]&lt;/code&gt; 看卡在哪个系统调用（通常是 &lt;code&gt;read/write&lt;/code&gt; 磁盘或 &lt;code&gt;NFS&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iostat -x 1&lt;/code&gt; 查看 &lt;code&gt;%util&lt;/code&gt; 和 &lt;code&gt;await&lt;/code&gt;，若接近 100% 或 &lt;code&gt;await&lt;/code&gt; 极高，说明磁盘 I/O 已饱和。&lt;/li&gt;
&lt;li&gt;若磁盘正常，检查是否有 NFS 挂载超时：&lt;code&gt;df -h&lt;/code&gt; 卡住不动说明 NFS 服务端不可达。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;存储&lt;/h2&gt;
&lt;h3&gt;磁盘空间报警，但 &lt;code&gt;du&lt;/code&gt; 统计的总大小远小于磁盘已用空间，怎么回事？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;根因&lt;/strong&gt;：&lt;strong&gt;文件被删除但进程仍持有句柄&lt;/strong&gt;，空间未真正释放；或 &lt;strong&gt;inode 耗尽&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先检查 inode：&lt;code&gt;df -i&lt;/code&gt;，如果 &lt;code&gt;IUse%&lt;/code&gt; 100%，说明小文件太多，用 &lt;code&gt;find / -type f | wc -l&lt;/code&gt; 定位目录。&lt;/li&gt;
&lt;li&gt;若 inode 正常，查句柄泄露：&lt;code&gt;lsof +L1&lt;/code&gt; 列出所有已删除但未释放句柄的文件（标记为 &lt;code&gt;(deleted)&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;找到占用进程后：&lt;code&gt;ls -l /proc/[PID]/fd/ | grep deleted&lt;/code&gt; 确认，重启该进程即可释放空间。&lt;/li&gt;
&lt;li&gt;若不重启，可 &lt;code&gt;echo &amp;gt; /proc/[PID]/fd/[fd号]&lt;/code&gt; 清空文件（风险操作，需确认业务影响）。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;网络&lt;/h2&gt;
&lt;h3&gt;客户端无法访问服务器8080端口，怎么全链路排查？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;：从服务器着手，从&lt;strong&gt;物理层 → 网络层 → 传输层 → 应用层&lt;/strong&gt;逐层递进。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;服务器本机确认（物理层）&lt;/strong&gt;：&lt;code&gt;netstat -tlnp | grep 8080&lt;/code&gt; 或 &lt;code&gt;ss -tlnp | grep 8080&lt;/code&gt;，确认进程是否在监听 &lt;code&gt;0.0.0.0&lt;/code&gt; 还是 &lt;code&gt;127.0.0.1&lt;/code&gt;（后者仅本机可访）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务器防火墙（网络层）&lt;/strong&gt;：&lt;code&gt;iptables -L -n | grep 8080&lt;/code&gt; 和 &lt;code&gt;firewall-cmd --list-all&lt;/code&gt;，检查是否有 DROP/REJECT 规则。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;连通性测试（传输层）&lt;/strong&gt;：从客户端 &lt;code&gt;telnet [IP] 8080&lt;/code&gt; 或 &lt;code&gt;nc -zv [IP] 8080&lt;/code&gt; 看是否通；不通则逐跳 &lt;code&gt;traceroute&lt;/code&gt; 看丢在哪。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;抓包分析（传输层）&lt;/strong&gt;：&lt;code&gt;tcpdump -i any port 8080 -nn&lt;/code&gt;，看三次握手是否完成（SYN→SYN+ACK→ACK）。若只有 SYN 无响应，说明服务端未回包；若回 RST，说明进程拒绝连接（可能是 backlog 满了或应用层拒绝）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;应用层&lt;/strong&gt;：&lt;code&gt;curl -v [IP]:8080&lt;/code&gt; 看 HTTP 状态码，或查看应用日志是否有 &lt;code&gt;Connection refused&lt;/code&gt; 异常。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;无法 Ping 通目标主机/域名，如何排查？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;：若域名不通 IP 通，直接定位到 DNS 故障。都不通则按&lt;strong&gt;分层排查&lt;/strong&gt;思路。&lt;strong&gt;从下往上（物理层 → 网络层 → 传输层 → 应用层）&lt;/strong&gt;，逐层缩小范围。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;简洁版&lt;/strong&gt;：先确认本地网卡和 IP 配置，再 ping 网关判断是否局域网问题；若网关通，用 &lt;code&gt;traceroute&lt;/code&gt; 定位丢包节点，同时检查本机防火墙；若域名不通 IP 通，定位到 DNS 故障，检查 &lt;code&gt;/etc/resolv.conf&lt;/code&gt;，ping 域名服务器确定是域名服务器不可达还是解析问题；最后，考虑到很多生产环境出于安全考虑会主动禁 ICMP 协议，我会改用 &lt;code&gt;telnet&lt;/code&gt;  &lt;strong&gt;端口探测&lt;/strong&gt; 代替 ping。&lt;/p&gt;
&lt;h4&gt;第一层：自查（排除本地低级错误/物理层）&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;网络连通性&lt;/strong&gt;：先 ping &lt;code&gt;127.0.0.1&lt;/code&gt; 确认本机 TCP/IP 协议栈正常；再 ping 本机 IP（非 lo）确认网卡驱动正常。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网卡状态&lt;/strong&gt;：&lt;code&gt;ip a&lt;/code&gt; 或 &lt;code&gt;ifconfig&lt;/code&gt; 确认网卡是否 &lt;code&gt;UP&lt;/code&gt;，&lt;code&gt;RUNNING&lt;/code&gt;；检查网线/WiFi（物理层）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;第二层：网关与路由（局域网/网络层）&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ping 网关&lt;/strong&gt;：ping 默认网关（&lt;code&gt;ip route | grep default&lt;/code&gt; 查），&lt;strong&gt;网关不通&lt;/strong&gt; → 问题在交换机/路由器/无线信号；&lt;strong&gt;网关通&lt;/strong&gt; → 问题在外网或目标端。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;traceroute 追踪&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;Linux：&lt;code&gt;traceroute -n [目标IP]&lt;/code&gt;（加 &lt;code&gt;-n&lt;/code&gt; 跳过 DNS 解析更快）。&lt;/li&gt;
&lt;li&gt;Windows：&lt;code&gt;tracert -d [目标IP]&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;看在哪一跳 &lt;strong&gt;超时/星号&lt;/strong&gt;，大概率是该节点路由丢包或防火墙拦截了 ICMP 包（很多云厂商安全组默认屏蔽 ICMP）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;第三层：防火墙/安全组拦截（传输层/网络层）&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;本机防火墙&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;iptables -L -n -v | grep DROP&lt;/code&gt; 看是否有 DROP 规则。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;firewall-cmd --state&lt;/code&gt;（CentOS 7+）或 &lt;code&gt;ufw status&lt;/code&gt;（Ubuntu）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;如果有目标主机访问权，检查：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;云安全组/ACL&lt;/strong&gt;：登录云控制台，检查目标机器的 &lt;strong&gt;入方向安全组&lt;/strong&gt; 是否放行了 ICMP 协议（允许 &lt;code&gt;type 8&lt;/code&gt; 入站）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;目标主机防火墙&lt;/strong&gt;：目标主机如果开启 &lt;code&gt;iptables&lt;/code&gt; 且 DROP 了 ICMP，本地 ping 会超时（但业务端口如 80/443 可能依然通，要区分）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;第四层：DNS 解析问题（应用层）&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;现象：ping 域名不通，但 ping IP 通&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;排查命令&lt;/strong&gt;：
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;cat /etc/resolv.conf&lt;/code&gt; 检查 DNS Server 配置（如 &lt;code&gt;114.114.114.114&lt;/code&gt; 或内网 DNS）。&lt;/li&gt;
&lt;li&gt;ping 域名服务器确定是域名服务器不可达还是解析问题&lt;/li&gt;
&lt;li&gt;检查 &lt;code&gt;/etc/hosts&lt;/code&gt; 是否写死了解析（被错误覆盖）。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;如果有装 &lt;code&gt;nslookup&lt;/code&gt; &lt;code&gt;dig&lt;/code&gt; 可以使用 &lt;code&gt;dig @8.8.8.8&lt;/code&gt; 或 &lt;code&gt;dig [目标域名]&lt;/code&gt; 排查&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;第五层：目标服务存活（终极确认）&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：很多安全策略会 &lt;strong&gt;禁止 ICMP 协议（ping）&lt;/strong&gt;，但 &lt;strong&gt;业务端口（如 80/443）是通的&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;此时应该用 &lt;strong&gt;端口探测&lt;/strong&gt; 代替 ping：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;telnet [目标IP] [端口]&lt;/code&gt; 或 &lt;code&gt;nc -zv [目标IP] [端口]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;如果端口通但 ping 不通 → &lt;strong&gt;属于正常现象&lt;/strong&gt;（云厂商/运维策略屏蔽 ICMP）。&lt;/li&gt;
&lt;li&gt;如果端口也不通 → 目标服务挂了，或目标主机本身无法访问。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;综合&lt;/h2&gt;
&lt;h3&gt;如何查看服务/进程是否正常运行？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;原则&lt;/strong&gt;：&lt;strong&gt;进程在 ≠ 服务正常。&lt;/strong&gt; 要分层判断：&lt;strong&gt;状态 → 进程 → 端口 → 健康探针 → 日志&lt;/strong&gt;。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;托管状态&lt;/strong&gt;：systemd 用 &lt;code&gt;systemctl is-active&lt;/code&gt; + &lt;code&gt;is-enabled&lt;/code&gt;，SysV 用 &lt;code&gt;service xxx status&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;进程&lt;/strong&gt;：没有托管就用 &lt;code&gt;pgrep -af&lt;/code&gt; / &lt;code&gt;ps -ef&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;端口&lt;/strong&gt;：&lt;code&gt;ss -lntp&lt;/code&gt; 确认监听；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;健康探针&lt;/strong&gt;：&lt;code&gt;curl&lt;/code&gt; 打业务健康接口，这才是真验证；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;日志&lt;/strong&gt;：&lt;code&gt;journalctl -u xxx&lt;/code&gt; 或日志文件，看有无报错。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;只做①②不算查完，必须做到④才算真健康。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;参考 Shell 脚本&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash
# check_service.sh &amp;lt;name&amp;gt; [port] [health_url]
NAME=&quot;$1&quot;; PORT=&quot;$2&quot;; URL=&quot;$3&quot;
[ -z &quot;$NAME&quot; ] &amp;amp;&amp;amp; { echo &quot;Usage: $0 &amp;lt;name&amp;gt; [port] [health_url]&quot;; exit 2; }
FAIL=0

# systemd 优先
if systemctl list-unit-files 2&amp;gt;/dev/null | grep -q &quot;^${NAME}\.service&quot;; then
    echo &quot;&amp;gt;&amp;gt;&amp;gt; systemd unit: $NAME.service&quot;
    systemctl is-active --quiet &quot;$NAME&quot; \
        &amp;amp;&amp;amp; echo &quot;[OK] active&quot; \
        || { echo &quot;[FAIL] not active&quot;; FAIL=1; }
    systemctl is-enabled --quiet &quot;$NAME&quot; \
        || echo &quot;[WARN] not enabled (won&apos;t start on boot)&quot;
    PID=$(systemctl show -p MainPID --value &quot;$NAME&quot;)
else
    echo &quot;&amp;gt;&amp;gt;&amp;gt; fallback: process check&quot;
    if pgrep -f &quot;$NAME&quot; &amp;gt;/dev/null; then
        PID=$(pgrep -f &quot;$NAME&quot; | head -1)
        echo &quot;[OK] process PID=$PID&quot;
    else
        echo &quot;[FAIL] process not found&quot;; FAIL=1; PID=&quot;&quot;
    fi
fi

# 端口
if [ -n &quot;$PORT&quot; ]; then
    ss -lntp 2&amp;gt;/dev/null | grep -q &quot;:$PORT &quot; \
        &amp;amp;&amp;amp; echo &quot;[OK] port $PORT listening&quot; \
        || { echo &quot;[FAIL] port $PORT not listening&quot;; FAIL=1; }
fi

# 健康探针
if [ -n &quot;$URL&quot; ]; then
    CODE=$(curl -s -o /dev/null -w &quot;%{http_code}&quot; --max-time 5 &quot;$URL&quot;)
    [ &quot;$CODE&quot; = &quot;200&quot; ] \
        &amp;amp;&amp;amp; echo &quot;[OK] health $URL -&amp;gt; 200&quot; \
        || { echo &quot;[FAIL] health $URL -&amp;gt; $CODE&quot;; FAIL=1; }
fi

[ $FAIL -eq 0 ] &amp;amp;&amp;amp; echo &quot;=== HEALTHY ===&quot; || echo &quot;=== UNHEALTHY ===&quot;
exit $FAIL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;恢复&lt;/h2&gt;
&lt;h3&gt;rm -rf / 误操作或误删重要文件后，怎么恢复（前提是进程未重启）？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;核心原理&lt;/strong&gt;：Linux 中文件名和 inode 分离，文件删除只是移除目录项，只要进程还在打开该文件，数据块未被回收。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;恢复步骤&lt;/strong&gt;（假设误删 &lt;code&gt;/var/log/nginx/access.log&lt;/code&gt;）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;立即停止写入&lt;/strong&gt;：&lt;code&gt;lsof | grep deleted&lt;/code&gt; 找到仍持有该文件句柄的进程（nginx 的 worker 进程）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;查看 fd 路径&lt;/strong&gt;：&lt;code&gt;ls -l /proc/[PID]/fd/&lt;/code&gt; 找到对应 fd 编号（如 4），显示为 &lt;code&gt;/var/log/nginx/access.log (deleted)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重定向恢复&lt;/strong&gt;：&lt;code&gt;cat /proc/[PID]/fd/4 &amp;gt; /var/log/nginx/access.log&lt;/code&gt; 将文件内容原样拷回。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全操作&lt;/strong&gt;：通过 kill -HUP [PID] 重新加载配置让进程重新打开新文件句柄。&lt;/li&gt;
&lt;li&gt;&lt;em&gt;注：若进程已重启，则需依赖 extundelete 或 TestDisk 等工具做文件系统级别的恢复，但成功率取决于是否立即卸载分区并停止写入。&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>Linux 八股</title><link>https://blog-l7wd3.pages.dev/posts/interview/linux/</link><guid isPermaLink="true">https://blog-l7wd3.pages.dev/posts/interview/linux/</guid><description>速记用 Linux 八股</description><pubDate>Sun, 02 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1. 基础命令&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Linux常用文件操作命令？&lt;/strong&gt;
ls、cd、pwd、mkdir、touch、cp、mv、rm、cat、vi/vim。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何查看系统版本？&lt;/strong&gt;
&lt;code&gt;uname -a&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何查找文件？&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 按名称查找
find [路径] [匹配条件] [动作]
find / -name &quot;filename&quot; 
# 基于数据库快速查找（-i 忽略大小写; -n x 显示前x条）
locate -i &quot;filename&quot; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;如何查看文件内容 / 如何查看大文件？&lt;/strong&gt;
&lt;code&gt;cat&lt;/code&gt;（全部）、&lt;code&gt;less/more&lt;/code&gt;（分页）、&lt;code&gt;head/tail&lt;/code&gt;（头尾）、&lt;code&gt;grep&lt;/code&gt;（过滤）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;less/more 区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;more 只能向前翻页，加载大文件慢，无交互搜索；&lt;/li&gt;
&lt;li&gt;less 支持双向滚动，按需加载性能优，内置搜索功能强，且在管道中可回溯，更适合大型文件和复杂操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;如何查看当前目录？&lt;/strong&gt;
&lt;code&gt;pwd&lt;/code&gt; （Print Working Directory）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何管理用户？&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;useradd 选项 用户名
userdel 选项 用户名
usermod 选项 用户名
passwd 选项 用户名
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;如何管理权限？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;chmod&lt;/code&gt; 改变文件/目录权限，三个数字owner/group/others，八进制表示法（读4 写2 执行1）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chown&lt;/code&gt; 改变所有者，&lt;code&gt;chgrp&lt;/code&gt; 改变所在组&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;目录权限含义？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;读（r）&lt;/strong&gt;：允许列出目录中的文件和子目录名称（ls）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;写（w）&lt;/strong&gt;：允许在目录中创建、删除、重命名文件或子目录（会改变目录的文件列表）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;执行（x）&lt;/strong&gt;：允许进入目录（cd）并访问其中的文件或子目录。&lt;/li&gt;
&lt;li&gt;注意：
&lt;ul&gt;
&lt;li&gt;只有 &lt;strong&gt;x&lt;/strong&gt; 权限而无 &lt;strong&gt;r&lt;/strong&gt; 权限，可以进入目录但无法列出文件名。&lt;/li&gt;
&lt;li&gt;只有 &lt;strong&gt;r&lt;/strong&gt; 权限而无 &lt;strong&gt;x&lt;/strong&gt; 权限，可以看到文件列表但无法进入目录或访问文件内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;子目录有写权限但父目录没有，能修改子目录吗？&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;操作&lt;/th&gt;
&lt;th&gt;需要父目录权限&lt;/th&gt;
&lt;th&gt;需要子目录权限&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;修改子目录内文件&lt;/td&gt;
&lt;td&gt;x（穿过）&lt;/td&gt;
&lt;td&gt;w + x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;在子目录内创建/删除文件&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;w + x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;进入子目录 &lt;code&gt;cd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;删除/重命名子目录本身&lt;/td&gt;
&lt;td&gt;w + x&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;列出父目录内容&lt;/td&gt;
&lt;td&gt;r&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;如何设置定时任务？&lt;/strong&gt;
&lt;code&gt;crontab -e&lt;/code&gt; 编辑当前用户 crontab 文件，&lt;code&gt;* * * * * command&lt;/code&gt; 分/时/日/月/星期&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;硬链接与软链接（符号链接）的底层区别？&lt;/strong&gt;
硬链接是&lt;strong&gt;同一inode&lt;/strong&gt;的多个入口，不能跨文件系统，不能指向目录，删除源不影响；软链接是&lt;strong&gt;新inode&lt;/strong&gt;存储路径字符串，指向源文件路径，源删除则失效（高亮闪烁）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;硬链接为什么不能跨文件系统？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;硬链接指向的是 inode，而 inode 号只在当前文件系统内有意义。每个文件系统都有自己的 inode 表，另一个文件系统里的同一个 inode 号不代表同一个文件。&lt;/li&gt;
&lt;li&gt;软链接保存的是路径字符串，解析时按路径重新查找目标文件，所以可以跨文件系统&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;如何查看文件被哪个进程占用？&lt;/strong&gt;
&lt;code&gt;lsof filename&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linux系统结构，主要目录作用？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;分层的树形结构，主要目录作用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/bin 存放常用的用户命令，如ls、cp等，普通用户和管理员均可使用。&lt;/li&gt;
&lt;li&gt;/sbin 存放系统管理员使用的管理命令，如ifconfig、reboot等。&lt;/li&gt;
&lt;li&gt;/etc 存放系统配置文件和子目录，例如网络配置文件/etc/hosts和DNS配置文件/etc/resolv.conf。&lt;/li&gt;
&lt;li&gt;/home 用户的主目录，每个用户都有一个以用户名命名的子目录。&lt;/li&gt;
&lt;li&gt;/root 超级用户（root）的主目录，仅供系统管理员使用。&lt;/li&gt;
&lt;li&gt;/lib和/lib64 存放系统的共享库文件，类似于Windows的DLL文件，几乎所有程序都依赖这些库。&lt;/li&gt;
&lt;li&gt;/usr 存放用户应用程序和文件，包括/usr/bin（用户命令）、/usr/sbin（管理员命令）和/usr/local（本地安装的软件）。&lt;/li&gt;
&lt;li&gt;/var 存放动态数据，如日志文件（/var/log）、邮件（/var/mail）和临时文件（/var/tmp）。&lt;/li&gt;
&lt;li&gt;/tmp 存放临时文件，系统重启后会清空。&lt;/li&gt;
&lt;li&gt;/dev 存放设备文件，例如硬盘（/dev/sda）和终端（/dev/tty）。&lt;/li&gt;
&lt;li&gt;/proc 虚拟文件系统，存储内核和进程信息，例如CPU信息（/proc/cpuinfo）和内存信息（/proc/meminfo）。&lt;/li&gt;
&lt;li&gt;/sys 类似于/proc，用于存储设备和内核模块的信息。&lt;/li&gt;
&lt;li&gt;/boot 存放启动相关文件，包括内核和引导加载器配置文件。&lt;/li&gt;
&lt;li&gt;/media和/mnt 用于挂载外部设备，如U盘和光驱。&lt;/li&gt;
&lt;li&gt;/opt 存放第三方软件或可选应用程序。&lt;/li&gt;
&lt;li&gt;/run 存储系统运行时的信息，系统重启后会清空。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;如何查看文件类型？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ls -l&lt;/code&gt; 看第一列&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-：普通文件&lt;/li&gt;
&lt;li&gt;d：目录文件&lt;/li&gt;
&lt;li&gt;b：块设备文件（一般位于&lt;code&gt;/dev&lt;/code&gt;，以块为单位进行读写的特殊设备文件，通常用于硬盘、光盘和U盘等存储设备）&lt;/li&gt;
&lt;li&gt;c：字符设备文件（一般位于&lt;code&gt;/dev&lt;/code&gt;，允许用户按&lt;strong&gt;字节顺序&lt;/strong&gt;与设备交互，例子包括键盘、鼠标、串口和终端设备）&lt;/li&gt;
&lt;li&gt;s：套接字文件&lt;/li&gt;
&lt;li&gt;p：管道文件&lt;/li&gt;
&lt;li&gt;l：链接文件（软链接）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;su命令作用、参数？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;作用：切换用户。主要参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;- / -l / --login&lt;/code&gt;	模拟完整登录，加载目标用户环境&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c &quot;cmd&quot;&lt;/code&gt;	以目标用户执行一条命令后退出&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s shell&lt;/code&gt;	指定使用的 shell&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m / -p&lt;/code&gt;	保留当前环境变量（不重置）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-g group&lt;/code&gt;	指定主组&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-G group&lt;/code&gt;	指定附加组&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;su user和su - user区别？&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;su user&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;su - user&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;环境变量&lt;/td&gt;
&lt;td&gt;保留当前用户环境&lt;/td&gt;
&lt;td&gt;重新加载目标用户环境&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;工作目录&lt;/td&gt;
&lt;td&gt;不变（当前目录）&lt;/td&gt;
&lt;td&gt;切换到目标用户 home&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PATH&lt;/td&gt;
&lt;td&gt;沿用原用户&lt;/td&gt;
&lt;td&gt;重置为目标用户的 PATH&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;shell 类型&lt;/td&gt;
&lt;td&gt;非登录 shell&lt;/td&gt;
&lt;td&gt;登录 shell&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;读取配置&lt;/td&gt;
&lt;td&gt;不读 &lt;code&gt;.bash_profile&lt;/code&gt; / &lt;code&gt;.profile&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;读取 &lt;code&gt;.bash_profile&lt;/code&gt; / &lt;code&gt;.profile&lt;/code&gt; / &lt;code&gt;.bashrc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;本质&lt;/td&gt;
&lt;td&gt;只切换身份&lt;/td&gt;
&lt;td&gt;完整登录模拟&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;用 &lt;code&gt;su user&lt;/code&gt; 跑脚本可能因 PATH 不对找不到命令；生产脚本建议用 &lt;code&gt;su - user -c &quot;cmd&quot;&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;2. 进程管理&lt;/h2&gt;
&lt;h3&gt;进程排查&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;如何查看所有运行中的进程？&lt;/strong&gt;
&lt;code&gt;ps aux&lt;/code&gt; 或 &lt;code&gt;ps -ef&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何实时监控进程和系统资源？&lt;/strong&gt;
&lt;code&gt;top&lt;/code&gt;（实时刷新），关注%CPU、%MEM、load average。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;top命令顶部输出含义？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tasks（进程任务）&lt;/strong&gt;：&lt;code&gt;total&lt;/code&gt; 总进程数；&lt;code&gt;running&lt;/code&gt; 正在运行；&lt;code&gt;sleeping&lt;/code&gt; 睡眠；&lt;code&gt;stopped&lt;/code&gt; 暂停；&lt;code&gt;zombie&lt;/code&gt; 僵尸进程（重点警戒值，不为0需关注）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;%Cpu(s)&lt;/strong&gt;：&lt;code&gt;us&lt;/code&gt; 用户态占用；&lt;code&gt;sy&lt;/code&gt; 内核态占用；&lt;code&gt;id&lt;/code&gt; 空闲；&lt;code&gt;wa&lt;/code&gt; I/O等待；&lt;code&gt;hi&lt;/code&gt;/&lt;code&gt;si&lt;/code&gt; 硬/软中断。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MiB Mem（物理内存）&lt;/strong&gt;：&lt;code&gt;total&lt;/code&gt; 总内存；&lt;code&gt;free&lt;/code&gt; 完全空闲；&lt;code&gt;used&lt;/code&gt; 已分配（含缓存）；&lt;code&gt;buff/cache&lt;/code&gt; 缓冲区+页缓存（Linux会把空闲内存拿来当缓存，所以看可用内存应看 &lt;code&gt;available&lt;/code&gt; 列）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;数值异常 &amp;amp; 常见原因&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;现象&lt;/th&gt;
&lt;th&gt;可能原因&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;us&lt;/code&gt; 高&lt;/td&gt;
&lt;td&gt;应用死循环、计算密集、代码 bug、QPS 突增&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sy&lt;/code&gt; 高&lt;/td&gt;
&lt;td&gt;系统调用频繁、上下文切换多、锁竞争、网络/磁盘驱动问题&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wa&lt;/code&gt; 高&lt;/td&gt;
&lt;td&gt;磁盘 I/O 瓶颈、NFS 慢（Network FileSystem）、数据库慢查询、swap 抖动&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;si&lt;/code&gt; 高&lt;/td&gt;
&lt;td&gt;网络软中断集中、单核跑满、网卡多队列未配置、DDoS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hi&lt;/code&gt; 高&lt;/td&gt;
&lt;td&gt;硬件中断频繁、网卡/磁盘中断风暴&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;st&lt;/code&gt; 高&lt;/td&gt;
&lt;td&gt;虚拟机被宿主机超卖、邻居抢占资源（云主机常见）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ni&lt;/code&gt; 高&lt;/td&gt;
&lt;td&gt;有人用 &lt;code&gt;nice&lt;/code&gt; 跑后台任务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;id&lt;/code&gt; 低但负载不高&lt;/td&gt;
&lt;td&gt;可能是 &lt;code&gt;st&lt;/code&gt; 或 &lt;code&gt;wa&lt;/code&gt; 吃掉了，需结合 &lt;code&gt;vmstat&lt;/code&gt; / &lt;code&gt;iostat&lt;/code&gt; 看&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;排查套路&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;us 高 → top 看进程 → perf/火焰图
sy 高 → vmstat 看 cs/in → strace
wa 高 → iostat -x 1 → 看 %util / await
si 高 → mpstat -P ALL 1 → 看是否单核 → 调 RPS/RSS/多队列
st 高 → 找云厂商 / 换宿主机
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ps aux / top命令各个关键字段含义？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PID&lt;/strong&gt;：进程ID&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;USER&lt;/strong&gt;：所属用户&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PR/NI&lt;/strong&gt;：优先级与 nice 值&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VIRT/RES/SHR&lt;/strong&gt;：虚拟内存、常驻内存、共享内存&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;%CPU/%MEM&lt;/strong&gt;：CPU/内存占用率&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TIME+&lt;/strong&gt;：累计 CPU 时间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;COMMAND&lt;/strong&gt;：命令名或完整命令行&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;CPU硬中断和软中断区别？&lt;/strong&gt;
硬中断由外部硬件触发，软中断由软件指令触发，它们在操作系统中分别处理实时事件和系统调用任务。&lt;/p&gt;
&lt;h3&gt;进程清理&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;kill与kill -9的区别？&lt;/strong&gt;
kill默认发SIGTERM（可捕获、可清理）；kill -9发SIGKILL（强制终止，不可捕获）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;kill 命令中信号编号 1、2、3、9、15、18、19 的具体区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1 (SIGHUP)&lt;/strong&gt;：终端挂起，常用于让进程&lt;strong&gt;重读配置&lt;/strong&gt;（如Nginx -s reload本质发此信号）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2 (SIGINT)&lt;/strong&gt;：键盘中断（Ctrl+C），进程可捕获清理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3 (SIGQUIT)&lt;/strong&gt;：键盘退出（Ctrl+\），会&lt;strong&gt;产生core dump&lt;/strong&gt;用于调试。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;9 (SIGKILL)&lt;/strong&gt;：强制终止，不可捕获/忽略，直接由内核回收，可能造成资源泄漏或脏数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;15 (SIGTERM)&lt;/strong&gt;：默认终止信号，可捕获，优雅停机首选（超时后补9）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;18 (SIGCONT)&lt;/strong&gt;：继续运行被暂停的进程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;19 (SIGSTOP)&lt;/strong&gt;：暂停进程（Ctrl+z，不可捕获，类似外部挂起）。&lt;/li&gt;
&lt;li&gt;补充：Ctrl+d 表示输入结束，不发送信号，若输入为空，则返回0，类似EOF&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;僵尸进程是什么？如何清理？&lt;/strong&gt;
子进程退出后父进程未调用wait()回收，进程描述符残留在进程表中。无法kill僵尸本身，需kill父进程（PPID），父进程死后僵尸被init收养并清理。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;孤儿进程是什么？&lt;/strong&gt;
父进程先退出，子进程被init（PID 1）收养，由init负责回收，通常无害。&lt;/p&gt;
&lt;h3&gt;进程间七种通信方式&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;管道（Pipe）&lt;/strong&gt;：父子进程间单向传输，数据无格式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;命名管道（FIFO）&lt;/strong&gt;：通过文件节点，允许无亲缘关系进程通信。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;信号（Signal）&lt;/strong&gt;：异步通知机制（如 &lt;code&gt;kill -9&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消息队列（Message Queue）&lt;/strong&gt;：内核维护的消息链表，有格式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;共享内存（Shared Memory）&lt;/strong&gt;：&lt;strong&gt;最快&lt;/strong&gt;的方式，映射同一块物理内存，需配合信号量使用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;信号量（Semaphore）&lt;/strong&gt;：本质上是一个计数器，用于进程/线程间的同步与互斥，而非传输数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;套接字（Socket）&lt;/strong&gt;：用于跨网络或本机不同进程间的通信（TCP/UDP）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;3. 内存与存储&lt;/h2&gt;
&lt;h3&gt;基础&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Buffer和Cache的区别？&lt;/strong&gt;
Buffer（Buffers）：块设备元数据缓存（inode、分区信息）。Cache（Page Cache）：文件内容缓存，读写都经过它。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;手动drop_caches有什么风险？&lt;/strong&gt;
&lt;code&gt;echo 3 &amp;gt; /proc/sys/vm/drop_caches&lt;/code&gt;会清空Page Cache，导致CPU飙升重建索引、磁盘I/O风暴（Cache Miss），生产环境慎用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何查看内存使用情况？&lt;/strong&gt;
&lt;code&gt;free -h&lt;/code&gt;；&lt;code&gt;vmstat&lt;/code&gt; 查看虚拟内存统计。&lt;/p&gt;
&lt;h3&gt;虚拟地址&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;缺页中断与内存映射&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内存映射（mmap）&lt;/strong&gt;：将磁盘文件或设备数据直接映射到进程的虚拟地址空间，使程序可以像访问内存一样访问文件数据，由内核在后台同步。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;懒加载（Lazy Loading）&lt;/strong&gt;：数据只有在首次访问时才会触发缺页异常，由内核将对应文件页加载到物理内存。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺页异常（Page Fault）&lt;/strong&gt;：当进程试图访问一个尚未加载到物理内存的虚拟页面时。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;次要异常/软缺页&lt;/strong&gt;：数据已在 page cache，只需建立页表映射即可，很快。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;主要异常/硬缺页&lt;/strong&gt;：数据不在 page cache，必须触发磁盘I/O将其读入内存（很慢，影响性能）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;虚拟内存&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;什么是Swap？什么时候会用到？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt;：Swap（交换分区）是硬盘上划出的一块空间。当物理内存（RAM）不足时，内核会将暂时不用的内存数据换出到Swap中，从而释放物理内存给当前活跃的进程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;触发时机&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;物理内存耗尽&lt;/strong&gt;（剩余可用内存低于阈值）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存回收压力大&lt;/strong&gt;（内核的 &lt;code&gt;kswapd0&lt;/code&gt; 线程被频繁唤醒）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;主动冷数据迁移&lt;/strong&gt;（即使内存还有余量，内核也会根据 &lt;code&gt;vm.swappiness&lt;/code&gt; 参数决定是否把不活跃的页换出去，默认值通常是60）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;OOM&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;什么是OOM？什么会导致OOM？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt;：&lt;strong&gt;Out Of Memory&lt;/strong&gt;，即内存溢出。当系统物理内存和Swap全部耗尽，内核无法再为任何进程分配内存时，会触发 &lt;strong&gt;OOM Killer&lt;/strong&gt; 机制，它会根据评分（&lt;code&gt;oom_score&lt;/code&gt;）挑选一个进程强制杀掉（发送 SIGKILL 信号）以释放内存，保障操作系统存活。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;常见诱因&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内存泄漏&lt;/strong&gt;（程序申请的内存没有释放，积少成多耗尽资源）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不合理的大对象/大查询&lt;/strong&gt;（如数据库一次性加载上亿行数据到内存）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;流量突增&lt;/strong&gt;（并发请求数暴增，导致创建大量线程或缓存对象）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存分配速度超过GC/回收速度&lt;/strong&gt;（特别是在 Java 或 Python 应用中）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Linux 下 OOM Killer 的运作机制？&lt;/strong&gt;
系统内存耗尽时触发，根据 &lt;code&gt;oom_score&lt;/code&gt;（受 &lt;code&gt;/proc/[pid]/oom_adj&lt;/code&gt; 调节）打分，分数最高者被杀。可通过 &lt;code&gt;echo -17 &amp;gt; /proc/[pid]/oom_adj&lt;/code&gt; 禁止被杀（仅对特定关键进程）。&lt;/p&gt;
&lt;h3&gt;ulimit&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;ulimit 什么作用？&lt;/strong&gt;
ulimit 是 Linux 系统中用于控制 Shell 程序资源限制的内建命令。允许用户查看或设置当前会话的资源限制，包括文件大小、内存使用、CPU 时间等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linux 下 ulimit 的 soft limit 和 hard limit 区别？&lt;/strong&gt;
soft 当前生效值（进程可主动修改，最多涨到hard），hard 系统硬上限（只有 root 能改）。生产常见坑：&lt;code&gt;nofile&lt;/code&gt;（最大文件句柄数）未调大导致&quot;Too many open files&quot;。&lt;/p&gt;
&lt;h3&gt;LVM&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;LVM是什么？基本概念？&lt;/strong&gt;
Logical Volume Manager，在线调整分区大小无需停机。三层：PV（物理卷）→ VG（卷组）→ LV（逻辑卷）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LVM常用操作命令？&lt;/strong&gt;
&lt;code&gt;pvcreate&lt;/code&gt;创建物理卷，&lt;code&gt;vgcreate&lt;/code&gt;创建卷组，&lt;code&gt;lvcreate&lt;/code&gt;创建逻辑卷，&lt;code&gt;vgextend&lt;/code&gt;扩展卷组，&lt;code&gt;lvextend&lt;/code&gt;扩展逻辑卷。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LVM 在线扩容完整流程？（以虚拟机扩容为例）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;最佳实践&lt;/strong&gt;：生产环境一般不动现有磁盘/分区，而是作为新磁盘加入。
&lt;strong&gt;流程&lt;/strong&gt;：虚拟层扩盘 → OS层执行rescan → 确认lsblk → PV/VG/LV操作 → xfs_growfs/resize2fs → df验证&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;虚拟化层操作&lt;/strong&gt;：在虚拟机管理平台（如VMware/vCenter）中加新磁盘。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OS层发现新设备&lt;/strong&gt;：扫描SCSI总线 &lt;code&gt;echo &quot;- - -&quot; &amp;gt; /sys/class/scsi_host/host0/scan&lt;/code&gt; 或重启（生产慎用）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;确认识别新容量&lt;/strong&gt;：用 &lt;code&gt;lsblk&lt;/code&gt; （list block）确认新容量已识别。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PV阶段&lt;/strong&gt;：&lt;code&gt;pvcreate /dev/sdb&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VG阶段&lt;/strong&gt;：&lt;code&gt;vgextend vg_data /dev/sdb&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LV阶段&lt;/strong&gt;：&lt;code&gt;lvextend -l +100%FREE /dev/vg_data/lv_data&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文件系统层&lt;/strong&gt;：&lt;code&gt;resize2fs&lt;/code&gt;（ext4）或 &lt;code&gt;xfs_growfs&lt;/code&gt;（xfs）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;确认扩容&lt;/strong&gt;：&lt;code&gt;df -h&lt;/code&gt; 验证扩容完成&lt;/li&gt;
&lt;li&gt;注意：缩减（reduce）极其危险且需离线，生产禁用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;**传统扩容方法 / 给机器加一块磁盘，如何识别？**OS 层执行 rescan → 确认 lsblk → PV/VG/LV 操作 → mkfs → mount → df 验证 → fstab 永久挂载 → mount -a 验证。详细说明可参考 &lt;a href=&quot;https://blog-l7wd3.pages.dev/lvm/&quot;&gt;一文讲通 LVM 与传统扩容的异同&lt;/a&gt;。&lt;/p&gt;
&lt;h3&gt;磁盘与I/O&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;如何查看磁盘空间？&lt;/strong&gt;
&lt;code&gt;df -h&lt;/code&gt; 查看分区使用；&lt;code&gt;du -sh *&lt;/code&gt; 查看目录大小。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何排查磁盘I/O瓶颈？&lt;/strong&gt;
&lt;code&gt;iostat -x 1&lt;/code&gt; 查看I/O负载；&lt;code&gt;iotop&lt;/code&gt; 查看进程I/O。&lt;/p&gt;
&lt;h2&gt;4. 网络&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;如何查看网络连接和监听端口？&lt;/strong&gt;
&lt;code&gt;netstat -tunlp&lt;/code&gt; 或 &lt;code&gt;ss -tunlp&lt;/code&gt;（ss更快）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;netstat 常用参数 / -tunlp 分别代表什么&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;-a (--all)&lt;/strong&gt;: 显示所有的网络连接和监听端口。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-t (--tcp)&lt;/strong&gt;: 仅显示TCP连接。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-u (--udp)&lt;/strong&gt;: 仅显示UDP连接。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-n (--numeric)&lt;/strong&gt;: 显示IP地址和端口号，而不是尝试解析域名和服务名。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-l (--listen)&lt;/strong&gt;: 显示监听中的端口&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-p (--programs)&lt;/strong&gt;: 显示哪个进程正在使用哪个套接字或网络端口。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-x (--unix)&lt;/strong&gt;: 仅显示Unix域套接字连接。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-r (--route)&lt;/strong&gt;: 显示路由表。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-i (--interfaces)&lt;/strong&gt;: 显示网络接口信息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-s (--statistics)&lt;/strong&gt;: 显示网络协议的统计数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;如何抓包/监听80端口数据？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tcpdump -i eth0 port 80 -w capture.pcap&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-i：指定接口&lt;/li&gt;
&lt;li&gt;-w：保存到文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;如何测试网络连通性？&lt;/strong&gt;
&lt;code&gt;ping&lt;/code&gt; 测试连通性；&lt;code&gt;telnet&lt;/code&gt;/&lt;code&gt;nc&lt;/code&gt; 测试端口。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何追踪数据包？&lt;/strong&gt;
&lt;code&gt;tracert&lt;/code&gt; 追踪数据包经过的路由路径，一层层显示路径。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;常见的TCP内核参数调优（sysctl）？&lt;/strong&gt;
&lt;code&gt;net.ipv4.tcp_tw_reuse=1&lt;/code&gt;（允许复用TIME_WAIT）、&lt;code&gt;net.ipv4.tcp_fin_timeout=30&lt;/code&gt;（缩短FIN超时）、&lt;code&gt;net.core.somaxconn=65535&lt;/code&gt;（监听队列最大长度，Nginx配合backlog）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何配置IP？&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 持久化配置
# Ubuntu 系统，可以调整 /etc/network/interface
iface eth0 inet static
    address 192.168.1.100
    netmask 255.255.255.0
    gateway 192.168.1.1
# 然后重启网络服务
sudo systemctl restart networking
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;如何配置DNS？&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo sh -c &apos;echo &quot;nameserver 8.8.8.8&quot; &amp;gt;&amp;gt; /etc/resolv.conf&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;如何查看IP/DNS？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IP 看 &lt;code&gt;ip addr&lt;/code&gt; 的 eth0，DNS 看 &lt;code&gt;cat /etc/resolv.conf&lt;/code&gt;  下的 nameserver&lt;/li&gt;
&lt;li&gt;DNS 常规为8.8.8.8，阿里云ECS默认100.100.2.136或138&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5. 系统管理与启动&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Linux系统从开机到登录的启动流程？&lt;/strong&gt;
上电复位 → BIOS/UEFI自检 → 引导加载程序（GRUB，GNU GRand Unified &lt;strong&gt;Bootloader&lt;/strong&gt;）→ 内核加载 → 挂载根文件系统 → init进程（Systemd）→ 运行级别（SysV）/目标（systemd） → 用户登录。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Load Average是什么？怎么看？&lt;/strong&gt;
系统平均负载，表示单位时间内处于运行或不可中断状态的进程数。&lt;code&gt;top&lt;/code&gt;或&lt;code&gt;uptime&lt;/code&gt;查看三个时间点（1/5/15分钟）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何排查服务器性能瓶颈？&lt;/strong&gt;
top看整体负载 → vmstat看CPU/内存/swap → iostat看磁盘I/O → netstat/iftop看网络。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;什么是服务？服务和进程区别？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;进程是操作系统资源调度的单位；服务是&quot;被托管、可启停、可自愈、有生命周期管理&quot;的长期运行进程，在后台持续运行、独立于用户会话，通常称为“守护进程”（Daemon）。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;进程 Process&lt;/th&gt;
&lt;th&gt;服务 Service&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;定义&lt;/td&gt;
&lt;td&gt;正在运行的程序实例&lt;/td&gt;
&lt;td&gt;被 init/systemd/管理器托管的长期进程&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;管理方&lt;/td&gt;
&lt;td&gt;内核&lt;/td&gt;
&lt;td&gt;systemd / SysV / supervisor / k8s 等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;生命周期&lt;/td&gt;
&lt;td&gt;手动起、手动死&lt;/td&gt;
&lt;td&gt;有 start/stop/restart/reload&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;开机自启&lt;/td&gt;
&lt;td&gt;不保证&lt;/td&gt;
&lt;td&gt;可 enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;崩溃自愈&lt;/td&gt;
&lt;td&gt;不会&lt;/td&gt;
&lt;td&gt;可自动重启（Restart=always）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;状态查询&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ps&lt;/code&gt; / &lt;code&gt;pgrep&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;systemctl status&lt;/code&gt; / &lt;code&gt;supervisorctl status&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;日志&lt;/td&gt;
&lt;td&gt;stdout / 文件&lt;/td&gt;
&lt;td&gt;journald / 统一日志&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;依赖管理&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;&lt;code&gt;After=&lt;/code&gt; / &lt;code&gt;Requires=&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;典型例子&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bash&lt;/code&gt;、&lt;code&gt;vim&lt;/code&gt;、一个 &lt;code&gt;python xx.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nginx.service&lt;/code&gt;、&lt;code&gt;sshd.service&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Systemd与Init的区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Systemd并行启动、按需启动、支持socket/DBus激活；&lt;/li&gt;
&lt;li&gt;SysV init串行启动，依赖 &lt;code&gt;/etc/init.d&lt;/code&gt; 目录下的脚本。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;如何查看服务？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Systemd 服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl --type=service
systemctl status xxx 看具体服务
systemctl start/restart/stop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SysV 服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;service --status-all
service xxx status
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6. 其他/操作系统&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;进程/线程区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;内存分配
&lt;ul&gt;
&lt;li&gt;进程：资源分配的基本单位，拥有独立的内存空间&lt;/li&gt;
&lt;li&gt;线程：CPU调度的基本单位，共享进程的资源&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;切换开销
&lt;ul&gt;
&lt;li&gt;进程：大，有独立代码和数据段&lt;/li&gt;
&lt;li&gt;线程：小，只维护独立的堆栈和程序计数器&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;稳定性
&lt;ul&gt;
&lt;li&gt;进程：隔离性更强，某个进程崩溃不会影响其他进程&lt;/li&gt;
&lt;li&gt;线程：弱，线程共享进程资源，崩溃可能导致整个进程异常&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;安全性
&lt;ul&gt;
&lt;li&gt;进程：有独立内存空间，安全性高&lt;/li&gt;
&lt;li&gt;线程：共享内存空间，存在数据竞争和线程安全问题，需要同步/互斥机制&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;补充：MySQL 多线程，PostgreSQL/Oracle 多线程&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;并发/并行区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;并发（Concurrency）&lt;/strong&gt;：&lt;strong&gt;逻辑上的“同时”&lt;/strong&gt;。单核CPU通过时间片轮转快速切换，看起来像是同时处理多个任务，本质是交替执行（强调结构，处理多件事）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并行（Parallelism）&lt;/strong&gt;：&lt;strong&gt;物理上的“同时”&lt;/strong&gt;。多核CPU在同一时刻真正地执行多个任务（强调执行，同时做多件事）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;死锁的四个条件&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;条件&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;th&gt;对应到 Java 或数据库&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;互斥&lt;/td&gt;
&lt;td&gt;某个资源同一时刻只能被一个执行单元占用&lt;/td&gt;
&lt;td&gt;&lt;code&gt;synchronized&lt;/code&gt; 锁对象、行级排他锁、独占文件锁&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;请求与保持（占有并等待）&lt;/td&gt;
&lt;td&gt;已经拿着一部分资源，同时继续等待其他资源&lt;/td&gt;
&lt;td&gt;线程持有 &lt;code&gt;resource1&lt;/code&gt; 时继续申请 &lt;code&gt;resource2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;非抢占&lt;/td&gt;
&lt;td&gt;资源不能被外部强行拿走，只能由持有者释放&lt;/td&gt;
&lt;td&gt;Java 内置锁不能被另一个线程直接剥夺&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;循环等待&lt;/td&gt;
&lt;td&gt;等待关系形成闭环&lt;/td&gt;
&lt;td&gt;线程 1 等线程 2，线程 2 又等线程 1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;用户态与内核态是什么？如何切换？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;用户态&lt;/strong&gt;：用户态下的程序只能访问受限的内存，不能直接访问硬件设备。用户态程序的执行权限较低，不能执行特权指令。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;内核态&lt;/strong&gt;：内核态下的程序可以访问所有的内存和硬件设备，具有最高的执行权限。内核态程序可以执行特权指令，如设置时钟、内存管理等。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用户态和内核态之间的切换是通过&lt;strong&gt;系统调用&lt;/strong&gt;、&lt;strong&gt;异常&lt;/strong&gt;和&lt;strong&gt;中断&lt;/strong&gt;来实现的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;系统调用&lt;/strong&gt;：用户态程序通过系统调用请求操作系统提供的服务，从而切换到内核态。例如，内存分配函数*malloc()&lt;em&gt;会调用&lt;/em&gt;sbrk()*系统调用，从而切换到内核态。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异常&lt;/strong&gt;：当CPU在执行用户态程序时发生异常（如缺页异常），会触发从用户态切换到内核态。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;中断&lt;/strong&gt;：当外围设备完成用户请求的操作后，会向CPU发出中断信号，CPU会暂停当前用户态程序的执行，转而执行中断处理程序，从而切换到内核态。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;听说过 CFS 吗？&lt;/strong&gt;
CFS（Completely Fair Scheduler，完全公平调度器）用于Linux系统中普通进程的调度。vruntime，红黑树结构，有利于交互式进程。&lt;a href=&quot;https://www.mianshiya.com/question/1863459885228146689&quot;&gt;听说过 CFS 吗？（Linux ） - 面试鸭 | 2026最新面试题+详细答案解析&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ps 常用参数&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-A：显示所有进程。&lt;/li&gt;
&lt;li&gt;-e：与 -A 效果相同，显示所有进程。&lt;/li&gt;
&lt;li&gt;-a：显示所有终端上的进程，包括其他用户的进程。&lt;/li&gt;
&lt;li&gt;-x：显示没有控制终端的进程。&lt;/li&gt;
&lt;li&gt;-u：以用户为主的格式显示进程信息。&lt;/li&gt;
&lt;li&gt;-f：显示完整格式的进程信息，包括 UID、PPID 等。&lt;/li&gt;
&lt;li&gt;-l：以长格式显示进程信息。&lt;/li&gt;
&lt;li&gt;-o：自定义输出格式，例如 ps -o pid,cmd 仅显示进程 ID 和命令。&lt;/li&gt;
&lt;li&gt;--sort：按指定字段排序，例如 --sort=-%cpu 按 CPU 使用率降序排列。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>【408】计算机网络</title><link>https://blog-l7wd3.pages.dev/posts/interview/408-network/</link><guid isPermaLink="true">https://blog-l7wd3.pages.dev/posts/interview/408-network/</guid><description>面试速记版 计算机网络 八股</description><pubDate>Sat, 01 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;部分内容来源于 &lt;a href=&quot;https://javaguide.cn/cs-basics/&quot;&gt;Java-Guide&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;基础&lt;/h2&gt;
&lt;h3&gt;分层模型&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;OSI七层模型与TCP/IP四层模型分别是什么？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OSI七层：物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。&lt;/li&gt;
&lt;li&gt;TCP/IP四层：网络接口层、网际层、传输层、应用层。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;每层功能？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;应用层：为用户提供服务&lt;/li&gt;
&lt;li&gt;表示层：数据表示（转换、加解密、解压缩）&lt;/li&gt;
&lt;li&gt;会话层：管理应用程序之间的会话&lt;/li&gt;
&lt;li&gt;传输层：主机通信（TCP/UDP）&lt;/li&gt;
&lt;li&gt;网络层：路由、寻址、IP&lt;/li&gt;
&lt;li&gt;数据链路层：帧编码、纠错、MAC地址&lt;/li&gt;
&lt;li&gt;物理层：网卡、光纤&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;计算机网络体系是怎么工作的？&lt;/h3&gt;
&lt;p&gt;三个&lt;strong&gt;核心原则&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;分层解耦（分工协作）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;每一层只干自己的活，不越界。比如传输层只关心端到端可靠性，不关心数据内容；应用层只关心业务逻辑，不关心数据怎么走光纤。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;好处&lt;/strong&gt;：各层独立升级（比如物理层从网线换光纤，应用层代码丝毫不用改）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对等通信（虚拟通信）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;虽然数据是物理上从上往下发、从下往上收，但&lt;strong&gt;逻辑上&lt;/strong&gt;，发送端的“网络层”觉得是在和接收端的“网络层”直接沟通（实际上中间隔着下层）。这种“对等层之间的协议”决定了整个体系的稳定性。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;封装与解封装（带信封装）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;发送方&lt;/strong&gt;：数据每往下一层，就包一层“信封”（头部 Header）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;接收方&lt;/strong&gt;：每往上一层，就拆一层“信封”。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;整个体系就是“数据不动，协议动”——用户数据本身没变过，每一层都在它外面加上了自己的控制信息（头部），直到变成比特流传输出去。&lt;/p&gt;
&lt;h2&gt;网络层&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;IP（Internet Protocol，网际协议）&lt;/strong&gt;：主要作用是定义数据包的格式、对数据包进行路由和寻址，以便它们可以跨网络传播并到达正确的目的地。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ARP（Address Resolution Protocol，地址解析协议）&lt;/strong&gt;，用于在局域网（LAN）中进行主机通信，是一种用于将网络层的地址转换为数据链路层地址的重要网络协议。
在TCP/IP网络中，ARP的主要功能是将IP地址转换为MAC地址。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ICMP（Internet Control Message Protocol，互联网控制报文协议）&lt;/strong&gt;：一种用于传输网络状态和错误消息的协议，常用于网络诊断和故障排除。例如，&lt;strong&gt;Ping 工具&lt;/strong&gt;就使用了 ICMP 协议来测试网络连通性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NAT（Network Address Translation，网络地址转换协议）&lt;/strong&gt;：NAT 协议的应用场景如同它的名称——网络地址转换，应用于内部网到外部网的地址转换过程中。具体地说，在一个小的子网（局域网，LAN）内，各主机使用的是同一个 LAN 下的 IP 地址，但在该 LAN 以外，在广域网（WAN）中，需要一个统一的 IP 地址来标识该 LAN 在整个 Internet 上的位置。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;传输层&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;TCP/UDP区别？&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;TCP&lt;/th&gt;
&lt;th&gt;UDP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;连接性&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;面向连接&lt;/td&gt;
&lt;td&gt;无连接&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;可靠性&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;可靠&lt;/td&gt;
&lt;td&gt;不可靠（尽力而为）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;状态维护&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;有状态&lt;/td&gt;
&lt;td&gt;无状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;传输效率&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;较低&lt;/td&gt;
&lt;td&gt;较高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;传输形式&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;面向字节流&lt;/td&gt;
&lt;td&gt;面向数据报（报文）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;头部开销&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;20 - 60 字节&lt;/td&gt;
&lt;td&gt;8 字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;通信模式&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;点对点（单播）&lt;/td&gt;
&lt;td&gt;单播、多播、广播&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;常见应用&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HTTP/HTTPS, FTP, SMTP, SSH&lt;/td&gt;
&lt;td&gt;DNS, DHCP, SNMP, TFTP, VoIP, 视频流&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;TCP三次握手的过程？&lt;/strong&gt;
客户端发送SYN → 服务端回复SYN+ACK → 客户端回复ACK，连接建立。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TCP四次挥手的过程？&lt;/strong&gt;
主动方发送FIN → 被动方回复ACK → 被动方发送FIN → 主动方回复ACK。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TIME_WAIT状态的作用？&lt;/strong&gt;
确保最后一个ACK能到达对方，让迟到的报文段有足够时间被丢弃。可通过&lt;code&gt;net.ipv4.tcp_tw_reuse&lt;/code&gt;允许复用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CLOSE_WAIT状态是什么？成因？&lt;/strong&gt;
被动关闭方收到FIN后回复ACK进入的状态，表示等待应用层调用close()。堆积说明程序没正确关闭连接。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TCP 如何保证可靠传输？&lt;/strong&gt;（重传/滑动窗口/拥塞控制）&lt;a href=&quot;https://javaguide.cn/cs-basics/network/tcp-reliability-guarantee.html#tcp-%E5%A6%82%E4%BD%95%E4%BF%9D%E8%AF%81%E4%BC%A0%E8%BE%93%E7%9A%84%E5%8F%AF%E9%9D%A0%E6%80%A7&quot;&gt;TCP 如何保证可靠传输？重传、滑动窗口与拥塞控制详解 | JavaGuide&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;应用层&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;应用层常见协议？基于TCP还是UDP？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HTTP（Hypertext Transfer Protocol，超文本传输协议）&lt;/strong&gt;：是一种用于传输超文本和多媒体内容的应用层协议，主要为 Web 客户端与服务器之间的通信而设计。HTTP/1.x 和 HTTP/2 通常基于 TCP，HTTP/3 则运行在基于 UDP 的 QUIC 之上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SMTP（Simple Mail Transfer Protocol，简单邮件发送协议）&lt;/strong&gt;：基于 TCP 协议，是一种用于发送电子邮件的协议。注意 ⚠️：SMTP 协议只负责邮件的发送，而不是接收。要从邮件服务器接收邮件，需要使用 POP3 或 IMAP 协议。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;POP3/IMAP（邮件接收协议）&lt;/strong&gt;：基于 TCP 协议，两者都是负责邮件接收的协议。IMAP 协议是比 POP3 更新的协议，它在功能和性能上都更加强大。IMAP 支持邮件搜索、标记、分类、归档等高级功能，而且可以在多个设备之间同步邮件状态。几乎所有现代电子邮件客户端和服务器都支持 IMAP。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FTP（File Transfer Protocol，文件传输协议）&lt;/strong&gt;：基于 TCP 协议，是一种用于在计算机之间传输文件的协议，可以屏蔽操作系统和文件存储方式。注意 ⚠️：FTP 是一种不安全的协议，因为它在传输过程中不会对数据进行加密。建议在传输敏感数据时使用更安全的协议，如 SFTP。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Telnet（远程登陆协议）&lt;/strong&gt;：基于 TCP 协议，用于通过一个终端登陆到其他服务器。Telnet 协议的最大缺点之一是所有数据（包括用户名和密码）均以明文形式发送，这有潜在的安全风险。这就是为什么如今很少使用 Telnet，而是使用一种称为 SSH 的非常安全的网络传输协议的主要原因。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSH（Secure Shell Protocol，安全的网络传输协议）&lt;/strong&gt;：基于 TCP 协议，通过加密和认证机制实现安全的访问和文件传输等业务&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RTP（Real-time Transport Protocol，实时传输协议）&lt;/strong&gt;：通常基于 UDP 协议，但也支持 TCP 协议。它提供了端到端的实时传输数据的功能，但不包含资源预留存、不保证实时传输质量，这些功能由 WebRTC 实现。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DNS（Domain Name System，域名管理系统）&lt;/strong&gt;：通常基于 UDP 协议（端口 53），用于解决域名和 IP 地址的映射问题。当响应数据过大或进行区域传送时会改用 TCP。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;HTTP状态码分类？&lt;/strong&gt;
1xx信息、2xx成功、3xx重定向、4xx客户端错误、5xx服务端错误。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;长连接与短连接的区别？&lt;/strong&gt;
短连接每次请求后断开；长连接保持连接复用（HTTP Keep-Alive），减少握手开销。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DNS解析的查询顺序？&lt;/strong&gt;
浏览器缓存 → 系统Hosts文件 → 本地DNS服务器 → 根域/顶级域递归查询。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HTTPS与HTTP的区别？&lt;/strong&gt;
HTTPS在HTTP下加TLS/SSL层，提供加密传输和身份认证。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HTTP/1.1 和 HTTP/2.0 有什么区别？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;多路复用（Multiplexing）&lt;/strong&gt;：HTTP/2.0 在同一连接上可以同时传输多个请求和响应（可以看作是 HTTP/1.1 中长链接的升级版本），互不干扰。HTTP/1.1 则使用串行方式，每个请求和响应都需要独立的连接，而浏览器为了控制资源会有 6-8 个 TCP 连接的限制。这使得 HTTP/2.0 在处理多个请求时更加高效，减少了网络延迟和提高了性能。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;二进制帧（Binary Frames）&lt;/strong&gt;：HTTP/2.0 使用二进制帧进行数据传输，而 HTTP/1.1 则使用文本格式的报文。二进制帧更加紧凑和高效，减少了传输的数据量和带宽消耗。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;队头阻塞&lt;/strong&gt;：HTTP/2 引入了多路复用技术，允许多个请求和响应在单个 TCP 连接上并行交错传输，解决了 HTTP/1.1 应用层的队头阻塞问题，但 HTTP/2 依然受到 TCP 层队头阻塞的影响。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;头部压缩（Header Compression）&lt;/strong&gt;：HTTP/1.1 支持 &lt;code&gt;Body&lt;/code&gt; 压缩，&lt;code&gt;Header&lt;/code&gt; 不支持压缩。HTTP/2.0 支持对 &lt;code&gt;Header&lt;/code&gt; 压缩，使用了专门为 &lt;code&gt;Header&lt;/code&gt; 压缩而设计的 HPACK 算法，减少了网络开销。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务器推送（Server Push）&lt;/strong&gt;：HTTP/2.0 支持服务器推送，可以在客户端请求一个资源时，将其他相关资源一并推送给客户端，从而减少了客户端的请求次数和延迟。而 HTTP/1.1 需要客户端自己发送请求来获取相关资源。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;HTTP请求从输入URL到页面展示的完整流程？&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;浏览器解析 URL 并检查缓存&lt;/strong&gt;：浏览器解析 URL 的各组成部分，并检查 HTTP 缓存（强缓存、协商缓存）是否已有该资源的有效副本。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DNS 解析&lt;/strong&gt;：浏览器通过 DNS 协议（Hosts→本地DNS→递归查询），获取域名对应的 IP 地址。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;建立传输连接&lt;/strong&gt;：HTTP/1.1 和 HTTP/2 通常先通过 TCP 三次握手建立连接；HTTP/3 则建立基于 UDP 的 QUIC 连接。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;建立安全通道（HTTPS）&lt;/strong&gt;：HTTP/1.1 和 HTTP/2 通常在 TCP 建连后进行 TLS 握手；HTTP/3 在 QUIC 建连过程中集成 TLS 1.3，完成密钥协商和服务器身份验证。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;发送 HTTP 请求&lt;/strong&gt;：浏览器在连接上向服务器发送 HTTP 请求报文，请求获取网页内容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务器处理并返回响应&lt;/strong&gt;：服务器收到请求后处理并返回 HTTP 响应报文。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;浏览器解析与渲染&lt;/strong&gt;：浏览器解析 HTML、CSS，执行 JavaScript，并加载页面中引用的其他资源（图片、字体等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;连接管理&lt;/strong&gt;：页面加载完成后，连接根据 keep-alive 策略复用或关闭。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;从OSI七层模型的角度看每一层做了什么：&lt;/p&gt;
&lt;p&gt;第一阶段：发送请求（应用层 → 物理层）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;应用层&lt;/strong&gt;：浏览器解析出协议（HTTP/HTTPS）、域名（如 &lt;code&gt;www.baidu.com&lt;/code&gt;）和路径。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;表示层&lt;/strong&gt;：对数据进行“翻译”和“加密”。如果是 HTTPS，在此层进行 TLS/SSL 握手和加解密；同时将字符编码统一（如 UTF-8）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;会话层&lt;/strong&gt;：建立、管理、维持本次通信的会话连接（Session）。虽然 HTTP 是无状态的，但此层负责确保断线重连时能续传。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;传输层&lt;/strong&gt;：通过 DNS 解析得到目标 IP 后，选择 &lt;strong&gt;TCP&lt;/strong&gt; 或 &lt;strong&gt;UDP&lt;/strong&gt; 协议。将数据切成数据段（Segment），并封装上&lt;strong&gt;源端口&lt;/strong&gt;和&lt;strong&gt;目标端口&lt;/strong&gt;（80/443）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网络层&lt;/strong&gt;：添加 &lt;strong&gt;IP 头部&lt;/strong&gt;（源 IP 和 目标 IP）。通过路由算法查询下一跳地址，决定数据包走哪条路到达服务器。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据链路层&lt;/strong&gt;：添加 &lt;strong&gt;MAC 地址&lt;/strong&gt;（源 MAC 和下一跳网关的 MAC）。通过 ARP 协议（地址解析协议）获取下一跳路由器的物理地址。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;物理层&lt;/strong&gt;：将数据帧转化为二进制 0/1 的&lt;strong&gt;比特流&lt;/strong&gt;，通过网线、光纤或 Wi-Fi 的电磁波发送出去。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第二阶段：接收响应（物理层 → 应用层）&lt;strong&gt;从下往上&lt;/strong&gt;逐层拆包（剥洋葱）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;物理层&lt;/strong&gt;：接收电信号/光信号，还原成比特流。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据链路层&lt;/strong&gt;：检查 MAC 地址是否匹配，拆掉 MAC 头部，交由上层。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网络层&lt;/strong&gt;：检查 IP 地址是否匹配，拆掉 IP 头部，交由上层。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;传输层&lt;/strong&gt;：拆掉 TCP 头部，&lt;strong&gt;回传 ACK 确认包&lt;/strong&gt;（三次握手的最后一步），并把乱序的数据包重排好，交给应用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;会话/表示层&lt;/strong&gt;：解密（HTTPS）、解压数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;应用层&lt;/strong&gt;：解析 HTTP 响应报文（状态码 200、HTML 内容），浏览器开始渲染引擎&lt;strong&gt;解析 HTML、加载 CSS/JS&lt;/strong&gt;，最终呈现出你看到的网页。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item></channel></rss>