<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>TAMAKARA&apos;s Blog</title><description>No description</description><link>https://tamakara.top/</link><language>zh_CN</language><item><title>云计算：云服务器与云存储</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E4%BA%91%E8%AE%A1%E7%AE%97%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8E%E4%BA%91%E5%AD%98%E5%82%A8/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E4%BA%91%E8%AE%A1%E7%AE%97%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8E%E4%BA%91%E5%AD%98%E5%82%A8/</guid><description>介绍云服务器、云网络、云存储和常见访问控制，配合基础部署与排障思路。</description><pubDate>Mon, 14 Sep 2026 05:33:17 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;云计算并不是“把服务器放到网上”这么简单，而是把计算、网络、存储、安全和流量管理等基础设施能力抽象成可以按需创建和管理的资源。&lt;/p&gt;
&lt;p&gt;本文主要从运维视角理解公有云中的 &lt;strong&gt;ECS、VPC、Subnet、Route Table、安全组、SLB、NAT Gateway、块存储、对象存储、文件存储&lt;/strong&gt;，并最终将这些组件组合成一个可以实际运行的 Web 应用架构。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;一、什么是云计算&lt;/h1&gt;
&lt;h2&gt;1.1 云计算&lt;/h2&gt;
&lt;p&gt;传统服务器部署通常需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;购买物理服务器
      ↓
机房
      ↓
网络
      ↓
电源
      ↓
操作系统
      ↓
应用
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而云计算将这些基础设施能力抽象为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Compute
Network
Storage
Security
Load Balancing
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用户通过控制台、API 或 CLI 创建资源：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User
 │
 ▼
Cloud API / Console
 │
 ├── Compute
 ├── Network
 ├── Storage
 └── Security
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此，云计算本质上是一种：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;按需获取计算资源
+
通过网络管理资源
+
按使用规模进行弹性配置
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的基础设施模式。&lt;/p&gt;
&lt;h2&gt;1.2 公有云&lt;/h2&gt;
&lt;p&gt;公有云是由云服务提供商建设并运营的云平台。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Alibaba Cloud
AWS
Microsoft Azure
Google Cloud
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用户不需要自己建设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;机房
物理服务器
交换机
存储设备
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是直接使用云厂商提供的资源。&lt;/p&gt;
&lt;p&gt;例如在阿里云中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS
VPC
SLB
NAT Gateway
OSS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;共同组成云上的基础设施。&lt;/p&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS
→ 计算

VPC
→ 网络

SLB
→ 流量分发

NAT Gateway
→ 出口访问

OSS
→ 对象存储
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;1.3 IaaS、PaaS、SaaS&lt;/h2&gt;
&lt;p&gt;云计算服务通常可以按抽象程度分为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IaaS
PaaS
SaaS
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;IaaS&lt;/h3&gt;
&lt;p&gt;IaaS（Infrastructure as a Service）提供比较底层的基础设施能力。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;虚拟机
网络
磁盘
负载均衡
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用户仍然需要负责：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;操作系统
软件
应用
数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS
EC2
Azure Virtual Machines
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;PaaS&lt;/h3&gt;
&lt;p&gt;PaaS 在基础设施之上进一步托管：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;运行环境
中间件
数据库
容器平台
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用户更加关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;虚拟机
操作系统
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;SaaS&lt;/h3&gt;
&lt;p&gt;SaaS 则直接提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;可使用的软件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;在线办公系统
邮件服务
在线 CRM
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以简单理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IaaS
→ 我租基础设施

PaaS
→ 我主要部署应用

SaaS
→ 我直接使用软件
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二、云服务器&lt;/h1&gt;
&lt;h2&gt;2.1 ECS 是什么&lt;/h2&gt;
&lt;p&gt;不同云厂商名称不同。&lt;/p&gt;
&lt;p&gt;阿里云通常使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS
Elastic Compute Service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;AWS 对应常见的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EC2
Elastic Compute Cloud
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Azure 则使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Virtual Machines
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它们解决的问题基本相同：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;提供云上的虚拟计算机
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此可以抽象成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cloud Server
   │
   ├── CPU
   ├── Memory
   ├── OS
   ├── Disk
   └── Network
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如创建一个 ECS 后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS
 │
 ├── Ubuntu
 ├── 2 vCPU
 ├── 4 GB Memory
 ├── System Disk
 └── Private IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后就可以像管理普通 Linux 服务器一样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh root@&amp;lt;public-ip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;软件安装
服务部署
配置管理
日志排查
监控
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.2 实例规格&lt;/h2&gt;
&lt;p&gt;云服务器通常可以选择：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
Memory
Network
Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2 vCPU
4 GiB Memory
100 GB Disk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不同实例规格还可能对应：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU 型
Memory 型
计算型
通用型
网络增强型
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此购买云服务器时，不应该只看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU 核数
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还需要关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;内存
网络带宽
磁盘类型
IOPS
实例网络能力
价格
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.3 镜像&lt;/h2&gt;
&lt;p&gt;创建 ECS 时通常需要选择：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Image
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是服务器初始操作系统和软件环境的模板。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ubuntu
Debian
Rocky Linux
Alibaba Cloud Linux
Windows Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;整体过程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Image
   │
   ▼
Create ECS
   │
   ▼
Running Instance
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;镜像还可以来自：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;官方镜像
自定义镜像
市场镜像
共享镜像
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见运维场景：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;服务器 A
   │
   ▼
制作自定义镜像
   │
   ▼
服务器 B / C / D
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样可以快速复制基础环境。&lt;/p&gt;
&lt;h1&gt;三、云服务器磁盘&lt;/h1&gt;
&lt;h2&gt;3.1 系统盘与数据盘&lt;/h2&gt;
&lt;p&gt;云服务器一般至少涉及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;System Disk
Data Disk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS
 │
 ├── System Disk
 │      └── /
 │
 └── Data Disk
        └── /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;系统盘主要存放：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;操作系统
系统软件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据盘更适合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据库
业务文件
日志
应用数据
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.2 块存储&lt;/h2&gt;
&lt;p&gt;云平台的云盘通常属于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Block Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以把它理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;云上的虚拟硬盘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;操作系统看到的仍然类似：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/dev/vda
/dev/vdb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lsblk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vda
├── vda1
└── vda2

vdb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以进一步：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkfs.ext4 /dev/vdb
mkdir /data
mount /dev/vdb /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cloud Block Storage
       ↓
Virtual Disk
       ↓
Linux Filesystem
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.3 云盘类型&lt;/h2&gt;
&lt;p&gt;云平台通常会提供不同性能级别的云盘，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;普通型
高性能型
SSD
ESSD / Premium SSD
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;性能通常需要关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IOPS
Throughput
Latency
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此数据库服务器选磁盘时，不能只看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;500 GB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还需要关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IOPS
吞吐量
延迟
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;四、VPC 与云网络&lt;/h1&gt;
&lt;h2&gt;4.1 什么是 VPC&lt;/h2&gt;
&lt;p&gt;VPC（Virtual Private Cloud）可以理解为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;云平台中属于你的逻辑隔离网络。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;VPC
10.0.0.0/16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;里面可以继续划分：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Subnet A
10.0.1.0/24

Subnet B
10.0.2.0/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ECS：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS A
10.0.1.10

ECS B
10.0.2.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都位于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10.0.0.0/16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;范围内。&lt;/p&gt;
&lt;p&gt;阿里云官方将 VPC 定义为逻辑隔离的私有网络，ECS、SLB、RDS 等资源都可以部署其中。&lt;/p&gt;
&lt;p&gt;参考：
&lt;a href=&quot;https://www.alibabacloud.com/help/en/vpc/&quot;&gt;Alibaba Cloud VPC&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;4.2 为什么需要 VPC&lt;/h2&gt;
&lt;p&gt;没有网络隔离时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;所有服务器
   │
   ▼
同一个平面
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安全性和管理都会比较混乱。&lt;/p&gt;
&lt;p&gt;而 VPC 可以形成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  VPC
                   │
          ┌────────┴────────┐
          ▼                 ▼
      Public Subnet     Private Subnet
          │                 │
        SLB                 │
        Bastion             │
                            ├── App
                            ├── DB
                            └── Redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样可以把：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;对公网服务
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;和：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;内部服务
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分离开。&lt;/p&gt;
&lt;h1&gt;五、Subnet&lt;/h1&gt;
&lt;h2&gt;5.1 子网&lt;/h2&gt;
&lt;p&gt;Subnet 是 VPC 内部进一步划分的网络。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;VPC
10.0.0.0/16

├── Subnet A
│   10.0.1.0/24
│
├── Subnet B
│   10.0.2.0/24
│
└── Subnet C
    10.0.3.0/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不同云厂商可能使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Subnet
vSwitch
Subnet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等不同术语。&lt;/p&gt;
&lt;p&gt;在阿里云中常见：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;VPC
  ↓
vSwitch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;vSwitch 是 VPC 中进一步划分的网络资源。&lt;/p&gt;
&lt;h2&gt;5.2 公网子网与私网子网&lt;/h2&gt;
&lt;p&gt;从架构设计角度经常会使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Public Subnet
Private Subnet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                Internet
                    │
                    ▼
             Public Subnet
                    │
                   SLB
                    │
          ┌─────────┴─────────┐
          ▼                   ▼
      Private Subnet      Private Subnet
          │                   │
        App 1                App 2
          │                   │
          └─────────┬─────────┘
                    ▼
                 Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SLB
→ 对外提供入口

App
→ 私网运行

DB
→ 更加严格限制访问
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;六、Route Table&lt;/h1&gt;
&lt;h2&gt;6.1 路由表是什么&lt;/h2&gt;
&lt;p&gt;云 VPC 中的 Route Table 决定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据包应该往哪里走
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10.0.0.0/16
→ local

0.0.0.0/0
→ Internet / NAT Gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Destination
       │
       ▼
Route Table
       │
       ▼
Next Hop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;阿里云官方将路由表描述为指导 VPC 流量转发的网络路径配置，并通过路由条目决定流量的下一跳。 (&lt;a href=&quot;https://www.alibabacloud.com/help/en/vpc/vpc-route-table/&quot;&gt;alibabacloud.com&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;6.2 默认路由&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.0.0.0/0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;代表：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;所有 IPv4 目的地址
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.0.0.0/0
→ NAT Gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就可以让私网资源通过 NAT 出网。&lt;/p&gt;
&lt;h2&gt;6.3 路由与安全组不是一回事&lt;/h2&gt;
&lt;p&gt;一个非常重要的区别：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Route Table
→ “流量往哪里走？”

Security Group
→ “允许不允许？”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Route Table
→ 找得到 Database

Security Group
→ 不允许 5432
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终仍然：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;连接失败
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此云网络排障一定要把：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Routing
Security
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分开看。&lt;/p&gt;
&lt;h1&gt;七、云安全组与 ACL&lt;/h1&gt;
&lt;h2&gt;7.1 Security Group&lt;/h2&gt;
&lt;p&gt;安全组是一种与云资源关联的网络访问控制机制。&lt;/p&gt;
&lt;p&gt;可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS
 │
 └── Security Group
       ├── Inbound Rules
       └── Outbound Rules
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;允许：
22/tcp
80/tcp
443/tcp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;拒绝：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;3306
5432
6379
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对公网开放的安全组应该尽量遵循：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;最小开放范围
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如 SSH：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.0.0.0/0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;意味着：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;任何公网地址都可能尝试访问
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果条件允许，更合理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;你的办公公网 IP
→ TCP 22
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7.2 Network ACL&lt;/h2&gt;
&lt;p&gt;不同云厂商的网络 ACL 能力和实现方式存在差异，但通常可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Subnet / Network level
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的访问控制。&lt;/p&gt;
&lt;p&gt;因此可以粗略区分：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Security Group
→ 资源 / 网卡层面的访问控制

Network ACL
→ 网络 / 子网层面的访问控制
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际规则模型需要根据具体云平台确认。&lt;/p&gt;
&lt;h2&gt;7.3 Security Group 与 Linux Firewall&lt;/h2&gt;
&lt;p&gt;云上通常存在多层安全控制：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Internet
   │
   ▼
Cloud Security Group
   │
   ▼
ECS Network
   │
   ▼
Linux Firewall
   │
   ▼
Application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;安全组放行
≠
Linux 防火墙一定放行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;反过来也一样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Linux Firewall 放行
≠
安全组一定放行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也是云上 Linux 排障最常见的问题之一。&lt;/p&gt;
&lt;h1&gt;八、云负载均衡 SLB / ELB&lt;/h1&gt;
&lt;h2&gt;8.1 为什么需要负载均衡&lt;/h2&gt;
&lt;p&gt;假设只有一台 Web Server：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client
  │
  ▼
Web Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当服务器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;宕机
流量过大
升级维护
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;整个业务可能受到影响。&lt;/p&gt;
&lt;p&gt;增加多个服务器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;              Load Balancer
                    │
          ┌─────────┼─────────┐
          ▼         ▼         ▼
        Web 1     Web 2     Web 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Load Balancer 负责将流量分发到后端。&lt;/p&gt;
&lt;p&gt;阿里云目前使用 SLB（Server Load Balancer）作为其负载均衡服务总称，并包含 ALB、NLB、CLB 等不同类型。 (&lt;a href=&quot;https://www.alibabacloud.com/help/en/cloud-network-well-architected-design/ecs-application-delivery-network-design&quot;&gt;alibabacloud.com&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;AWS 常见对应产品：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ELB
 ├── ALB
 └── NLB
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8.2 四层与七层&lt;/h2&gt;
&lt;p&gt;负载均衡大致可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;L4
L7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;来理解。&lt;/p&gt;
&lt;h3&gt;L4&lt;/h3&gt;
&lt;p&gt;根据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP
Port
TCP
UDP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进行流量转发。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP :80
TCP :443
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;L7&lt;/h3&gt;
&lt;p&gt;可以进一步理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
HTTPS
Host
Path
Header
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;example.com/api
       ↓
API Service

example.com/
       ↓
Web Service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;L4
→ TCP / UDP

L7
→ HTTP / HTTPS
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8.3 后端服务器&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SLB
 │
 ├── ECS 1
 ├── ECS 2
 └── ECS 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SLB 需要知道：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;哪些实例可以接收流量
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此通常配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Backend Server
Backend Pool
Listener
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8.4 健康检查&lt;/h2&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;已经：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;宕机
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但负载均衡仍然把请求发送给它，就会出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;请求失败
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Health Check
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET /health
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP 200
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;认为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Healthy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;否则：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Unhealthy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;流量就不再发送给异常实例。&lt;/p&gt;
&lt;h2&gt;8.5 负载均衡并不等于高可用&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SLB
 │
 └── 1 ECS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 ECS 挂了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SLB
 ↓
没有健康后端
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;仍然无法提供服务。&lt;/p&gt;
&lt;p&gt;因此完整高可用通常需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Load Balancer
+
Multiple Backend Instances
+
Health Check
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进一步还需要考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Multi-AZ
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等架构。&lt;/p&gt;
&lt;h1&gt;九、云 NAT Gateway 与公网访问&lt;/h1&gt;
&lt;h2&gt;9.1 为什么需要 NAT&lt;/h2&gt;
&lt;p&gt;很多应用服务器不应该拥有公网 IP：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Internet
   X
App Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但它们可能需要访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;软件仓库
API
镜像仓库
NTP
第三方服务
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时候可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Private ECS
      │
      ▼
NAT Gateway
      │
      ▼
Internet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是说：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;私网服务器
→ 通过 NAT 出网
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;云厂商官方文档也将 NAT Gateway 用于让私网资源进行 Internet-bound outbound connectivity，并与入站负载均衡形成不同的流量方向。 (&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateNatGateway.html?utm_source=chatgpt.com&quot;&gt;aws.amazon.com&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;9.2 SNAT&lt;/h2&gt;
&lt;p&gt;SNAT（Source Network Address Translation）修改：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;源 IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10.0.1.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问公网：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;8.8.8.8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;经过 NAT：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10.0.1.10
   ↓
203.0.113.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;公网看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;203.0.113.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Private IP
   ↓
NAT
   ↓
Public IP
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;9.3 NAT Gateway 主要解决出站&lt;/h2&gt;
&lt;p&gt;典型架构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                Internet
                    │
                    ▲
                    │
                NAT Gateway
                    ▲
                    │
            Private Subnet
                    │
             ┌──────┴──────┐
             ▼             ▼
           App 1         App 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;App → Internet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以通过 NAT。&lt;/p&gt;
&lt;p&gt;但：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Internet → App
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不会因为 App 使用 NAT 就自然成立。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NAT Gateway 的出站能力不能简单等同于公网入站能力。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;9.4 公网 IP&lt;/h2&gt;
&lt;p&gt;云服务器常见两种 IP：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Private IP
Public IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;私网：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10.x.x.x
172.16.x.x
192.168.x.x
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;公网：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Internet-routable Address
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;生产环境中更推荐：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用服务器
→ Private IP

公网入口
→ SLB / CDN / Gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;每台 ECS
→ 一个公网 IP
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十、云存储&lt;/h1&gt;
&lt;p&gt;云存储主要可以分为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Block Storage
Object Storage
File Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;三种类型解决的问题并不相同。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;              Cloud Storage
                    │
        ┌───────────┼───────────┐
        ▼           ▼           ▼
      Block       Object       File
        │           │           │
      Cloud       OSS/S3      NAS/EFS
       Disk
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十一、块存储&lt;/h1&gt;
&lt;h2&gt;11.1 Block Storage&lt;/h2&gt;
&lt;p&gt;块存储最接近传统硬盘。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS
 │
 └── Block Disk
       │
       ▼
     /dev/vdb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Linux 需要进一步：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkfs
mount
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;才能使用文件系统。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo mkfs.ext4 /dev/vdb
sudo mkdir /data
sudo mount /dev/vdb /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;适合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;操作系统
数据库
应用数据
高 I/O 工作负载
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见云厂商：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Alibaba Cloud → ESSD / Cloud Disk
AWS → EBS
Azure → Managed Disks
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;11.2 块存储的特点&lt;/h2&gt;
&lt;p&gt;可以把它理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“云上的硬盘”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;文件系统
权限
目录
挂载
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等仍然主要由操作系统负责。&lt;/p&gt;
&lt;h1&gt;十二、对象存储&lt;/h1&gt;
&lt;h2&gt;12.1 Object Storage&lt;/h2&gt;
&lt;p&gt;对象存储和块存储完全不同。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Bucket
 │
 ├── image/a.jpg
 ├── image/b.png
 ├── video/demo.mp4
 └── backup/db.sql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Bucket
→ 存储空间

Object
→ 一个对象
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;阿里云：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;OSS
Object Storage Service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;AWS：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;S3
Simple Storage Service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Azure：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Blob Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;12.2 对象存储访问方式&lt;/h2&gt;
&lt;p&gt;对象存储通常通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP / HTTPS API
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
   │
   │ HTTPS
   ▼
Object Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mount /dev/xxx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Block Storage
→ 类似磁盘

Object Storage
→ 类似通过 API 操作对象
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;12.3 对象存储的典型场景&lt;/h2&gt;
&lt;p&gt;非常适合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;图片
视频
备份
日志归档
安装包
静态资源
数据集
模型文件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如 Web 应用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User
  │
  ▼
Application
  │
  ├── Metadata → Database
  │
  └── Image → OSS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就不需要把大量图片直接塞进数据库。&lt;/p&gt;
&lt;h2&gt;12.4 Bucket&lt;/h2&gt;
&lt;p&gt;对象存储通常以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Bucket
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;作为逻辑存储空间。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;my-app-prod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;里面：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;images/
videos/
backups/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以通过权限控制决定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;谁可以读
谁可以写
谁可以删除
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十三、文件存储&lt;/h1&gt;
&lt;h2&gt;13.1 File Storage&lt;/h2&gt;
&lt;p&gt;文件存储提供共享文件系统。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Server A ─┐
Server B ─┼── File Storage
Server C ─┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;多个服务器可以访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/shared
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这和：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Block Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的最大区别之一是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;多个主机共享访问
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;云平台中常见：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Alibaba Cloud NAS
AWS EFS
Azure Files
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;13.2 文件存储适合什么&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;共享目录
上传文件
多实例共享文件
媒体文件
用户 Home
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型 Web 集群：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;          Load Balancer
                │
       ┌────────┼────────┐
       ▼        ▼        ▼
      App1     App2     App3
       │        │        │
       └────────┼────────┘
                ▼
          Shared File
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样三个实例都可以访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/shared/uploads
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十四、三类云存储对比&lt;/h1&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Block&lt;/td&gt;
&lt;td&gt;块设备 / 文件系统&lt;/td&gt;
&lt;td&gt;OS、数据库、应用磁盘&lt;/td&gt;
&lt;td&gt;ESSD、EBS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object&lt;/td&gt;
&lt;td&gt;API / HTTP&lt;/td&gt;
&lt;td&gt;图片、视频、备份、归档&lt;/td&gt;
&lt;td&gt;OSS、S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File&lt;/td&gt;
&lt;td&gt;共享文件系统&lt;/td&gt;
&lt;td&gt;多实例共享文件&lt;/td&gt;
&lt;td&gt;NAS、EFS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;一句话：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Block
→ 像一块硬盘

Object
→ 像一个通过 API 访问的文件仓库

File
→ 像一个可以被多台机器挂载的共享目录
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十五、云存储中的备份&lt;/h1&gt;
&lt;p&gt;云上的存储并不意味着：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;天然不会丢数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;被误删除：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;实例删除
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果数据只存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;实例本地临时存储
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;仍然可能丢失。&lt;/p&gt;
&lt;p&gt;因此需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Backup
Snapshot
Object Storage
Replication
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等机制。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Database
   │
   ▼
Backup
   │
   ▼
OSS / S3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样即使：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS 故障
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Restore
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;恢复数据。&lt;/p&gt;
&lt;h1&gt;十六、云服务器快照&lt;/h1&gt;
&lt;p&gt;云平台通常提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Snapshot
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Disk
 │
 ▼
Snapshot
 │
 ▼
New Disk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以用于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;升级前备份
故障恢复
环境复制
镜像制作
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但要注意：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Snapshot
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;主要是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;基础设施层面的磁盘状态保护
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Database Backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;则更关注数据库一致性和逻辑恢复。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;云盘快照不能简单等同于数据库备份。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;十七、云安全架构&lt;/h1&gt;
&lt;p&gt;一个比较常见的 Web 架构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                         Internet
                            │
                            ▼
                           CDN
                            │
                            ▼
                           SLB
                            │
                  ┌─────────┴─────────┐
                  ▼                   ▼
             Private Subnet      Private Subnet
                  │                   │
                App 1               App 2
                  │                   │
                  └─────────┬─────────┘
                            ▼
                         Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;App
 │
 └── NAT Gateway
         │
         ▼
      Internet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CDN
→ 靠近用户缓存和加速内容

SLB
→ 分发请求

NAT
→ 私网资源出站

Security Group
→ 控制访问

VPC
→ 网络隔离
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些组件职责不同。&lt;/p&gt;
&lt;h1&gt;十八、云服务器部署完整 Web 应用&lt;/h1&gt;
&lt;p&gt;现在把前面的组件组合起来。&lt;/p&gt;
&lt;h2&gt;18.1 基础架构&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                     Internet
                         │
                         ▼
                        DNS
                         │
                         ▼
                       SLB
                         │
            ┌────────────┴────────────┐
            ▼                         ▼
        App ECS 1                 App ECS 2
        Private IP                Private IP
            │                         │
            └────────────┬────────────┘
                         ▼
                      Redis
                         │
                         ▼
                     Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;出口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;App ECS
   │
   ▼
NAT Gateway
   │
   ▼
Internet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;静态资源：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;App
 │
 └──► OSS
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十九、DNS&lt;/h1&gt;
&lt;p&gt;用户首先通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问网站。&lt;/p&gt;
&lt;p&gt;DNS：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;example.com
     │
     ▼
DNS Record
     │
     ▼
SLB Public IP / CNAME
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Browser
   │
   │ DNS
   ▼
SLB Address
   │
   ▼
Web Application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见 DNS 记录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A
AAAA
CNAME
MX
TXT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里最重要的是理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DNS
→ 名称解析

SLB
→ 流量接入
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两者不是同一个组件。&lt;/p&gt;
&lt;h1&gt;二十、Nginx&lt;/h1&gt;
&lt;p&gt;如果 App 不直接对公网提供 HTTP，可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SLB
  │
  ▼
Nginx
  │
  ▼
Application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nginx 可以负责：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;反向代理
TLS
静态资源
请求转发
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;example.com/api
        │
        ▼
      Nginx
        │
        ▼
    localhost:8080
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十一、数据库安全&lt;/h1&gt;
&lt;p&gt;数据库通常不应该：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Internet
   │
   ▼
Database:5432
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更合理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Internet
   │
   ▼
SLB
   │
   ▼
App
   │
   ▼
Private Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安全组：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DB
↑
只允许 App Security Group
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;App → TCP 5432 → DB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Internet → TCP 5432 → DB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不允许。&lt;/p&gt;
&lt;p&gt;这就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;分层网络
+
最小权限
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十二、一个完整云 Web 请求流程&lt;/h1&gt;
&lt;p&gt;用户访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;整个过程可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;① DNS
   │
   ▼
example.com
   │
   ▼
② CDN / SLB
   │
   ▼
③ Nginx
   │
   ▼
④ Application
   │
   ├──► Redis
   │
   ├──► Database
   │
   └──► OSS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果应用需要访问公网：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
     │
     ▼
NAT Gateway
     │
     ▼
Internet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此完整的云应用并不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;一台 ECS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DNS
 ↓
CDN / SLB
 ↓
ECS
 ↓
Database / Redis / OSS
 ↓
NAT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等多个基础设施组件共同组成。&lt;/p&gt;
&lt;h1&gt;二十三、云上 Linux 故障排查&lt;/h1&gt;
&lt;p&gt;云上故障排查最大的特点：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Linux 本身
+
云平台基础设施
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两个层次同时存在。&lt;/p&gt;
&lt;p&gt;例如用户访问失败：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Internet
   │
   ▼
DNS
   │
   ▼
SLB
   │
   ▼
Security Group
   │
   ▼
ECS
   │
   ▼
Linux Firewall
   │
   ▼
Nginx
   │
   ▼
Application
   │
   ▼
Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;任何一层异常都可能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;访问失败
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十四、实例问题&lt;/h1&gt;
&lt;p&gt;首先检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS 是否 Running
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
Memory
Disk
Network
System Status
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Linux 内部再：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;uptime
top
free -h
df -h
ss -lntp
systemctl status nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS = Running
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不代表：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Nginx = Running
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更不代表：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网站 = 正常
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十五、安全组问题&lt;/h1&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;浏览器
   ↓
ECS:8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;连接失败。&lt;/p&gt;
&lt;p&gt;先检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Security Group
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是否允许：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -lntp | grep 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;安全组允许
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Linux 服务没有监听
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;仍然无法访问。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cloud Firewall
+
Linux Firewall
+
Application Port
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要一起检查。&lt;/p&gt;
&lt;h1&gt;二十六、云网络故障&lt;/h1&gt;
&lt;p&gt;检查 VPC：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;VPC
 ↓
Subnet / vSwitch
 ↓
Route Table
 ↓
Security Group
 ↓
ECS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如私网服务器无法访问 Internet：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS
 ↓
Route Table
 ↓
NAT Gateway
 ↓
EIP
 ↓
Internet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;逐层检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;有没有默认路由？
NAT Gateway 是否存在？
NAT 规则是否正确？
EIP 是否正常？
安全策略是否允许？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;阿里云当前文档也强调，VPC 默认与 Internet 隔离，需要通过 EIP、NAT Gateway、SLB 等机制提供具体的公网访问能力。 (&lt;a href=&quot;https://www.alibabacloud.com/help/en/vpc/public-network-access/&quot;&gt;alibabacloud.com&lt;/a&gt;)&lt;/p&gt;
&lt;h1&gt;二十七、磁盘故障&lt;/h1&gt;
&lt;p&gt;云服务器常见：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;磁盘空间不足
磁盘 I/O 异常
文件系统损坏
数据盘未挂载
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;先：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df -h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df -i
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看磁盘：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lsblk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看挂载：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mount
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进一步：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iostat -xz 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果发现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/dev/vdb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;存在但没有挂载：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lsblk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以进一步判断：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;分区
文件系统
挂载点
/etc/fstab
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十八、服务故障&lt;/h1&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS
→ 正常

端口
→ 开放

Nginx
→ 无法启动
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;继续：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status nginx
journalctl -u nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nginx -t
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此云上 Linux 故障排查应该始终：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;云平台层
+
Linux 层
+
应用层
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一起考虑。&lt;/p&gt;
&lt;h1&gt;二十九、SLB 故障排查&lt;/h1&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户
 ↓
SLB
 ↓
ECS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问失败，可以依次检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DNS
 ↓
SLB Listener
 ↓
Backend Server
 ↓
Health Check
 ↓
Security Group
 ↓
ECS Port
 ↓
Application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Health Check = Unhealthy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时应该检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;端口
路径
协议
应用监听地址
安全组
Nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是优先怀疑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SLB 本身坏了
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;三十、NAT 故障排查&lt;/h1&gt;
&lt;p&gt;私网服务器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl https://example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;失败。&lt;/p&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Route Table
 ↓
NAT Gateway
 ↓
SNAT
 ↓
EIP
 ↓
Security Policy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在 Linux：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ip route
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确认默认路由。&lt;/p&gt;
&lt;p&gt;进一步：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -v https://example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DNS
TCP
TLS
HTTP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分别在哪一层失败。&lt;/p&gt;
&lt;h1&gt;三十一、云存储故障排查&lt;/h1&gt;
&lt;h2&gt;31.1 Block Storage&lt;/h2&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lsblk
df -h
mount
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确认：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;磁盘存在
分区存在
文件系统存在
挂载正常
空间足够
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;31.2 Object Storage&lt;/h2&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Endpoint
Bucket
Credentials
Network
Permission
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;AccessDenied
NoSuchBucket
Timeout
DNS failure
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以对象存储的问题通常不只是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“磁盘有没有挂载”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;API
+
网络
+
权限
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;31.3 File Storage&lt;/h2&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Mount Target
Network
Security Group
DNS
Mount Options
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Linux：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mount
df -h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果共享目录不可访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络
+
认证
+
挂载
+
后端文件存储
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要一起检查。&lt;/p&gt;
&lt;h1&gt;三十二、云上监控&lt;/h1&gt;
&lt;p&gt;到了云环境之后，监控通常分成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cloud Metrics
+
Linux Metrics
+
Application Metrics
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cloud
├── ECS CPU
├── Network
├── Disk
└── Load Balancer

Linux
├── Process
├── Memory
├── Filesystem
└── Socket

Application
├── QPS
├── Latency
└── Error Rate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;云厂商监控
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不能完全代替：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Prometheus
Grafana
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际生产环境很可能两者同时使用。&lt;/p&gt;
&lt;h1&gt;三十三、云计算与 Docker / Kubernetes&lt;/h1&gt;
&lt;p&gt;之前学习了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker
Kubernetes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在放到云上：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  Cloud
                    │
               VPC Network
                    │
        ┌───────────┼───────────┐
        ▼           ▼           ▼
       ECS         SLB        Storage
        │
        ▼
      Docker
        │
        ▼
   Kubernetes
        │
        ▼
      Pods
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;云平台提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Compute
Network
Storage
Load Balancer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker
→ 容器

Kubernetes
→ 容器编排
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;云计算提供基础设施，容器提供应用打包方式，Kubernetes 负责在这些基础设施上运行和管理容器化工作负载。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;三十四、云计算与 Ansible / CI/CD&lt;/h1&gt;
&lt;p&gt;前面还学习了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ansible
Jenkins
Docker
Kubernetes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在可以组成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git
 │
 ▼
Jenkins
 │
 ├── Build
 ├── Test
 └── Docker Image
        │
        ▼
     Registry
        │
        ▼
     Ansible
        │
        ▼
    Cloud ECS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git
 │
 ▼
Jenkins
 │
 ▼
Docker Image
 │
 ▼
Registry
 │
 ▼
Kubernetes
 │
 ▼
Cloud
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就已经非常接近真实的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;云上 DevOps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;体系。&lt;/p&gt;
&lt;h1&gt;三十五、一个典型公有云 Web 架构&lt;/h1&gt;
&lt;p&gt;综合前面的知识，可以建立一个比较完整的架构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                         Internet
                            │
                            ▼
                           DNS
                            │
                            ▼
                           CDN
                            │
                            ▼
                           SLB
                            │
              ┌─────────────┼─────────────┐
              ▼             ▼             ▼
           ECS App1      ECS App2      ECS App3
          Private IP     Private IP     Private IP
              │             │             │
              └─────────────┼─────────────┘
                            │
               ┌────────────┼────────────┐
               ▼            ▼            ▼
             Redis       Database       OSS
                            │
                         Backup
                            │
                            ▼
                       Object Storage

ECS App
   │
   ▼
NAT Gateway
   │
   ▼
Internet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安全控制：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Internet
   │
   ▼
SLB
   │
   ▼
Security Group
   │
   ▼
ECS
   │
   ▼
Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据库不直接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.0.0.0/0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;暴露到互联网。&lt;/p&gt;
&lt;h1&gt;三十六、云基础设施的核心关系&lt;/h1&gt;
&lt;p&gt;到这里可以把各个组件串成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  Cloud Platform
                        │
        ┌───────────────┼────────────────┐
        ▼               ▼                ▼
      Compute         Network          Storage
        │               │                │
       ECS              VPC              │
        │          ┌────┼────┐           │
        │          ▼    ▼    ▼           │
        │       Subnet Route SG           │
        │               │                │
        │              NAT              Block
        │               │               Object
        │              SLB               File
        │               │                │
        └───────────────┼────────────────┘
                        ▼
                    Application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以把它理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS
→ 计算在哪里运行

VPC
→ 网络在哪里运行

Subnet
→ 网络怎么划分

Route Table
→ 流量往哪里走

Security Group
→ 谁可以访问

SLB
→ 请求发给谁

NAT
→ 私网如何访问公网

Storage
→ 数据存在哪里
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;三十七、云上故障排查总模型&lt;/h1&gt;
&lt;p&gt;云上遇到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“网站打不开”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以建立固定思维：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    User Request
                         │
                         ▼
                        DNS
                         │
                         ▼
                     CDN / SLB
                         │
                         ▼
                    Load Balancer
                         │
                         ▼
                   Security Group
                         │
                         ▼
                        ECS
                         │
                  ┌──────┴──────┐
                  ▼             ▼
                Linux        Network
                  │             │
                  ▼             ▼
              Nginx/App     Route/NAT
                  │
                  ▼
              Redis / DB
                  │
                  ▼
               Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每一层都有自己的检查方法。&lt;/p&gt;
&lt;p&gt;Linux：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;top
free -h
df -h
ss -lntp
systemctl status
journalctl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;网络：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ip addr
ip route
ss
curl
ping
traceroute
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;云平台：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Instance
Security Group
Route Table
Load Balancer
NAT Gateway
Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;三十八、云计算中的高可用&lt;/h1&gt;
&lt;p&gt;“上云”本身并不等于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;高可用
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SLB
 │
 └── ECS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;依然存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;单点
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更合理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;              SLB
           /    |    \
          /     |     \
       ECS1    ECS2    ECS3
         │       │       │
         └───────┼───────┘
                 │
              Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进一步：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Availability Zone A
       │
       ├── ECS
       └── Storage

Availability Zone B
       │
       ├── ECS
       └── Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样即使某个：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;实例
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;甚至：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;可用区
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发生故障，系统仍可能保持服务。&lt;/p&gt;
&lt;p&gt;高可用最终依赖：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;冗余
+
故障检测
+
流量切换
+
数据恢复
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是简单地：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“买一台更贵的 ECS”
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;三十九、云计算的成本意识&lt;/h1&gt;
&lt;p&gt;云上资源是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;弹性
+
按使用付费
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此运维不仅需要考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;可用性
性能
安全
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还需要考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;成本
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS
磁盘
公网带宽
NAT Gateway
SLB
OSS
日志
快照
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都有可能产生费用。&lt;/p&gt;
&lt;p&gt;因此生产架构需要考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;资源是否过大？
是否存在闲置？
日志保留是否过长？
备份是否合理？
公网流量是否过高？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终目标不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;最贵
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;满足 SLA
+
合理成本
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;四十、总结&lt;/h1&gt;
&lt;p&gt;云计算最核心的基础组件，可以整理成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ECS
→ 计算

VPC
→ 私有网络

Subnet
→ 网络划分

Route Table
→ 流量路径

Security Group
→ 网络访问控制

SLB
→ 负载均衡

NAT Gateway
→ 私网出站

Block Storage
→ 云硬盘

Object Storage
→ 对象文件

File Storage
→ 共享文件系统
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它们最终组合成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                         Internet
                            │
                            ▼
                           DNS
                            │
                            ▼
                           SLB
                            │
                  ┌─────────┴─────────┐
                  ▼                   ▼
                ECS                  ECS
                  │                   │
                  └─────────┬─────────┘
                            ▼
                     Private Network
                       │          │
                       ▼          ▼
                     Redis       DB
                       │
                       ▼
                      OSS

                    ECS
                     │
                     ▼
                 NAT Gateway
                     │
                     ▼
                  Internet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从运维角度，可以把整个云基础设施理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;计算
 ↓
网络
 ↓
安全
 ↓
存储
 ↓
流量
 ↓
监控
 ↓
故障恢复
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而排查问题时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DNS
 ↓
Load Balancer
 ↓
Security Group
 ↓
VPC / Route
 ↓
ECS
 ↓
Linux
 ↓
Application
 ↓
Database / Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;必须逐层定位。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;云计算真正改变的并不是 Linux 服务器本身，而是把计算、网络、存储、安全和流量管理等基础设施能力变成了可以通过 API 快速创建、修改和销毁的资源。对于运维人员而言，核心能力也从“会登录一台服务器”进一步扩展成“理解整个云上基础设施是如何协同工作的”。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.alibabacloud.com/help/en/ecs/&quot;&gt;Alibaba Cloud ECS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.alibabacloud.com/help/en/vpc/&quot;&gt;Alibaba Cloud VPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.alibabacloud.com/help/en/slb/&quot;&gt;Alibaba Cloud Server Load Balancer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.alibabacloud.com/help/en/nat-gateway/&quot;&gt;Alibaba Cloud NAT Gateway&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.alibabacloud.com/help/en/oss/&quot;&gt;Alibaba Cloud Object Storage Service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/vpc/&quot;&gt;AWS VPC Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ebs/&quot;&gt;AWS Amazon EBS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/s3/&quot;&gt;AWS Amazon S3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/virtual-network/&quot;&gt;Microsoft Azure Virtual Network&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>自动化：CICD 流水线</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E8%87%AA%E5%8A%A8%E5%8C%96cicd-%E6%B5%81%E6%B0%B4%E7%BA%BF/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E8%87%AA%E5%8A%A8%E5%8C%96cicd-%E6%B5%81%E6%B0%B4%E7%BA%BF/</guid><description>说明 CI/CD 中的构建、测试、制品、发布、验证和回滚流程。</description><pubDate>Mon, 14 Sep 2026 05:03:34 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Ansible 解决的是“如何自动化配置和操作服务器”，而 CI/CD 解决的是“代码发生变化以后，如何自动完成构建、测试、打包、发布和回滚”。&lt;/p&gt;
&lt;p&gt;CI/CD 的核心不是某个具体工具，而是一条稳定、可重复、可追踪的软件交付流水线。&lt;/p&gt;
&lt;p&gt;本文从 CI、CD、Pipeline 开始，逐步介绍 Docker 镜像 CI/CD、Linux 自动部署、版本发布与回滚，并使用 Jenkins 搭建一个简单的 Pipeline。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;一、什么是 CI/CD&lt;/h1&gt;
&lt;h2&gt;1.1 为什么需要 CI/CD&lt;/h2&gt;
&lt;p&gt;传统的软件发布流程可能是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;开发者修改代码
      ↓
手动打包
      ↓
手动上传服务器
      ↓
SSH 登录服务器
      ↓
停止旧版本
      ↓
替换文件
      ↓
启动新版本
      ↓
检查
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当项目越来越大、发布越来越频繁时，手工流程会产生：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;重复劳动
人为错误
环境不一致
发布不可追踪
回滚困难
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;CI/CD 的目标就是把这些重复步骤自动化。&lt;/p&gt;
&lt;p&gt;典型流程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git Push
   ↓
CI
   ├── Build
   ├── Test
   └── Package
          ↓
        Artifact
          ↓
CD
   ├── Deploy
   ├── Verify
   └── Rollback
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;1.2 CI&lt;/h2&gt;
&lt;p&gt;CI（Continuous Integration，持续集成）的核心思想是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;代码频繁集成
+
自动构建
+
自动测试
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;开发者 A
   │
   ▼
git push
   │
   ▼
CI Pipeline
   │
   ├── Checkout
   ├── Build
   ├── Unit Test
   └── Static Check
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果构建或测试失败：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pipeline Failed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;开发者就能更早发现问题。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CI 主要关注“代码提交之后能不能稳定地被构建和验证”。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;二、CD：Continuous Delivery 与 Continuous Deployment&lt;/h1&gt;
&lt;p&gt;CD 在实际语境中可能表示两个相近但不同的概念：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Continuous Delivery
持续交付

Continuous Deployment
持续部署
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.1 Continuous Delivery&lt;/h2&gt;
&lt;p&gt;持续交付强调：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;代码
 ↓
Build
 ↓
Test
 ↓
Package
 ↓
Ready for Release
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;系统自动完成发布前流程，但正式上线可能仍然需要人工确认。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Build
 ↓
Test
 ↓
Staging
 ↓
Manual Approval
 ↓
Production
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.2 Continuous Deployment&lt;/h2&gt;
&lt;p&gt;持续部署进一步自动化：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Code Push
   ↓
Build
   ↓
Test
   ↓
Deploy
   ↓
Production
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只要流水线通过，就自动部署生产环境。&lt;/p&gt;
&lt;p&gt;两者区别可以简单记成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Continuous Delivery
→ “随时可以发布”

Continuous Deployment
→ “通过验证就自动发布”
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;三、Pipeline&lt;/h1&gt;
&lt;h2&gt;3.1 什么是 Pipeline&lt;/h2&gt;
&lt;p&gt;Pipeline（流水线）就是把：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Build
Test
Package
Deploy
Verify
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等步骤按照一定顺序组织起来。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  Pipeline
                     │
        ┌────────────┼────────────┐
        ▼            ▼            ▼
      Build         Test        Deploy
        │            │            │
        ▼            ▼            ▼
      Image       Test Pass      Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个非常典型的流程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Checkout
   ↓
Build
   ↓
Test
   ↓
Docker Build
   ↓
Docker Push
   ↓
Deploy
   ↓
Health Check
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.2 Stage&lt;/h2&gt;
&lt;p&gt;Pipeline 通常拆分成多个 Stage：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Stage 1: Checkout
Stage 2: Build
Stage 3: Test
Stage 4: Package
Stage 5: Deploy
Stage 6: Verify
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样可以让：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;执行过程
日志
失败位置
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更加清晰。&lt;/p&gt;
&lt;h2&gt;3.3 Artifact&lt;/h2&gt;
&lt;p&gt;Build 完成后通常会产生：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Artifact
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;app.jar
app.tar.gz
Docker Image
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型流程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Source Code
    ↓
Build
    ↓
Artifact
    ↓
Deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在容器化环境中，最常见的 Artifact 之一就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker Image
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;四、CI/CD 与 Git&lt;/h1&gt;
&lt;p&gt;CI/CD 的起点通常是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git Repository
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Developer
    │
    │ git push
    ▼
Git Repository
    │
    ▼
CI Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;触发方式常见：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Push
Pull Request
Tag
Schedule
Manual
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;push main
   ↓
trigger pipeline
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者发布：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git tag v1.2.0
   ↓
build
   ↓
release
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此 Git 不只是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;代码备份
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它还提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;版本
提交记录
分支
Tag
审核
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;为 CI/CD 提供天然的版本来源。&lt;/p&gt;
&lt;h1&gt;五、Docker 镜像 CI/CD&lt;/h1&gt;
&lt;p&gt;前面已经学习过 Docker：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dockerfile
   ↓
docker build
   ↓
Image
   ↓
Container
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在把它接入 CI/CD：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git Push
   ↓
CI
   ↓
Docker Build
   ↓
Docker Image
   ↓
Registry
   ↓
Deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完整流程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;              Git Repository
                    │
                  Push
                    │
                    ▼
               CI Pipeline
                    │
          ┌─────────┼─────────┐
          ▼         ▼         ▼
       Build       Test    Docker Build
                              │
                              ▼
                           Image
                              │
                              ▼
                          Registry
                              │
                              ▼
                           Server
                              │
                              ▼
                         Container
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Docker 官方也提供了针对 CI 平台的 Build / Push Action 和 Buildx 等能力，用于自动构建和推送镜像。 (&lt;a href=&quot;https://docs.docker.com/build/ci/github-actions/?utm_source=chatgpt.com&quot;&gt;docs.docker.com&lt;/a&gt;)&lt;/p&gt;
&lt;h1&gt;六、Docker Image Tag&lt;/h1&gt;
&lt;p&gt;CI/CD 中不要简单地只使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更推荐让镜像 Tag 能体现版本。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;myapp:1.0.0
myapp:1.1.0
myapp:1.2.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;甚至：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;myapp:git-8f3a21c
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;版本
 ↓
Image Tag
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;建立了明确对应关系。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;v1.4.2
   │
   ▼
myapp:1.4.2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发布时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Production
→ myapp:1.4.2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;出了问题就可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;myapp:1.4.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进行回滚。&lt;/p&gt;
&lt;h2&gt;6.1 为什么不要依赖 latest&lt;/h2&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;myapp:latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;昨天是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;今天变成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么你无法直接从：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;知道生产环境具体运行的是哪个版本。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;可追踪版本
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;非常重要。&lt;/p&gt;
&lt;h1&gt;七、Docker Registry&lt;/h1&gt;
&lt;p&gt;镜像构建之后，需要放到 Registry：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CI
 │
 │ docker push
 ▼
Registry
 │
 │ docker pull
 ▼
Production
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker build -t registry.example.com/myapp:1.0.0 .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;登录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker login registry.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;推送：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker push registry.example.com/myapp:1.0.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;服务器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker pull registry.example.com/myapp:1.0.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样生产服务器不需要自己：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git clone
 ↓
Maven build
 ↓
npm build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而只需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pull Image
 ↓
Run Container
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;八、一个完整的 Docker CI Pipeline&lt;/h1&gt;
&lt;p&gt;例如 Java 项目：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git Push
   ↓
Checkout
   ↓
Maven Build
   ↓
Unit Test
   ↓
Docker Build
   ↓
Docker Push
   ↓
Deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dockerfile：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM eclipse-temurin:21-jre

WORKDIR /app

COPY target/app.jar app.jar

EXPOSE 8080

ENTRYPOINT [&quot;java&quot;, &quot;-jar&quot;, &quot;app.jar&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;构建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mvn clean package

docker build \
  -t registry.example.com/myapp:${VERSION} .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;推送：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker push \
  registry.example.com/myapp:${VERSION}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;myapp:1.0.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进入 Registry。&lt;/p&gt;
&lt;h1&gt;九、Linux 自动部署 Web 服务&lt;/h1&gt;
&lt;p&gt;假设服务器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Linux
Docker
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要部署：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Web Application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;手工方式：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh server
 ↓
docker pull
 ↓
docker stop
 ↓
docker rm
 ↓
docker run
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以自动化成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CI
 ↓
Registry
 ↓
SSH
 ↓
Linux Server
 ↓
docker pull
 ↓
replace container
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;9.1 基本部署脚本&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/usr/bin/env bash

set -euo pipefail

IMAGE=&quot;registry.example.com/myapp:1.0.0&quot;
CONTAINER=&quot;myapp&quot;

docker pull &quot;$IMAGE&quot;

docker stop &quot;$CONTAINER&quot; || true
docker rm &quot;$CONTAINER&quot; || true

docker run -d \
  --name &quot;$CONTAINER&quot; \
  --restart unless-stopped \
  -p 8080:8080 \
  &quot;$IMAGE&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set -euo pipefail
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以减少脚本静默失败。&lt;/p&gt;
&lt;h2&gt;9.2 部署流程&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Registry
   │
   ▼
docker pull
   │
   ▼
Stop Old
   │
   ▼
Remove Old
   │
   ▼
Run New
   │
   ▼
Health Check
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但这种：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;停止旧版本
→ 启动新版本
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;存在短暂服务中断。&lt;/p&gt;
&lt;p&gt;因此生产环境可能进一步使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Rolling Update
Blue-Green
Canary
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等发布策略。&lt;/p&gt;
&lt;h1&gt;十、应用发布&lt;/h1&gt;
&lt;h2&gt;10.1 发布版本&lt;/h2&gt;
&lt;p&gt;假设当前：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;v1.2.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;准备发布：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;v1.3.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完整流程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git Tag v1.3.0
       │
       ▼
      CI
       │
       ├── Build
       ├── Test
       └── Docker Build
              │
              ▼
        myapp:1.3.0
              │
              ▼
           Registry
              │
              ▼
          Production
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样每一次发布都具有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git Version
Image Version
Deployment Version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;三者之间的对应关系。&lt;/p&gt;
&lt;h1&gt;十一、应用版本回滚&lt;/h1&gt;
&lt;h2&gt;11.1 为什么需要回滚&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;v1.3.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发布之后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;5xx ↑
Latency ↑
Application Error
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时候最快的恢复方式可能不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;现场修改代码
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Rollback
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;回到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;v1.2.0
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;11.2 Docker 回滚&lt;/h2&gt;
&lt;p&gt;因为镜像具有明确版本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;myapp:1.2.0
myapp:1.3.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以直接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker pull registry.example.com/myapp:1.2.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后重新启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Production
   │
   ▼
myapp:1.2.0
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;11.3 回滚的前提&lt;/h2&gt;
&lt;p&gt;回滚不是简单地：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“把旧镜像重新启动”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还需要确认：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据库 Schema
配置文件
依赖版本
数据格式
API 兼容性
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;v1.3.0
 ↓
数据库迁移
 ↓
Schema changed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时候直接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application → v1.2.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能无法工作。&lt;/p&gt;
&lt;p&gt;因此真正可靠的回滚体系还需要考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用版本
+
配置版本
+
数据库迁移
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之间的兼容性。&lt;/p&gt;
&lt;h1&gt;十二、Blue-Green Deployment&lt;/h1&gt;
&lt;p&gt;为了减少发布过程中的中断，可以同时运行两个版本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  Load Balancer
                       │
              ┌────────┴────────┐
              ▼                 ▼
          Blue v1.2          Green v1.3
          Production          Testing
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;新版本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Green v1.3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;部署完成后进行验证：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Health Check
Smoke Test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确认正常后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Traffic
Blue → Green
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;切换：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;之前：
LB → Blue

之后：
LB → Green
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果出现问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Green
  X
  │
  ▼
Traffic → Blue
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;快速回滚。&lt;/p&gt;
&lt;h1&gt;十三、Canary Deployment&lt;/h1&gt;
&lt;p&gt;Canary（灰度发布）不是一次把所有流量切换到新版本。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;100% Traffic
       │
       ▼
90% → v1.2
10% → v1.3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;观察：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Error Rate
Latency
CPU
Business Metrics
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果正常：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;80 / 20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;50 / 50
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 / 100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样可以降低新版本故障的影响范围。&lt;/p&gt;
&lt;h1&gt;十四、Jenkins&lt;/h1&gt;
&lt;h2&gt;14.1 Jenkins 是什么&lt;/h2&gt;
&lt;p&gt;Jenkins 是一个自动化服务器，提供大量插件和 Pipeline 能力，可以用于构建、测试和持续交付。&lt;/p&gt;
&lt;p&gt;Jenkins 的 Pipeline 是通过代码描述交付过程的重要机制，通常使用 &lt;code&gt;Jenkinsfile&lt;/code&gt; 保存 Pipeline 定义。Jenkins 官方推荐把 &lt;code&gt;Jenkinsfile&lt;/code&gt; 放入源码控制，以获得代码审查、审计和单一事实来源等好处。 (&lt;a href=&quot;https://www.jenkins.io/doc/book/pipeline/jenkinsfile/?utm_source=chatgpt.com&quot;&gt;jenkins.io&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Jenkins
   │
   ├── Build
   ├── Test
   ├── Package
   ├── Docker
   └── Deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;14.2 Jenkins Controller 与 Agent&lt;/h2&gt;
&lt;p&gt;Jenkins 可以通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Controller
   │
   ├── Agent 1
   ├── Agent 2
   └── Agent 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分配任务。&lt;/p&gt;
&lt;p&gt;简单理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Controller
→ 管理 Pipeline

Agent
→ 实际执行构建任务
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此不一定所有构建工作都直接跑在 Jenkins Controller 上。&lt;/p&gt;
&lt;h1&gt;十五、Jenkins Docker 部署&lt;/h1&gt;
&lt;p&gt;Jenkins 官方提供 Docker 镜像，并推荐使用 &lt;code&gt;jenkins/jenkins&lt;/code&gt; 镜像。当前官方 Docker 安装文档还特别说明，如果 Jenkins Pipeline 需要执行 Docker 命令，需要额外配置 Docker CLI / Docker Engine 访问。 (&lt;a href=&quot;https://www.jenkins.io/doc/book/installing/docker/?utm_source=chatgpt.com&quot;&gt;jenkins.io&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;最简单的学习环境：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker volume create jenkins-data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d \
  --name jenkins \
  --restart unless-stopped \
  -p 8080:8080 \
  -p 50000:50000 \
  -v jenkins-data:/var/jenkins_home \
  jenkins/jenkins:lts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker logs jenkins
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://&amp;lt;server&amp;gt;:8080
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;15.1 为什么需要 Volume&lt;/h2&gt;
&lt;p&gt;Jenkins 会保存：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Job
Credentials
Plugins
Build Information
Pipeline
Configuration
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些数据需要持久化。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Jenkins Container
       │
       ▼
/var/jenkins_home
       │
       ▼
Volume
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不能简单把 Jenkins 当作一次性的无状态容器。&lt;/p&gt;
&lt;h2&gt;15.2 Jenkins 与 Docker&lt;/h2&gt;
&lt;p&gt;如果 Jenkins 需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker build
docker push
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就需要让 Pipeline 所运行的 Agent 能访问 Docker。&lt;/p&gt;
&lt;p&gt;典型架构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Jenkins
   │
   ▼
Agent
   │
   ▼
Docker CLI
   │
   ▼
Docker Engine
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以采用 Docker-in-Docker 等方式，但安全性和架构复杂度更高。Jenkins 官方的 Docker 安装指南也提供了使用独立 &lt;code&gt;docker:dind&lt;/code&gt; 容器的示例。 (&lt;a href=&quot;https://www.jenkins.io/doc/book/installing/docker/?utm_source=chatgpt.com&quot;&gt;jenkins.io&lt;/a&gt;)&lt;/p&gt;
&lt;h1&gt;十六、Jenkinsfile&lt;/h1&gt;
&lt;h2&gt;16.1 为什么使用 Jenkinsfile&lt;/h2&gt;
&lt;p&gt;早期 Jenkins 可以直接在 Web UI 里写 Pipeline：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Jenkins UI
   ↓
Pipeline Script
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但这样存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;难以版本控制
难以审查
难以迁移
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更推荐：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git
 │
 └── Jenkinsfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pipeline as Code
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Jenkins 官方明确推荐将 &lt;code&gt;Jenkinsfile&lt;/code&gt; 存入源码管理系统。 (&lt;a href=&quot;https://www.jenkins.io/doc/book/pipeline/jenkinsfile/?utm_source=chatgpt.com&quot;&gt;jenkins.io&lt;/a&gt;)&lt;/p&gt;
&lt;h1&gt;十七、Declarative Pipeline&lt;/h1&gt;
&lt;p&gt;Jenkins Pipeline 有两种主要语法：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Declarative Pipeline
Scripted Pipeline
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于入门，通常从 Declarative Pipeline 开始。&lt;/p&gt;
&lt;p&gt;一个最简单的结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pipeline {
    agent any

    stages {

        stage(&apos;Build&apos;) {
            steps {
                echo &apos;Building...&apos;
            }
        }

        stage(&apos;Test&apos;) {
            steps {
                echo &apos;Testing...&apos;
            }
        }

        stage(&apos;Deploy&apos;) {
            steps {
                echo &apos;Deploying...&apos;
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Jenkins 官方文档将 &lt;code&gt;pipeline&lt;/code&gt;、&lt;code&gt;agent&lt;/code&gt;、&lt;code&gt;stages&lt;/code&gt;、&lt;code&gt;steps&lt;/code&gt; 作为 Declarative Pipeline 的基本结构。 (&lt;a href=&quot;https://www.jenkins.io/doc/book/pipeline/jenkinsfile/?utm_source=chatgpt.com&quot;&gt;jenkins.io&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pipeline
   │
   ├── agent
   │
   └── stages
         ├── Build
         ├── Test
         └── Deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十八、编写一个简易 Jenkins Pipeline&lt;/h1&gt;
&lt;p&gt;假设项目：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Java + Maven + Docker
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Jenkinsfile：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pipeline {
    agent any

    environment {
        IMAGE = &apos;registry.example.com/myapp&apos;
        VERSION = &quot;${BUILD_NUMBER}&quot;
    }

    stages {

        stage(&apos;Checkout&apos;) {
            steps {
                checkout scm
            }
        }

        stage(&apos;Build&apos;) {
            steps {
                sh &apos;mvn clean package&apos;
            }
        }

        stage(&apos;Test&apos;) {
            steps {
                sh &apos;mvn test&apos;
            }
        }

        stage(&apos;Docker Build&apos;) {
            steps {
                sh &quot;&quot;&quot;
                    docker build \
                      -t ${IMAGE}:${VERSION} .
                &quot;&quot;&quot;
            }
        }

        stage(&apos;Docker Push&apos;) {
            steps {
                sh &quot;&quot;&quot;
                    docker push \
                      ${IMAGE}:${VERSION}
                &quot;&quot;&quot;
            }
        }

        stage(&apos;Deploy&apos;) {
            steps {
                sh &quot;&quot;&quot;
                    ./deploy.sh ${IMAGE}:${VERSION}
                &quot;&quot;&quot;
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;整体：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Checkout
   ↓
Build
   ↓
Test
   ↓
Docker Build
   ↓
Docker Push
   ↓
Deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是一条最基本的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CI/CD Pipeline
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Jenkins 官方示例同样使用 Build → Test → Deploy 这样的阶段结构作为持续交付 Pipeline 的基础模型。 (&lt;a href=&quot;https://www.jenkins.io/doc/book/pipeline/tour/deployment/?utm_source=chatgpt.com&quot;&gt;jenkins.io&lt;/a&gt;)&lt;/p&gt;
&lt;h1&gt;十九、Pipeline 中的 Credentials&lt;/h1&gt;
&lt;p&gt;CI/CD 经常需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git Token
Registry Password
SSH Key
Cloud Credentials
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不能直接写：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sh &apos;docker login -u admin -p 123456&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样会产生严重的敏感信息泄露风险。&lt;/p&gt;
&lt;p&gt;Jenkins 提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Credentials
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;机制来管理这些凭据。&lt;/p&gt;
&lt;p&gt;典型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Jenkins
 │
 └── Credentials
       ├── SSH Key
       ├── Username / Password
       └── Token
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pipeline 再引用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;withCredentials([
    usernamePassword(
        credentialsId: &apos;docker-registry&apos;,
        usernameVariable: &apos;REGISTRY_USER&apos;,
        passwordVariable: &apos;REGISTRY_PASSWORD&apos;
    )
]) {
    sh &apos;&apos;&apos;
        echo &quot;$REGISTRY_PASSWORD&quot; |
        docker login \
          -u &quot;$REGISTRY_USER&quot; \
          --password-stdin \
          registry.example.com
    &apos;&apos;&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;核心原则：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Secrets
≠
代码
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而应该：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Secrets
→ Credentials Management
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十、Pipeline 条件控制&lt;/h1&gt;
&lt;h2&gt;20.1 测试失败不发布&lt;/h2&gt;
&lt;p&gt;最基本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Build
 ↓
Test
 ↓
失败
 X
Deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是说：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Test Failed
→ Pipeline Failed
→ 不应该进入 Production
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是 CI/CD 的重要价值。&lt;/p&gt;
&lt;h2&gt;20.2 Manual Approval&lt;/h2&gt;
&lt;p&gt;生产环境可能需要人工确认：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;stage(&apos;Production Approval&apos;) {
    steps {
        input message: &apos;确认发布到生产环境？&apos;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;形成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Build
 ↓
Test
 ↓
Staging
 ↓
Manual Approval
 ↓
Production
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这更接近：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Continuous Delivery
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十一、自动部署与 Ansible&lt;/h1&gt;
&lt;p&gt;前一篇已经学习：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ansible
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在可以把 Jenkins 与 Ansible 组合。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git
 ↓
Jenkins
 ↓
Build
 ↓
Test
 ↓
Docker Image
 ↓
Registry
 ↓
Ansible
 ↓
Linux Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;stage(&apos;Deploy&apos;) {
    steps {
        sh &apos;&apos;&apos;
            ansible-playbook \
              -i inventory \
              deploy.yml \
              -e image_tag=${BUILD_NUMBER}
        &apos;&apos;&apos;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Jenkins
→ 负责 Pipeline

Ansible
→ 负责服务器配置 / 部署
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;职责非常清晰。&lt;/p&gt;
&lt;h1&gt;二十二、CI/CD 与 Kubernetes&lt;/h1&gt;
&lt;p&gt;前面已经学习 Kubernetes。&lt;/p&gt;
&lt;p&gt;因此还可以形成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git
 ↓
Jenkins
 ↓
Build
 ↓
Docker Image
 ↓
Registry
 ↓
Kubernetes
 ↓
Deployment
 ↓
Pods
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如发布新的镜像：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;containers:
  - name: app
    image: registry.example.com/myapp:1.3.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl apply -f deployment.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl set image deployment/myapp \
  app=registry.example.com/myapp:1.3.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kubernetes 再负责：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Rolling Update
Self-healing
Scheduling
Service Discovery
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是整个技术体系串起来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ansible
→ 服务器自动化

Docker
→ 容器化

Kubernetes
→ 容器编排

Jenkins
→ CI/CD

Prometheus
→ Metrics

Grafana
→ Visualization
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十三、CI/CD 中的健康检查&lt;/h1&gt;
&lt;p&gt;部署完成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container = Running
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不代表：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application = Healthy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以发布之后应该执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Health Check
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -f http://127.0.0.1:8080/health
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP 200
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;才认为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Deploy Successful
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完整流程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Deploy
  ↓
Start
  ↓
Health Check
  │
  ├── PASS → Success
  │
  └── FAIL → Rollback
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;自动部署
+
自动验证
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十四、应用发布与自动回滚&lt;/h1&gt;
&lt;p&gt;可以把前面的内容组合成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    Git Push
                       │
                       ▼
                    Jenkins
                       │
                 ┌─────┴─────┐
                 ▼           ▼
               Build        Test
                 │           │
                 └─────┬─────┘
                       ▼
                 Docker Build
                       │
                       ▼
                    Registry
                       │
                       ▼
                    Deploy
                       │
                       ▼
                 Health Check
                  /         \
               PASS         FAIL
                │             │
                ▼             ▼
             Success       Rollback
                              │
                              ▼
                         Previous Version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这已经是一条比较完整的 CI/CD 基础流水线。&lt;/p&gt;
&lt;h1&gt;二十五、流水线中的版本管理&lt;/h1&gt;
&lt;p&gt;一个生产环境应该尽可能做到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Code Version
     │
     ▼
Build Version
     │
     ▼
Image Version
     │
     ▼
Deployment Version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git Tag
v2.3.1

Docker Image
myapp:2.3.1

Production
myapp:2.3.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;谁发布的？
什么时候发布的？
发布了什么？
现在运行什么？
如何回滚？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都更容易回答。&lt;/p&gt;
&lt;h1&gt;二十六、CI/CD 常见故障排查&lt;/h1&gt;
&lt;h2&gt;26.1 Pipeline Build 失败&lt;/h2&gt;
&lt;p&gt;首先看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Console Output
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Build
Test
Docker Build
Deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;哪个 Stage 失败。&lt;/p&gt;
&lt;p&gt;不要直接重新运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Build #125
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而应该先找到失败阶段。&lt;/p&gt;
&lt;h2&gt;26.2 Docker Build 失败&lt;/h2&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dockerfile
Build Context
Base Image
Network
Dependency
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;COPY target/app.jar
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但前面的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mvn package
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;没有生成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;target/app.jar
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么 Docker Build 当然会失败。&lt;/p&gt;
&lt;p&gt;因此流水线的 Stage 之间存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;依赖关系
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;26.3 Docker Push 失败&lt;/h2&gt;
&lt;p&gt;重点检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Registry
Login
Credentials
Network
Image Tag
Repository
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker push
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;失败：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;unauthorized
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就应该先检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Credentials
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是修改 Dockerfile。&lt;/p&gt;
&lt;h2&gt;26.4 Deploy 失败&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker pull
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;成功：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;却失败。&lt;/p&gt;
&lt;p&gt;继续检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;端口
Volume
Environment
Container Name
旧容器
权限
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker logs &amp;lt;container&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;26.5 Health Check 失败&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container = running

HTTP /health
→ 500
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker 正常
应用异常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;继续检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application Logs
Database
Redis
Environment
Configuration
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker restart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不停重启。&lt;/p&gt;
&lt;h1&gt;二十七、CI/CD 安全&lt;/h1&gt;
&lt;p&gt;CI/CD 可以操作：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;源码
镜像
服务器
生产环境
Secrets
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此本身就是高权限系统。&lt;/p&gt;
&lt;p&gt;应该重点考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;凭据保护
最小权限
Registry 权限
SSH Key
Webhook 安全
构建环境隔离
供应链安全
审计
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Jenkins
   │
   └── Production SSH Key
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 Jenkins 被完全控制：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;攻击者
   ↓
Jenkins
   ↓
SSH Key
   ↓
Production
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CI/CD 系统本身必须被当作生产基础设施进行安全保护。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;二十八、CI/CD 与监控&lt;/h1&gt;
&lt;p&gt;部署并不意味着流程结束。&lt;/p&gt;
&lt;p&gt;一个完整过程应该是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Deploy
   ↓
Health Check
   ↓
Metrics
   ↓
Logs
   ↓
Business Validation
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Jenkins
  │
  ▼
Deploy v1.3.0
  │
  ▼
Prometheus
  │
  ├── Error Rate
  ├── Latency
  └── CPU
  │
  ▼
Grafana
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;5xx ↑
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就可以触发：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Rollback
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以最终可以形成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CI/CD
+
Monitoring
+
Logging
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;自动化闭环。&lt;/p&gt;
&lt;h1&gt;二十九、CI/CD 整体架构&lt;/h1&gt;
&lt;p&gt;把前面几个章节全部连接起来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                         Developer
                             │
                           Git Push
                             │
                             ▼
                       Git Repository
                             │
                             ▼
                          Jenkins
                             │
              ┌──────────────┼──────────────┐
              ▼              ▼              ▼
            Build           Test         Security
              │              │              │
              └──────────────┼──────────────┘
                             ▼
                       Docker Build
                             │
                             ▼
                           Image
                             │
                             ▼
                          Registry
                             │
                  ┌──────────┴──────────┐
                  ▼                     ▼
                Ansible             Kubernetes
                  │                     │
                  ▼                     ▼
             Linux Server              Pods
                  │                     │
                  └──────────┬──────────┘
                             ▼
                         Health Check
                             │
                  ┌──────────┴──────────┐
                  ▼                     ▼
                Success                Fail
                  │                     │
                  ▼                     ▼
              Monitoring             Rollback
                  │
          ┌───────┼────────┐
          ▼       ▼        ▼
       Metrics   Logs    Traces
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后面的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Logs
ELK
OpenTelemetry
Observability
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就可以继续接在这里。&lt;/p&gt;
&lt;h1&gt;三十、自动化体系中的工具分工&lt;/h1&gt;
&lt;p&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;Ansible&lt;/td&gt;
&lt;td&gt;服务器和配置自动化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker&lt;/td&gt;
&lt;td&gt;应用容器化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kubernetes&lt;/td&gt;
&lt;td&gt;容器集群编排&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jenkins&lt;/td&gt;
&lt;td&gt;CI/CD 流水线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prometheus&lt;/td&gt;
&lt;td&gt;Metrics 监控&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grafana&lt;/td&gt;
&lt;td&gt;Metrics 可视化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ELK&lt;/td&gt;
&lt;td&gt;日志收集与分析&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenTelemetry&lt;/td&gt;
&lt;td&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;哪个工具最好？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;不同层解决不同问题
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;代码
 ↓
Jenkins
 ↓
Docker
 ↓
Registry
 ↓
Ansible / Kubernetes
 ↓
Application
 ↓
Prometheus / Grafana
 ↓
Logs / ELK
 ↓
OpenTelemetry
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;三十一、从手工发布到自动化发布&lt;/h1&gt;
&lt;p&gt;最原始：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;开发者
 ↓
SSH
 ↓
服务器
 ↓
手工部署
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;加入 Docker：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;开发者
 ↓
Docker Build
 ↓
Image
 ↓
Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;加入 CI：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git Push
 ↓
Jenkins
 ↓
Build
 ↓
Test
 ↓
Image
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;加入 Registry：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git
 ↓
Jenkins
 ↓
Build
 ↓
Registry
 ↓
Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;加入自动部署：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git
 ↓
Jenkins
 ↓
Build
 ↓
Test
 ↓
Push Image
 ↓
Deploy
 ↓
Health Check
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;加入监控：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Deploy
 ↓
Health Check
 ↓
Prometheus
 ↓
Grafana
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;自动构建
+
自动测试
+
自动发布
+
自动验证
+
自动监控
+
快速回滚
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是现代 DevOps / 运维自动化体系的基本雏形。&lt;/p&gt;
&lt;h1&gt;三十二、总结&lt;/h1&gt;
&lt;p&gt;CI/CD 最核心的概念可以整理成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CI
→ 持续集成

CD
→ 持续交付 / 持续部署

Pipeline
→ 把整个交付过程组织起来

Artifact
→ 构建产生的可发布产物

Registry
→ 保存和分发 Docker Image

Jenkins
→ 执行 CI/CD Pipeline

Jenkinsfile
→ 用代码定义 Pipeline

Deploy
→ 把版本发布到目标环境

Health Check
→ 验证发布结果

Rollback
→ 出现问题后恢复到稳定版本
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一条典型流水线：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git Push
   ↓
Checkout
   ↓
Build
   ↓
Test
   ↓
Docker Build
   ↓
Docker Push
   ↓
Deploy
   ↓
Health Check
   │
   ├── PASS → Release Success
   │
   └── FAIL → Rollback
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而之前学习的内容可以组合成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ansible
→ 自动化服务器

Docker
→ 容器化应用

Kubernetes
→ 管理容器集群

Jenkins
→ 自动化软件交付

Prometheus
→ 监控运行状态

Grafana
→ 展示监控数据

ELK
→ 分析日志

OpenTelemetry
→ 连接 Metrics / Logs / Traces
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终形成：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CI/CD 的核心目标，是把“代码发生变化”到“一个经过验证的版本安全地运行在生产环境”之间的重复工作自动化，并且让整个过程具备版本追踪、失败阻断、健康验证和快速回滚能力。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/book/pipeline/&quot;&gt;Jenkins Pipeline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/book/pipeline/jenkinsfile/&quot;&gt;Jenkinsfile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/book/pipeline/syntax/&quot;&gt;Jenkins Pipeline Syntax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/book/installing/docker/&quot;&gt;Jenkins Docker Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/build/ci/&quot;&gt;Docker Build with CI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>自动化：Ansible</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E8%87%AA%E5%8A%A8%E5%8C%96ansible/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E8%87%AA%E5%8A%A8%E5%8C%96ansible/</guid><description>使用 Inventory 和 Playbook 描述主机配置，完成可重复的常见自动化任务。</description><pubDate>Mon, 14 Sep 2026 04:55:56 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;当服务器数量从 1 台变成 10 台、100 台甚至更多时，依靠 SSH 登录服务器逐台执行命令会越来越低效，也容易产生环境差异。&lt;/p&gt;
&lt;p&gt;Ansible 通过 Inventory 管理目标主机，通过 Playbook 描述目标状态，再利用 Modules、Variables、Templates、Handlers 和 Roles 将运维操作自动化。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ansible 的核心不是“远程执行命令”，而是把基础设施的配置和运维操作变成可以重复执行的代码。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;一、Ansible 概述&lt;/h1&gt;
&lt;h2&gt;1.1 什么是 Ansible&lt;/h2&gt;
&lt;p&gt;Ansible 是一种 IT 自动化工具，可以用于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;配置管理
应用部署
批量执行任务
服务器初始化
服务管理
系统维护
网络设备自动化
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如现在有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;web01
web02
web03
web04
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;手工执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh web01
ssh web02
ssh web03
ssh web04
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后重复：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apt update
apt install nginx
systemctl enable nginx
systemctl start nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;机器越多，重复劳动越严重。&lt;/p&gt;
&lt;p&gt;Ansible 的目标则是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Inventory
    │
    ▼
Ansible
    │
    ├── web01
    ├── web02
    ├── web03
    └── web04
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行一次：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook deploy.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就可以批量完成任务。&lt;/p&gt;
&lt;p&gt;Ansible 官方：
&lt;a href=&quot;https://docs.ansible.com/projects/ansible/latest/getting_started/introduction.html&quot;&gt;Ansible Introduction&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;1.2 Ansible 的核心特点&lt;/h2&gt;
&lt;p&gt;Ansible 的几个核心特点：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Agentless
YAML
Idempotent
Declarative
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Agentless&lt;/h3&gt;
&lt;p&gt;Ansible 通常不要求在被管理主机上额外安装 Ansible Agent。&lt;/p&gt;
&lt;p&gt;典型 Linux 环境：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Control Node
    │
    │ SSH
    ├────────► Managed Node 1
    ├────────► Managed Node 2
    └────────► Managed Node 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 官方文档明确说明，Managed Node 一般不需要安装 Ansible 本身，而 Control Node 运行 Ansible 并通过 SSH 等方式管理远程节点。&lt;/p&gt;
&lt;h3&gt;YAML&lt;/h3&gt;
&lt;p&gt;Playbook 使用 YAML 编写：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- hosts: web
  tasks:
    - name: Install nginx
      ansible.builtin.apt:
        name: nginx
        state: present
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;相比：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Shell Script
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Playbook 更强调：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;我要系统达到什么状态
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Idempotent&lt;/h3&gt;
&lt;p&gt;幂等性是 Ansible 非常重要的设计思想。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;state: present
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;意味着：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“确保 nginx 存在”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果已经安装：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;不需要重复安装
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果没有安装：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;执行安装
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;第一次执行
→ Changed

第二次执行
→ 通常不会再产生变化
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 官方也将 idempotence 和 predictability 作为核心设计原则。&lt;/p&gt;
&lt;h1&gt;二、Ansible 架构&lt;/h1&gt;
&lt;h2&gt;2.1 Control Node&lt;/h2&gt;
&lt;p&gt;Control Node 是运行 Ansible 的机器。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;管理服务器
      │
      └── Ansible
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以查看版本。&lt;/p&gt;
&lt;h2&gt;2.2 Managed Node&lt;/h2&gt;
&lt;p&gt;Managed Node 是被管理的目标机器。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;web01
web02
db01
redis01
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Linux Managed Node 通常至少需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SSH
Python
用户权限
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;具体 Module 的要求可能有所不同。&lt;/p&gt;
&lt;h2&gt;2.3 Inventory&lt;/h2&gt;
&lt;p&gt;Inventory 是 Ansible 的主机清单。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;web01
web02
web03
db01
redis01
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以按角色组织：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;web
├── web01
├── web02
└── web03

db
├── db01
└── db02

redis
└── redis01
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 官方将 Inventory 定义为组织 Managed Nodes 的主机清单。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Control Node
      │
      ▼
  Inventory
      │
      ├── web
      ├── db
      └── redis
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;三、安装 Ansible&lt;/h1&gt;
&lt;h2&gt;3.1 使用 pip 安装&lt;/h2&gt;
&lt;p&gt;在 Control Node 中，可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python3 -m pip install ansible
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者使用官方推荐的 Python 包管理方式之一，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pipx install ansible
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 官方当前提供 &lt;code&gt;ansible&lt;/code&gt; 和 &lt;code&gt;ansible-core&lt;/code&gt; 两种主要包形态：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible
→ 更完整的社区内容集合

ansible-core
→ 核心运行时和内置功能
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;具体安装方式和版本支持应以官方 Installation Guide 为准。&lt;/p&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible --version
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.2 创建项目目录&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir -p ~/ansible-demo
cd ~/ansible-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;inventory
ansible.cfg
playbook.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-demo/
├── ansible.cfg
├── inventory
└── playbook.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;四、Inventory&lt;/h1&gt;
&lt;h2&gt;4.1 INI Inventory&lt;/h2&gt;
&lt;p&gt;最简单：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[web]
web01 ansible_host=192.168.1.101
web02 ansible_host=192.168.1.102

[db]
db01 ansible_host=192.168.1.103
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;指定 SSH 用户：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[web]
web01 ansible_host=192.168.1.101 ansible_user=ubuntu
web02 ansible_host=192.168.1.102 ansible_user=ubuntu
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4.2 YAML Inventory&lt;/h2&gt;
&lt;p&gt;也可以使用 YAML：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;all:
  children:

    web:
      hosts:
        web01:
          ansible_host: 192.168.1.101
        web02:
          ansible_host: 192.168.1.102

    db:
      hosts:
        db01:
          ansible_host: 192.168.1.103
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 官方支持多种 Inventory 形式，并可以为 Host 或 Group 设置变量。&lt;/p&gt;
&lt;h2&gt;4.3 Group&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[web]
web01
web02
web03

[db]
db01
db02
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible web -m ping
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只对：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;组执行。&lt;/p&gt;
&lt;h2&gt;4.4 Group of Groups&lt;/h2&gt;
&lt;p&gt;还可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[frontend]
web01
web02

[backend]
app01
app02

[production:children]
frontend
backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;production
├── frontend
└── backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible production -m ping
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就可以管理整个生产环境。&lt;/p&gt;
&lt;h1&gt;五、ansible.cfg&lt;/h1&gt;
&lt;p&gt;Ansible 可以通过配置文件统一管理默认行为。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[defaults]
inventory = ./inventory
host_key_checking = False
interpreter_python = auto_silent
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就不需要每次都：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible -i inventory ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看当前配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-config dump
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-config list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;host_key_checking = False
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在学习环境中比较方便，但生产环境不应该无条件关闭 SSH 主机密钥验证。&lt;/p&gt;
&lt;h1&gt;六、Ansible Ad-hoc 命令&lt;/h1&gt;
&lt;h2&gt;6.1 什么是 Ad-hoc&lt;/h2&gt;
&lt;p&gt;Ad-hoc Command 用于临时执行任务。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible all -m ping
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;意思是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;对 Inventory 中的所有主机执行 ping Module
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方文档将 &lt;code&gt;ansible&lt;/code&gt; 命令和 Ad-hoc Commands 作为 Ansible 日常命令行操作的一部分。&lt;/p&gt;
&lt;h2&gt;6.2 ping Module&lt;/h2&gt;
&lt;p&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible all -m ansible.builtin.ping
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;成功可能返回：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;web01 | SUCCESS =&amp;gt; {
    &quot;changed&quot;: false,
    &quot;ping&quot;: &quot;pong&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SUCCESS
→ Ansible 能够正常管理目标主机

changed: false
→ 没有修改目标系统
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ansible ping
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不是普通 ICMP：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ping 192.168.1.101
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它主要用于验证 Ansible 与目标节点之间的管理通信和模块执行环境。&lt;/p&gt;
&lt;h1&gt;七、常见 Ad-hoc 操作&lt;/h1&gt;
&lt;h2&gt;7.1 查看主机&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;ansible all -m ansible.builtin.command -a &quot;hostname&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7.2 查看内存&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;ansible all \
  -m ansible.builtin.command \
  -a &quot;free -h&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7.3 查看磁盘&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;ansible all \
  -m ansible.builtin.command \
  -a &quot;df -h&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7.4 查看服务&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;ansible web \
  -m ansible.builtin.command \
  -a &quot;systemctl status nginx&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不过实际修改系统时，更推荐使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;专用 Module
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是到处执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Shell Command
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为 Module 通常能够更好地表达目标状态，并提供幂等行为。&lt;/p&gt;
&lt;h1&gt;八、Module&lt;/h1&gt;
&lt;h2&gt;8.1 什么是 Module&lt;/h2&gt;
&lt;p&gt;Module 是 Ansible 用来执行具体工作的功能单元。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apt
dnf
service
systemd
file
copy
template
user
group
command
shell
package
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Playbook
   │
   ▼
 Module
   │
   ▼
Managed Node
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Install nginx
  ansible.builtin.apt:
    name: nginx
    state: present
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apt
→ Module

name
state
→ Module 参数
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8.2 ansible-doc&lt;/h2&gt;
&lt;p&gt;查看 Module 文档：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-doc ansible.builtin.apt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-doc ansible.builtin.copy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是非常实用的命令。&lt;/p&gt;
&lt;p&gt;不要记住所有参数，更推荐：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-doc &amp;lt;module&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要什么就查什么。&lt;/p&gt;
&lt;h1&gt;九、Playbook&lt;/h1&gt;
&lt;h2&gt;9.1 什么是 Playbook&lt;/h2&gt;
&lt;p&gt;Playbook 是 Ansible 自动化任务的主要描述形式。&lt;/p&gt;
&lt;p&gt;典型结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Playbook
   │
   └── Play
        │
        └── Tasks
              │
              ├── Task 1
              ├── Task 2
              └── Task 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 官方将 Play 定义为将目标主机映射到任务的执行上下文，Playbook 则由一个或多个 Play 组成。&lt;/p&gt;
&lt;h2&gt;9.2 第一个 Playbook&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;---
- name: Install nginx
  hosts: web
  become: true

  tasks:
    - name: Install nginx
      ansible.builtin.apt:
        name: nginx
        state: present

    - name: Start nginx
      ansible.builtin.systemd:
        name: nginx
        state: started
        enabled: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook playbook.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;指定 Inventory：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook \
  -i inventory \
  playbook.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;9.3 Play 的主要组成&lt;/h2&gt;
&lt;p&gt;一个 Play 常见：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Web server
  hosts: web
  become: true

  vars:
    http_port: 80

  tasks:
    ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;核心部分：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name
hosts
vars
tasks
handlers
roles
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十、Task&lt;/h1&gt;
&lt;p&gt;Task 是一个具体操作。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tasks:

  - name: Install nginx
    ansible.builtin.apt:
      name: nginx
      state: present
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每个 Task 通常具有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name
module
module arguments
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Task
 │
 └── apt
      ├── name
      └── state
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10.1 Task 顺序&lt;/h2&gt;
&lt;p&gt;默认情况下，Playbook 中的 Task 按照定义顺序执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Task 1
 ↓
Task 2
 ↓
Task 3
 ↓
Task 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此可以建立：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;安装
 ↓
配置
 ↓
启动
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样的执行流程。&lt;/p&gt;
&lt;h1&gt;十一、变量 Variables&lt;/h1&gt;
&lt;h2&gt;11.1 为什么需要变量&lt;/h2&gt;
&lt;p&gt;假设开发环境：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;port = 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;生产环境：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;port = 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果把数字直接写死：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;port: 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不同环境就需要修改 Playbook。&lt;/p&gt;
&lt;p&gt;更好的方式：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http_port: 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;port: &quot;{{ http_port }}&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 官方支持在 Inventory、Playbook、Role、命令行等多处定义变量，并按照变量优先级规则处理。&lt;/p&gt;
&lt;h2&gt;11.2 Playbook 变量&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;vars:
  app_name: myapp
  app_port: 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;引用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Show app port
  ansible.builtin.debug:
    msg: &quot;Application port is {{ app_port }}&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;11.3 Inventory 变量&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[web]
web01 ansible_host=192.168.1.101
web02 ansible_host=192.168.1.102
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以进一步设置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;group_vars/
host_vars/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;组织变量。&lt;/p&gt;
&lt;h2&gt;11.4 Extra Vars&lt;/h2&gt;
&lt;p&gt;运行时传入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook \
  -i inventory \
  playbook.yml \
  -e &quot;app_port=8080&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Extra Vars 具有很高的变量优先级。&lt;/p&gt;
&lt;h1&gt;十二、Facts&lt;/h1&gt;
&lt;h2&gt;12.1 什么是 Facts&lt;/h2&gt;
&lt;p&gt;Ansible 可以自动收集远程主机的信息。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;操作系统
IP 地址
CPU
内存
磁盘
文件系统
主机名
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些数据称为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Facts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 官方文档将远程系统信息称为 Facts，并通过 &lt;code&gt;setup&lt;/code&gt; Module 收集。&lt;/p&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible web \
  -m ansible.builtin.setup
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;12.2 使用 Facts&lt;/h2&gt;
&lt;p&gt;例如根据操作系统执行不同任务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Install package
  ansible.builtin.package:
    name: nginx
    state: present
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible_facts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Show OS
  ansible.builtin.debug:
    var: ansible_facts.distribution
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这让 Playbook 能够根据目标机器的实际环境动态执行。&lt;/p&gt;
&lt;h1&gt;十三、Conditionals&lt;/h1&gt;
&lt;h2&gt;13.1 when&lt;/h2&gt;
&lt;p&gt;有时任务只应该在特定条件下执行。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Install nginx on Debian
  ansible.builtin.apt:
    name: nginx
    state: present
  when: ansible_facts.distribution in [&quot;Ubuntu&quot;, &quot;Debian&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Red Hat 系：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Install nginx on RedHat
  ansible.builtin.dnf:
    name: nginx
    state: present
  when: ansible_facts.os_family == &quot;RedHat&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ubuntu
 → apt

RHEL / Fedora
 → dnf
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;13.2 Condition 的意义&lt;/h2&gt;
&lt;p&gt;这使一个 Playbook 能适应：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;多个发行版
多个环境
多个节点类型
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;一台机器一个脚本
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十四、Loops&lt;/h1&gt;
&lt;h2&gt;14.1 基本循环&lt;/h2&gt;
&lt;p&gt;例如安装多个软件包：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Install packages
  ansible.builtin.apt:
    name: &quot;{{ item }}&quot;
    state: present
  loop:
    - curl
    - vim
    - git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;逻辑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;item = curl
item = vim
item = git
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;14.2 为什么需要循环&lt;/h2&gt;
&lt;p&gt;如果没有 loop：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- apt:
    name: curl

- apt:
    name: vim

- apt:
    name: git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重复内容很多。&lt;/p&gt;
&lt;p&gt;使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;loop:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更简洁。&lt;/p&gt;
&lt;h1&gt;十五、常用 Module&lt;/h1&gt;
&lt;h2&gt;15.1 package / apt / dnf&lt;/h2&gt;
&lt;p&gt;跨发行版时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible.builtin.package:
  name: nginx
  state: present
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Debian / Ubuntu：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible.builtin.apt:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;RHEL / Fedora：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible.builtin.dnf:
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;15.2 service / systemd&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Start nginx
  ansible.builtin.systemd:
    name: nginx
    state: started
    enabled: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对应：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl start nginx
systemctl enable nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;15.3 file&lt;/h2&gt;
&lt;p&gt;创建目录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Create application directory
  ansible.builtin.file:
    path: /opt/myapp
    state: directory
    owner: root
    group: root
    mode: &quot;0755&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;15.4 copy&lt;/h2&gt;
&lt;p&gt;复制文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Copy config
  ansible.builtin.copy:
    src: files/app.conf
    dest: /etc/myapp/app.conf
    mode: &quot;0644&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;15.5 user&lt;/h2&gt;
&lt;p&gt;创建用户：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Create deploy user
  ansible.builtin.user:
    name: deploy
    shell: /bin/bash
    create_home: true
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十六、Template 与 Jinja2&lt;/h1&gt;
&lt;h2&gt;16.1 为什么需要 Template&lt;/h2&gt;
&lt;p&gt;如果配置文件中存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;端口
域名
IP
路径
环境
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;直接复制固定文件并不灵活。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dev
→ port=8080

prod
→ port=80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Jinja2 Template
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;16.2 模板&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;templates/nginx.conf.j2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;内容：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {
    listen {{ http_port }};

    server_name {{ server_name }};

    location / {
        proxy_pass http://{{ backend_host }}:{{ backend_port }};
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Playbook：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Deploy nginx config
  ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/conf.d/app.conf
    mode: &quot;0644&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终不同机器可能生成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server01
listen 80;

server02
listen 8080;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为变量不同。&lt;/p&gt;
&lt;h2&gt;16.3 Template 的核心&lt;/h2&gt;
&lt;p&gt;可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Template
   +
Variables
   │
   ▼
Rendered Config
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 官方也支持在模板中使用 Jinja2 语法处理变量、循环和条件。&lt;/p&gt;
&lt;h1&gt;十七、Handlers&lt;/h1&gt;
&lt;h2&gt;17.1 为什么需要 Handler&lt;/h2&gt;
&lt;p&gt;假设修改了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nginx.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改后才需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果配置没有发生变化：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;不需要 reload
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是 Handler 的用途。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tasks:

  - name: Deploy nginx config
    ansible.builtin.template:
      src: nginx.conf.j2
      dest: /etc/nginx/conf.d/app.conf
    notify:
      - Reload nginx

handlers:

  - name: Reload nginx
    ansible.builtin.systemd:
      name: nginx
      state: reloaded
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;逻辑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Template changed
      │
      ▼
notify
      │
      ▼
Handler
      │
      ▼
Reload nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;没有变化
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;则：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Handler 不执行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也是幂等性的重要体现。&lt;/p&gt;
&lt;h1&gt;十八、Become 与权限提升&lt;/h1&gt;
&lt;p&gt;很多运维操作需要 root：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;安装软件
修改 /etc
管理 systemd
创建系统用户
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 常用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;become: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- hosts: web
  become: true

  tasks:
    - name: Install nginx
      ansible.builtin.apt:
        name: nginx
        state: present
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行时也可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook \
  -i inventory \
  playbook.yml \
  -b
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-b
→ become
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通常最终通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等方式获得目标权限。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SSH User
   │
   ▼
Become / sudo
   │
   ▼
Root-level Task
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十九、Command 与 Shell&lt;/h1&gt;
&lt;h2&gt;19.1 command&lt;/h2&gt;
&lt;p&gt;执行命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Check hostname
  ansible.builtin.command:
    cmd: hostname
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;19.2 shell&lt;/h2&gt;
&lt;p&gt;需要 Shell 特性时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Check logs
  ansible.builtin.shell:
    cmd: &quot;journalctl -u nginx | tail -n 20&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但应该注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;能使用专用 Module 时，优先使用 Module，而不是把所有操作都写成 Shell。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;p&gt;不要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible.builtin.shell:
  cmd: &quot;systemctl start nginx&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更推荐：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible.builtin.systemd:
  name: nginx
  state: started
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemd Module
→ 表达目标状态

shell systemctl
→ 只是执行命令
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后者更难保证幂等性。&lt;/p&gt;
&lt;h1&gt;二十、Check Mode 与 Diff&lt;/h1&gt;
&lt;h2&gt;20.1 Check Mode&lt;/h2&gt;
&lt;p&gt;运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook \
  -i inventory \
  playbook.yml \
  --check
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以在尽可能不修改目标系统的情况下，预览哪些任务可能产生变化。&lt;/p&gt;
&lt;p&gt;这对于生产环境非常有价值：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;修改之前
 ↓
--check
 ↓
确认变化
 ↓
正式执行
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;20.2 Diff&lt;/h2&gt;
&lt;p&gt;对于部分文件修改操作，可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook \
  -i inventory \
  playbook.yml \
  --diff
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看配置变化。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;old config
     ↓
new config
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样比直接修改生产配置更安全。&lt;/p&gt;
&lt;h1&gt;二十一、Ansible Playbook 的幂等性&lt;/h1&gt;
&lt;p&gt;考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Ensure nginx installed
  ansible.builtin.apt:
    name: nginx
    state: present
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一次：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;changed = true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第二次：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;changed = false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;目标状态已经满足
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Idempotency
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;21.1 为什么幂等性重要&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;100 台服务器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要反复执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;安装
配置
更新
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果脚本每次都会：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;重复修改
重复创建
重复启动
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就很危险。&lt;/p&gt;
&lt;p&gt;而幂等自动化强调：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Desired State
      │
      ▼
当前状态检查
      │
      ├── 已满足 → 不修改
      │
      └── 未满足 → 修改
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此 Playbook 可以安全地反复执行。&lt;/p&gt;
&lt;h1&gt;二十二、Roles&lt;/h1&gt;
&lt;h2&gt;22.1 为什么需要 Role&lt;/h2&gt;
&lt;p&gt;一个大型 Playbook 很容易越来越长：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;install
configure
deploy
firewall
monitor
backup
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;全部写在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;playbook.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;会越来越难维护。&lt;/p&gt;
&lt;p&gt;于是可以拆成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Role
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;22.2 Role 目录&lt;/h2&gt;
&lt;p&gt;典型结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;roles/
└── nginx/
    ├── tasks/
    │   └── main.yml
    ├── handlers/
    │   └── main.yml
    ├── templates/
    ├── files/
    ├── vars/
    ├── defaults/
    ├── meta/
    └── README.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 官方将 Role 定义为用于复用 Tasks、Handlers、Variables、Templates、Files 等自动化内容的一种组织方式。&lt;/p&gt;
&lt;h2&gt;22.3 使用 Role&lt;/h2&gt;
&lt;p&gt;Playbook：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Deploy web server
  hosts: web
  become: true

  roles:
    - nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Playbook
   │
   ▼
 nginx Role
   │
   ├── Tasks
   ├── Handlers
   ├── Templates
   └── Variables
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;22.4 Role 的价值&lt;/h2&gt;
&lt;p&gt;Role 的本质是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;复用
组织
抽象
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nginx-role
mysql-role
redis-role
docker-role
node-exporter-role
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以后换一批服务器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;重新执行 Role
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就可以快速完成环境部署。&lt;/p&gt;
&lt;h1&gt;二十三、Ansible Vault&lt;/h1&gt;
&lt;p&gt;自动化配置中经常需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;密码
Token
SSH Key
数据库凭证
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不应该直接写在 Git 仓库的普通 YAML 中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;db_password: &quot;123456&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-vault
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用于加密敏感数据。&lt;/p&gt;
&lt;p&gt;创建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-vault create secrets.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编辑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-vault edit secrets.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行 Playbook：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook \
  -i inventory \
  playbook.yml \
  --ask-vault-pass
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git
 ↓
加密文件
 ↓
Ansible Vault
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git
 ↓
明文密码
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十四、Ansible Galaxy 与 Collections&lt;/h1&gt;
&lt;p&gt;Ansible 自动化内容不一定全部自己编写。&lt;/p&gt;
&lt;p&gt;还可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Collections
Roles
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-galaxy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;管理。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-galaxy collection install community.general
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-galaxy collection list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当前 Ansible 生态大量功能已经通过 Collections 组织。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-core
      │
      ├── Built-in Modules
      │
      └── Collections
             │
             ├── community.general
             ├── vendor collections
             └── ...
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十五、一个完整的 Web 服务 Playbook&lt;/h1&gt;
&lt;p&gt;现在把前面的知识组合起来。&lt;/p&gt;
&lt;p&gt;目录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-demo/
├── inventory
├── playbook.yml
└── templates/
    └── nginx.conf.j2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inventory：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[web]
web01 ansible_host=192.168.1.101
web02 ansible_host=192.168.1.102
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Playbook：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
- name: Deploy web server
  hosts: web
  become: true

  vars:
    http_port: 8080
    server_name: example.local

  tasks:

    - name: Install nginx
      ansible.builtin.package:
        name: nginx
        state: present

    - name: Deploy nginx config
      ansible.builtin.template:
        src: nginx.conf.j2
        dest: /etc/nginx/conf.d/app.conf
        mode: &quot;0644&quot;
      notify:
        - Reload nginx

    - name: Ensure nginx is running
      ansible.builtin.systemd:
        name: nginx
        state: started
        enabled: true

  handlers:

    - name: Reload nginx
      ansible.builtin.systemd:
        name: nginx
        state: reloaded
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;模板：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {
    listen {{ http_port }};

    server_name {{ server_name }};

    location / {
        return 200 &quot;Hello from {{ inventory_hostname }}\n&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook \
  -i inventory \
  playbook.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Control Node
     │
     ▼
Inventory
     │
     ▼
Playbook
     │
     ├── Install nginx
     ├── Render Template
     ├── Start nginx
     └── Handler
           │
           ▼
       Managed Nodes
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十六、Ansible 执行过程&lt;/h1&gt;
&lt;p&gt;理解 Ansible 时，可以把一次 Playbook 执行抽象为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook
        │
        ▼
    Inventory
        │
        ▼
      Hosts
        │
        ▼
      Facts
        │
        ▼
       Tasks
        │
        ▼
      Modules
        │
        ▼
   Managed Nodes
        │
        ▼
Desired State
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“nginx 必须安装并运行”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 会检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;当前状态
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再决定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;需要修改
还是
已经满足
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此它不是简单的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SSH
+
Shell Script
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Desired State
+
State Reconciliation
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十七、Ansible 常见故障排查&lt;/h1&gt;
&lt;p&gt;自动化工具本身也会出问题。&lt;/p&gt;
&lt;p&gt;排查时建议按照：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Inventory
 ↓
Network
 ↓
SSH
 ↓
Privilege
 ↓
Module
 ↓
Variable
 ↓
Task
 ↓
Managed Service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;逐层定位。&lt;/p&gt;
&lt;h1&gt;二十八、Inventory 故障&lt;/h1&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible web -m ping
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;返回：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;No hosts matched
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;先检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-inventory \
  -i inventory \
  --graph
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;web
├── web01
└── web02
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-inventory \
  -i inventory \
  --list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确认 Inventory 是否被正确解析。&lt;/p&gt;
&lt;h1&gt;二十九、SSH 故障&lt;/h1&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UNREACHABLE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;首先从 SSH 入手：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh user@192.168.1.101
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP
端口
用户名
SSH Key
密码
Known Hosts
防火墙
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果手工 SSH 都连接不上：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ansible 通常也不可能正常工作
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ansible 问题
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;有时候根本不是 Ansible 本身的问题，而是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;基础网络 / SSH
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;29.1 指定 SSH Key&lt;/h2&gt;
&lt;p&gt;Inventory：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[web]
web01 ansible_host=192.168.1.101 \
      ansible_user=ubuntu \
      ansible_ssh_private_key_file=~/.ssh/id_ed25519
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以命令行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible web \
  -m ping \
  --private-key ~/.ssh/id_ed25519
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;三十、权限问题&lt;/h1&gt;
&lt;p&gt;如果出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Permission denied
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SSH User
sudo
become
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;become: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还要确认：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户是否可以 sudo
是否需要密码
sudo 配置是否允许
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook \
  -i inventory \
  playbook.yml \
  -K
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以提示输入 Become 密码。&lt;/p&gt;
&lt;h1&gt;三十一、Module 故障&lt;/h1&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Module failed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-doc &amp;lt;module&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查参数。&lt;/p&gt;
&lt;p&gt;也可以增加详细输出：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook \
  -i inventory \
  playbook.yml \
  -vvv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-vvv&lt;/code&gt; 会输出更详细的执行信息。&lt;/p&gt;
&lt;p&gt;对于进一步排查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Module 参数
Python
权限
目标系统
模块兼容性
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都需要考虑。&lt;/p&gt;
&lt;h1&gt;三十二、变量问题&lt;/h1&gt;
&lt;p&gt;如果出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&apos;xxx&apos; is undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;变量名称
变量作用域
Inventory
group_vars
host_vars
Role
Extra Vars
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Debug variable
  ansible.builtin.debug:
    var: app_port
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;帮助确认变量实际值。&lt;/p&gt;
&lt;h2&gt;32.1 变量优先级&lt;/h2&gt;
&lt;p&gt;Ansible 存在复杂的变量优先级体系。&lt;/p&gt;
&lt;p&gt;初学阶段不需要背完整优先级表，但应该知道：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;同一个变量
在不同位置重复定义
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终只会有一个值真正生效。&lt;/p&gt;
&lt;p&gt;因此大型项目中最好：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;明确变量来源
避免重复定义
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方变量文档提供了完整的变量优先级规则。&lt;/p&gt;
&lt;h1&gt;三十三、Playbook 调试&lt;/h1&gt;
&lt;h2&gt;33.1 Verbosity&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook -v playbook.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更详细：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook -vvv playbook.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;连接
模块
参数
执行结果
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;33.2 Debug Module&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Debug hostname
  ansible.builtin.debug:
    var: inventory_hostname
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- name: Debug message
  ansible.builtin.debug:
    msg: &quot;Port is {{ http_port }}&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这在排查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;变量
条件
Facts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;时非常有用。&lt;/p&gt;
&lt;h1&gt;三十四、Ansible 运维自动化的典型应用&lt;/h1&gt;
&lt;p&gt;Ansible 可以覆盖大量运维任务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;服务器初始化
软件安装
用户管理
SSH 配置
Nginx 部署
数据库部署
Docker 部署
Kubernetes 节点初始化
日志配置
监控 Agent 部署
防火墙配置
定时任务
应用发布
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;新服务器上线
      │
      ▼
Ansible
      │
      ├── 创建用户
      ├── 配置 SSH
      ├── 配置时区
      ├── 安装 Docker
      ├── 安装 node_exporter
      ├── 配置 Nginx
      └── 加入监控
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;原本可能需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;30 分钟
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;自动化之后可以变成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook bootstrap.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;三十五、Ansible 与 Docker / Kubernetes&lt;/h1&gt;
&lt;p&gt;前面已经学习：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker
Kubernetes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 则可以站在更高层做自动化。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ansible
    │
    ├── 安装 Docker
    ├── 配置 Docker
    ├── 部署 Compose
    │
    └── 准备 Kubernetes Node
              │
              ├── containerd
              ├── kubeadm
              ├── kubelet
              └── 网络配置
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker
→ 容器运行

Kubernetes
→ 容器编排

Ansible
→ 自动化配置和部署
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;三者解决的问题不同。&lt;/p&gt;
&lt;h1&gt;三十六、Ansible 与 CI/CD&lt;/h1&gt;
&lt;p&gt;Ansible 还可以被 CI/CD 调用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Git Push
   │
   ▼
CI Pipeline
   │
   ▼
Build
   │
   ▼
Docker Image
   │
   ▼
Ansible
   │
   ▼
Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GitHub Actions
      │
      ▼
ansible-playbook deploy.yml
      │
      ▼
Production Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就可以形成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;代码提交
 ↓
自动测试
 ↓
构建镜像
 ↓
自动部署
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible 可以作为发布流程中的一个执行步骤，具体编排取决于现有流水线。&lt;/p&gt;
&lt;h1&gt;三十七、Ansible 项目推荐目录&lt;/h1&gt;
&lt;p&gt;小型项目：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible/
├── ansible.cfg
├── inventory
└── site.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;稍大的项目：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible/
├── ansible.cfg
├── inventory/
│   ├── production
│   └── development
├── group_vars/
├── host_vars/
├── playbooks/
│   ├── site.yml
│   ├── web.yml
│   └── db.yml
├── roles/
│   ├── nginx/
│   ├── docker/
│   └── node_exporter/
└── requirements.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样能够把：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机
变量
Playbook
Role
依赖
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分别组织起来。&lt;/p&gt;
&lt;p&gt;Ansible 官方也提供了按功能组织 Inventory、Playbook、Roles、Variables、Files 等内容的示例项目结构。&lt;/p&gt;
&lt;h1&gt;三十八、从手工运维到自动化运维&lt;/h1&gt;
&lt;p&gt;传统方式：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;服务器 1
   ↓
SSH
   ↓
手工操作

服务器 2
   ↓
SSH
   ↓
手工操作

服务器 3
   ↓
SSH
   ↓
手工操作
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;容易出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;人为失误
环境不一致
配置漂移
重复劳动
难以审计
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;              Playbook
                  │
                  ▼
              Inventory
                  │
      ┌───────────┼───────────┐
      ▼           ▼           ▼
    Server 1    Server 2    Server 3
      │           │           │
      └───────────┼───────────┘
                  ▼
           Desired State
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;同一份配置
→ 多台机器
→ 重复执行
→ 保持一致
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;三十九、Ansible 核心模型&lt;/h1&gt;
&lt;p&gt;学习到这里，可以把 Ansible 浓缩成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    Ansible
                       │
              ┌────────┴────────┐
              ▼                 ▼
          Control Node       Inventory
              │                 │
              └────────┬────────┘
                       ▼
                    Playbook
                       │
            ┌──────────┼──────────┐
            ▼          ▼          ▼
          Tasks      Variables   Templates
            │                     │
            ▼                     ▼
         Modules                Config
            │
            ▼
       Managed Nodes
            │
            ▼
      Desired State
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Role 再提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;复用与组织
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Vault 提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;敏感变量保护
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check Mode 提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;执行前验证
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Handlers 提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;变更后的条件化操作
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;四十、Ansible 故障排查总模型&lt;/h1&gt;
&lt;p&gt;最终可以形成一套固定排查顺序：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                Playbook 执行失败
                        │
                        ▼
                  Inventory 正确吗？
                        │
                        ▼
                   Host 能解析吗？
                        │
                        ▼
                    SSH 能连接吗？
                        │
                        ▼
                   权限是否足够？
                        │
                        ▼
                    Module 正确吗？
                        │
                        ▼
                   Variables 正确吗？
                        │
                        ▼
                    Task 失败原因
                        │
                        ▼
                   服务本身正常吗？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常用命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 查看版本
ansible --version

# 检查 Inventory
ansible-inventory -i inventory --graph

# 测试连接
ansible all -m ansible.builtin.ping

# 查看 Module
ansible-doc ansible.builtin.apt

# 执行 Playbook
ansible-playbook -i inventory playbook.yml

# 检查模式
ansible-playbook -i inventory playbook.yml --check

# 查看配置变化
ansible-playbook -i inventory playbook.yml --diff

# 更详细日志
ansible-playbook -i inventory playbook.yml -vvv
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;四十一、总结&lt;/h1&gt;
&lt;p&gt;Ansible 的核心知识可以整理成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Inventory
→ 管理哪些机器

Playbook
→ 要做什么

Task
→ 一个具体步骤

Module
→ 用什么方式完成

Variable
→ 不同机器有什么差异

Facts
→ 机器当前是什么状态

Template
→ 根据变量生成配置

Handler
→ 配置变化后执行什么

Role
→ 如何复用和组织自动化内容

Vault
→ 如何保存敏感数据

Become
→ 如何执行需要高权限的操作

Check Mode
→ 执行之前如何检查
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完整执行链：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Inventory
    │
    ▼
Playbook
    │
    ▼
Tasks
    │
    ├── Variables
    ├── Facts
    ├── Conditions
    ├── Loops
    ├── Templates
    └── Handlers
    │
    ▼
Modules
    │
    ▼
Managed Nodes
    │
    ▼
Desired State
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终可以用一句话理解 Ansible：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ansible 把原本需要运维人员逐台 SSH 登录执行的重复操作，转换成可以批量执行、重复运行和版本管理的自动化配置。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;而从运维视角看，它真正重要的价值是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;少手工
少错误
保持一致
可重复
可审计
可扩展
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当服务器只有一台时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ansible
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看起来可能有些“重”。&lt;/p&gt;
&lt;p&gt;但当环境变成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10 台
100 台
1000 台
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;甚至需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker
Kubernetes
监控
日志
应用发布
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一起维护时，自动化就会逐渐从：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“方便的工具”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;变成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“基础设施管理的一部分”
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/&quot;&gt;Ansible Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/projects/ansible/latest/installation_guide/intro_installation.html&quot;&gt;Installing Ansible&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/projects/ansible/latest/getting_started/index.html&quot;&gt;Getting Started with Ansible&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_intro.html&quot;&gt;Ansible Playbooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_reuse_roles.html&quot;&gt;Ansible Roles&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>监控：日志收集与分析</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%9B%91%E6%8E%A7%E6%97%A5%E5%BF%97%E6%94%B6%E9%9B%86%E4%B8%8E%E5%88%86%E6%9E%90%E5%9F%BA%E7%A1%80/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%9B%91%E6%8E%A7%E6%97%A5%E5%BF%97%E6%94%B6%E9%9B%86%E4%B8%8E%E5%88%86%E6%9E%90%E5%9F%BA%E7%A1%80/</guid><description>介绍日志产生、采集、解析、存储、检索和保留策略，以及常见排障方法。</description><pubDate>Mon, 14 Sep 2026 04:22:13 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Metrics 告诉我们“系统发生了什么变化”，而 Logs 更擅长告诉我们“具体发生了什么”。&lt;/p&gt;
&lt;p&gt;日志收集的核心并不是简单地把日志文件复制到另一台机器，而是建立一条从&lt;strong&gt;产生、采集、解析、传输、存储到查询分析&lt;/strong&gt;的完整链路。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;一、日志与日志系统&lt;/h1&gt;
&lt;h2&gt;1.1 什么是日志&lt;/h2&gt;
&lt;p&gt;日志（Log）是系统运行过程中产生的事件记录。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2026-09-14 10:32:11 INFO  Application started
2026-09-14 10:32:15 INFO  Request GET /api/users
2026-09-14 10:32:18 ERROR Database connection refused
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一条日志通常包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;时间
级别
来源
消息
上下文
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2026-09-14 10:32:18
       │
       ├── 时间
       ├── ERROR
       ├── backend
       └── Database connection refused
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;日志和 Metrics 的区别可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Metrics
→ 数值化状态

Logs
→ 具体事件记录
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU = 95%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;属于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Metric
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;OutOfMemoryError: Java heap space
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;属于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Log
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;1.2 为什么需要日志&lt;/h2&gt;
&lt;p&gt;当监控发现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP 5xx ↑
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Metric 可以告诉我们：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;错误率升高了
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但还需要知道：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;什么请求失败？
为什么失败？
哪个服务失败？
什么时候开始？
异常信息是什么？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时就需要日志。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Metrics
   │
   ▼
发现异常
   │
   ▼
Logs
   │
   ▼
分析原因
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也是实际运维中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;监控
+
日志
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;经常配合使用的原因。&lt;/p&gt;
&lt;h1&gt;二、日志的来源&lt;/h1&gt;
&lt;p&gt;一个 Linux 系统中，日志可能来自多个位置。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                        Logs
                          │
       ┌──────────────────┼──────────────────┐
       │                  │                  │
       ▼                  ▼                  ▼
     System            Application        Container
       │                  │                  │
   journald            log file           stdout
   syslog              stdout             stderr
   kernel              stderr
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.1 系统日志&lt;/h2&gt;
&lt;p&gt;Linux 本身会产生：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;内核事件
服务状态
认证信息
启动信息
系统错误
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现代 Linux 系统中常见来源之一是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemd-journald
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;journalctl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;journalctl -u nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只查看最近一小时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;journalctl --since &quot;1 hour ago&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看本次启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;journalctl -b
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.2 文件日志&lt;/h2&gt;
&lt;p&gt;很多应用会直接写入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/var/log/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/var/log/
├── nginx/
├── mysql/
├── redis/
└── ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nginx 常见：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;access.log
error.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用也可能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/app/logs/application.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此日志采集器需要能够：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;读取文件
持续跟踪文件
识别新增内容
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.3 标准输出与标准错误&lt;/h2&gt;
&lt;p&gt;现代容器化应用非常常见的日志方式是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;stdout
stderr
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
   ├── stdout
   └── stderr
         │
         ▼
Container Runtime
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kubernetes 官方也建议容器化应用将日志写入标准输出和标准错误，这也是 Kubernetes 日志收集最常见的基础方式。&lt;/p&gt;
&lt;p&gt;Docker 同样提供专门的 Logging Driver 来处理容器的日志输出。Docker Engine 默认使用 &lt;code&gt;json-file&lt;/code&gt; logging driver，但也支持 &lt;code&gt;local&lt;/code&gt;、&lt;code&gt;journald&lt;/code&gt;、&lt;code&gt;syslog&lt;/code&gt;、&lt;code&gt;fluentd&lt;/code&gt; 等方式。&lt;/p&gt;
&lt;h1&gt;三、日志级别&lt;/h1&gt;
&lt;p&gt;应用通常会对日志进行分级。&lt;/p&gt;
&lt;p&gt;常见级别：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TRACE
DEBUG
INFO
WARN
ERROR
FATAL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不同框架名称可能略有不同。&lt;/p&gt;
&lt;p&gt;可以粗略理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DEBUG
→ 调试细节

INFO
→ 正常运行信息

WARN
→ 潜在问题

ERROR
→ 请求或操作发生错误

FATAL
→ 严重错误，可能导致程序退出
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;INFO
Application started

WARN
Connection pool is near capacity

ERROR
Database connection refused
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.1 为什么不能全部输出 DEBUG&lt;/h2&gt;
&lt;p&gt;开发环境可能需要大量 DEBUG 日志。&lt;/p&gt;
&lt;p&gt;但生产环境如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;所有请求
+
所有变量
+
所有 SQL
+
大量调试信息
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;全部输出，就可能导致：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;日志量暴增
磁盘增长
网络带宽增加
存储成本增加
查询困难
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此生产环境通常会根据实际需要设置日志级别。&lt;/p&gt;
&lt;h1&gt;四、日志格式&lt;/h1&gt;
&lt;h2&gt;4.1 非结构化日志&lt;/h2&gt;
&lt;p&gt;最简单的日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2026-09-14 10:31:20 ERROR Database connection refused
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;人比较容易阅读，但程序解析起来比较麻烦。&lt;/p&gt;
&lt;h2&gt;4.2 结构化日志&lt;/h2&gt;
&lt;p&gt;更适合集中式日志系统：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;timestamp&quot;: &quot;2026-09-14T10:31:20Z&quot;,
  &quot;level&quot;: &quot;ERROR&quot;,
  &quot;service&quot;: &quot;backend&quot;,
  &quot;message&quot;: &quot;Database connection refused&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结构化日志可以明确区分：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;timestamp
level
service
message
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后续查询时可以直接按照字段过滤：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;level = ERROR
service = backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是通过字符串搜索整行文本。&lt;/p&gt;
&lt;h2&gt;4.3 为什么结构化日志重要&lt;/h2&gt;
&lt;p&gt;假设有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;100 万条日志
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果都是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;纯文本字符串
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分析器通常需要先进行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;解析
提取字段
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果日志本身已经结构化：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;JSON
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么采集系统更容易建立：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;字段
索引
过滤条件
聚合
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这会直接影响后面的集中式日志分析。&lt;/p&gt;
&lt;h1&gt;五、日志轮转 Log Rotation&lt;/h1&gt;
&lt;h2&gt;5.1 为什么需要日志轮转&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;application.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每天增长：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2 GB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个月之后可能达到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;60 GB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果一直写同一个文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;磁盘最终会被写满
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Log Rotation
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型过程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;application.log
       │
       ▼
application.log.1
       │
       ▼
application.log.2
       │
       ▼
application.log.3.gz
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;旧日志可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;压缩
保留
删除
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.2 logrotate&lt;/h2&gt;
&lt;p&gt;Linux 中常见工具：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;logrotate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以根据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;时间
文件大小
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;轮转日志，并支持压缩、保留数量等操作。&lt;/p&gt;
&lt;p&gt;例如配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/var/log/myapp/*.log {
    daily
    rotate 7
    compress
    missingok
    notifempty
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;含义大致是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;每天轮转
保留 7 份
压缩旧日志
日志不存在不报错
空日志不轮转
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.3 日志轮转的一个常见坑&lt;/h2&gt;
&lt;p&gt;应用打开了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;application.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行轮转后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;application.log
→ application.log.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果应用仍然持有原文件描述符，就可能出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;文件名已经变了
但进程仍然写旧文件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此某些应用轮转后需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;reload
reopen
HUP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等机制重新打开日志文件。&lt;/p&gt;
&lt;p&gt;所以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Log Rotation
≠
只改文件名
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还要考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用如何重新打开日志
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;六、日志收集&lt;/h1&gt;
&lt;h2&gt;6.1 什么是日志采集&lt;/h2&gt;
&lt;p&gt;日志采集就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Log Source
    │
    ▼
Collector / Agent
    │
    ▼
Backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/var/log/nginx/access.log
          │
          ▼
      Log Agent
          │
          ▼
   Central Log Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;日志采集器通常需要完成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;读取
解析
过滤
添加字段
缓存
批量发送
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6.2 Agent&lt;/h2&gt;
&lt;p&gt;Agent 通常运行在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;被监控服务器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Server A
  └── Log Agent

Server B
  └── Log Agent

Server C
  └── Log Agent
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;统一发送：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        ┌── Server A ── Agent ──┐
        ├── Server B ── Agent ──┤
        └── Server C ── Agent ──┘
                                 │
                                 ▼
                         Central Log Backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种方式非常适合大量服务器。&lt;/p&gt;
&lt;h2&gt;6.3 为什么通常使用 Agent&lt;/h2&gt;
&lt;p&gt;如果没有 Agent：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Central Server
   │
   ├── SSH Server A
   ├── SSH Server B
   ├── SSH Server C
   └── ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;中心服务器主动去每台机器拉日志，管理会比较复杂。&lt;/p&gt;
&lt;p&gt;使用 Agent：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Server
  │
  └── Agent
       │
       └──► Central Backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;日志产生在哪里，就在那里进行采集。&lt;/p&gt;
&lt;h1&gt;七、日志采集器应该做什么&lt;/h1&gt;
&lt;p&gt;一个成熟的日志采集器通常不仅是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是完整的数据处理过程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;              Log File
                 │
                 ▼
              Tail
                 │
                 ▼
             Parse
                 │
                 ▼
            Transform
                 │
                 ▼
              Enrich
                 │
                 ▼
              Buffer
                 │
                 ▼
               Send
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7.1 Tail&lt;/h2&gt;
&lt;p&gt;持续读取新增日志。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;application.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用继续写：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Line 100
Line 101
Line 102
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agent 只读取新增内容，而不是每次都重新读取整个文件。&lt;/p&gt;
&lt;h2&gt;7.2 Position / Offset&lt;/h2&gt;
&lt;p&gt;采集器需要知道：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“我已经读到哪里了？”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;application.log
             │
             ├── 已读取到 Line 1000
             │
             └── 新增 Line 1001+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此通常需要保存：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;文件位置
offset
inode / file identity
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样 Agent 重启后才能尽量从正确位置继续。&lt;/p&gt;
&lt;p&gt;OpenTelemetry 的 &lt;code&gt;filelog&lt;/code&gt; receiver 等日志采集能力同样包含文件跟踪、日志轮转识别和 checkpoint 等机制。&lt;/p&gt;
&lt;h2&gt;7.3 Parse&lt;/h2&gt;
&lt;p&gt;例如原始日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;127.0.0.1 - - [14/Sep/2026:10:30:12 +0800] &quot;GET /api HTTP/1.1&quot; 200 1234
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;采集器可以解析成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;client_ip = 127.0.0.1
method    = GET
path      = /api
status    = 200
bytes     = 1234
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7.4 Enrich&lt;/h2&gt;
&lt;p&gt;采集器还可以增加额外字段：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;host
service
environment
container
pod
namespace
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;service&quot;: &quot;backend&quot;,
  &quot;environment&quot;: &quot;production&quot;,
  &quot;host&quot;: &quot;node-01&quot;,
  &quot;level&quot;: &quot;ERROR&quot;,
  &quot;message&quot;: &quot;Database connection refused&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样后面的集中式系统就可以方便地进行过滤和聚合。&lt;/p&gt;
&lt;h1&gt;八、集中式日志&lt;/h1&gt;
&lt;h2&gt;8.1 为什么需要集中式日志&lt;/h2&gt;
&lt;p&gt;假设有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;100 台服务器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每台都有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/var/log/app.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用户访问出现异常时，如果要求运维：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SSH 到 Server 1
SSH 到 Server 2
SSH 到 Server 3
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;逐台搜索：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ERROR
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;效率会非常低。&lt;/p&gt;
&lt;p&gt;集中式日志就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Server 1 ─┐
Server 2 ─┤
Server 3 ─┤
Server 4 ─┤
           ▼
      Central Backend
           │
           ▼
         Search
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是可以统一查询：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;service = backend
level = ERROR
time &amp;gt; 10:30
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8.2 集中式日志的核心能力&lt;/h2&gt;
&lt;p&gt;一个日志平台通常需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;采集
传输
存储
索引
查询
过滤
聚合
可视化
权限
保留策略
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;日志系统
≠
日志文件服务器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它实际上是一整套数据处理系统。&lt;/p&gt;
&lt;h1&gt;九、集中式日志的典型架构&lt;/h1&gt;
&lt;p&gt;最简单：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                ┌── Agent ── Server A
                │
Log Sources ────┼── Agent ── Server B
                │
                └── Agent ── Server C
                         │
                         ▼
                  Central Backend
                         │
                         ▼
                      Query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更完整：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Logs
 │
 ▼
Collection
 │
 ▼
Parsing
 │
 ▼
Buffer / Queue
 │
 ▼
Storage
 │
 ▼
Index
 │
 ▼
Search
 │
 ▼
Visualization
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;中间还可以加入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Filtering
Sampling
Enrichment
Routing
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十、日志传输&lt;/h1&gt;
&lt;p&gt;日志从 Agent 到中心系统，通常需要通过网络发送。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Agent
  │
  │ TCP / HTTP / gRPC / Syslog
  ▼
Log Backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络断开
连接超时
服务不可用
认证失败
数据发送过快
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此日志系统也会受到网络质量影响。&lt;/p&gt;
&lt;h2&gt;10.1 Buffer&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;日志产生速度
&amp;gt;
日志发送速度
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;日志会积压
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Producer
  │
  │ 10000 logs/s
  ▼
Agent
  │
  │ 5000 logs/s
  ▼
Backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时候需要考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Memory Buffer
Disk Buffer
Queue
Backpressure
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;否则后端短暂故障可能直接造成日志丢失。&lt;/p&gt;
&lt;h1&gt;十一、日志可靠性&lt;/h1&gt;
&lt;h2&gt;11.1 至少要回答几个问题&lt;/h2&gt;
&lt;p&gt;一个日志系统不能只问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“能查到日志吗？”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还应该考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;日志会不会丢？
日志会不会重复？
日志会延迟多久？
后端挂了怎么办？
磁盘满了怎么办？
日志保留多久？
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;11.2 At-least-once 与重复日志&lt;/h2&gt;
&lt;p&gt;日志采集中，经常需要在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;不丢日志
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;与：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;不重复
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之间做权衡。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送成功
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但 Agent 在收到确认前突然崩溃。&lt;/p&gt;
&lt;p&gt;重启后可能重新发送之前的数据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Log A
Log A
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Duplicate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此集中式日志系统经常需要依赖：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;offset
ack
checkpoint
id
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等机制提高可靠性。&lt;/p&gt;
&lt;p&gt;对于日志而言：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;至少一次
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通常比：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;完全不重复
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更容易保证。&lt;/p&gt;
&lt;h1&gt;十二、Docker 日志&lt;/h1&gt;
&lt;p&gt;容器环境通常会把应用输出写到标准输出和标准错误：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;stdout
stderr
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里进一步从日志系统角度理解。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container
   │
   ├── stdout
   └── stderr
         │
         ▼
     Docker Logging Driver
         │
         ▼
       Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Docker 当前默认 logging driver 为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;json-file
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时还提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;local
syslog
journald
gelf
fluentd
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等驱动。&lt;/p&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker info
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以直接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker info --format &apos;{{.LoggingDriver}}&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看当前默认 Logging Driver。&lt;/p&gt;
&lt;h2&gt;12.1 Docker 日志磁盘问题&lt;/h2&gt;
&lt;p&gt;容器日志如果持续增长：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container
   │
   ▼
Logs
   │
   ▼
Host Disk
   │
   ▼
100%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终可能导致：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker 异常
数据库异常
应用写文件失败
整个服务器磁盘不足
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;容器日志
+
日志轮转
+
日志保留策略
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;必须一起考虑。&lt;/p&gt;
&lt;p&gt;Docker 官方也特别提示日志文件可能造成宿主机磁盘耗尽，并提供 &lt;code&gt;local&lt;/code&gt; logging driver 等机制减少这类风险。&lt;/p&gt;
&lt;h1&gt;十三、Kubernetes 日志&lt;/h1&gt;
&lt;p&gt;Kubernetes 环境的日志结构比单机 Docker 更复杂。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
 │
 ├── Container A
 └── Container B
        │
        ▼
      stdout
      stderr
        │
        ▼
   Node-level logging
        │
        ▼
 Central Logging
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kubernetes 官方将：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Node-level logging agent
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;作为常见的集群级日志方案，并推荐在每个 Node 上运行一个日志 Agent；常见实现方式是使用 DaemonSet，使每个节点运行一个 Agent。&lt;/p&gt;
&lt;h2&gt;13.1 为什么不能只依赖 Pod 本地日志&lt;/h2&gt;
&lt;p&gt;Pod 可能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;被删除
被重新调度
Node 故障
Container 重启
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果日志只保存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod / Node 本地
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就可能随着运行环境消失。&lt;/p&gt;
&lt;p&gt;因此集群日志应该尽量做到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod Logs
   │
   ▼
Node Agent
   │
   ▼
Central Backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使日志生命周期独立于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
Container
Node
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kubernetes 官方也明确指出，集群级日志应该拥有独立于 Node、Pod 和 Container 生命周期的存储与管理方式。&lt;/p&gt;
&lt;h1&gt;十四、Node Agent、Sidecar 与直接上报&lt;/h1&gt;
&lt;p&gt;Kubernetes 集群级日志常见有三种基本思路。&lt;/p&gt;
&lt;h2&gt;14.1 Node-level Agent&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Node
 │
 ├── Pod A
 ├── Pod B
 ├── Pod C
 │
 └── Log Agent
          │
          ▼
       Backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;每个 Node 一个 Agent
应用基本无需修改
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也是非常常见的方案。&lt;/p&gt;
&lt;h2&gt;14.2 Sidecar&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Pod
├── Application
└── Log Sidecar
         │
         ▼
      Backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;适合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用只能输出文件
不同日志需要特殊处理
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但代价是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;每个 Pod 增加额外容器
CPU / Memory 增加
配置复杂
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;14.3 应用直接发送&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Application
     │
     ▼
Log Backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用自己负责：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送
重试
认证
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样可以减少中间层，但会让应用与日志基础设施耦合。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Node Agent
→ 通用性强

Sidecar
→ 针对单个工作负载定制

Direct
→ 应用主动管理日志输出
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十五、日志解析与多行日志&lt;/h1&gt;
&lt;h2&gt;15.1 为什么多行日志是问题&lt;/h2&gt;
&lt;p&gt;很多异常不是一行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ERROR Application failed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是一整个 Stack Trace：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ERROR Application failed
java.lang.RuntimeException: ...
    at com.example.App.run(App.java:100)
    at com.example.Main.main(Main.java:20)
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果采集器简单按：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;一行 = 一条日志
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终可能变成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Log 1 → ERROR Application failed
Log 2 → java.lang.RuntimeException
Log 3 → at com.example.App.run
Log 4 → at com.example.Main.main
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;原本的一次异常就被拆散了。&lt;/p&gt;
&lt;p&gt;因此日志采集器需要支持：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Multiline Parsing
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;把多行内容重新组合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Stack Trace
     │
     ▼
Single Log Record
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;15.2 多行解析要谨慎&lt;/h2&gt;
&lt;p&gt;如果正则配置错误：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;正常日志
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能被错误合并成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;一条超长日志
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以多行规则需要根据具体应用日志格式设计。&lt;/p&gt;
&lt;h1&gt;十六、时间戳与时区&lt;/h1&gt;
&lt;p&gt;日志分析中非常重要的一项信息：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Timestamp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2026-09-14 10:30:00
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果不同服务器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Server A → UTC
Server B → UTC+8
Server C → UTC+9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;集中后可能导致：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;事件顺序混乱
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此日志系统应该明确：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;时间格式
时区
时间同步
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;生产系统通常需要保证服务器时钟同步，否则：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Log
+
Metric
+
Trace
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之间可能难以正确关联。&lt;/p&gt;
&lt;h1&gt;十七、日志与敏感信息&lt;/h1&gt;
&lt;p&gt;日志里非常容易出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;密码
Token
Cookie
Session ID
身份证号码
手机号
邮箱
数据库连接信息
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是一类很严重的问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用正常运行
 ↓
日志记录敏感信息
 ↓
集中式日志平台
 ↓
更多人可以查询
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是敏感信息的暴露范围反而扩大。&lt;/p&gt;
&lt;p&gt;因此日志系统应该遵循：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;不要记录不必要的敏感信息
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并同时考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;脱敏
权限控制
加密传输
访问审计
保留期限
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;password=123456
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不应该直接写进生产日志。&lt;/p&gt;
&lt;p&gt;更合理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;password=******
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者根本不记录。&lt;/p&gt;
&lt;h1&gt;十八、日志保留策略&lt;/h1&gt;
&lt;p&gt;日志并不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;保存越久越好
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为日志量可能非常大。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;每天 20 GB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一年就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;7 TB+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此需要制定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Retention Policy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;热数据
→ 7 天

温数据
→ 30 天

归档
→ 180 天
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;具体策略取决于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;业务需求
合规要求
成本
排障周期
审计要求
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时需要明确：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;删除
压缩
归档
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之间的区别。&lt;/p&gt;
&lt;h1&gt;十九、日志系统的性能问题&lt;/h1&gt;
&lt;p&gt;日志系统本身也可能成为性能瓶颈。&lt;/p&gt;
&lt;p&gt;主要观察：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;日志产生速率
采集速率
传输速率
写入速率
查询速率
存储容量
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
  │
  │ 50 MB/s
  ▼
Agent
  │
  │ 40 MB/s
  ▼
Backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10 MB/s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;会持续积压。&lt;/p&gt;
&lt;p&gt;进一步：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Buffer
→ 越来越大
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后可能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Agent 磁盘写满
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此日志系统也需要监控：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Queue Length
Dropped Logs
Send Errors
Backend Latency
Disk Usage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“监控日志系统本身”
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十、日志故障排查&lt;/h1&gt;
&lt;p&gt;日志系统出现问题时，可以按照：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Source
 ↓
Agent
 ↓
Network
 ↓
Backend
 ↓
Query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;逐层排查。&lt;/p&gt;
&lt;h2&gt;20.1 Agent 没有采集&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;application.log
有新日志
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但中心平台没有。&lt;/p&gt;
&lt;p&gt;首先：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;文件路径对吗？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Agent 是否运行？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Agent 是否读取到新增内容？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;offset 是否正确？
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;20.2 日志采集后没有发送&lt;/h2&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Agent Logs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;连接
认证
TLS
后端地址
队列
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;20.3 网络问题&lt;/h2&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -ntp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nc -vz &amp;lt;backend&amp;gt; &amp;lt;port&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果使用 HTTP，可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -v http://&amp;lt;backend&amp;gt;:&amp;lt;port&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;20.4 后端收到了，但查不到&lt;/h2&gt;
&lt;p&gt;这时继续检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;索引
时间范围
字段
解析
写入状态
查询条件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个非常常见的问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;日志实际上已经写入
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但 Dashboard 查询的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;时间范围
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不正确。&lt;/p&gt;
&lt;h1&gt;二十一、一个完整的集中式日志案例&lt;/h1&gt;
&lt;p&gt;假设有三台 Web Server：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Server 1
Nginx

Server 2
Nginx

Server 3
Nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每台都有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;access.log
error.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;架构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Server 1
 ├── access.log
 ├── error.log
 └── Agent
       │
       │
Server 2│
 ├── access.log
 ├── error.log
 └── Agent
       │
       │
Server 3│
 ├── access.log
 ├── error.log
 └── Agent
       │
       └──────────────┐
                      ▼
              Central Log Backend
                      │
                      ▼
                   Search
                      │
                      ▼
                Visualization
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终可以统一查询：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;service = nginx
status &amp;gt;= 500
time = last 1 hour
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;得到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Server 1 → 502
Server 2 → 500
Server 3 → 502
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后再进一步根据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;upstream
request_uri
client_ip
response_time
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;定位问题。&lt;/p&gt;
&lt;h1&gt;二十二、日志与 Metrics 的结合&lt;/h1&gt;
&lt;p&gt;假设 Prometheus 发现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP 500 ↑
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Grafana 显示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        5xx
          │
          │        /\
          │       /  \
          │______/    \____
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个时候可以根据时间：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10:30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;去查询日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10:30 ERROR Database connection refused
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Metric
→ 告诉你异常从什么时候开始

Log
→ 告诉你具体发生了什么
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是可观测性中非常核心的协同方式。&lt;/p&gt;
&lt;h1&gt;二十三、日志与 Trace 的关系&lt;/h1&gt;
&lt;p&gt;随着系统变成微服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client
  │
  ▼
API Gateway
  │
  ▼
Service A
  │
  ▼
Service B
  │
  ▼
Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一次用户请求可能经过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A
B
C
D
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时只搜索：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ERROR
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能找到数千条日志。&lt;/p&gt;
&lt;p&gt;如果日志中包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;trace_id
span_id
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Trace ID = abc123
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查询与这一次请求有关的日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Service A
Service B
Service C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Metrics
   │
   ▼
异常发生

Logs
   │
   ▼
具体错误

Traces
   │
   ▼
请求经过哪些服务
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;OpenTelemetry 当前的日志设计也非常重视与其他遥测信号的关联，并支持把 Trace ID、Span ID 等上下文关联到日志中。&lt;/p&gt;
&lt;p&gt;不过：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Trace、OpenTelemetry 和完整的 Metrics / Logs / Traces 体系属于进阶主题。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;二十四、常见日志采集工具&lt;/h1&gt;
&lt;p&gt;日志采集领域存在大量工具。&lt;/p&gt;
&lt;p&gt;典型可以分成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;轻量 Agent
   │
   ├── Fluent Bit
   ├── Vector
   └── Filebeat
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Telemetry Collector
   │
   └── OpenTelemetry Collector
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如 Fluent Bit 可以作为轻量级日志采集器，负责：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Input
→ Filter
→ Output
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而 OpenTelemetry Collector 则进一步提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Receiver
→ Processor
→ Exporter
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样的通用遥测处理管道，并支持日志数据。&lt;/p&gt;
&lt;p&gt;OpenTelemetry 官方日志规范明确支持：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;文件日志
日志轮转
文件位置 checkpoint
Syslog
解析
处理
导出
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并强调与现有日志系统和日志库进行兼容。&lt;/p&gt;
&lt;h1&gt;二十五、日志系统的整体模型&lt;/h1&gt;
&lt;p&gt;到这里可以把日志系统串起来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  Application
                       │
              ┌────────┴────────┐
              ▼                 ▼
           Log File           stdout
              │                 │
              └────────┬────────┘
                       ▼
                    Agent
                       │
             ┌─────────┼─────────┐
             ▼         ▼         ▼
           Parse     Filter    Enrich
             │         │         │
             └─────────┼─────────┘
                       ▼
                    Buffer
                       │
                       ▼
                    Network
                       │
                       ▼
               Central Backend
                       │
             ┌─────────┼─────────┐
             ▼         ▼         ▼
           Storage    Index     Query
                                 │
                                 ▼
                           Visualization
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此集中式日志系统真正解决的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;统一采集
统一存储
统一检索
统一分析
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十六、日志系统与 ELK / Elastic Stack&lt;/h1&gt;
&lt;p&gt;后续文章会进入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ELK / Elastic Stack
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最经典的组合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Log
 │
 ▼
Logstash
 │
 ▼
Elasticsearch
 │
 ▼
Kibana
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以暂时这样理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Logstash
→ 日志采集 / 处理 / 转发

Elasticsearch
→ 日志存储 / 索引 / 查询

Kibana
→ 日志可视化 / 分析
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不过现代 Elastic Stack 的实际架构可以加入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Beats
Elastic Agent
Logstash
Elasticsearch
Kibana
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等不同组件。&lt;/p&gt;
&lt;p&gt;因此这一篇只建立：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;日志为什么要集中化
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下一篇再重点研究：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Elasticsearch
Logstash
Kibana
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的具体实现。&lt;/p&gt;
&lt;h1&gt;二十七、日志收集与分析的运维思维&lt;/h1&gt;
&lt;p&gt;从运维角度，一条日志真正的生命周期是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;产生
 ↓
采集
 ↓
解析
 ↓
传输
 ↓
存储
 ↓
索引
 ↓
查询
 ↓
分析
 ↓
保留 / 删除
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;任何一环出现问题，都可能导致：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;日志丢失
日志延迟
查询不到
磁盘爆满
成本增加
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以排查日志问题时，不应该只检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“日志平台有没有这条日志”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而应该从源头一路追：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
 ↓
Log Source
 ↓
Agent
 ↓
Buffer
 ↓
Network
 ↓
Backend
 ↓
Index
 ↓
Query
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十八、总结&lt;/h1&gt;
&lt;p&gt;日志系统可以先记住下面这条主线：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Log Source
    │
    ▼
Collection Agent
    │
    ├── Tail
    ├── Parse
    ├── Filter
    ├── Enrich
    └── Buffer
    │
    ▼
Central Backend
    │
    ├── Storage
    ├── Index
    └── Query
          │
          ▼
      Visualization
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Linux 环境中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemd-journald
logrotate
应用日志文件
stdout / stderr
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解决的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;日志产生与本地管理
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而集中式日志进一步解决：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;多服务器
多容器
多服务
统一采集
统一搜索
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终可以把三类可观测数据暂时区分为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Metrics
→ 数值变化
→ Prometheus

Logs
→ 具体事件
→ 日志系统 / ELK

Traces
→ 请求调用链
→ OpenTelemetry 等
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下一阶段再把它们逐渐关联起来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Metrics
   │
   ▼
发现异常
   │
   ▼
Logs
   │
   ▼
定位错误
   │
   ▼
Traces
   │
   ▼
定位调用链上的具体环节
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;日志收集不是“把文件搬到另一台机器”，而是建立一条可持续、可检索、可分析的数据管道。对于运维而言，真正重要的是知道日志从哪里产生、经过哪些环节、在哪里可能丢失，以及如何最终利用日志定位故障。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/cluster-administration/logging/&quot;&gt;Kubernetes Logging Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/logging/configure/&quot;&gt;Docker Logging Drivers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://opentelemetry.io/docs/specs/otel/logs/&quot;&gt;OpenTelemetry Logs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.man7.org/linux/man-pages/man8/logrotate.8.html&quot;&gt;logrotate Linux Manual&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>监控：Prometheus 与 Grafana</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%9B%91%E6%8E%A7prometheus-%E4%B8%8E-grafana/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%9B%91%E6%8E%A7prometheus-%E4%B8%8E-grafana/</guid><description>介绍指标采集、Prometheus 查询、Grafana 可视化和基础告警流程。</description><pubDate>Mon, 14 Sep 2026 04:20:11 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;监控系统需要持续采集、保存、查询、可视化和告警。&lt;/p&gt;
&lt;p&gt;但这些命令主要解决“现在发生了什么”，而监控系统需要进一步解决“持续采集、保存、查询、可视化和告警”。&lt;/p&gt;
&lt;p&gt;Prometheus 负责采集和存储指标，PromQL 负责查询，Grafana 负责把这些数据展示出来，并进一步形成 Dashboard 与告警。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;一、Prometheus 与 Grafana 概述&lt;/h1&gt;
&lt;h2&gt;1.1 为什么需要监控系统&lt;/h2&gt;
&lt;p&gt;在 Linux 主机上，可以先用以下命令查看当前状态：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;top
free -h
df -h
ss -lntp
systemctl status nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看当前系统状态。&lt;/p&gt;
&lt;p&gt;但是这些工具存在一个问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;需要人工执行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU = 30%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只能说明：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;现在 CPU 大约是 30%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果希望知道：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;过去 24 小时 CPU 怎么变化？
什么时候开始升高？
部署之后有没有明显变化？
什么时候超过阈值？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就需要持续采集并保存数据。&lt;/p&gt;
&lt;p&gt;因此监控系统的基本流程是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;目标主机
   │
   ▼
指标暴露
   │
   ▼
Prometheus
   │
   ├── 采集
   ├── 存储
   └── 查询
        │
        ▼
      PromQL
        │
        ▼
      Grafana
        │
        ├── Dashboard
        └── Alerting
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;1.2 Prometheus 是什么&lt;/h2&gt;
&lt;p&gt;Prometheus 是开源的监控与告警工具，同时具备时间序列数据库能力。&lt;/p&gt;
&lt;p&gt;它最核心的数据模型是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Metric
+
Labels
+
Timestamp
+
Value
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http_requests_total{
    job=&quot;api&quot;,
    method=&quot;GET&quot;,
    status=&quot;200&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在某一个时间点可能对应：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;15320
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;随着时间变化：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10000
11000
12500
13800
15320
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些数据就组成了一条时间序列。&lt;/p&gt;
&lt;p&gt;Prometheus 官方将自己的核心特点概括为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;多维度时间序列数据模型&lt;/li&gt;
&lt;li&gt;PromQL 查询语言&lt;/li&gt;
&lt;li&gt;HTTP Pull 模型&lt;/li&gt;
&lt;li&gt;Service Discovery&lt;/li&gt;
&lt;li&gt;本地时间序列存储&lt;/li&gt;
&lt;li&gt;告警规则与 Alertmanager&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;官方文档：
&lt;a href=&quot;https://prometheus.io/docs/introduction/overview/&quot;&gt;Prometheus Overview&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;1.3 Grafana 是什么&lt;/h2&gt;
&lt;p&gt;Grafana 更偏向：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;查询
+
可视化
+
Dashboard
+
告警
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它本身不是 Prometheus 的替代品。&lt;/p&gt;
&lt;p&gt;典型关系：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Prometheus
    │
    │ PromQL
    ▼
 Grafana
    │
    ├── Graph
    ├── Gauge
    ├── Table
    ├── Stat
    └── Alert
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Grafana 通过 Data Source 连接外部数据系统。&lt;/p&gt;
&lt;p&gt;除了 Prometheus，还可以连接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Loki
Elasticsearch
MySQL
PostgreSQL
InfluxDB
CloudWatch
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是说：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Prometheus
→ 保存和提供 Metrics

Grafana
→ 查询和展示 Metrics
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Grafana 官方：
&lt;a href=&quot;https://grafana.com/docs/grafana/latest/datasources/&quot;&gt;Grafana Data Sources&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;二、Prometheus 的核心数据模型&lt;/h1&gt;
&lt;h2&gt;2.1 Metric&lt;/h2&gt;
&lt;p&gt;Metric 就是需要观察的指标。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU 使用率
内存使用量
磁盘空间
HTTP 请求数
HTTP 错误数
数据库连接数
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node_cpu_seconds_total
node_memory_MemAvailable_bytes
node_filesystem_avail_bytes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等指标表示。&lt;/p&gt;
&lt;h2&gt;2.2 Labels&lt;/h2&gt;
&lt;p&gt;Prometheus 最大的特点之一就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Labels
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http_requests_total{
    method=&quot;GET&quot;,
    status=&quot;200&quot;,
    instance=&quot;10.0.0.10:8080&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同一个 Metric：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http_requests_total
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过不同的 Label 可以形成不同的时间序列：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;method=GET
status=200

method=GET
status=500

method=POST
status=200
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Metric Name
+
Labels
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;共同确定一条具体的时间序列。&lt;/p&gt;
&lt;p&gt;Prometheus 官方数据模型：
&lt;a href=&quot;https://prometheus.io/docs/concepts/data_model/&quot;&gt;Data model&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;2.3 Label Cardinality&lt;/h2&gt;
&lt;p&gt;Label 虽然非常强大，但不能无限制地增加。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;user_id
request_id
session_id
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果每个请求都产生不同的 Label 值：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;request_id=abc001
request_id=abc002
request_id=abc003
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就会产生大量时间序列。&lt;/p&gt;
&lt;p&gt;这就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;High Cardinality
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能导致：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;内存增加
磁盘增加
查询变慢
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此 Prometheus 中需要谨慎设计 Label。&lt;/p&gt;
&lt;p&gt;一般来说：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;服务名
实例
HTTP Method
HTTP Status
环境
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这类有限集合更适合作为 Label。&lt;/p&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户 ID
订单 ID
请求 ID
UUID
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通常不适合直接作为高频 Metric Label。&lt;/p&gt;
&lt;h1&gt;三、Prometheus 的 Pull 模型&lt;/h1&gt;
&lt;h2&gt;3.1 Prometheus 如何获取指标&lt;/h2&gt;
&lt;p&gt;Prometheus 最典型的工作方式是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Exporter / Application
        │
        │ HTTP /metrics
        ▼
    Prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Prometheus 主动去目标地址抓取：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET /metrics
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pull
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;模型。&lt;/p&gt;
&lt;p&gt;官方文档明确说明，Prometheus 默认通过 HTTP Pull 模型采集时间序列。&lt;/p&gt;
&lt;h2&gt;3.2 /metrics&lt;/h2&gt;
&lt;p&gt;很多 Prometheus Exporter 会提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/metrics
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://10.0.0.10:9100/metrics
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;内容通常类似：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# HELP node_cpu_seconds_total ...
# TYPE node_cpu_seconds_total counter

node_cpu_seconds_total{
    cpu=&quot;0&quot;,
    mode=&quot;idle&quot;
} 12345
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/metrics
→ 向 Prometheus 暴露可采集指标
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.3 Push 与 Pull&lt;/h2&gt;
&lt;p&gt;Prometheus 主要采用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pull
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但也支持某些特殊场景下通过 Pushgateway 接收短生命周期任务推送的数据。&lt;/p&gt;
&lt;p&gt;不过应该注意：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pushgateway
≠
Prometheus 默认采集方式
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于长期运行的服务，通常优先使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Prometheus → Pull → Target
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;四、Exporter&lt;/h1&gt;
&lt;h2&gt;4.1 Exporter 是什么&lt;/h2&gt;
&lt;p&gt;Exporter 可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;把某个系统的数据
转换成 Prometheus Metrics
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Linux
  │
  ▼
node_exporter
  │
  ▼
/metrics
  │
  ▼
Prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不同系统可能使用不同 Exporter：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Linux
→ node_exporter

MySQL
→ mysqld_exporter

Redis
→ redis_exporter

PostgreSQL
→ postgres_exporter
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这使 Prometheus 能够统一采集不同系统的指标。&lt;/p&gt;
&lt;h2&gt;4.2 node_exporter&lt;/h2&gt;
&lt;p&gt;Linux 主机监控中最常见的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node_exporter
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它可以暴露：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
Memory
Disk
Network
Filesystem
Load
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Linux Kernel / /proc / /sys
             │
             ▼
        node_exporter
             │
             ▼
         /metrics
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方：
&lt;a href=&quot;https://github.com/prometheus/node_exporter&quot;&gt;node_exporter&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;五、安装 Prometheus&lt;/h1&gt;
&lt;p&gt;Prometheus 可以直接以二进制方式运行，也可以运行在容器中。&lt;/p&gt;
&lt;p&gt;对于理解 Linux 运维，直接二进制部署是一个很好的学习方式：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Linux
 ├── prometheus
 └── node_exporter
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而实际项目中也常见：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker
 ├── prometheus
 └── grafana
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.1 创建 Prometheus 用户&lt;/h2&gt;
&lt;p&gt;生产环境不应该默认使用 root 运行 Prometheus。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo useradd \
  --no-create-home \
  --shell /usr/sbin/nologin \
  prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建目录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo mkdir -p /etc/prometheus
sudo mkdir -p /var/lib/prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;设置权限：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo chown -R prometheus:prometheus \
  /etc/prometheus \
  /var/lib/prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.2 配置文件&lt;/h2&gt;
&lt;p&gt;Prometheus 的核心配置文件通常是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;prometheus.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个最简单的配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;global:
  scrape_interval: 15s

scrape_configs:

  - job_name: prometheus
    static_configs:
      - targets:
          - localhost:9090
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;scrape_interval
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;决定采集间隔。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;15s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;意味着：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;每 15 秒采集一次
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.3 启动 Prometheus&lt;/h2&gt;
&lt;p&gt;直接运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;prometheus \
  --config.file=/etc/prometheus/prometheus.yml \
  --storage.tsdb.path=/var/lib/prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;验证：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl http://127.0.0.1:9090/-/ready
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果正常，Prometheus Web UI 通常可以通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://&amp;lt;server&amp;gt;:9090
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问。&lt;/p&gt;
&lt;h1&gt;六、使用 systemd 管理 Prometheus&lt;/h1&gt;
&lt;p&gt;将 Prometheus 作为长期运行的服务时，可以使用 systemd。&lt;/p&gt;
&lt;p&gt;创建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/etc/systemd/system/prometheus.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=Prometheus
After=network.target

[Service]
User=prometheus
Group=prometheus

ExecStart=/usr/local/bin/prometheus \
  --config.file=/etc/prometheus/prometheus.yml \
  --storage.tsdb.path=/var/lib/prometheus

Restart=on-failure

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重新加载：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl daemon-reload
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl start prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;设置开机启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;journalctl -u prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就把上一篇 Linux 服务监控的知识连接到了 Prometheus：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemd
   │
   ▼
Prometheus Service
   │
   ▼
Metrics
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;七、配置 node_exporter&lt;/h1&gt;
&lt;h2&gt;7.1 启动 node_exporter&lt;/h2&gt;
&lt;p&gt;node_exporter 默认监听：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;9100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl http://127.0.0.1:9100/metrics
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果能够看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node_cpu_seconds_total
node_memory_...
node_filesystem_...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;说明 Exporter 工作正常。&lt;/p&gt;
&lt;h2&gt;7.2 systemd&lt;/h2&gt;
&lt;p&gt;也可以把 node_exporter 配置成服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=Node Exporter
After=network.target

[Service]
User=node_exporter
Group=node_exporter

ExecStart=/usr/local/bin/node_exporter

Restart=on-failure

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status node_exporter
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7.3 Prometheus 配置 Target&lt;/h2&gt;
&lt;p&gt;修改：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;scrape_configs:

  - job_name: node
    static_configs:
      - targets:
          - 127.0.0.1:9100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后让 Prometheus 重新加载配置。&lt;/p&gt;
&lt;p&gt;最简单的方式可以直接重启：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;生产环境也可以通过 Prometheus 提供的配置 reload 机制减少中断。&lt;/p&gt;
&lt;h1&gt;八、Target 与 Job&lt;/h1&gt;
&lt;p&gt;Prometheus 中非常重要的两个概念：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Job
Target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- job_name: linux
  static_configs:
    - targets:
        - 192.168.1.10:9100
        - 192.168.1.11:9100
        - 192.168.1.12:9100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;job = linux
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;targets
=
192.168.1.10:9100
192.168.1.11:9100
192.168.1.12:9100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Job
 │
 ├── Target A
 ├── Target B
 └── Target C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Prometheus 会根据配置定期抓取这些 Target。&lt;/p&gt;
&lt;h1&gt;九、Prometheus Targets 页面&lt;/h1&gt;
&lt;p&gt;Prometheus 自带 Web UI。&lt;/p&gt;
&lt;p&gt;打开：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://&amp;lt;prometheus&amp;gt;:9090
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Status
→ Targets
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UP
DOWN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;linux/node
192.168.1.10:9100
UP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Prometheus
   ↓
192.168.1.10:9100
   ↓
成功采集
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DOWN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Exporter 没启动
端口错误
网络不通
防火墙
DNS
目标机器故障
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Prometheus Targets 页面本身就是非常重要的故障排查入口。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;十、PromQL 基础&lt;/h1&gt;
&lt;p&gt;PromQL 是 Prometheus 的查询语言。&lt;/p&gt;
&lt;p&gt;官方文档：
&lt;a href=&quot;https://prometheus.io/docs/prometheus/latest/querying/basics/&quot;&gt;PromQL basics&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;10.1 查询 Metric&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node_load1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示查询：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1 分钟 Load
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;又例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node_memory_MemAvailable_bytes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;可用内存
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10.2 Label 过滤&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node_load1{instance=&quot;192.168.1.10:9100&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只查询某个实例。&lt;/p&gt;
&lt;p&gt;也可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http_requests_total{status=&quot;500&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查询：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP 500
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10.3 Rate&lt;/h2&gt;
&lt;p&gt;很多指标是 Counter，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http_requests_total
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它通常只增加：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;100
120
140
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果我们想知道：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;每秒增加多少请求
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rate(http_requests_total[5m])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;意思可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;根据最近 5 分钟的数据
计算平均每秒增长速度
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10.4 Sum&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sum(rate(http_requests_total[5m]))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将多个时间序列聚合到一起。&lt;/p&gt;
&lt;h2&gt;10.5 By&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sum by (status) (
  rate(http_requests_total[5m])
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以得到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;200 → xxx req/s
404 → xxx req/s
500 → xxx req/s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此 PromQL 的核心能力之一就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;选择
+
过滤
+
计算
+
聚合
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方文档也将 PromQL 定义为用于实时选择和聚合时间序列数据的函数式查询语言。&lt;/p&gt;
&lt;h1&gt;十一、常用 Linux 监控 PromQL&lt;/h1&gt;
&lt;h2&gt;11.1 CPU&lt;/h2&gt;
&lt;p&gt;CPU 使用率可以从：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node_cpu_seconds_total
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;计算。&lt;/p&gt;
&lt;p&gt;常见查询：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;100 - (
  avg by (instance) (
    rate(node_cpu_seconds_total{
      mode=&quot;idle&quot;
    }[5m])
  ) * 100
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU 使用率 %
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;11.2 Memory&lt;/h2&gt;
&lt;p&gt;可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;100 * (
  1 -
  node_memory_MemAvailable_bytes
  /
  node_memory_MemTotal_bytes
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;得到大致的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Memory 使用率
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这与上一篇：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;free -h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所观察的概念对应。&lt;/p&gt;
&lt;h2&gt;11.3 Disk&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;100 * (
  1 -
  node_filesystem_avail_bytes
  /
  node_filesystem_size_bytes
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以估算文件系统使用率。&lt;/p&gt;
&lt;h2&gt;11.4 Network&lt;/h2&gt;
&lt;p&gt;例如统计网络接收速率：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rate(
  node_network_receive_bytes_total[5m]
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发送：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rate(
  node_network_transmit_bytes_total[5m]
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样上一篇：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ip
ss
网络统计
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就进入了持续监控体系。&lt;/p&gt;
&lt;h1&gt;十二、Prometheus 的指标类型&lt;/h1&gt;
&lt;p&gt;Prometheus 常见 Metric Type：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Counter
Gauge
Histogram
Summary
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;12.1 Counter&lt;/h2&gt;
&lt;p&gt;Counter 表示只增不减的累计值。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP 请求总数
错误请求总数
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;类似：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;100
120
150
180
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;适合计算：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rate(...)
increase(...)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;12.2 Gauge&lt;/h2&gt;
&lt;p&gt;Gauge 表示可以上下变化的当前值。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU 温度
内存使用量
并发连接数
队列长度
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;100
80
120
60
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;12.3 Histogram&lt;/h2&gt;
&lt;p&gt;Histogram 用于观察一组数值的分布。&lt;/p&gt;
&lt;p&gt;最常见：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP 请求耗时
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.1s
0.2s
0.5s
1s
2s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Histogram 可以帮助回答：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;P50
P90
P95
P99
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这对于服务性能监控非常重要。&lt;/p&gt;
&lt;h2&gt;12.4 Summary&lt;/h2&gt;
&lt;p&gt;Summary 也可以描述分布和分位数，但它与 Histogram 在计算方式和适用场景上有所区别。&lt;/p&gt;
&lt;p&gt;初学阶段最需要掌握：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Counter
Gauge
Histogram
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十三、Grafana 安装与运行&lt;/h1&gt;
&lt;p&gt;Grafana 可以直接安装在 Linux 上，也可以运行在 Docker 中。&lt;/p&gt;
&lt;p&gt;对于学习环境，可以使用 Docker Compose 快速启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:

  grafana:
    image: grafana/grafana
    ports:
      - &quot;3000:3000&quot;
    volumes:
      - grafana-data:/var/lib/grafana

volumes:
  grafana-data:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose ps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose logs grafana
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://&amp;lt;server&amp;gt;:3000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Grafana 官方安装文档：
&lt;a href=&quot;https://grafana.com/docs/grafana/latest/setup-grafana/&quot;&gt;Install Grafana&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;十四、Grafana Data Source&lt;/h1&gt;
&lt;p&gt;Grafana 启动之后，需要告诉它：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据在哪里？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Data Source
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Grafana
   │
   ▼
Prometheus
http://prometheus:9090
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Grafana 官方把 Data Source 定义为连接到实际数据存储后端的连接；Grafana 可以通过这些数据源查询、可视化和告警，而不会要求把数据迁移到 Grafana 中。&lt;/p&gt;
&lt;p&gt;添加 Prometheus：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Connections
   ↓
Data Sources
   ↓
Prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;填写：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;URL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如 Docker Compose 环境：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://prometheus:9090
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://localhost:9090
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是容器化环境中非常常见的区别：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Grafana Container
       │
       │
       ▼
prometheus:9090
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是 Compose 网络中的服务名。&lt;/p&gt;
&lt;h1&gt;十五、Grafana Dashboard&lt;/h1&gt;
&lt;p&gt;Dashboard 是 Grafana 最核心的使用方式之一。&lt;/p&gt;
&lt;p&gt;可以包含多个 Panel：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────────────────────────────┐
│ CPU Usage                            │
│              /\                      │
│         /\   /  \__                  │
│ _______/  \_/       \___             │
└──────────────────────────────────────┘

┌───────────────────┐
│ Memory Usage      │
│       62%         │
└───────────────────┘

┌───────────────────┐
│ Disk Usage        │
│       74%         │
└───────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个 Linux Server Dashboard 可以包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
Memory
Load
Disk
Network
Filesystem
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;15.1 Panel&lt;/h2&gt;
&lt;p&gt;每个 Panel 通常包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Query
+
Visualization
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node_load1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后选择：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Time Series
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就可以看到 Load 随时间变化的曲线。&lt;/p&gt;
&lt;h2&gt;15.2 常见 Visualization&lt;/h2&gt;
&lt;p&gt;Grafana 中常见：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Time Series
Stat
Gauge
Table
Bar Chart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不同数据应该选择合适的展示方式。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU 趋势
→ Time Series

当前 CPU
→ Gauge / Stat

多个服务状态
→ Table / Stat
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十六、Grafana 变量&lt;/h1&gt;
&lt;p&gt;当 Dashboard 面向多个主机时，不能为每台机器建立一张完全独立的 Dashboard。&lt;/p&gt;
&lt;p&gt;可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Variables
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;instance
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用户选择：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10:9100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dashboard 自动切换。&lt;/p&gt;
&lt;p&gt;例如 PromQL：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node_load1{
  instance=&quot;$instance&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;一个 Dashboard
     │
     ├── server1
     ├── server2
     ├── server3
     └── server4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这对于实际运维非常重要。&lt;/p&gt;
&lt;h1&gt;十七、Prometheus 告警&lt;/h1&gt;
&lt;h2&gt;17.1 为什么需要 Alert&lt;/h2&gt;
&lt;p&gt;监控系统不应该要求运维人员：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;一直盯着 Grafana
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;凌晨 3 点
CPU &amp;gt; 95%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应该主动产生：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Alert
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是等到早上才发现。&lt;/p&gt;
&lt;p&gt;Prometheus 的传统告警体系可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Prometheus
    │
    │ Alert Rule
    ▼
 Alert
    │
    ▼
Alertmanager
    │
    ├── Grouping
    ├── Inhibition
    ├── Silence
    └── Notification
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Prometheus 官方明确将告警分成两个部分：Prometheus 中定义和评估告警规则，Alertmanager 负责对告警进行聚合、抑制、静默和通知。&lt;/p&gt;
&lt;h2&gt;17.2 Alert Rule&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;groups:
  - name: node
    rules:

      - alert: HighCPUUsage
        expr: |
          (
            100 - (
              avg by (instance) (
                rate(node_cpu_seconds_total{
                  mode=&quot;idle&quot;
                }[5m])
              ) * 100
            )
          ) &amp;gt; 90
        for: 5m

        labels:
          severity: warning

        annotations:
          summary: &quot;CPU 使用率过高&quot;
          description: &quot;实例 {{ $labels.instance }} CPU 使用率超过 90%&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;expr
→ 告警条件

for
→ 持续多久才触发

labels
→ 告警分类

annotations
→ 告警描述
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;17.3 为什么需要 for&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU = 95%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只持续：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10 秒
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能只是瞬时波动。&lt;/p&gt;
&lt;p&gt;如果规定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for: 5m
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;则表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;条件持续 5 分钟
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;才触发。&lt;/p&gt;
&lt;p&gt;这样可以减少：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;瞬时波动
→ 大量误告警
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十八、Alertmanager&lt;/h1&gt;
&lt;p&gt;Alertmanager 并不是用来计算：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU &amp;gt; 90%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它主要负责收到 Prometheus 产生的告警后进行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Grouping
Inhibition
Silencing
Routing
Notifications
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Prometheus
  │
  ├── CPU Alert
  ├── Memory Alert
  ├── Disk Alert
  └── Service Alert
          │
          ▼
     Alertmanager
          │
          ├── Group
          ├── Route
          └── Notify
               │
               ├── Email
               ├── Webhook
               └── On-call
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方：
&lt;a href=&quot;https://prometheus.io/docs/alerting/latest/overview/&quot;&gt;Alerting Overview&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;十九、Grafana Alerting&lt;/h1&gt;
&lt;p&gt;现在 Grafana 自身也提供完整的 Alerting 能力。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Grafana
   │
   ▼
Prometheus Data Source
   │
   ▼
PromQL
   │
   ▼
Alert Rule
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Grafana 官方目前支持：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Grafana-managed alert rules
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以查看 Prometheus 自己管理的规则；对于 Prometheus 原生告警规则，Grafana 中主要作为查看入口，而规则修改仍然需要回到 Prometheus 配置或规则文件中。&lt;/p&gt;
&lt;p&gt;因此学习阶段可以先这样理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Prometheus
→ Metrics + PromQL + 原生告警规则

Alertmanager
→ 告警聚合与通知

Grafana
→ Dashboard + Query + Grafana Alerting
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十、Prometheus 与 Grafana 的典型架构&lt;/h1&gt;
&lt;p&gt;一个最基础的 Linux 监控系统：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                 Linux Server
                     │
                     ▼
               node_exporter
                     │
                  /metrics
                     │
                     ▼
                Prometheus
             ┌───────┴────────┐
             │                │
          TSDB             PromQL
                                │
                                ▼
                             Grafana
                                │
                    ┌───────────┴───────────┐
                    ▼                       ▼
                Dashboard                 Alert
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;多个服务器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Node 1 ── node_exporter ──┐
Node 2 ── node_exporter ──┤
Node 3 ── node_exporter ──┤
Node 4 ── node_exporter ──┤
                           ▼
                       Prometheus
                           │
                           ▼
                        Grafana
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十一、Service Discovery&lt;/h1&gt;
&lt;p&gt;前面的配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;static_configs:
  - targets:
      - 192.168.1.10:9100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;属于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Static Configuration
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;服务器多了以后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;100 台
500 台
1000 台
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;手动维护就很麻烦。&lt;/p&gt;
&lt;p&gt;因此 Prometheus 支持：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Service Discovery
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如 Kubernetes 环境中，可以通过 Kubernetes Service Discovery 动态发现目标。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Kubernetes
   │
   ├── Pod
   ├── Service
   └── Node
        │
        ▼
Service Discovery
        │
        ▼
Prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也是 Prometheus 非常适合云原生环境的重要原因之一。&lt;/p&gt;
&lt;h1&gt;二十二、Kubernetes 与 Prometheus&lt;/h1&gt;
&lt;p&gt;前面的 Kubernetes 文章里学习了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Node
Pod
Service
Deployment
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在可以将它们与监控连接起来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Kubernetes
    │
    ├── Node
    │     └── node_exporter
    │
    ├── Pod
    │     └── application metrics
    │
    └── Service
            │
            ▼
       Prometheus
            │
            ▼
         Grafana
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Kubernetes
→ 管理工作负载

Prometheus
→ 观察工作负载

Grafana
→ 展示观察结果
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十三、一个完整的 Linux 监控案例&lt;/h1&gt;
&lt;p&gt;假设现在有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Server A
192.168.1.10

Server B
192.168.1.11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每台服务器运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node_exporter
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;架构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Server A
  │
  └── node_exporter :9100
          │
          ▼
          ┐
          │
Server B  │
  │       │
  └── node_exporter :9100
          │
          ▼
      Prometheus
          │
          ▼
       Grafana
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Prometheus 配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;scrape_configs:

  - job_name: linux
    static_configs:
      - targets:
          - 192.168.1.10:9100
          - 192.168.1.11:9100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 Prometheus 中查询：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;up
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;serverA → 1
serverB → 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;serverB → 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就说明 Prometheus 当前无法成功采集：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.11:9100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进一步排查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node_exporter
   ↓
端口 9100
   ↓
网络
   ↓
防火墙
   ↓
服务器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是监控系统与 Linux 运维排障的结合。&lt;/p&gt;
&lt;h1&gt;二十四、Prometheus 常见故障&lt;/h1&gt;
&lt;h2&gt;24.1 Target DOWN&lt;/h2&gt;
&lt;p&gt;现象：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Prometheus
→ Targets
→ DOWN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一步：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl http://&amp;lt;target&amp;gt;:9100/metrics
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果直接失败：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Exporter
   ↓
网络
   ↓
端口
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;继续检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status node_exporter
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -lntp | grep 9100
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;24.2 Prometheus 启动失败&lt;/h2&gt;
&lt;p&gt;首先：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;journalctl -u prometheus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果修改了 YAML：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;YAML 格式错误
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能导致 Prometheus 无法加载配置。&lt;/p&gt;
&lt;p&gt;因此修改配置后应该先验证配置，而不是直接不断重启服务。&lt;/p&gt;
&lt;h2&gt;24.3 查询没有数据&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node_cpu_seconds_total
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;没有返回数据。&lt;/p&gt;
&lt;p&gt;排查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Metric 是否存在
       ↓
Target 是否 UP
       ↓
Exporter 是否正常
       ↓
Prometheus 是否成功采集
       ↓
时间范围是否正确
       ↓
Label 是否匹配
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;尤其注意：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;instance=&quot;...&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;写错后也可能导致：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;No data
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;24.4 Grafana 没有数据&lt;/h2&gt;
&lt;p&gt;首先不要马上修改 Dashboard。&lt;/p&gt;
&lt;p&gt;先检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Grafana
   ↓
Data Source
   ↓
Prometheus
   ↓
PromQL
   ↓
Metrics
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 Grafana Data Source 中进行连接测试。&lt;/p&gt;
&lt;p&gt;Grafana 当前官方文档也把 Prometheus 作为标准 Data Source，并提供 PromQL Query Editor。&lt;/p&gt;
&lt;p&gt;如果 Data Source 正常，再检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dashboard Query
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十五、监控系统的几个重要原则&lt;/h1&gt;
&lt;h2&gt;25.1 监控不是越多越好&lt;/h2&gt;
&lt;p&gt;如果一个 Dashboard：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1000 个 Panel
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看起来非常“专业”。&lt;/p&gt;
&lt;p&gt;但真正故障时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;找不到重点
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就失去了监控的价值。&lt;/p&gt;
&lt;p&gt;更好的方式是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Overview
   ↓
发现异常
   ↓
Service
   ↓
Host
   ↓
Detail
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;25.2 从业务目标设计指标&lt;/h2&gt;
&lt;p&gt;不要只监控：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
Memory
Disk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还要问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户是否能够访问？
请求是否成功？
响应是否变慢？
错误率有没有增加？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如 Web 服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Availability
Latency
Traffic
Errors
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些比单纯：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU = 50%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更接近业务健康程度。&lt;/p&gt;
&lt;h2&gt;25.3 监控指标应该能解释问题&lt;/h2&gt;
&lt;p&gt;例如发现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP 5xx ↑
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接下来应该能够通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
Memory
Database Connections
Latency
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进一步判断：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;资源不足？
数据库问题？
网络问题？
应用本身异常？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样监控才真正成为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;故障排查工具
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十六、从 Metrics 走向 Logs&lt;/h1&gt;
&lt;p&gt;到这里，我们主要处理的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Metrics
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU = 80%
Memory = 70%
QPS = 1000
Latency = 200ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它们很适合回答：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发生了什么？
什么时候发生？
严重程度如何？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但是它们往往不能直接回答：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;为什么发生？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Logs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2026-09-14 10:30:01 ERROR
Database connection refused
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此后续会进入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Metrics
→ Prometheus

Visualization
→ Grafana

Logs
→ 日志收集 / ELK

Metrics + Logs + Traces
→ OpenTelemetry / 可观测性体系
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十七、监控体系整体模型&lt;/h1&gt;
&lt;p&gt;目前已经可以把前两篇监控内容串起来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Linux Server
     │
     ├── CPU
     ├── Memory
     ├── Disk
     ├── Network
     ├── Process
     └── Service
            │
            ▼
        Exporter
            │
            ▼
       Prometheus
            │
            ├── Time Series
            ├── PromQL
            └── Alert Rules
                    │
                    ▼
               Alertmanager
                    │
                    ▼
                Notification

            Prometheus
                 │
                 ▼
              Grafana
                 │
                 ├── Dashboard
                 ├── Visualization
                 └── Alerting
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而完整的可观测性体系会继续扩展成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  Observability
                       │
          ┌────────────┼────────────┐
          ▼            ▼            ▼
       Metrics        Logs        Traces
          │            │            │
      Prometheus       │        OpenTelemetry
          │            │            │
       Grafana       ELK/...        │
          │            │            │
          └────────────┼────────────┘
                       ▼
                   Correlation
                       │
                       ▼
                  Root Cause
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十八、Prometheus 与 Grafana 的关系总结&lt;/h1&gt;
&lt;p&gt;最后可以用一句非常简单的话区分两者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Prometheus
→ “把指标收进来、存下来、查出来”

Grafana
→ “把数据展示出来，让人看懂”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更加完整地说：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Exporter
   ↓
Metrics
   ↓
Prometheus
   ├── Storage
   ├── PromQL
   └── Alert Rules
         ↓
    Alertmanager

Prometheus
   ↓
Grafana
   ├── Dashboard
   ├── Visualization
   └── Alerting
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而上一篇 Linux 服务监控中的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;top
free
df
iostat
ss
systemctl
journalctl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在变成了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;人工查看
     ↓
Exporter
     ↓
Prometheus
     ↓
Grafana
     ↓
持续监控
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Prometheus 解决“持续采集和查询指标”，Grafana 解决“把指标组织成可视化界面”，而 Exporter 则负责把 Linux、数据库和其他系统的状态转换成 Prometheus 能理解的 Metrics。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://prometheus.io/docs/introduction/overview/&quot;&gt;Prometheus Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prometheus.io/docs/concepts/data_model/&quot;&gt;Prometheus Data Model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prometheus.io/docs/prometheus/latest/querying/basics/&quot;&gt;PromQL Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prometheus.io/docs/alerting/latest/overview/&quot;&gt;Prometheus Alerting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/docs/grafana/latest/&quot;&gt;Grafana Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>监控：Linux 服务监控</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%9B%91%E6%8E%A7linux-%E6%9C%8D%E5%8A%A1%E7%9B%91%E6%8E%A7/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%9B%91%E6%8E%A7linux-%E6%9C%8D%E5%8A%A1%E7%9B%91%E6%8E%A7/</guid><description>使用 Linux 常用工具观察服务状态、进程、资源、网络和日志，并按症状定位故障。</description><pubDate>Mon, 14 Sep 2026 04:09:20 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;监控的第一步不是安装 Prometheus，而是先知道一个 Linux 系统和其中的服务究竟应该观察什么。&lt;/p&gt;
&lt;p&gt;本文从 Linux 主机和服务本身出发，介绍进程、systemd、CPU、内存、磁盘、网络、负载、文件描述符等基础监控指标，并建立一套基础的服务故障定位方法。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;一、Linux 服务监控概述&lt;/h1&gt;
&lt;h2&gt;1.1 什么是服务监控&lt;/h2&gt;
&lt;p&gt;在 Linux 服务器上运行着大量服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Nginx
MySQL
Redis
Docker
SSH
Kubernetes
Java Application
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;服务出现问题时，可能表现为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;进程消失
端口关闭
请求超时
CPU 过高
内存不足
磁盘写满
网络异常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此监控并不是单纯地：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“这个进程还在不在？”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是需要同时观察：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;服务状态
进程状态
CPU
Memory
Disk
Network
Load
Connection
Logs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以简单抽象成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    Linux Server
                         │
       ┌─────────────────┼─────────────────┐
       │                 │                 │
       ▼                 ▼                 ▼
     Service           Resource          Network
       │                 │                 │
       │          ┌──────┼──────┐          │
       │          │      │      │          │
       ▼          ▼      ▼      ▼          ▼
     systemd     CPU   Memory   Disk     Socket
       │
       ▼
    Process
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;1.2 监控与故障排查&lt;/h2&gt;
&lt;p&gt;监控和故障排查并不是一回事。&lt;/p&gt;
&lt;p&gt;监控更关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“现在是否正常？”
“最近有没有异常？”
“趋势是否发生变化？”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;故障排查则关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“为什么异常？”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU = 95%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是一个监控结果。&lt;/p&gt;
&lt;p&gt;接下来还需要排查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;哪个进程占用 CPU？
为什么占用？
是不是流量增加？
是不是程序死循环？
是不是频繁 GC？
是不是磁盘 I/O 等待？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;监控
→ 发现问题

排查
→ 定位原因

处理
→ 恢复服务

复盘
→ 找出长期改进方案
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二、Linux 服务与 systemd&lt;/h1&gt;
&lt;h2&gt;2.1 服务是什么&lt;/h2&gt;
&lt;p&gt;Linux 中的“服务”通常是长期运行、为其他程序或用户提供功能的进程。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sshd
nginx
redis-server
mysqld
docker
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现代 Linux 发行版中，很多系统服务由 &lt;code&gt;systemd&lt;/code&gt; 管理。&lt;/p&gt;
&lt;p&gt;systemd 官方文档：
&lt;a href=&quot;https://systemd.io/&quot;&gt;systemd&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;2.2 systemctl&lt;/h2&gt;
&lt;p&gt;最常用的服务管理命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl start nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;停止：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl stop nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重启：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重新加载配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;设置开机启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;取消开机启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl disable nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看是否设置了开机启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl is-enabled nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看当前是否运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl is-active nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.3 service 与 process 的区别&lt;/h2&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Service
≠
Process
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;描述的是 systemd 管理的服务单元。&lt;/p&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ps aux | grep nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看的是实际进程。&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemd
   │
   ▼
Service Unit
   │
   ▼
Process
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此遇到服务故障时，通常需要同时查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl
+
process
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;三、服务健康状态&lt;/h1&gt;
&lt;h2&gt;3.1 Active / Inactive / Failed&lt;/h2&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见状态包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;active
inactive
failed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;active
→ 服务当前处于活动状态

inactive
→ 当前没有运行

failed
→ 启动或运行过程中发生失败
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;active
≠
业务一定正常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Nginx Process
     │
     ▼
systemd = active
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;后端服务不可用
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终用户仍然可能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP 502
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以更完整的健康判断应该是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Service
  │
  ├── Process
  ├── Port
  ├── Dependency
  └── Application Response
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.2 自动重启&lt;/h2&gt;
&lt;p&gt;systemd 可以配置服务失败后的自动重启，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Service]
Restart=on-failure
RestartSec=5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Process
   ↓
Crash
   ↓
systemd
   ↓
Restart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以提高服务的自恢复能力。&lt;/p&gt;
&lt;p&gt;但需要注意：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;自动重启
≠
问题已经解决
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果服务不断：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;启动
 ↓
崩溃
 ↓
启动
 ↓
崩溃
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能会形成持续重启。&lt;/p&gt;
&lt;p&gt;因此还需要观察：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status nginx
journalctl -u nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;四、进程监控&lt;/h1&gt;
&lt;h2&gt;4.1 ps&lt;/h2&gt;
&lt;p&gt;最基础的进程查看工具：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ps aux
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看指定进程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ps aux | grep nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更适合查看完整进程关系：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ps -ef
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root       100   1  ...
nginx      200 100  ...
nginx      201 100  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以帮助分析：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PID
PPID
User
CPU
Memory
Command
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4.2 top&lt;/h2&gt;
&lt;p&gt;实时查看系统和进程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;top
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
Memory
Load Average
Processes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及各进程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PID
USER
%CPU
%MEM
TIME
COMMAND
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是 Linux 服务故障排查中非常常用的工具。&lt;/p&gt;
&lt;h2&gt;4.3 htop&lt;/h2&gt;
&lt;p&gt;如果系统安装了 &lt;code&gt;htop&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;htop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它提供更加直观的交互式进程查看界面。&lt;/p&gt;
&lt;p&gt;不过运维环境中仍然应该掌握：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;top
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为它更加常见且通常预装。&lt;/p&gt;
&lt;h2&gt;4.4 pstree&lt;/h2&gt;
&lt;p&gt;查看进程树：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pstree
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemd
 ├─ sshd
 │   └─ sshd
 │       └─ bash
 │
 └─ nginx
     ├─ nginx
     └─ nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当服务存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;父进程
子进程
worker
daemon
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等关系时，进程树非常有帮助。&lt;/p&gt;
&lt;h1&gt;五、CPU 监控&lt;/h1&gt;
&lt;p&gt;CPU 是最常见的系统资源之一。&lt;/p&gt;
&lt;h2&gt;5.1 CPU 使用率&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU = 95%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;首先需要确定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User
System
I/O Wait
Idle
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些 CPU 时间的来源不同。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User 高
→ 用户态程序计算较多

System 高
→ 内核态工作较多

I/O Wait 高
→ CPU 正在等待 I/O 完成

Idle 高
→ CPU 大量空闲
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU 高
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不能直接等价于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用有 bug
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.2 top 查看 CPU&lt;/h2&gt;
&lt;p&gt;运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;top
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到类似：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;%Cpu(s): 20.0 us, 5.0 sy, 0.0 ni, 70.0 id, 5.0 wa
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以重点关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;us
sy
wa
id
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.3 mpstat&lt;/h2&gt;
&lt;p&gt;安装 &lt;code&gt;sysstat&lt;/code&gt; 后可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mpstat
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看更细粒度的 CPU 统计：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mpstat -P ALL 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-P ALL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示查看所有 CPU。&lt;/p&gt;
&lt;p&gt;这在多核服务器上尤其有用，因为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;整体 CPU 不高
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不意味着：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;所有核心都正常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU 0 = 100%
CPU 1 = 10%
CPU 2 = 8%
CPU 3 = 9%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可能造成某些单线程应用性能问题。&lt;/p&gt;
&lt;h1&gt;六、内存监控&lt;/h1&gt;
&lt;h2&gt;6.1 free&lt;/h2&gt;
&lt;p&gt;查看内存：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;free -h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;               total   used   free   shared  buff/cache
Mem:             16G    10G     1G      ...        5G
Swap:             2G   500M    1.5G
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现代 Linux 中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;used
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不能简单理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“程序真正占满的内存”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为 Linux 会利用空闲内存作为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Page Cache
Buffers
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;提高 I/O 性能。&lt;/p&gt;
&lt;p&gt;因此更重要的是关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;available
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是只盯着：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;free
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6.2 Swap&lt;/h2&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;free -h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果发现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Swap
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;持续增长，需要进一步检查内存压力。&lt;/p&gt;
&lt;p&gt;可能原因：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用内存泄漏
进程占用过高
系统内存不足
缓存压力
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Swap 使用
≠
系统一定有故障
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键是观察：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;是否持续增长
是否产生大量 I/O
应用延迟是否受到影响
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6.3 vmstat&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;vmstat&lt;/code&gt; 可以同时观察：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Process
Memory
Swap
I/O
System
CPU
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vmstat 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;非常适合判断系统整体资源状态。&lt;/p&gt;
&lt;h1&gt;七、磁盘与文件系统监控&lt;/h1&gt;
&lt;h2&gt;7.1 df&lt;/h2&gt;
&lt;p&gt;查看文件系统空间：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df -h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/
100%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时应用可能出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;日志无法写入
数据库无法写入
临时文件创建失败
服务异常
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7.2 inode&lt;/h2&gt;
&lt;p&gt;除了磁盘容量，还需要关注 inode：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df -i
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为文件系统同时存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;空间
+
inode
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;磁盘还有 50GB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;inode = 100%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;仍然可能无法创建新文件。&lt;/p&gt;
&lt;p&gt;常见原因：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;大量小文件
日志文件
缓存文件
临时文件
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7.3 du&lt;/h2&gt;
&lt;p&gt;查看具体目录占用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;du -sh /var/log/*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;du -xh /var | sort -h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以帮助定位：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;到底哪个目录占满了磁盘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7.4 磁盘 I/O&lt;/h2&gt;
&lt;p&gt;磁盘空间正常：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df -h
→ 正常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不意味着：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;磁盘性能正常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还需要观察 I/O。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iostat
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iostat -xz 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IOPS
吞吐量
await
util
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这有助于判断：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU 问题
还是
磁盘 I/O 问题
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;八、网络监控&lt;/h1&gt;
&lt;h2&gt;8.1 网卡状态&lt;/h2&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ip link
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看地址：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ip addr
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface
state
IP
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8.2 路由&lt;/h2&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ip route
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重点关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;default route
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及目标网段是否存在对应路由。&lt;/p&gt;
&lt;h2&gt;8.3 监听端口&lt;/h2&gt;
&lt;p&gt;使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -lntp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;LISTEN
0.0.0.0:80
0.0.0.0:22
127.0.0.1:6379
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以判断：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;服务有没有监听
监听在哪个地址
监听哪个端口
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这在排查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“服务已经启动，但是访问不了”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;时非常重要。&lt;/p&gt;
&lt;h2&gt;8.4 网络连接&lt;/h2&gt;
&lt;p&gt;查看 TCP 连接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -ant
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;统计：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ESTABLISHED
TIME-WAIT
CLOSE-WAIT
LISTEN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CLOSE-WAIT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;大量增加时，可以进一步检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用是否正确关闭连接
上游是否异常
连接是否泄漏
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;九、系统负载 Load Average&lt;/h1&gt;
&lt;h2&gt;9.1 Load Average 是什么&lt;/h2&gt;
&lt;p&gt;可以通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;uptime
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;top
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;load average: 1.20, 0.80, 0.60
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分别代表：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1 分钟
5 分钟
15 分钟
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Load Average 不是简单的“CPU 使用率”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它反映的是系统中处于可运行状态以及不可中断睡眠状态等任务的整体压力情况。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Load 高
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能来自：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU 压力
I/O 压力
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是只有 CPU。&lt;/p&gt;
&lt;h2&gt;9.2 Load 与 CPU 核数&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1 核 CPU
Load = 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;压力通常比较明显。&lt;/p&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;8 核 CPU
Load = 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不能简单理解为“系统已经 4 倍超载”。&lt;/p&gt;
&lt;p&gt;因此判断负载时要结合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU 核数
CPU 使用率
I/O Wait
系统响应时间
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;综合分析。&lt;/p&gt;
&lt;h1&gt;十、文件描述符与系统资源&lt;/h1&gt;
&lt;p&gt;Linux 中很多服务不仅消耗：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
Memory
Disk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还可能受到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;File Descriptor
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;限制。&lt;/p&gt;
&lt;h2&gt;10.1 文件描述符&lt;/h2&gt;
&lt;p&gt;查看当前 Shell 限制：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ulimit -n
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看进程打开的文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lsof -p &amp;lt;PID&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ls /proc/&amp;lt;PID&amp;gt;/fd | wc -l
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;网络连接也会占用文件描述符。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;连接数暴增
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能最终表现为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Too many open files
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10.2 系统级限制&lt;/h2&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat /proc/sys/fs/file-max
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat /proc/sys/fs/file-nr
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果应用出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;无法建立连接
无法打开文件
Too many open files
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就需要同时检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;进程限制
系统限制
应用连接管理
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十一、日志与 systemd Journal&lt;/h1&gt;
&lt;p&gt;基础服务监控至少要能够查看本机服务日志；集中式日志系统则在此基础上统一保存和检索。&lt;/p&gt;
&lt;h2&gt;11.1 journalctl&lt;/h2&gt;
&lt;p&gt;查看系统日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;journalctl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看指定服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;journalctl -u nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;持续跟踪：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;journalctl -u nginx -f
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看最近日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;journalctl -u nginx --since &quot;1 hour ago&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看本次启动以来的日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;journalctl -b
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;11.2 为什么日志是监控的一部分&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;显示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;active
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但用户访问失败。&lt;/p&gt;
&lt;p&gt;继续：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -lntp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;80 端口正常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl http://127.0.0.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;502 Bad Gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时候真正的原因可能存在于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nginx error log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;backend journal
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Metrics
→ 告诉你“异常了”

Logs
→ 帮助你解释“为什么异常”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;指标和日志系统可以在此基础上扩展统一采集与告警。&lt;/p&gt;
&lt;h1&gt;十二、服务监控中的关键指标&lt;/h1&gt;
&lt;p&gt;不同服务需要观察的指标不同，但可以建立一套基础框架。&lt;/p&gt;
&lt;h2&gt;12.1 主机级指标&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;CPU
Memory
Load
Disk Usage
Disk I/O
Network
Process Count
File Descriptors
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;12.2 服务级指标&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Service Status
Process
Port
Connections
Response Time
Error Rate
Restart Count
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;12.3 应用级指标&lt;/h2&gt;
&lt;p&gt;不同应用还可能关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;QPS
TPS
Latency
Error Rate
Queue Length
Cache Hit Rate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如 Redis：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Memory
Connections
Commands
Hit Rate
Evictions
Latency
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MySQL：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Connections
QPS
TPS
Slow Queries
Buffer Pool
Locks
Replication
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nginx：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Requests
Status Codes
Response Time
Connections
Traffic
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“监控服务器”并不意味着所有服务器都监控同一组指标。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;真正有效的监控应该围绕：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;服务的工作方式
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;来设计。&lt;/p&gt;
&lt;h1&gt;十三、服务监控的基本层次&lt;/h1&gt;
&lt;p&gt;可以把 Linux 服务监控分成几个层次：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    Service Monitoring
                           │
          ┌────────────────┼────────────────┐
          │                │                │
          ▼                ▼                ▼
       Availability      Resource         Performance
          │                │                │
       服务是否运行       CPU/Memory       Latency
       端口是否监听       Disk/Network     QPS
       是否能访问         FD              Error Rate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进一步：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Availability
→ 有没有活着

Resource
→ 有没有资源压力

Performance
→ 活着的时候是否正常工作
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是后续学习 Prometheus 非常重要的基础。&lt;/p&gt;
&lt;h1&gt;十四、一个实际的 Linux 服务监控示例&lt;/h1&gt;
&lt;p&gt;假设服务器运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Nginx
Java Application
Redis
PostgreSQL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以建立如下监控思路：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  Linux Server
                       │
       ┌───────────────┼────────────────┐
       │               │                │
      Nginx            Java             Redis
       │                │                │
     Port 80        Port 8080         Port 6379
       │                │                │
       └────────────────┼────────────────┘
                        │
                    PostgreSQL
                       5432
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;主机层：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
Memory
Disk
Network
Load
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;服务层：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Nginx → HTTP
Java  → HTTP
Redis → TCP
PostgreSQL → TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;服务器 CPU 正常
      ↓
Nginx 正常
      ↓
Java 正常
      ↓
Redis 正常
      ↓
PostgreSQL 正常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用户最终得到的才是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;业务正常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这说明：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;单个服务正常，并不能证明整个业务正常；主机正常，也不能证明业务正常。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;十五、Linux 服务故障排查流程&lt;/h1&gt;
&lt;p&gt;假设用户反馈：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网站打不开
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不要直接重启服务器。&lt;/p&gt;
&lt;p&gt;可以按照：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    网站打不开
                         │
                         ▼
                  服务是否运行？
                         │
                    systemctl
                         │
                         ▼
                   进程是否存在？
                         │
                         ▼
                    端口是否监听？
                         │
                         ▼
                    网络是否正常？
                         │
                         ▼
                本机 curl 是否正常？
                         │
                         ▼
                    查看日志
                         │
                         ▼
                检查 CPU / Memory
                         │
                         ▼
                    检查磁盘
                         │
                         ▼
                    检查依赖
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;具体可以依次执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status nginx

ps -ef | grep nginx

ss -lntp | grep :80

curl -I http://127.0.0.1

journalctl -u nginx --since &quot;30 min ago&quot;

free -h

df -h

top
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 Nginx 本身正常：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Nginx
 ↓
Backend
 ↓
Database
 ↓
Redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;继续检查后端依赖。&lt;/p&gt;
&lt;h1&gt;十六、几个典型故障案例&lt;/h1&gt;
&lt;h2&gt;16.1 CPU 持续 100%&lt;/h2&gt;
&lt;p&gt;现象：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU = 100%
Load ↑
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;排查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;top
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;找到高 CPU 进程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PID 1234
CPU 300%
java
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进一步：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;top -H -p 1234
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看线程。&lt;/p&gt;
&lt;p&gt;接下来再结合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用日志
GC
请求量
线程状态
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;定位原因。&lt;/p&gt;
&lt;p&gt;所以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU 高
→ 只是症状
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不能直接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kill -9
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;16.2 磁盘满&lt;/h2&gt;
&lt;p&gt;现象：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df -h
/
100%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;继续：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;du -xh /var | sort -h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/var/log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;非常大。&lt;/p&gt;
&lt;p&gt;继续检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;哪个日志
为什么没有轮转
是否存在异常日志刷屏
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正确处理应该是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;找到原因
 ↓
合理清理 / 轮转
 ↓
恢复磁盘空间
 ↓
修复日志配置
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是简单：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rm -rf /var/log/*
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;16.3 服务 active 但访问失败&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;active
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl http://127.0.0.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;返回：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;502 Bad Gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时说明：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Nginx Process
→ 正常

Nginx HTTP
→ 正常响应

Backend
→ 可能异常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;继续：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Nginx
 ↓
upstream
 ↓
Backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;排查后端。&lt;/p&gt;
&lt;h2&gt;16.4 内存持续下降&lt;/h2&gt;
&lt;p&gt;现象：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;available memory
持续下降
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要观察：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;进程 RSS
Page Cache
Swap
OOM
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果某一个应用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RSS 持续增长
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就需要进一步考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;内存泄漏
缓存无限增长
连接累积
对象无法释放
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;OOM Killer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;则需要检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dmesg
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;journalctl -k
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看内核日志。&lt;/p&gt;
&lt;h1&gt;十七、监控数据的三个维度&lt;/h1&gt;
&lt;p&gt;后续学习 Prometheus 和 Grafana 前，需要先建立一个非常重要的概念：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;状态
趋势
异常
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;17.1 当前状态&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU = 30%
Memory = 45%
Disk = 60%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;现在怎么样？
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;17.2 趋势&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Disk Usage

60%
61%
63%
66%
70%
75%
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;虽然今天：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;75%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不一定是故障。&lt;/p&gt;
&lt;p&gt;但趋势告诉我们：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;磁盘正在持续增长
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能很快产生问题。&lt;/p&gt;
&lt;h2&gt;17.3 异常&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;平时 QPS = 1000

突然：
QPS = 10000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;平时 CPU = 30%

突然：
CPU = 95%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这才是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Anomaly
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此真正的监控系统不仅要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;采集数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;判断
告警
可视化
趋势分析
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些内容就是下一篇 Prometheus 与 Grafana 的核心。&lt;/p&gt;
&lt;h1&gt;十八、从 Linux 本机监控到 Prometheus&lt;/h1&gt;
&lt;p&gt;到这里，Linux 自带工具已经能够观察大量基础数据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemd
ps
top
free
vmstat
df
du
iostat
ss
journalctl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但它们的问题是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;只能人工执行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;top
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只能告诉你：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“现在 CPU 是多少”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果希望：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;每 15 秒采集
保存 30 天
生成图表
超过阈值自动告警
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就需要专门的监控系统。&lt;/p&gt;
&lt;p&gt;于是进入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Linux
 │
 ├── Metrics
 ├── Logs
 └── Status
       │
       ▼
   Monitoring System
       │
       ▼
   Prometheus
       │
       ▼
    Grafana
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下一篇可以进一步解决：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据怎么采集？
指标怎么定义？
Prometheus 怎么存？
怎么查询？
Grafana 怎么画？
怎么告警？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而日志体系则继续拆开：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Logs
 ↓
Log Collection
 ↓
ELK / Elastic Stack
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再往后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Metrics
Logs
Traces
      ↓
OpenTelemetry
      ↓
完整可观测性体系
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十九、总结&lt;/h1&gt;
&lt;p&gt;Linux 服务监控可以先建立这样一套思维框架：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  Linux Service
                       │
          ┌────────────┼────────────┐
          ▼            ▼            ▼
       Availability  Resource    Performance
          │            │            │
       Service       CPU          Latency
       Process       Memory       QPS
       Port          Disk         Error
       Health        Network
                       │
                       ▼
                    Logs
                       │
                       ▼
                 Root Cause
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;日常排查最常用的基础工具可以归纳为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl
→ 服务状态

ps / top
→ 进程与 CPU

free / vmstat
→ 内存与系统状态

df / du / iostat
→ 磁盘与 I/O

ip / ss
→ 网络

journalctl
→ 服务与系统日志
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终形成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发现异常
   ↓
确认服务
   ↓
检查进程
   ↓
检查资源
   ↓
检查网络
   ↓
检查日志
   ↓
检查依赖
   ↓
定位原因
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这套基础能力是后面的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Prometheus
Grafana
ELK
OpenTelemetry
可观测性
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的基础。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;监控系统解决的是“持续观察系统”，而 Linux 基础工具解决的是“理解系统当前发生了什么”。在真正使用 Prometheus 之前，先掌握后者，才能看懂监控数据背后的含义。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://systemd.io/&quot;&gt;systemd Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.freedesktop.org/software/systemd/man/latest/systemctl.html&quot;&gt;systemctl — Control the systemd system and service manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.freedesktop.org/software/systemd/man/latest/journalctl.html&quot;&gt;journalctl — Query the systemd journal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gitlab.com/procps-ng/procps&quot;&gt;procps-ng / Linux process monitoring tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sysstat/sysstat&quot;&gt;sysstat&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>容器化：Kubernetes</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%AE%B9%E5%99%A8%E5%8C%96kubernetes/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%AE%B9%E5%99%A8%E5%8C%96kubernetes/</guid><description>介绍 Kubernetes 的集群、Pod、Deployment、Service 和配置对象，覆盖基础发布与排障。</description><pubDate>Mon, 14 Sep 2026 03:14:54 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Docker 解决的是“如何运行容器”，而 Kubernetes 进一步解决的是“如何在一组机器上持续、可靠地运行和管理大量容器”。&lt;/p&gt;
&lt;p&gt;Kubernetes 的核心不是某一条 &lt;code&gt;kubectl&lt;/code&gt; 命令，而是理解 &lt;strong&gt;Cluster、Node、Pod、Deployment、Service、ConfigMap、Secret、PV/PVC、Ingress、调度与网络&lt;/strong&gt; 之间的关系。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;一、Kubernetes 概述&lt;/h1&gt;
&lt;h2&gt;1.1 什么是 Kubernetes&lt;/h2&gt;
&lt;p&gt;Kubernetes（简称 K8s）是一个用于管理容器化工作负载和服务的平台，核心思想是通过声明式配置和控制器自动维护集群的目标状态。&lt;/p&gt;
&lt;p&gt;Docker 更关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;运行一个容器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而 Kubernetes 关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;运行一组应用
 ↓
保持副本数量
 ↓
发现服务
 ↓
分配资源
 ↓
故障自动恢复
 ↓
滚动更新
 ↓
扩缩容
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用要求：
3 个 Web 实例

Kubernetes
    │
    ├── Pod 1
    ├── Pod 2
    └── Pod 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果其中一个 Pod 出现故障：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod 1
  X
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;控制器会根据声明的目标状态创建新的 Pod，使系统重新回到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod 1
Pod 2
Pod 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是 Kubernetes 中非常重要的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Desired State
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;与：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Actual State
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之间的持续协调。&lt;/p&gt;
&lt;p&gt;Kubernetes 官方概念文档：
&lt;a href=&quot;https://kubernetes.io/docs/concepts/&quot;&gt;Kubernetes Concepts&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;1.2 Kubernetes 的核心特点&lt;/h2&gt;
&lt;p&gt;Kubernetes 的典型能力包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;容器编排
自动调度
服务发现
负载分发
故障自愈
滚动更新
水平扩缩容
配置管理
存储管理
资源管理
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此 Kubernetes 并不是简单的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“Docker 的批量启动器”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它实际上提供了一套完整的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;集群控制系统
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二、Kubernetes Cluster 与 Node&lt;/h1&gt;
&lt;h2&gt;2.1 Cluster&lt;/h2&gt;
&lt;p&gt;Cluster（集群）是 Kubernetes 的整体运行环境。&lt;/p&gt;
&lt;p&gt;可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Kubernetes Cluster
│
├── Control Plane
│
└── Worker Nodes
    ├── Node 1
    ├── Node 2
    └── Node 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kubernetes 官方架构中，一个集群由控制平面和一个或多个工作节点组成。控制平面负责管理集群状态，Worker Node 负责运行 Pod。&lt;/p&gt;
&lt;h2&gt;2.2 Control Plane&lt;/h2&gt;
&lt;p&gt;Control Plane 可以理解为 Kubernetes 的“大脑”。&lt;/p&gt;
&lt;p&gt;主要组件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kube-apiserver
etcd
kube-scheduler
kube-controller-manager
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;h3&gt;kube-apiserver&lt;/h3&gt;
&lt;p&gt;Kubernetes 的 API 入口。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl
   │
   ▼
kube-apiserver
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所有主要的集群资源操作都会通过 Kubernetes API 进行。&lt;/p&gt;
&lt;h3&gt;etcd&lt;/h3&gt;
&lt;p&gt;用于保存 Kubernetes 的集群状态和 API 数据。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kube-apiserver
      │
      ▼
     etcd
      │
      └── Cluster State
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以把它理解成 Kubernetes 的核心状态存储。&lt;/p&gt;
&lt;h3&gt;kube-scheduler&lt;/h3&gt;
&lt;p&gt;负责给尚未绑定 Node 的 Pod 选择合适的节点。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pending Pod
    │
    ▼
kube-scheduler
    │
    ▼
Node
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;kube-controller-manager&lt;/h3&gt;
&lt;p&gt;运行各种 Controller，不断比较：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Desired State
      vs
Actual State
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后执行对应操作。&lt;/p&gt;
&lt;p&gt;例如 Deployment 想要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;replicas = 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当前只有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2 Pods
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Controller 就会推动系统创建第 3 个 Pod。&lt;/p&gt;
&lt;h2&gt;2.3 Worker Node&lt;/h2&gt;
&lt;p&gt;Worker Node 是真正运行工作负载的节点。&lt;/p&gt;
&lt;p&gt;主要组件包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubelet
container runtime
kube-proxy（传统 Service 实现中）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;h3&gt;kubelet&lt;/h3&gt;
&lt;p&gt;kubelet 运行在每个 Node 上，负责确保 Pod 中声明的容器处于运行状态。&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Control Plane
      │
      ▼
Node
      │
   kubelet
      │
      ▼
   Container
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Container Runtime&lt;/h3&gt;
&lt;p&gt;负责实际运行容器。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;containerd
CRI-O
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kubernetes 通过 CRI 与容器运行时协作。&lt;/p&gt;
&lt;h3&gt;kube-proxy&lt;/h3&gt;
&lt;p&gt;在传统 Kubernetes Service 实现中，kube-proxy 负责在节点上维护实现 Service 流量转发所需的网络规则。&lt;/p&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;kube-proxy 并不是 Kubernetes Pod 网络本身。Pod 网络由 CNI 等网络实现负责。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;三、Pod&lt;/h1&gt;
&lt;h2&gt;3.1 Pod 是什么&lt;/h2&gt;
&lt;p&gt;Pod 是 Kubernetes 中最小的可部署计算对象。&lt;/p&gt;
&lt;p&gt;一个 Pod 可以包含一个或多个容器，这些容器共享：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Network
Storage
生命周期
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并且通常会被调度到同一个 Node。&lt;/p&gt;
&lt;p&gt;最常见的情况：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
└── Container
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但也可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
├── App Container
└── Sidecar Container
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
├── application
└── log-agent
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.2 Pod 网络&lt;/h2&gt;
&lt;p&gt;每个 Pod 在 Kubernetes 网络模型中拥有自己的 IP。&lt;/p&gt;
&lt;p&gt;同一个 Pod 内的容器共享网络命名空间，因此可以通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;localhost
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;互相通信。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
├── app :8080
└── sidecar :9000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两个容器可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;localhost:8080
localhost:9000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但由于共享同一个网络命名空间，一个 Pod 内两个容器不能同时监听完全相同的端口。&lt;/p&gt;
&lt;h2&gt;3.3 Pod 为什么通常不直接管理&lt;/h2&gt;
&lt;p&gt;虽然可以直接创建 Pod：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl run nginx --image=nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但生产环境一般不直接管理裸 Pod，而是交给：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Deployment
StatefulSet
DaemonSet
Job
CronJob
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等更高级的控制器管理。&lt;/p&gt;
&lt;p&gt;最常见的无状态应用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Deployment
   ↓
ReplicaSet
   ↓
Pods
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;四、Namespace&lt;/h1&gt;
&lt;p&gt;Namespace 用于在同一个 Kubernetes Cluster 中对资源进行逻辑隔离。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cluster
│
├── default
│   ├── web
│   └── redis
│
├── dev
│   ├── web
│   └── redis
│
└── prod
    ├── web
    └── redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get namespaces
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get ns
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl create namespace dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get pods -n dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就能只查看 &lt;code&gt;dev&lt;/code&gt; Namespace 中的 Pod。&lt;/p&gt;
&lt;p&gt;Namespace 并不是完整的安全边界，但它是 Kubernetes 中组织和隔离资源的重要机制。&lt;/p&gt;
&lt;h1&gt;五、使用 kubectl 管理 Kubernetes&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;kubectl&lt;/code&gt; 是 Kubernetes 最常用的命令行工具。&lt;/p&gt;
&lt;p&gt;基本结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl
   │
   ├── get
   ├── describe
   ├── create
   ├── apply
   ├── edit
   ├── exec
   └── delete
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.1 kubectl get&lt;/h2&gt;
&lt;p&gt;查看资源：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get pods
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看 Deployment：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get deployments
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看 Service：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get svc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看所有 Namespace：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get ns
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看 Node：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看更多信息：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get pods -o wide
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.2 kubectl describe&lt;/h2&gt;
&lt;p&gt;查看资源详细信息：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl describe pod nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它特别适合故障排查。&lt;/p&gt;
&lt;p&gt;例如可以看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Events
Volumes
Containers
Conditions
Node
Image
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后面的很多故障排查都离不开：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl describe
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.3 kubectl create&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl create deployment nginx \
  --image=nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建 Namespace：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl create namespace dev
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.4 kubectl apply&lt;/h2&gt;
&lt;p&gt;Kubernetes 非常强调声明式配置。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl apply -f deployment.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;意思不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;执行一堆命令
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“让集群状态变成 YAML 描述的状态”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此实际生产环境中经常使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;YAML
   ↓
kubectl apply
   ↓
Kubernetes API
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.5 kubectl edit&lt;/h2&gt;
&lt;p&gt;可以直接编辑正在运行的资源：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl edit deployment nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kubernetes 会打开资源当前的 YAML 表示。&lt;/p&gt;
&lt;p&gt;不过生产环境通常更推荐：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;修改 Git 中的 YAML
      ↓
提交
      ↓
部署
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是长期直接手工 &lt;code&gt;kubectl edit&lt;/code&gt;，这样更容易保持配置可追踪和可审计。&lt;/p&gt;
&lt;h2&gt;5.6 kubectl exec&lt;/h2&gt;
&lt;p&gt;进入容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl exec -it nginx -- /bin/sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 Pod 中有多个容器，可以指定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl exec -it nginx \
  -c app \
  -- /bin/sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常用于排查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;配置
DNS
网络
文件
环境变量
进程
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.7 kubectl delete&lt;/h2&gt;
&lt;p&gt;删除资源：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl delete pod nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl delete -f deployment.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;p&gt;如果 Pod 由 Deployment 管理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Deployment
   ↓
ReplicaSet
   ↓
Pod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;直接删除 Pod：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl delete pod nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不一定意味着应用永久减少一个副本。&lt;/p&gt;
&lt;p&gt;Controller 会发现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Desired = 3
Actual = 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后重新创建 Pod。&lt;/p&gt;
&lt;h1&gt;六、Deployment 与 ReplicaSet&lt;/h1&gt;
&lt;h2&gt;6.1 Deployment&lt;/h2&gt;
&lt;p&gt;Deployment 用于声明和管理无状态应用的副本以及更新。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl apply -f deployment.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get deployment
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看 Pod：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get pods
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6.2 ReplicaSet&lt;/h2&gt;
&lt;p&gt;Deployment 通常不会直接管理 Pod，而是通过 ReplicaSet：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Deployment
     │
     ▼
ReplicaSet
     │
     ├── Pod
     ├── Pod
     └── Pod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;replicas: 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;意味着 ReplicaSet 会尽可能维持：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;3 Pods
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6.3 自愈&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod A
Pod B
Pod C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 Pod B 崩溃：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod A
Pod B X
Pod C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ReplicaSet 会发现实际数量变成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是创建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod D
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;恢复：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod A
Pod C
Pod D
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是 Kubernetes 的控制器模型。&lt;/p&gt;
&lt;h2&gt;6.4 Deployment 更新&lt;/h2&gt;
&lt;p&gt;修改镜像：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nginx:1.27
↓
nginx:1.28
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl apply -f deployment.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Deployment 会创建新的 ReplicaSet，并逐步替换旧 Pod。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Deployment
    │
    ├── Old ReplicaSet
    │      ├── Pod
    │      └── Pod
    │
    └── New ReplicaSet
           ├── Pod
           └── Pod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是常见的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Rolling Update
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看发布状态：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl rollout status deployment/nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看历史：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl rollout history deployment/nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;回滚：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl rollout undo deployment/nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;七、Service 与 Kubernetes 网络&lt;/h1&gt;
&lt;p&gt;Pod 有 IP，但是 Pod 本身并不适合作为稳定的访问入口。&lt;/p&gt;
&lt;p&gt;因为 Pod 可能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;被删除
被重新创建
被调度到其他 Node
IP 改变
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此 Kubernetes 使用 Service 为一组 Pod 提供稳定的网络入口。&lt;/p&gt;
&lt;p&gt;Kubernetes 官方网络模型中，Service 提供稳定的 IP 或 DNS 名称，并通过 EndpointSlice 记录当前后端 Pod。&lt;/p&gt;
&lt;h2&gt;7.1 Service&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;             Service
           10.96.10.20
                │
       ┌────────┼────────┐
       ▼        ▼        ▼
     Pod A    Pod B    Pod C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Service 一般通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Label Selector
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;选择后端 Pod。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;selector:
  app: nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对应：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;labels:
  app: nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7.2 ClusterIP&lt;/h2&gt;
&lt;p&gt;默认类型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type: ClusterIP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它主要用于集群内部访问。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;backend
   │
   ▼
redis.default.svc.cluster.local
   │
   ▼
Redis Pods
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以通过 Service 的 DNS 名称访问。&lt;/p&gt;
&lt;h2&gt;7.3 NodePort&lt;/h2&gt;
&lt;p&gt;NodePort 会在节点上开放一个端口。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type: NodePort
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client
  │
  ▼
NodeIP:30080
  │
  ▼
Service
  │
  ▼
Pod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此可以通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;NodeIP&amp;gt;:NodePort
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问服务。&lt;/p&gt;
&lt;h2&gt;7.4 LoadBalancer&lt;/h2&gt;
&lt;p&gt;在支持云厂商负载均衡器的环境中，可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type: LoadBalancer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Internet
   │
   ▼
Cloud Load Balancer
   │
   ▼
Service
   │
   ▼
Pods
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果是裸机环境，则需要额外的 LoadBalancer 实现，例如 MetalLB 等方案。&lt;/p&gt;
&lt;h2&gt;7.5 Service 的本质&lt;/h2&gt;
&lt;p&gt;可以把 Service 理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;稳定入口
   +
Pod 集合
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
→ 容易变化

Service
→ 提供稳定访问入口
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;八、Kubernetes 集群网络基础&lt;/h1&gt;
&lt;p&gt;Kubernetes 网络涉及多个层次：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container → Container
Pod → Pod
Pod → Service
External → Service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方文档把这些视为不同的网络问题。&lt;/p&gt;
&lt;h2&gt;8.1 Pod 网络&lt;/h2&gt;
&lt;p&gt;每个 Pod 获得一个集群范围内唯一的 IP。&lt;/p&gt;
&lt;p&gt;基本模型是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod A
10.244.1.10
   │
   │
   ▼
Pod B
10.244.2.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即使两个 Pod 位于不同 Node：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Node 1
  └── Pod A

Node 2
  └── Pod B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也应该能够按照 Kubernetes 网络模型直接通信。&lt;/p&gt;
&lt;h2&gt;8.2 CNI&lt;/h2&gt;
&lt;p&gt;Kubernetes 本身定义网络模型，但不会替你实现整个 Pod 网络。&lt;/p&gt;
&lt;p&gt;通常通过 CNI（Container Network Interface）插件实现 Pod 网络。&lt;/p&gt;
&lt;p&gt;常见方案包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cilium
Calico
Flannel
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其职责可能涉及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod IP 分配
跨节点 Pod 通信
网络路由
NetworkPolicy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Kubernetes
   │
   └── 网络模型

CNI
   │
   └── 具体网络实现
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8.3 Service 网络&lt;/h2&gt;
&lt;p&gt;Service 是另一层抽象：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod IP
   ↓
Service IP
   ↓
Service Backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以排查 Kubernetes 网络问题时，不应该把：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod IP
Service IP
Node IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;混为一谈。&lt;/p&gt;
&lt;h1&gt;九、ConfigMap 与 Secret&lt;/h1&gt;
&lt;p&gt;Kubernetes 支持把应用配置与容器镜像分离。&lt;/p&gt;
&lt;h2&gt;9.1 ConfigMap&lt;/h2&gt;
&lt;p&gt;ConfigMap 用于保存：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;非敏感配置
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  APP_ENV: production
  LOG_LEVEL: info
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl apply -f configmap.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ConfigMap 可以通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;环境变量
命令参数
Volume
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等方式提供给 Pod。&lt;/p&gt;
&lt;h2&gt;9.2 Secret&lt;/h2&gt;
&lt;p&gt;Secret 用于保存：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;密码
Token
密钥
证书
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
stringData:
  DB_USER: app
  DB_PASSWORD: example
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Secret 主要表达“这是敏感数据”，并不意味着数据天然就具备完整的安全保护。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;生产环境还应该考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RBAC
API Server 安全
静态数据加密
外部 Secret 管理系统
访问审计
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kubernetes 官方文档也将 Secret 与 ConfigMap 区分开：ConfigMap 用于非机密配置，Secret 面向密码、Token、Key 等敏感数据。&lt;/p&gt;
&lt;h2&gt;9.3 为什么配置应该与镜像分离&lt;/h2&gt;
&lt;p&gt;不推荐：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker Image
  └── production-config
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更推荐：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application Image
       +
ConfigMap / Secret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;同一个 Image
      │
      ├── dev
      ├── test
      └── prod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只需要注入不同配置。&lt;/p&gt;
&lt;h1&gt;十、Kubernetes Volume、PV 与 PVC&lt;/h1&gt;
&lt;h2&gt;10.1 Volume&lt;/h2&gt;
&lt;p&gt;Pod 可以声明 Volume。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;volumes:
  - name: data
    emptyDir: {}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后挂载：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;volumeMounts:
  - name: data
    mountPath: /data
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10.2 emptyDir&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;emptyDir&lt;/code&gt; 会随着 Pod 创建而产生一个空目录。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
└── emptyDir
       └── /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;适用于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;临时文件
缓存
Pod 内多个容器共享临时数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但 Pod 被删除后，该 Volume 中的数据也会消失。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;emptyDir
≠
持久化存储
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10.3 PersistentVolume&lt;/h2&gt;
&lt;p&gt;PV（PersistentVolume）代表集群中的持久化存储资源。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Storage
   │
   ▼
PersistentVolume
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它可以来自不同存储后端。&lt;/p&gt;
&lt;h2&gt;10.4 PersistentVolumeClaim&lt;/h2&gt;
&lt;p&gt;PVC（PersistentVolumeClaim）是工作负载对存储的请求：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
 │
 ▼
PVC
 │
 ▼
PV
 │
 ▼
Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-data
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pod 使用 PVC：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;volumes:
  - name: data
    persistentVolumeClaim:
      claimName: app-data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样应用就不需要直接关心底层磁盘的具体实现。&lt;/p&gt;
&lt;h1&gt;十一、Ingress 与 HTTP 流量管理&lt;/h1&gt;
&lt;h2&gt;11.1 Ingress&lt;/h2&gt;
&lt;p&gt;Ingress 用于描述从集群外部进入 Kubernetes Service 的 HTTP/HTTPS 路由。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                Internet
                    │
                    ▼
                 Ingress
              /     |     \
             /      |      \
            ▼       ▼       ▼
          web     api     admin
           │        │        │
        Service  Service  Service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ingress 可以根据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host
Path
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进行路由。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;example.com/
        ↓
web-service

example.com/api
        ↓
api-service

admin.example.com
        ↓
admin-service
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;11.2 Ingress Controller&lt;/h2&gt;
&lt;p&gt;Ingress 资源本身只是 API 对象，并不会自动处理网络流量。&lt;/p&gt;
&lt;p&gt;需要实际的 Ingress Controller：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ingress
    │
    ▼
Ingress Controller
    │
    ▼
Service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见实现包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NGINX Ingress Controller
Traefik
HAProxy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;具体选择取决于集群和平台。&lt;/p&gt;
&lt;h2&gt;11.3 Ingress 的当前定位&lt;/h2&gt;
&lt;p&gt;Ingress API 从 Kubernetes v1.19 起稳定，但目前已经冻结，不再继续增加新的 API 功能；Kubernetes 官方推荐新项目考虑 Gateway API。&lt;/p&gt;
&lt;p&gt;因此学习 Ingress 仍然非常重要，因为大量现有 Kubernetes 集群仍在使用它：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;历史与现有系统
→ Ingress

新的流量管理设计
→ Gateway API
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;11.4 Ingress 不是什么&lt;/h2&gt;
&lt;p&gt;Ingress 主要针对：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
HTTPS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它不是一个通用 TCP/UDP 端口代理。&lt;/p&gt;
&lt;p&gt;如果需要暴露其他协议，通常仍然会使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NodePort
LoadBalancer
Gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等方案。&lt;/p&gt;
&lt;h1&gt;十二、资源请求、限制与调度&lt;/h1&gt;
&lt;p&gt;Kubernetes 调度的重要输入之一，就是 Pod 对资源的声明。&lt;/p&gt;
&lt;p&gt;最常见的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
Memory
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;12.1 Requests&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;resources:
  requests:
    cpu: &quot;500m&quot;
    memory: &quot;512Mi&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“我至少希望调度系统为我考虑这么多资源”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Scheduler 会根据 Pod 的资源请求等条件选择合适的 Node。&lt;/p&gt;
&lt;h2&gt;12.2 Limits&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;resources:
  limits:
    cpu: &quot;1&quot;
    memory: &quot;1Gi&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用于限制容器可以使用的资源上限。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;requests
→ 调度参考

limits
→ 资源约束
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kubernetes 官方资源管理文档将 Requests、Limits 作为工作负载资源管理的核心机制。&lt;/p&gt;
&lt;h2&gt;12.3 CPU&lt;/h2&gt;
&lt;p&gt;Kubernetes 中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1 CPU
= 1 个 CPU 核心或对应计算单位
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;500m
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.5 CPU
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;12.4 Memory&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;512Mi
1Gi
2Gi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示内存大小。&lt;/p&gt;
&lt;h2&gt;12.5 为什么必须合理设置资源&lt;/h2&gt;
&lt;p&gt;如果没有合理的资源声明：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Node
 ├── App A
 ├── App B
 └── App C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 App A 可能不断消耗资源：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Memory ↑↑↑
CPU    ↑↑↑
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终影响整个 Node。&lt;/p&gt;
&lt;p&gt;因此 Kubernetes 需要结合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Requests
Limits
QoS
Scheduling
Eviction
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;来进行资源管理。&lt;/p&gt;
&lt;h1&gt;十三、Kubernetes 调度&lt;/h1&gt;
&lt;p&gt;Scheduler 的基本流程可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pending Pod
      │
      ▼
Scheduler
      │
      ├── Node 是否满足资源？
      ├── 是否满足约束？
      ├── 是否存在污点？
      ├── 是否满足亲和性？
      └── ...
      │
      ▼
选择 Node
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Node A
CPU: 剩余 100m

Pod 需要：
CPU: 500m
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么 Pod 不适合调度到 Node A。&lt;/p&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Node B
CPU: 剩余 2 CPU
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;则更适合。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Kubernetes 调度不是简单地“找一台空闲机器”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它需要综合考虑资源、节点属性和各种调度约束。&lt;/p&gt;
&lt;h1&gt;十四、kubeadm 搭建 Kubernetes 集群&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;kubeadm&lt;/code&gt; 是 Kubernetes 官方提供的集群引导工具之一。&lt;/p&gt;
&lt;p&gt;它适合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;学习环境
实验环境
裸机集群
自建 Kubernetes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方文档：
&lt;a href=&quot;https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/&quot;&gt;Installing kubeadm&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;14.1 一个典型集群&lt;/h2&gt;
&lt;p&gt;实验环境可以准备：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Control Plane
192.168.1.10

Worker Node 1
192.168.1.11

Worker Node 2
192.168.1.12
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;整体：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;             Control Plane
             192.168.1.10
                  │
        ┌─────────┼─────────┐
        ▼         ▼         ▼
     Node 1     Node 2    Node ...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;14.2 准备条件&lt;/h2&gt;
&lt;p&gt;具体要求会随着 Kubernetes 版本和发行版变化，但通常需要准备：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Linux
稳定主机名 / DNS
网络连通
容器运行时
kubeadm
kubelet
kubectl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此外还需要正确处理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Swap
内核模块
sysctl
cgroup
防火墙 / 端口
时间同步
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际部署应该按照目标 Kubernetes 版本对应的官方 kubeadm 文档逐项准备，而不要完全照抄旧教程。&lt;/p&gt;
&lt;p&gt;截至 2026 年 9 月，Kubernetes 官方当前维护的最新三个 minor release 为 1.37、1.36、1.35，其中 1.37.0 于 2026 年 8 月 26 日发布。&lt;/p&gt;
&lt;h2&gt;14.3 安装容器运行时&lt;/h2&gt;
&lt;p&gt;Kubernetes Node 需要容器运行时。&lt;/p&gt;
&lt;p&gt;常见：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;containerd
CRI-O
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如完成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;containerd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装与配置后，再准备：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubeadm
kubelet
kubectl
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;14.4 初始化 Control Plane&lt;/h2&gt;
&lt;p&gt;在控制平面节点运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo kubeadm init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际生产或多网卡环境中通常需要明确指定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiserver-advertise-address
pod-network-cidr
control-plane-endpoint
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo kubeadm init \
  --apiserver-advertise-address=192.168.1.10 \
  --pod-network-cidr=10.244.0.0/16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pod-network-cidr
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;必须与后续选择的 CNI 配置匹配。&lt;/p&gt;
&lt;h2&gt;14.5 配置 kubectl&lt;/h2&gt;
&lt;p&gt;初始化完成后，通常需要为当前用户配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir -p $HOME/.kube

sudo cp -i /etc/kubernetes/admin.conf \
  $HOME/.kube/config

sudo chown &quot;$(id -u)&quot;:&quot;$(id -g)&quot; \
  $HOME/.kube/config
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;测试：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时可能看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NAME      STATUS     ROLES           AGE
master    NotReady   control-plane   ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;为什么是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NotReady
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为此时通常还没有安装 Pod Network。&lt;/p&gt;
&lt;h2&gt;14.6 安装 CNI&lt;/h2&gt;
&lt;p&gt;接下来安装选定的 CNI，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Calico
Cilium
Flannel
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装后再检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果网络配置正常，Node 通常会逐渐变成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ready
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;14.7 加入 Worker Node&lt;/h2&gt;
&lt;p&gt;在 Worker Node 上先完成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;container runtime
kubeadm
kubelet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后使用 Control Plane 初始化时生成的 join 命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubeadm join &amp;lt;control-plane&amp;gt;:6443 \
  --token &amp;lt;token&amp;gt; \
  --discovery-token-ca-cert-hash sha256:&amp;lt;hash&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;回到 Control Plane：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NAME      STATUS   ROLES
master    Ready    control-plane
worker1   Ready    &amp;lt;none&amp;gt;
worker2   Ready    &amp;lt;none&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;14.8 kubeadm 背后的架构&lt;/h2&gt;
&lt;p&gt;使用 kubeadm 后，可以进一步理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Control Plane
├── kube-apiserver
├── etcd
├── kube-scheduler
├── kube-controller-manager
└── static Pods

Worker
├── kubelet
├── container runtime
└── kube-proxy / CNI
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;kubeadm 常见的控制平面组件可以以 Static Pod 方式运行，这是当前官方 kubeadm 架构中的典型做法。&lt;/p&gt;
&lt;h1&gt;十五、Kubernetes 日志&lt;/h1&gt;
&lt;p&gt;Kubernetes 中排查应用故障时，最常用的命令之一：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl logs
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;15.1 查看 Pod 日志&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;kubectl logs nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;持续查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl logs -f nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看上一次崩溃的容器日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl logs nginx --previous
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;15.2 多容器 Pod&lt;/h2&gt;
&lt;p&gt;如果 Pod 中有多个容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl logs nginx -c app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;指定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-c &amp;lt;container&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;15.3 日志与容器&lt;/h2&gt;
&lt;p&gt;通常：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
   │
   ├── stdout
   └── stderr
         │
         ▼
    Container Runtime
         │
         ▼
 Kubernetes logs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此应用容器最好能够把关键日志输出到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;stdout
stderr
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是只写在容器内部不易收集的文件里。&lt;/p&gt;
&lt;p&gt;生产环境再进一步通过日志系统进行集中收集：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
 │
 ▼
Log Collector
 │
 ▼
Central Log System
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kubernetes 本身不会强制绑定某一种日志系统。&lt;/p&gt;
&lt;h1&gt;十六、Events 与故障排查&lt;/h1&gt;
&lt;p&gt;很多 Kubernetes 故障不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application Exception
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Scheduler
Image
Volume
Network
Node
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;层面的问题。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get events
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl describe pod &amp;lt;pod&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;非常重要。&lt;/p&gt;
&lt;h2&gt;16.1 Pod Pending&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;STATUS: Pending
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;排查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl describe pod &amp;lt;pod&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重点看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Events
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见原因：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;资源不足
节点不可用
PVC 未绑定
调度约束
Taint / Toleration
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;16.2 ImagePullBackOff&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ImagePullBackOff
ErrImagePull
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重点检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;镜像名称
Tag
Registry
网络
认证
imagePullSecrets
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl describe pod &amp;lt;pod&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看 Events。&lt;/p&gt;
&lt;h2&gt;16.3 CrashLoopBackOff&lt;/h2&gt;
&lt;p&gt;如果 Pod：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;启动
 ↓
崩溃
 ↓
重启
 ↓
再次崩溃
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终可能出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CrashLoopBackOff
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重点检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl logs &amp;lt;pod&amp;gt;
kubectl logs &amp;lt;pod&amp;gt; --previous
kubectl describe pod &amp;lt;pod&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见原因：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;配置错误
环境变量错误
依赖服务不可用
启动命令错误
权限问题
应用本身崩溃
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;16.4 Service 无法访问&lt;/h2&gt;
&lt;p&gt;排查顺序：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
 ↓
Pod IP
 ↓
Pod Label
 ↓
Service Selector
 ↓
EndpointSlice
 ↓
Service
 ↓
Ingress / LoadBalancer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get pods --show-labels
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get svc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get endpointslices
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 Service 存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但没有对应后端：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EndpointSlice = empty
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通常需要检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Selector
Labels
Pod Ready 状态
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十七、Kubernetes 存储故障&lt;/h1&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
   ↓
PVC
   ↓
PV
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中任何一层异常，都可能导致 Pod 无法正常运行。&lt;/p&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get pvc
kubectl get pv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;详细信息：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl describe pvc &amp;lt;name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PVC Pending
StorageClass 不存在
PV 无法绑定
权限错误
CSI 异常
存储后端不可用
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此 Kubernetes 存储排查不能只看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而要一直追踪到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
 ↓
PVC
 ↓
PV
 ↓
StorageClass / CSI
 ↓
Storage Backend
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十八、Kubernetes 网络故障排查&lt;/h1&gt;
&lt;p&gt;网络排查需要区分：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod → Pod
Pod → Service
Node → Pod
External → Service
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;18.1 Pod → Pod&lt;/h2&gt;
&lt;p&gt;检查 Pod：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get pods -o wide
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看 Pod IP 和 Node。&lt;/p&gt;
&lt;p&gt;然后进入容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl exec -it &amp;lt;pod&amp;gt; -- /bin/sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;测试：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ping &amp;lt;pod-ip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl http://&amp;lt;pod-ip&amp;gt;:8080
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;18.2 Pod → Service&lt;/h2&gt;
&lt;p&gt;先查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get svc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再查看 EndpointSlice：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get endpointslices
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查 DNS：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl exec -it &amp;lt;pod&amp;gt; -- \
  nslookup &amp;lt;service-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;18.3 External → Service&lt;/h2&gt;
&lt;p&gt;如果使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NodePort
LoadBalancer
Ingress
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;则需要继续检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;外部入口
 ↓
Node / LoadBalancer
 ↓
Service
 ↓
EndpointSlice
 ↓
Pod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;任何一层异常，都可能导致：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;浏览器访问失败
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十九、Helm 基础&lt;/h1&gt;
&lt;p&gt;当 Kubernetes YAML 增多以后，直接维护大量 YAML 会变得复杂。&lt;/p&gt;
&lt;p&gt;例如一个生产应用可能包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Deployment
Service
ConfigMap
Secret
Ingress
PVC
HPA
ServiceAccount
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是出现了 Helm。&lt;/p&gt;
&lt;h2&gt;19.1 Helm 是什么&lt;/h2&gt;
&lt;p&gt;Helm 是 Kubernetes 常见的软件包管理工具。&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Helm
   │
   └── Package Manager
             │
             ▼
        Kubernetes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Helm 中一个应用包通常叫：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Chart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个 Chart 可以包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Chart.yaml
values.yaml
templates/
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;19.2 Helm Chart&lt;/h2&gt;
&lt;p&gt;典型结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;myapp/
├── Chart.yaml
├── values.yaml
└── templates/
    ├── deployment.yaml
    ├── service.yaml
    ├── configmap.yaml
    └── ingress.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;templates/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;保存模板。&lt;/p&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;values.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;保存可配置参数。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;replicaCount: 3

image:
  repository: nginx
  tag: &quot;1.28&quot;

service:
  port: 80
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;19.3 Helm Install&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;helm install myapp ./myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;helm list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;卸载：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;helm uninstall myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;19.4 Helm Upgrade&lt;/h2&gt;
&lt;p&gt;修改：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;values.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;helm upgrade myapp ./myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样可以复用同一个 Chart：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dev
 ↓
values-dev.yaml

test
 ↓
values-test.yaml

prod
 ↓
values-prod.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是维护三套几乎相同的 YAML。&lt;/p&gt;
&lt;h2&gt;19.5 Helm 的定位&lt;/h2&gt;
&lt;p&gt;可以这样理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dockerfile
→ 构建容器镜像

Helm
→ 打包 Kubernetes 应用部署配置
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它不负责替代：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Kubernetes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是帮助更方便地管理 Kubernetes 应用。&lt;/p&gt;
&lt;h1&gt;二十、Kubernetes 常用命令速查&lt;/h1&gt;
&lt;p&gt;虽然 Kubernetes 学习不能只靠背命令，但下面这些命令是日常运维中非常常见的。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Node
kubectl get nodes
kubectl describe node &amp;lt;node&amp;gt;

# Pod
kubectl get pods
kubectl get pods -o wide
kubectl describe pod &amp;lt;pod&amp;gt;
kubectl logs &amp;lt;pod&amp;gt;
kubectl logs &amp;lt;pod&amp;gt; --previous
kubectl exec -it &amp;lt;pod&amp;gt; -- /bin/sh

# Deployment
kubectl get deployment
kubectl describe deployment &amp;lt;name&amp;gt;
kubectl rollout status deployment/&amp;lt;name&amp;gt;
kubectl rollout history deployment/&amp;lt;name&amp;gt;
kubectl rollout undo deployment/&amp;lt;name&amp;gt;

# Service
kubectl get svc
kubectl describe svc &amp;lt;name&amp;gt;

# Config / Secret
kubectl get configmap
kubectl get secret

# Storage
kubectl get pv
kubectl get pvc

# Events
kubectl get events

# Namespace
kubectl get ns

# Apply / Delete
kubectl apply -f app.yaml
kubectl delete -f app.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中最值得熟悉的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;get
describe
logs
exec
apply
delete
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以把它们理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;get
→ 看有什么

describe
→ 看为什么

logs
→ 看应用说了什么

exec
→ 进入容器检查

apply
→ 让集群变成声明的状态

delete
→ 删除资源
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十一、Kubernetes 故障排查总模型&lt;/h1&gt;
&lt;p&gt;Kubernetes 故障排查最好不要一上来就：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl delete pod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而应该先定位故障层级。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    用户访问失败
                         │
                         ▼
                    Ingress / LB
                         │
                         ▼
                      Service
                         │
                         ▼
                     Endpoint
                         │
                         ▼
                        Pod
                    ┌────┴────┐
                    ▼         ▼
                 Container   Volume
                    │
                    ▼
                  Process
                    │
                    ▼
                 Application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 Pod 本身有问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
 │
 ├── Pending
 │
 ├── ImagePullBackOff
 │
 ├── CrashLoopBackOff
 │
 └── Running but not Ready
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就继续沿着：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl describe
kubectl logs
kubectl logs --previous
kubectl exec
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进行定位。&lt;/p&gt;
&lt;p&gt;如果是网络问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod IP
 ↓
DNS
 ↓
Service
 ↓
EndpointSlice
 ↓
Ingress / LoadBalancer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果是存储问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
 ↓
Volume
 ↓
PVC
 ↓
PV
 ↓
StorageClass / CSI
 ↓
Storage Backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果是调度问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod Pending
 ↓
Events
 ↓
Requests
 ↓
Node
 ↓
Taint / Affinity
 ↓
Scheduler
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十二、Docker 与 Kubernetes 的关系&lt;/h1&gt;
&lt;p&gt;学习完 Docker 和 Kubernetes，可以把两者放在一起理解。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker
│
├── Image
├── Container
├── Network
├── Volume
└── Compose
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更偏向：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;单机容器运行与管理
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而 Kubernetes：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cluster
│
├── Node
│
├── Pod
│
├── Deployment
│
├── Service
│
├── ConfigMap / Secret
│
├── PV / PVC
│
├── Ingress / Gateway
│
└── Scheduler
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更偏向：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;集群级容器编排与管理
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两者并不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker
VS
Kubernetes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的简单竞争关系。&lt;/p&gt;
&lt;p&gt;更接近：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container Image
      │
      ▼
Container Runtime
      │
      ▼
 Kubernetes
      │
      ├── Scheduling
      ├── Networking
      ├── Storage
      ├── Service Discovery
      ├── Scaling
      └── Self-Healing
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十三、从运维视角理解 Kubernetes&lt;/h1&gt;
&lt;p&gt;Docker 学习之后，真正值得建立的是 Kubernetes 的整体运行模型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                        Kubernetes Cluster
                               │
                ┌──────────────┴──────────────┐
                │                             │
          Control Plane                    Nodes
                │                             │
      ┌─────────┼─────────┐          ┌────────┼────────┐
      ▼         ▼         ▼          ▼        ▼        ▼
   API Server  etcd   Scheduler    kubelet   CNI    Runtime
      │
      ▼
 Controllers
      │
      ▼
Deployment
      │
      ▼
ReplicaSet
      │
      ▼
Pods
      │
      ├── ConfigMap / Secret
      ├── Volume / PVC
      └── Resources
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对外提供服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Internet
   │
   ▼
Ingress / Gateway
   │
   ▼
Service
   │
   ▼
Pods
   │
   ▼
Application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;真正进行故障排查时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户
 ↓
Ingress
 ↓
Service
 ↓
Pod
 ↓
Container
 ↓
Process
 ↓
Application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而 Pod 无法启动时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
 ↓
Scheduler
 ↓
Node
 ↓
Image
 ↓
Runtime
 ↓
Volume
 ↓
Network
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是 Kubernetes 运维中最核心的思维方式：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;不要只记资源对象，而要理解一个请求、一个 Pod 和一份配置是怎样穿过整个 Kubernetes 系统的。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;二十四、总结&lt;/h1&gt;
&lt;p&gt;Kubernetes 的核心知识可以整理成下面这条主线：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cluster
   │
   ├── Control Plane
   │
   └── Node
        │
        ▼
       Pod
        │
        ▼
   Deployment
        │
        ▼
    ReplicaSet
        │
        ▼
      Pods
        │
        ├── ConfigMap
        ├── Secret
        ├── Volume
        └── Resources
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;网络：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
 │
 ▼
Service
 │
 ├── ClusterIP
 ├── NodePort
 └── LoadBalancer
 │
 ▼
Ingress / Gateway
 │
 ▼
External Traffic
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;存储：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
 ↓
PVC
 ↓
PV
 ↓
Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;网络：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod
 ↓
CNI
 ↓
Pod Network
 ↓
Service Network
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运维：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get
      ↓
kubectl describe
      ↓
kubectl logs
      ↓
kubectl exec
      ↓
Events
      ↓
Node / Network / Storage / Resource
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终可以用一句话概括 Kubernetes：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Kubernetes 通过声明式 API 和控制器，把分散在多台机器上的容器组织成一个可以自动调度、自动恢复、扩缩容和对外提供稳定服务的集群系统。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/&quot;&gt;Kubernetes Concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/overview/components/&quot;&gt;Kubernetes Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/architecture/&quot;&gt;Cluster Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/services-networking/&quot;&gt;Services, Load Balancing, and Networking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/&quot;&gt;Installing kubeadm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>容器化：Docker</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%AE%B9%E5%99%A8%E5%8C%96docker/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%AE%B9%E5%99%A8%E5%8C%96docker/</guid><description>从镜像、容器、网络和数据卷入门 Docker，并说明常见运行与排障方法。</description><pubDate>Mon, 14 Sep 2026 02:48:40 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Docker 是现代容器化技术中最常见的工具之一。&lt;/p&gt;
&lt;p&gt;学习 Docker 的重点并不是记住大量命令，而是理解 &lt;strong&gt;Image、Container、Registry、Dockerfile、Layer、Network、Volume、Compose&lt;/strong&gt; 之间的关系，以及容器出现问题时应该从哪里开始排查。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;一、Docker 与容器化&lt;/h1&gt;
&lt;h2&gt;1.1 什么是容器化&lt;/h2&gt;
&lt;p&gt;传统部署通常需要在服务器上直接安装：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;JDK
Python
Node.js
MySQL
Nginx
各种依赖
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不同应用之间可能出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;版本冲突
依赖冲突
环境差异
部署困难
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;容器化则把应用及其运行环境组织成一个相对独立的运行单元：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用
 +
运行依赖
 +
配置
      │
      ▼
   Container
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是可以把应用从：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“在这台机器上安装并运行”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;转变为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“运行这个容器”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Docker Engine 采用客户端—服务端架构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker CLI
    │
    │ Docker API
    ▼
dockerd
    │
    ├── Images
    ├── Containers
    ├── Networks
    └── Volumes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker&lt;/code&gt;：命令行客户端&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dockerd&lt;/code&gt;：Docker 守护进程&lt;/li&gt;
&lt;li&gt;Image：镜像&lt;/li&gt;
&lt;li&gt;Container：容器&lt;/li&gt;
&lt;li&gt;Network：网络&lt;/li&gt;
&lt;li&gt;Volume：数据卷&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;1.2 容器不是虚拟机&lt;/h2&gt;
&lt;p&gt;容器经常被称为“轻量级虚拟化”，但它与传统虚拟机并不相同。&lt;/p&gt;
&lt;p&gt;典型虚拟机：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;物理机
  │
  ▼
Hypervisor
  │
  ├── VM
  │    ├── Guest OS
  │    └── Application
  │
  └── VM
       ├── Guest OS
       └── Application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host Linux Kernel
       │
       ├── Container
       │    └── Application
       │
       ├── Container
       │    └── Application
       │
       └── Container
            └── Application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;容器通过 Linux 的命名空间、控制组等机制实现进程、网络、资源等方面的隔离。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container
≠
完整虚拟机
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是运行在宿主机内核之上的隔离进程环境。&lt;/p&gt;
&lt;h1&gt;二、Docker 核心对象&lt;/h1&gt;
&lt;p&gt;理解 Docker 最重要的一步，就是先把几个核心对象区分开。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker

┌──────────────┐
│   Registry   │
│  镜像仓库     │
└──────┬───────┘
       │ pull / push
       ▼
┌──────────────┐
│    Image     │
│     镜像      │
└──────┬───────┘
       │ run
       ▼
┌──────────────┐
│  Container   │
│     容器      │
└──────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;另外：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dockerfile
    │
    │ build
    ▼
  Image
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container
   │
   ├── Network
   │
   └── Volume / Bind Mount
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.1 Image&lt;/h2&gt;
&lt;p&gt;Image（镜像）可以理解为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;创建容器所使用的只读模板。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nginx
redis
ubuntu
postgres
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都可以作为镜像。&lt;/p&gt;
&lt;p&gt;查看本地镜像：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker image ls
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;REPOSITORY   TAG       IMAGE ID
nginx        latest    ...
redis        8         ...
ubuntu       24.04    ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;镜像本身并不是正在运行的应用。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Image
   │
   └──► docker run
             │
             ▼
         Container
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.2 Container&lt;/h2&gt;
&lt;p&gt;Container（容器）是镜像运行后的实例。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d --name web nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这条命令的逻辑可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nginx Image
     │
     ▼
创建 Container
     │
     ▼
启动 nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看运行中的容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看所有容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker ps -a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;停止：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker stop web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker start web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;删除：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker rm web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此最核心的关系就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Image
  │
  │ run
  ▼
Container
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同一个镜像可以创建多个容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        nginx:latest
             │
       ┌─────┼─────┐
       ▼     ▼     ▼
     web1   web2  web3
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.3 Registry&lt;/h2&gt;
&lt;p&gt;Registry（镜像仓库）用于保存和分发镜像。&lt;/p&gt;
&lt;p&gt;典型流程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;开发者
  │
  │ docker build
  ▼
Image
  │
  │ docker push
  ▼
Registry
  │
  │ docker pull
  ▼
服务器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见 Registry 包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker Hub
GitHub Container Registry
私有 Registry
云厂商镜像仓库
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;镜像引用通常类似：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nginx:latest
redis:8
ubuntu:24.04
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以包含 Registry 地址：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ghcr.io/example/myapp:1.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Registry
→ 存放和分发 Image

Image
→ 创建 Container

Container
→ 实际运行应用
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;三、Dockerfile、Build 与 Layer&lt;/h1&gt;
&lt;h2&gt;3.1 Dockerfile&lt;/h2&gt;
&lt;p&gt;Dockerfile 是描述镜像如何构建的文本文件。&lt;/p&gt;
&lt;p&gt;Docker 会按照 Dockerfile 中的指令构建镜像。Dockerfile 必须以 &lt;code&gt;FROM&lt;/code&gt; 开始建立一个基础构建阶段。&lt;/p&gt;
&lt;p&gt;最简单的例子：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM nginx:alpine

COPY ./html /usr/share/nginx/html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;构建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker build -t my-nginx:1.0 .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-t my-nginx:1.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示给镜像命名。&lt;/p&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示当前目录作为 Build Context。&lt;/p&gt;
&lt;h2&gt;3.2 常见 Dockerfile 指令&lt;/h2&gt;
&lt;h3&gt;FROM&lt;/h3&gt;
&lt;p&gt;指定基础镜像：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM ubuntu:24.04
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;RUN&lt;/h3&gt;
&lt;p&gt;在构建阶段执行命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RUN apt-get update &amp;amp;&amp;amp; \
    apt-get install -y curl
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;COPY&lt;/h3&gt;
&lt;p&gt;把构建上下文中的文件复制到镜像：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;COPY app.jar /app/app.jar
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;WORKDIR&lt;/h3&gt;
&lt;p&gt;设置工作目录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WORKDIR /app
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ENV&lt;/h3&gt;
&lt;p&gt;设置环境变量：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ENV APP_ENV=production
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;EXPOSE&lt;/h3&gt;
&lt;p&gt;声明应用预期监听的端口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EXPOSE 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EXPOSE
≠
端口发布
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;EXPOSE&lt;/code&gt; 更多是镜像元数据和文档说明，并不会自动把端口发布到宿主机。真正进行端口发布通常需要在运行容器时使用 &lt;code&gt;-p&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;CMD&lt;/h3&gt;
&lt;p&gt;定义默认启动命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CMD [&quot;java&quot;, &quot;-jar&quot;, &quot;app.jar&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ENTRYPOINT&lt;/h3&gt;
&lt;p&gt;定义容器的主要执行程序：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ENTRYPOINT [&quot;java&quot;, &quot;-jar&quot;, &quot;app.jar&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;CMD&lt;/code&gt; 与 &lt;code&gt;ENTRYPOINT&lt;/code&gt; 可以组合使用。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ENTRYPOINT [&quot;java&quot;, &quot;-jar&quot;, &quot;app.jar&quot;]
CMD [&quot;--server.port=8080&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.3 Docker Build&lt;/h2&gt;
&lt;p&gt;构建流程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dockerfile
    +
Build Context
    │
    ▼
 Docker Build
    │
    ├── FROM
    ├── RUN
    ├── COPY
    ├── ...
    ▼
   Image
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker build -t myapp:1.0 .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看镜像：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker image ls
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看镜像详细信息：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker image inspect myapp:1.0
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.4 Layer&lt;/h2&gt;
&lt;p&gt;Docker 镜像不是一个简单的大文件，而是由多个只读层组成。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application Image
┌─────────────────────┐
│ COPY application     │  Layer
├─────────────────────┤
│ RUN install deps     │  Layer
├─────────────────────┤
│ Base Image           │  Layers
└─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dockerfile 中的部分指令会形成新的镜像层，而底层层可以被多个镜像复用。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ubuntu
   │
   ├── app1
   └── app2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两个镜像可以共享相同的基础层。&lt;/p&gt;
&lt;p&gt;这也是 Docker 镜像缓存和分层存储的重要基础。&lt;/p&gt;
&lt;h2&gt;3.5 Build Cache&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM node:alpine

COPY package*.json ./
RUN npm install

COPY . .
RUN npm run build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果只修改：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;源代码
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;没有改变，那么前面的依赖安装步骤通常可以复用缓存。&lt;/p&gt;
&lt;p&gt;因此 Dockerfile 一般会尽量把：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;变化少的步骤
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;放在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;变化多的步骤
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之前。&lt;/p&gt;
&lt;h2&gt;3.6 .dockerignore&lt;/h2&gt;
&lt;p&gt;构建上下文不应该把所有文件都发送给 Docker。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.git
node_modules
target
__pycache__
.env
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以写入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.dockerignore
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;减少：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Build Context 大小
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时避免把无关文件甚至敏感文件带入构建上下文。Docker 官方 Dockerfile 文档也将 &lt;code&gt;.dockerignore&lt;/code&gt; 作为控制构建上下文的重要机制。&lt;/p&gt;
&lt;h1&gt;四、运行第一个 Docker 容器&lt;/h1&gt;
&lt;h2&gt;4.1 docker run&lt;/h2&gt;
&lt;p&gt;最简单：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后台运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;指定名称：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d --name web nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;指定端口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d \
  --name web \
  -p 8080:80 \
  nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host:8080
     │
     ▼
Container:80
     │
     ▼
   nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://localhost:8080
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4.2 容器的生命周期&lt;/h2&gt;
&lt;p&gt;一个简单的生命周期：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;create
  │
  ▼
created
  │
  ▼
running
  │
  ├──── stop ────► stopped
  │
  ▼
exited
  │
  └──── rm ──────► deleted
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看状态：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker ps -a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker start web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;停止：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker stop web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;删除：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker rm web
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4.3 容器退出不一定代表 Docker 出错&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run ubuntu
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能立即退出。&lt;/p&gt;
&lt;p&gt;原因是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;容器运行时依赖前台主进程
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果容器中的主进程结束，容器通常也就结束。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container
   │
   └── PID 1
         │
         └── 应用主进程
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用进程退出：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PID 1 exit
   │
   ▼
Container exited
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也是排查“容器启动后立刻停止”时最重要的思路之一。&lt;/p&gt;
&lt;h1&gt;五、Docker 网络&lt;/h1&gt;
&lt;p&gt;Docker Networking 负责容器之间、容器与宿主机、容器与外部网络之间的通信。Linux Docker Engine 默认存在 &lt;code&gt;bridge&lt;/code&gt; 网络，也支持 &lt;code&gt;host&lt;/code&gt;、&lt;code&gt;none&lt;/code&gt;、overlay 等网络驱动。&lt;/p&gt;
&lt;h2&gt;5.1 查看网络&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;docker network ls
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看网络详情：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker network inspect bridge
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.2 Bridge&lt;/h2&gt;
&lt;p&gt;Bridge 是 Docker 最常见的网络模式。&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;             Host
              │
           docker0
          /       \
         /         \
Container A       Container B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每个连接到 Bridge 网络的容器都会获得自己的网络接口和 IP 地址。&lt;/p&gt;
&lt;p&gt;Docker 的 Bridge 网络默认允许同一网络中的容器互相通信，同时通过 NAT/masquerading 为容器提供外部网络访问能力。&lt;/p&gt;
&lt;p&gt;创建自定义 Bridge：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker network create mynet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d \
  --name web \
  --network mynet \
  nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再运行一个：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d \
  --name app \
  --network mynet \
  alpine
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在同一个用户自定义 Bridge 网络中，容器可以通过容器名称进行 DNS 解析：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;app
web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这比直接依赖容器 IP 更方便，也更适合实际部署。&lt;/p&gt;
&lt;h2&gt;5.3 Host&lt;/h2&gt;
&lt;p&gt;Host 网络模式会减少容器与宿主机之间的网络隔离，容器直接使用宿主机的网络命名空间，因此不会获得独立的容器 IP。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run --network host nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时 nginx 如果监听：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际上就是使用宿主机对应的网络端口。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;host network
→ 更接近直接运行在 Host 上
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意，在 &lt;code&gt;host&lt;/code&gt; 模式下使用 &lt;code&gt;-p&lt;/code&gt; 进行端口映射没有意义，Docker 会忽略这些发布端口选项。&lt;/p&gt;
&lt;h2&gt;5.4 Container 网络&lt;/h2&gt;
&lt;p&gt;Docker 还支持共享其他容器的网络命名空间，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run --network container:web ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时两个容器共享同一个网络栈。&lt;/p&gt;
&lt;p&gt;这种方式使用场景相对特殊，日常部署中更常见的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;自定义 bridge
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.5 端口映射&lt;/h2&gt;
&lt;p&gt;最常见：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d \
  -p 8080:80 \
  nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;含义：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;宿主机 8080
     │
     ▼
容器 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以进一步指定宿主机 IP：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d \
  -p 127.0.0.1:8080:80 \
  nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样发布端口只绑定到宿主机的本地回环地址。&lt;/p&gt;
&lt;p&gt;Docker 官方文档指出，如果不指定宿主机地址，端口发布默认可能绑定到宿主机所有地址，因此发布端口时需要注意暴露范围。&lt;/p&gt;
&lt;h2&gt;5.6 端口映射与容器间通信&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;web
  └── 80

app
  └── 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两者位于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mynet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;web → app:8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-p 8080:8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为同一 Docker 网络中的容器本身就可以直接通信。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;容器之间通信
→ Docker Network

外部访问容器
→ Publish Port
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是两个不同的问题。&lt;/p&gt;
&lt;h1&gt;六、Docker Volume 与 Bind Mount&lt;/h1&gt;
&lt;p&gt;容器的可写层并不适合作为重要业务数据的唯一存储位置。&lt;/p&gt;
&lt;p&gt;Docker 官方将 Volume 和 Bind Mount 作为两类主要的文件系统挂载方式。&lt;/p&gt;
&lt;h2&gt;6.1 为什么需要持久化&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container
   │
   └── /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据库把数据存放在那里。&lt;/p&gt;
&lt;p&gt;然后删除容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker rm db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果数据只存在容器自身的可写层，那么数据也可能随容器一起消失。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container
+
Persistent Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应该分开理解。&lt;/p&gt;
&lt;h2&gt;6.2 Volume&lt;/h2&gt;
&lt;p&gt;创建 Volume：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker volume create db-data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker volume ls
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d \
  --name mysql \
  -v db-data:/var/lib/mysql \
  mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker Managed Volume
        │
        ▼
     db-data
        │
        ▼
Container:/var/lib/mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Volume 的存储位置由 Docker 管理。&lt;/p&gt;
&lt;p&gt;Docker 官方将 Volume 定位为适合持久化容器数据，以及在多个容器之间共享数据的一种机制。&lt;/p&gt;
&lt;h2&gt;6.3 Bind Mount&lt;/h2&gt;
&lt;p&gt;Bind Mount 则直接把宿主机某个文件或目录挂载到容器中。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d \
  -v /opt/myapp/config:/app/config \
  myapp:1.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host
└── /opt/myapp/config
          │
          ▼
Container
└── /app/config
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Bind Mount 的特点是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;宿主机路径明确可见
Docker 不负责选择存储目录
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此特别适合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;配置文件
源码
构建产物
开发环境共享目录
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Docker 官方也明确区分了两者：Volume 的数据目录由 Docker 管理，而 Bind Mount 直接使用宿主机指定的路径。&lt;/p&gt;
&lt;h2&gt;6.4 Volume 与 Bind Mount 对比&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项目&lt;/th&gt;
&lt;th&gt;Volume&lt;/th&gt;
&lt;th&gt;Bind Mount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;存储路径&lt;/td&gt;
&lt;td&gt;Docker 管理&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;明确&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;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;code&gt;docker volume&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;/p&gt;
&lt;pre&gt;&lt;code&gt;Volume
→ “数据交给 Docker 管理”

Bind Mount
→ “数据目录由我指定”
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;七、Docker Logs&lt;/h1&gt;
&lt;p&gt;容器中的应用通常应该把日志输出到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;stdout
stderr
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Docker 再负责收集这些输出。&lt;/p&gt;
&lt;p&gt;查看日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker logs web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;持续查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker logs -f web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只查看最近内容：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker logs --tail 100 web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;带时间：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker logs -t web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
   │
   ├── stdout
   └── stderr
         │
         ▼
    Docker Logging
         │
         ▼
    docker logs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Docker 的具体日志驱动可以配置，Compose 中也可以进一步配置 service 的 logging 行为。&lt;/p&gt;
&lt;p&gt;排查容器启动失败时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker ps -a
docker logs &amp;lt;container&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;往往是最先应该执行的两条命令。&lt;/p&gt;
&lt;h1&gt;八、Docker 资源限制&lt;/h1&gt;
&lt;p&gt;一个常见误区是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;容器隔离了
→ 那么它就不会影响宿主机
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际上，如果没有合理限制，容器中的程序仍可能大量消耗宿主机资源。&lt;/p&gt;
&lt;p&gt;因此 Docker 支持对容器进行资源限制。&lt;/p&gt;
&lt;h2&gt;8.1 内存限制&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d \
  --memory=512m \
  nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示限制容器可以使用的内存。&lt;/p&gt;
&lt;p&gt;Docker &lt;code&gt;run&lt;/code&gt; 支持包括内存限制、CPU 等多种运行时约束。&lt;/p&gt;
&lt;h2&gt;8.2 CPU 限制&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d \
  --cpus=&quot;1.5&quot; \
  myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示限制 CPU 使用量。&lt;/p&gt;
&lt;p&gt;Compose 中也可以定义资源限制，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  app:
    image: myapp:1.0
    deploy:
      resources:
        limits:
          cpus: &quot;1.0&quot;
          memory: 512M
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compose Deploy Specification 将 CPU、Memory、PIDs 等限制定义为资源约束。&lt;/p&gt;
&lt;h2&gt;8.3 为什么需要资源限制&lt;/h2&gt;
&lt;p&gt;没有资源限制：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container
   │
   ├── CPU 高
   └── Memory 高
         │
         ▼
       Host
         │
         ▼
其他服务受到影响
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;有资源限制：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container
   │
   ├── CPU ≤ limit
   └── Memory ≤ limit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样可以减少单个工作负载拖垮整台机器的风险。&lt;/p&gt;
&lt;h1&gt;九、Healthcheck&lt;/h1&gt;
&lt;p&gt;“容器在运行”并不一定意味着：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用正常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container: running
Process: running
Application: 无法处理请求
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此 Docker 提供 Healthcheck。&lt;/p&gt;
&lt;h2&gt;9.1 HEALTHCHECK&lt;/h2&gt;
&lt;p&gt;Dockerfile：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HEALTHCHECK --interval=30s \
            --timeout=5s \
            --retries=3 \
            CMD curl -f http://localhost:8080/health || exit 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;健康检查返回：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 → healthy
1 → unhealthy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;容器启动后会经历：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;starting
   │
   ▼
healthy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;starting
   │
   ▼
unhealthy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Docker 官方文档明确说明，Healthcheck 用于判断容器中的应用是否仍然正常工作，而不仅仅是查看容器进程是否存在。&lt;/p&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker inspect &amp;lt;container&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以找到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;State.Health
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;9.2 Compose Healthcheck&lt;/h2&gt;
&lt;p&gt;Compose 也可以定义：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  app:
    image: myapp:1.0
    healthcheck:
      test:
        - CMD
        - curl
        - -f
        - http://localhost:8080/health
      interval: 30s
      timeout: 5s
      retries: 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还可以配合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;depends_on:
  db:
    condition: service_healthy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;让依赖服务在健康检查通过后再启动依赖它的服务。&lt;/p&gt;
&lt;h1&gt;十、Docker Compose&lt;/h1&gt;
&lt;h2&gt;10.1 为什么需要 Compose&lt;/h2&gt;
&lt;p&gt;假设一个 Web 项目包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Nginx
Backend
MySQL
Redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果全部使用 &lt;code&gt;docker run&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run ...
docker run ...
docker run ...
docker run ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;命令会非常多。&lt;/p&gt;
&lt;p&gt;Compose 可以把多个服务写进一个 YAML 文件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;compose.yaml
     │
     ├── web
     ├── backend
     ├── mysql
     └── redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后统一管理。&lt;/p&gt;
&lt;p&gt;Docker 官方将 Compose 定义为用于多容器应用的配置方式，可以在一个 YAML 文件中管理服务、网络和卷。&lt;/p&gt;
&lt;h2&gt;10.2 一个简单的 Compose&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;services:
  web:
    image: nginx:alpine
    ports:
      - &quot;8080:80&quot;

  redis:
    image: redis:8

  db:
    image: postgres:18
    environment:
      POSTGRES_PASSWORD: example
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose ps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose logs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;单独看某个服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose logs web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;停止：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose down
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重新构建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动并构建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose up -d --build
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10.3 Compose 中的服务&lt;/h2&gt;
&lt;p&gt;Compose 的核心单位是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  backend:
    image: my-backend:1.0

  redis:
    image: redis:8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;backend
redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是服务名。&lt;/p&gt;
&lt;p&gt;同一个 Compose 项目里的服务可以通过服务名进行访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;backend → redis:6379
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不需要寻找 Redis 容器的实际 IP。&lt;/p&gt;
&lt;h2&gt;10.4 Compose 网络&lt;/h2&gt;
&lt;p&gt;Compose 默认会为项目创建网络，使服务之间可以通过服务名称通信。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;frontend
    │
    ▼
backend
    │
    ▼
redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用可以配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;REDIS_HOST=redis
REDIS_PORT=6379
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;REDIS_HOST=172.18.0.3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种方式更适合容器动态创建和替换的环境。&lt;/p&gt;
&lt;h2&gt;10.5 Compose Volume&lt;/h2&gt;
&lt;p&gt;例如数据库：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  db:
    image: postgres:18
    volumes:
      - db-data:/var/lib/postgresql/data

volumes:
  db-data:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;db-data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是命名 Volume。&lt;/p&gt;
&lt;p&gt;也可以使用 Bind Mount：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  app:
    image: myapp:1.0
    volumes:
      - ./config:/app/config
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10.6 Compose 完整示例&lt;/h2&gt;
&lt;p&gt;一个稍完整的 Web 应用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:

  backend:
    build: .
    ports:
      - &quot;8080:8080&quot;
    environment:
      REDIS_HOST: redis
      REDIS_PORT: 6379
    depends_on:
      redis:
        condition: service_healthy

  redis:
    image: redis:8
    volumes:
      - redis-data:/data
    healthcheck:
      test:
        - CMD
        - redis-cli
        - ping
      interval: 10s
      timeout: 3s
      retries: 5

volumes:
  redis-data:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里已经把前面几个概念串起来了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dockerfile
    │
    ▼
 Build
    │
    ▼
Image
    │
    ▼
Compose Service
    │
    ▼
Container
    │
    ├── Network
    ├── Healthcheck
    └── Volume
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十一、Docker 常见故障排查&lt;/h1&gt;
&lt;p&gt;学习 Docker 最重要的内容之一，就是出现问题时能够确定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;到底是镜像问题？
容器问题？
网络问题？
存储问题？
应用问题？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;推荐按照：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;状态
 ↓
日志
 ↓
进程
 ↓
网络
 ↓
存储
 ↓
资源
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;逐层检查。&lt;/p&gt;
&lt;h1&gt;十二、容器启动故障&lt;/h1&gt;
&lt;h2&gt;12.1 容器启动后立即退出&lt;/h2&gt;
&lt;p&gt;首先：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker ps -a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;STATUS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Exited (1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker logs &amp;lt;container&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker inspect &amp;lt;container&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重点关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Entrypoint
Cmd
Environment
Mounts
NetworkSettings
State
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型原因：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;启动命令错误
配置文件错误
环境变量缺失
依赖服务不可用
权限错误
端口冲突
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;12.2 Exit Code&lt;/h2&gt;
&lt;p&gt;容器退出状态可以提供重要线索。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Exited (1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通常表示应用返回了非零退出状态。&lt;/p&gt;
&lt;p&gt;如果是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Exited (0)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;则更可能是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主进程正常结束
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以排查时不要只看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;容器没启动
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而应该继续问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主进程为什么退出？
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十三、Docker 网络故障&lt;/h1&gt;
&lt;h2&gt;13.1 端口没有暴露&lt;/h2&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PORTS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.0.0.0:8080-&amp;gt;80/tcp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host 8080
   ↓
Container 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果没有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-p 8080:80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即使 nginx 在容器内部监听 80，也不代表外部客户端可以通过宿主机 8080 访问。&lt;/p&gt;
&lt;h2&gt;13.2 容器内部服务监听错误地址&lt;/h2&gt;
&lt;p&gt;一个很常见的问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用监听：
127.0.0.1:8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而其他容器访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;container:8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能无法连接。&lt;/p&gt;
&lt;p&gt;因为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;127.0.0.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示当前容器自己的回环地址。&lt;/p&gt;
&lt;p&gt;容器内的服务如果需要被其他容器访问，通常需要监听适当的容器网络地址，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.0.0.0:8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是 Web 应用容器化时非常常见的问题。&lt;/p&gt;
&lt;h2&gt;13.3 DNS 问题&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;backend
   │
   └── redis:6379
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解析失败，就应该检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker network inspect &amp;lt;network&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker exec -it backend getent hosts redis
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;13.4 网络排查顺序&lt;/h2&gt;
&lt;p&gt;可以按照：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;容器是否运行
      ↓
网络是否连接
      ↓
DNS 是否解析
      ↓
目标端口是否监听
      ↓
防火墙 / 网络策略
      ↓
应用是否接受请求
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;逐层排查。&lt;/p&gt;
&lt;h1&gt;十四、Docker 存储故障&lt;/h1&gt;
&lt;h2&gt;14.1 容器删除后数据丢失&lt;/h2&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker inspect &amp;lt;container&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Mounts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果数据库没有挂载：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Volume
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Bind Mount
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么重要数据可能只存在容器可写层。&lt;/p&gt;
&lt;h2&gt;14.2 Volume 不生效&lt;/h2&gt;
&lt;p&gt;常见问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;路径写错
权限不对
挂载目标错误
容器内原有数据被挂载覆盖
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker inspect &amp;lt;container&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确认：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Source
Destination
RW
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;14.3 宿主机磁盘不足&lt;/h2&gt;
&lt;p&gt;容器大量写数据时，也可能把宿主机磁盘写满。&lt;/p&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df -h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及 Docker 磁盘使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker system df
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;清理无用资源时可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker system prune
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但是生产环境执行清理命令前必须确认要删除的对象，避免误删仍然需要的资源。&lt;/p&gt;
&lt;h1&gt;十五、Docker 镜像故障&lt;/h1&gt;
&lt;h2&gt;15.1 镜像拉取失败&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker pull nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;失败时检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DNS
网络
Registry
认证
镜像名称
Tag
代理配置
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;15.2 镜像不存在&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pull access denied
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;镜像名称错误
仓库不存在
仓库为私有
未登录 Registry
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker image ls
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker login
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;15.3 镜像构建失败&lt;/h2&gt;
&lt;p&gt;执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker build -t myapp:1.0 .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;失败时重点检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dockerfile
Build Context
基础镜像
依赖下载
网络
文件路径
权限
缓存
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;特别需要注意：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;COPY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只能访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Build Context
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;中的文件。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker build -t myapp .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;中的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不是随便写的，它决定了 Docker 可以看到哪些构建输入。&lt;/p&gt;
&lt;h1&gt;十六、Docker 资源故障&lt;/h1&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;容器运行很慢
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不能直接判断成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker 性能差
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应该先检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker stats
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
Memory
Network I/O
Block I/O
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker stats
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能发现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;backend
CPU 185%
MEM 900MB

redis
CPU 5%
MEM 300MB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时就可以进一步定位：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;backend
→ CPU 异常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再继续查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用日志
线程
请求
代码
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是直接修改 Docker 配置。&lt;/p&gt;
&lt;h1&gt;十七、Docker 故障排查总模型&lt;/h1&gt;
&lt;p&gt;面对一个容器问题，可以建立如下思维模型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    Docker 故障
                         │
          ┌──────────────┼──────────────┐
          │              │              │
          ▼              ▼              ▼
        Image         Container       Runtime
          │              │              │
      build/pull       state/logs    resource
          │              │              │
          └──────────────┼──────────────┘
                         │
             ┌───────────┴───────────┐
             ▼                       ▼
          Network                 Storage
             │                       │
       DNS / port / bridge      volume / mount
             │                       │
             └───────────┬───────────┘
                         ▼
                    Application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际排查时，可以形成一个固定顺序：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1. docker ps -a
        ↓
2. docker logs
        ↓
3. docker inspect
        ↓
4. docker stats
        ↓
5. docker network inspect
        ↓
6. 检查 Volume / Bind Mount
        ↓
7. 宿主机系统资源
        ↓
8. 回到应用本身
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十八、Docker 整体模型&lt;/h1&gt;
&lt;p&gt;到这里，可以把 Docker 的核心知识串成一个完整体系：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                     Registry
                         │
                    pull / push
                         │
                         ▼
                      Image
                         │
                  Dockerfile / Build
                         │
                         ▼
                    Container
                    /    |    \
                   /     |     \
                  ▼      ▼      ▼
               Network  Volume  Logs
                  │       │
                  │       ▼
                  │    Persistent
                  │      Data
                  │
                  ▼
             Port Mapping
                  │
                  ▼
               External
                Client
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compose 则站在更高一层：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                 compose.yaml
                       │
         ┌─────────────┼─────────────┐
         ▼             ▼             ▼
       backend        redis          db
         │             │             │
         ▼             ▼             ▼
     Container     Container      Container
         │             │             │
         └─────────────┼─────────────┘
                       ▼
                    Network
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此可以这样理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dockerfile
→ 怎么构建镜像

Image
→ 应用运行模板

Container
→ 镜像运行实例

Registry
→ 镜像存储与分发

Network
→ 容器怎么通信

Volume / Bind Mount
→ 数据放在哪里

Logs
→ 应用出了什么问题

Healthcheck
→ 应用现在是否健康

Resource Limit
→ 容器最多能消耗多少资源

Compose
→ 多个容器如何组合成一个应用
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十九、从运维角度理解 Docker&lt;/h1&gt;
&lt;p&gt;对于运维而言，Docker 最重要的并不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run
docker stop
docker rm
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些命令本身。&lt;/p&gt;
&lt;p&gt;真正重要的是理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用
 │
 ├── Image
 │
 ├── Container
 │
 ├── Network
 │
 ├── Storage
 │
 ├── Resource
 │
 ├── Logs
 │
 └── Health
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当一个服务出现故障：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Web 访问失败
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应该逐层问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Container 在运行吗？
        ↓
应用进程存在吗？
        ↓
日志有没有报错？
        ↓
端口有没有监听？
        ↓
端口映射正确吗？
        ↓
Network 正常吗？
        ↓
依赖服务正常吗？
        ↓
Volume 是否正常？
        ↓
磁盘是否满？
        ↓
CPU / Memory 是否异常？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这比单纯背诵 Docker 命令更接近真正的容器运维。&lt;/p&gt;
&lt;h1&gt;二十、总结&lt;/h1&gt;
&lt;p&gt;Docker 可以归纳成下面这条主线：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dockerfile
    │
    │ build
    ▼
  Image
    │
    │ run
    ▼
Container
    │
    ├── Network
    │      ├── bridge
    │      ├── host
    │      └── port mapping
    │
    ├── Storage
    │      ├── Volume
    │      └── Bind Mount
    │
    ├── Logs
    ├── Healthcheck
    └── Resource Limits
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而当多个 Container 共同组成一个完整应用时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Compose
   │
   ├── Service
   ├── Network
   ├── Volume
   └── Healthcheck
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此，学习 Docker 最终应该形成这样的认识：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;镜像负责“装什么”，容器负责“跑起来”，网络负责“怎么通信”，存储负责“数据放哪里”，Compose 负责“多个服务怎么一起运行”，而运维负责“出现问题时找到到底是哪一层出了问题”。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/&quot;&gt;Docker Engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/reference/dockerfile/&quot;&gt;Dockerfile Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/network/&quot;&gt;Docker Networking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/storage/&quot;&gt;Docker Storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/compose/&quot;&gt;Docker Compose&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>数据库：主流 NoSQL 数据库系统</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%BB%E6%B5%81-nosql-%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%BB%E6%B5%81-nosql-%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F/</guid><description>比较 Redis、MongoDB 和搜索型数据库的用途、基本操作、持久化与常见问题。</description><pubDate>Sun, 13 Sep 2026 23:34:12 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;NoSQL 数据库并不是“不要 SQL 的数据库”这么简单，而是针对缓存、文档、搜索与向量检索等不同场景，对数据模型和访问方式做出的不同取舍。&lt;/p&gt;
&lt;p&gt;本文主要介绍 Redis、MongoDB 与 Milvus，并从 Linux 运维视角理解它们的部署、配置、数据安全、备份恢复与故障排查。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;一、NoSQL 数据库概述&lt;/h1&gt;
&lt;p&gt;传统关系型数据库以表、行、列和 SQL 为核心，适合结构化数据以及复杂事务处理。&lt;/p&gt;
&lt;p&gt;NoSQL（Not Only SQL）则泛指一类非关系型或非纯关系模型数据库。它们通常针对某类数据模型或访问场景进行了专门优化。&lt;/p&gt;
&lt;p&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Key-Value&lt;/td&gt;
&lt;td&gt;Redis&lt;/td&gt;
&lt;td&gt;Key → Value&lt;/td&gt;
&lt;td&gt;缓存、Session、计数器、排行榜&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Document&lt;/td&gt;
&lt;td&gt;MongoDB&lt;/td&gt;
&lt;td&gt;BSON/Document&lt;/td&gt;
&lt;td&gt;JSON 类业务数据、内容系统&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wide Column&lt;/td&gt;
&lt;td&gt;Cassandra、HBase&lt;/td&gt;
&lt;td&gt;列族&lt;/td&gt;
&lt;td&gt;海量分布式数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graph&lt;/td&gt;
&lt;td&gt;Neo4j&lt;/td&gt;
&lt;td&gt;Node + Edge&lt;/td&gt;
&lt;td&gt;社交关系、知识图谱&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vector Database&lt;/td&gt;
&lt;td&gt;Milvus&lt;/td&gt;
&lt;td&gt;Vector + Scalar&lt;/td&gt;
&lt;td&gt;向量检索、RAG、语义搜索&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;因此，&lt;strong&gt;NoSQL 不是某一种数据库，而是一类数据库系统的统称。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;本文选择 Redis、MongoDB 和 Milvus，是因为三者分别代表了当前应用开发与基础设施场景中非常典型的三种数据存储需求：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  NoSQL / 非关系型数据系统
                           │
          ┌────────────────┼────────────────┐
          │                │                │
        Redis           MongoDB          Milvus
          │                │                │
       Key-Value        Document        Vector
          │                │                │
      高速缓存         灵活业务数据      向量相似度检索
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二、Redis 基础与 Linux 部署&lt;/h1&gt;
&lt;h2&gt;2.1 Redis 是什么&lt;/h2&gt;
&lt;p&gt;Redis 是一种内存型数据存储系统，核心特点是将数据保存在内存中，并提供丰富的数据结构和高性能的数据访问能力。&lt;/p&gt;
&lt;p&gt;它最常见的使用方式并不是替代 MySQL、PostgreSQL，而是作为应用系统旁边的一层高速数据存储。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户请求
   │
   ▼
 Web / API 服务
   │
   ├──── Redis ────► 高速缓存
   │
   └──── MySQL ────► 持久业务数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此，一个典型 Web 系统可能同时使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MySQL / PostgreSQL
        │
        │ 主业务数据
        ▼
      应用服务
        │
        │ 高频访问数据
        ▼
       Redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Redis 官方文档：
&lt;a href=&quot;https://redis.io/docs/&quot;&gt;Redis Documentation&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;2.2 Redis 常见数据类型&lt;/h2&gt;
&lt;p&gt;Redis 最重要的特点之一，是它提供了多种内置数据结构。&lt;/p&gt;
&lt;h3&gt;String&lt;/h3&gt;
&lt;p&gt;最基础的数据类型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;key → value
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;user:1001:name → &quot;Alice&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以保存字符串、数字甚至二进制数据。&lt;/p&gt;
&lt;p&gt;常见操作：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SET user:1001:name Alice
GET user:1001:name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;String 还非常适合计数器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SET page:view 100
INCR page:view
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;101
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方文档：
&lt;a href=&quot;https://redis.io/docs/latest/develop/data-types/&quot;&gt;Redis Data Types&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Hash&lt;/h3&gt;
&lt;p&gt;Hash 可以表示一个对象中的多个字段：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;user:1001
 ├── name → Alice
 ├── age  → 20
 └── city → Guangzhou
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HSET user:1001 name Alice age 20 city Guangzhou
HGET user:1001 name
HGETALL user:1001
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它非常适合保存简单对象。&lt;/p&gt;
&lt;h3&gt;List&lt;/h3&gt;
&lt;p&gt;List 是有序字符串集合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;LPUSH queue task1
LPUSH queue task2
RPOP queue
&lt;/code&gt;&lt;/pre&gt;
&lt;p&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;h3&gt;Set&lt;/h3&gt;
&lt;p&gt;Set 中的元素具有唯一性：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SADD tags linux
SADD tags docker
SADD tags linux
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第二次添加 &lt;code&gt;linux&lt;/code&gt; 不会产生重复元素。&lt;/p&gt;
&lt;p&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;h3&gt;Sorted Set&lt;/h3&gt;
&lt;p&gt;Sorted Set 在元素之外还具有一个 score：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;user1 → 100
user2 → 80
user3 → 95
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此特别适合排行榜：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ZADD ranking 100 user1
ZADD ranking 80 user2
ZADD ranking 95 user3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后按照分数排序获取结果。&lt;/p&gt;
&lt;h3&gt;Stream&lt;/h3&gt;
&lt;p&gt;Redis Stream 用于保存一系列消息记录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;message1
message2
message3
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更适合事件流、消息处理等场景。&lt;/p&gt;
&lt;p&gt;因此 Redis 常见数据结构可以简单理解为：&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;String&lt;/td&gt;
&lt;td&gt;单值&lt;/td&gt;
&lt;td&gt;缓存、计数器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hash&lt;/td&gt;
&lt;td&gt;字段集合&lt;/td&gt;
&lt;td&gt;对象&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List&lt;/td&gt;
&lt;td&gt;有序序列&lt;/td&gt;
&lt;td&gt;队列、列表&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set&lt;/td&gt;
&lt;td&gt;唯一集合&lt;/td&gt;
&lt;td&gt;去重、集合运算&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sorted Set&lt;/td&gt;
&lt;td&gt;元素 + 分数&lt;/td&gt;
&lt;td&gt;排行榜&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stream&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;h2&gt;2.3 Linux 安装 Redis&lt;/h2&gt;
&lt;p&gt;Redis 官方提供了 Linux 安装方式。&lt;/p&gt;
&lt;p&gt;Ubuntu / Debian 可以使用官方 APT 源：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install lsb-release curl gpg

curl -fsSL https://packages.redis.io/gpg \
  | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg

sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg

echo &quot;deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] \
https://packages.redis.io/deb $(lsb_release -cs) main&quot; \
| sudo tee /etc/apt/sources.list.d/redis.list

sudo apt-get update
sudo apt-get install redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参考：
&lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/&quot;&gt;Redis - Install on Linux&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;安装完成后，可以查看服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl status redis-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl start redis-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;设置开机启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable redis-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;停止：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl stop redis-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重启：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart redis-server
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.4 Redis 默认端口&lt;/h2&gt;
&lt;p&gt;Redis 默认监听：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;6379
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -lntp | grep 6379
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查监听状态。&lt;/p&gt;
&lt;p&gt;也可以直接使用客户端：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;redis-cli
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;测试：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;127.0.0.1:6379&amp;gt; PING
PONG
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PONG
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;说明客户端已经成功连接 Redis。&lt;/p&gt;
&lt;h2&gt;2.5 Redis 配置文件&lt;/h2&gt;
&lt;p&gt;Redis 的具体配置位置取决于安装方式和发行版。&lt;/p&gt;
&lt;p&gt;常见配置项包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bind
port
protected-mode
requirepass / ACL
maxmemory
maxmemory-policy
appendonly
save
dir
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看当前实例配置可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;redis-cli CONFIG GET port
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;redis-cli CONFIG GET maxmemory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运维过程中首先应该确认：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;配置文件
   │
   ├── 监听地址
   ├── 监听端口
   ├── 内存限制
   ├── 持久化策略
   ├── 日志
   └── 认证与访问控制
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;三、Redis 缓存与常见应用场景&lt;/h1&gt;
&lt;h2&gt;3.1 Redis 为什么适合缓存&lt;/h2&gt;
&lt;p&gt;缓存的核心思想是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;             Cache Hit
请求 ───► Redis ─────────► 返回结果
           │
           │ Cache Miss
           ▼
        MySQL / API
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 Redis 中已经存在需要的数据，应用就不需要再次访问数据库。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET user:1001
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果缓存存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Redis → 用户信息
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;否则：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Redis Miss
   │
   ▼
MySQL 查询
   │
   ▼
写入 Redis
   │
   ▼
返回客户端
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这可以减少数据库压力，同时降低响应延迟。&lt;/p&gt;
&lt;h2&gt;3.2 Cache&lt;/h2&gt;
&lt;p&gt;最典型的缓存形式：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;key:
user:1001

value:
{
    &quot;name&quot;: &quot;Alice&quot;,
    &quot;age&quot;: 20
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并设置过期时间：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SET user:1001 Alice EX 300
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示 300 秒后自动过期。&lt;/p&gt;
&lt;p&gt;常见缓存策略包括：&lt;/p&gt;
&lt;h3&gt;Cache Aside&lt;/h3&gt;
&lt;p&gt;应用先查询缓存：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;查询 Redis
   │
   ├── 命中 → 返回
   │
   └── 未命中
         │
         ▼
      查询数据库
         │
         ▼
      写入 Redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是业务系统中非常常见的模式。&lt;/p&gt;
&lt;h2&gt;3.3 Session&lt;/h2&gt;
&lt;p&gt;Web 应用的 Session 也可以放入 Redis：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Browser
   │
   │ Cookie: SESSION_ID
   ▼
Application
   │
   ▼
Redis
   │
   └── Session Data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样在多个应用实例之间就可以共享 Session：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;             ┌── Web 1 ──┐
Client ──────┼── Web 2 ──┼──── Redis
             └── Web 3 ──┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这对于负载均衡后的多实例部署非常有用。&lt;/p&gt;
&lt;h2&gt;3.4 计数器&lt;/h2&gt;
&lt;p&gt;Redis 的原子递增操作适合实现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;访问量
点赞数
库存计数
API 调用次数
限流计数
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;INCR article:1001:view
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;原子操作&lt;/h3&gt;
&lt;p&gt;Redis 提供很多原子操作，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;INCR counter
DECR counter
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这比先读取再写回更加适合并发计数场景。&lt;/p&gt;
&lt;h2&gt;3.5 排行榜&lt;/h2&gt;
&lt;p&gt;Sorted Set 天然适合排行榜：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;100 userA
98  userC
85  userB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用可以根据 score 获取排名。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ZREVRANGE ranking 0 9 WITHSCORES
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;获取前 10 名。&lt;/p&gt;
&lt;h2&gt;3.6 分布式锁&lt;/h2&gt;
&lt;p&gt;Redis 也经常被用于实现分布式协调机制。&lt;/p&gt;
&lt;p&gt;最基本的思想是利用带条件的写入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SET lock_key unique_value NX EX 30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NX&lt;/code&gt;：仅当 key 不存在时设置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EX 30&lt;/code&gt;：30 秒后自动过期&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实际生产环境中的分布式锁要考虑过期、续期、客户端异常和释放锁安全等问题，因此不能简单理解成“SET 一个 key 就完成了分布式锁”。&lt;/p&gt;
&lt;h1&gt;四、Redis 持久化与数据安全&lt;/h1&gt;
&lt;p&gt;虽然 Redis 主要使用内存，但它并不是只能存在内存中。&lt;/p&gt;
&lt;p&gt;Redis 提供多种持久化方式，其中最核心的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RDB
AOF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以组合使用。&lt;/p&gt;
&lt;p&gt;官方文档：
&lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/&quot;&gt;Redis Persistence&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;4.1 RDB&lt;/h2&gt;
&lt;p&gt;RDB 是定期生成数据快照。&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Redis 内存数据
      │
      │ 某个时间点
      ▼
   RDB Snapshot
      │
      ▼
   磁盘文件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它保存的是某一时刻的数据状态。&lt;/p&gt;
&lt;p&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;p&gt;缺点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;两次快照之间发生故障可能丢失部分数据&lt;/li&gt;
&lt;li&gt;快照生成可能带来额外资源开销&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.2 AOF&lt;/h2&gt;
&lt;p&gt;AOF（Append Only File）记录写操作。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SET user Alice
INCR counter
DEL session
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些写操作会被写入 AOF，Redis 重启后可以重新执行这些操作来恢复数据。&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;客户端写入
    │
    ▼
 Redis
    │
    └──► AOF
            │
            ▼
        重放写操作
            │
            ▼
        恢复数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;AOF 一般比普通快照具有更细粒度的数据恢复能力，但也会带来额外的磁盘和恢复开销。&lt;/p&gt;
&lt;h2&gt;4.3 RDB + AOF&lt;/h2&gt;
&lt;p&gt;Redis 可以同时使用 RDB 和 AOF。&lt;/p&gt;
&lt;p&gt;典型思路是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RDB → 快速恢复的基础快照
AOF → 更细粒度的写操作记录
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应该根据业务的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据重要性
可接受数据丢失量
恢复时间要求
磁盘资源
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;选择持久化策略。&lt;/p&gt;
&lt;h2&gt;4.4 备份不能等于持久化&lt;/h2&gt;
&lt;p&gt;这是运维中非常容易混淆的概念：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;开启 AOF
≠
已经完成备份
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为 AOF/RDB 本身也是数据库运行时产生的数据文件。&lt;/p&gt;
&lt;p&gt;真正的备份还需要考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据库文件
      │
      ▼
独立存储
      │
      ├── 本机其他磁盘
      ├── NAS
      ├── 对象存储
      └── 远程备份服务器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;备份必须与原机器故障隔离。&lt;/p&gt;
&lt;h2&gt;4.5 Redis 数据安全&lt;/h2&gt;
&lt;p&gt;生产环境不要直接把 Redis 暴露到公网。&lt;/p&gt;
&lt;p&gt;应该至少考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络隔离
防火墙
访问控制
认证
最小权限
TLS
备份
监控
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;尤其不能简单认为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Redis 默认端口 6379
→ 改掉端口
→ 就安全了
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改端口只能降低一部分自动化扫描风险，并不能替代认证和网络访问控制。&lt;/p&gt;
&lt;h1&gt;五、Redis 常见故障与性能排查&lt;/h1&gt;
&lt;p&gt;Redis 的故障排查应该从：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;服务
 │
 ├── 进程
 ├── 端口
 ├── 连接
 ├── 内存
 ├── 慢查询
 ├── 热点 Key
 └── 持久化
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;逐层分析。&lt;/p&gt;
&lt;h2&gt;5.1 服务无法启动&lt;/h2&gt;
&lt;p&gt;首先：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status redis-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;journalctl -u redis-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;配置文件
端口占用
目录权限
磁盘空间
日志
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查端口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -lntp | grep 6379
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.2 Redis 内存过高&lt;/h2&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;redis-cli INFO memory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重点关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;used_memory
used_memory_peak
maxmemory
mem_fragmentation_ratio
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 Redis 是缓存，通常应该设置合理的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;maxmemory
maxmemory-policy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如缓存场景中可以使用淘汰策略：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;allkeys-lru
allkeys-lfu
volatile-lru
volatile-lfu
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;具体选择需要结合业务访问模式。&lt;/p&gt;
&lt;h2&gt;5.3 连接过多&lt;/h2&gt;
&lt;p&gt;可以查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;redis-cli INFO clients
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;redis-cli CLIENT LIST
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见原因包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;连接池配置不合理
客户端没有及时释放连接
大量短连接
应用实例数量过多
连接泄漏
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此 Redis 连接数异常时，不应该只看 Redis，还需要检查应用侧。&lt;/p&gt;
&lt;h2&gt;5.4 慢查询&lt;/h2&gt;
&lt;p&gt;Redis 可以记录执行时间较长的命令。&lt;/p&gt;
&lt;p&gt;查看慢查询：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;redis-cli SLOWLOG GET
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;p&gt;Redis 单线程执行模型意味着，一个运行时间过长的命令可能阻塞其他请求。&lt;/p&gt;
&lt;p&gt;因此应避免对超大数据集合执行不合理操作，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;KEYS *
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在生产环境中应谨慎使用。&lt;/p&gt;
&lt;p&gt;可以优先考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SCAN 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进行渐进式遍历。&lt;/p&gt;
&lt;h2&gt;5.5 热点 Key&lt;/h2&gt;
&lt;p&gt;所谓热点 Key，就是某些 Key 被大量请求访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;大量请求
   │
   ├──► key:A
   ├──► key:A
   ├──► key:A
   └──► key:A
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果某个 Redis Key 的访问量远高于其他 Key，可能导致：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;单节点压力过高
CPU 增加
网络集中
请求延迟增加
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;排查热点 Key 时需要结合业务访问模式、监控以及 Redis 统计信息综合判断。&lt;/p&gt;
&lt;h1&gt;六、MongoDB 基础与 Linux 部署&lt;/h1&gt;
&lt;h2&gt;6.1 MongoDB 是什么&lt;/h2&gt;
&lt;p&gt;MongoDB 是一种文档型数据库。&lt;/p&gt;
&lt;p&gt;它不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Table → Row → Column
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是更接近：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Database
   │
   └── Collection
          │
          ├── Document
          ├── Document
          └── Document
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Document 通常使用 BSON 表示，形式上与 JSON 很接近：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;_id&quot;: 1001,
  &quot;name&quot;: &quot;Alice&quot;,
  &quot;age&quot;: 20,
  &quot;tags&quot;: [&quot;linux&quot;, &quot;docker&quot;]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MongoDB 官方文档：
&lt;a href=&quot;https://www.mongodb.com/docs/&quot;&gt;MongoDB Documentation&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;6.2 Database、Collection、Document&lt;/h2&gt;
&lt;p&gt;MongoDB 的核心层级：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MongoDB
  │
  └── Database
        │
        └── Collection
              │
              └── Document
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以类比关系数据库：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;MongoDB&lt;/th&gt;
&lt;th&gt;关系数据库&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collection&lt;/td&gt;
&lt;td&gt;Table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Document&lt;/td&gt;
&lt;td&gt;Row&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Field&lt;/td&gt;
&lt;td&gt;Column&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;但这种对应关系只是帮助理解，两者的数据模型并不完全相同。&lt;/p&gt;
&lt;h2&gt;6.3 MongoDB 文档模型&lt;/h2&gt;
&lt;p&gt;MongoDB 的一个优势是文档结构灵活。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;Alice&quot;,
  &quot;address&quot;: {
    &quot;city&quot;: &quot;Guangzhou&quot;,
    &quot;country&quot;: &quot;China&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以保存数组：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;Alice&quot;,
  &quot;skills&quot;: [
    &quot;Linux&quot;,
    &quot;Docker&quot;,
    &quot;Kubernetes&quot;
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这非常适合结构变化较快的业务数据。&lt;/p&gt;
&lt;h2&gt;6.4 MongoDB 安装&lt;/h2&gt;
&lt;p&gt;MongoDB 官方建议在 Ubuntu 上使用官方软件源和 APT 安装。&lt;/p&gt;
&lt;p&gt;例如 MongoDB 8.0 的 Ubuntu 安装流程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get update
sudo apt-get install -y \
  ca-certificates \
  curl \
  gnupg
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;随后配置 MongoDB 官方仓库并安装：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install -y mongodb-org
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不同 Ubuntu 版本对应的软件源配置不同，因此实际安装时应以 MongoDB 官方对应版本文档为准：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.mongodb.com/docs/v8.0/tutorial/install-mongodb-on-ubuntu/&quot;&gt;Install MongoDB Community Edition on Ubuntu&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;6.5 systemd 服务管理&lt;/h2&gt;
&lt;p&gt;安装后可以通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl start mongod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动 MongoDB。&lt;/p&gt;
&lt;p&gt;查看状态：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl status mongod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;开机启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable mongod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;停止：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl stop mongod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重启：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart mongod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;日志通常可以从 MongoDB 日志文件或 systemd 日志中查看。&lt;/p&gt;
&lt;h2&gt;6.6 MongoDB 默认端口&lt;/h2&gt;
&lt;p&gt;MongoDB 默认端口通常是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;27017
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -lntp | grep 27017
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mongosh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;连接数据库。&lt;/p&gt;
&lt;h1&gt;七、MongoDB 配置、用户与权限&lt;/h1&gt;
&lt;h2&gt;7.1 MongoDB 配置&lt;/h2&gt;
&lt;p&gt;MongoDB 常用配置内容包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bindIp
port
dbPath
systemLog
security
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bindIp&lt;/code&gt;：控制监听哪些网络地址&lt;/li&gt;
&lt;li&gt;&lt;code&gt;port&lt;/code&gt;：控制监听端口&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dbPath&lt;/code&gt;：数据库文件目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;systemLog&lt;/code&gt;：日志配置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;security&lt;/code&gt;：安全配置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;生产环境最重要的原则之一仍然是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;不要无防护暴露数据库到公网
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7.2 用户与角色&lt;/h2&gt;
&lt;p&gt;MongoDB 使用基于角色的访问控制。&lt;/p&gt;
&lt;p&gt;可以创建用户：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use admin

db.createUser({
  user: &quot;admin&quot;,
  pwd: &quot;strong-password&quot;,
  roles: [
    { role: &quot;userAdminAnyDatabase&quot;, db: &quot;admin&quot; }
  ]
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后应用应该使用业务专用账号，而不是管理员账号。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;admin
 │
 ├── 管理员账号
 │
 └── application_user
       │
       └── 只访问 application 数据库
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MongoDB 官方：
&lt;a href=&quot;https://www.mongodb.com/docs/manual/core/security-users/&quot;&gt;Users and Roles&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;7.3 最小权限&lt;/h2&gt;
&lt;p&gt;数据库用户应该遵循最小权限原则：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用只需要读
→ 授予读权限

应用需要读写
→ 授予读写权限

运维账号
→ 根据管理职责授予管理权限
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不要让普通应用直接使用超级管理员账号。&lt;/p&gt;
&lt;h1&gt;八、MongoDB 数据备份与恢复&lt;/h1&gt;
&lt;p&gt;MongoDB 常见逻辑备份工具包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mongodump
mongorestore
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8.1 mongodump&lt;/h2&gt;
&lt;p&gt;备份数据库：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mongodump \
  --uri=&quot;mongodb://localhost:27017/mydb&quot; \
  --out=/backup/mydb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结果可能类似：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/backup/mydb/
├── collection1.bson
├── collection1.metadata.json
├── collection2.bson
└── collection2.metadata.json
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8.2 mongorestore&lt;/h2&gt;
&lt;p&gt;恢复：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mongorestore \
  --uri=&quot;mongodb://localhost:27017/mydb&quot; \
  /backup/mydb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;备份和恢复首先解决的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据误删
数据库损坏
机器故障后的数据恢复
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但真正的生产备份还必须考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;备份频率
备份位置
备份保留时间
恢复测试
RPO
RTO
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MongoDB 官方：
&lt;a href=&quot;https://www.mongodb.com/docs/manual/core/backups/&quot;&gt;Backup and Restore Methods&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;8.3 备份恢复测试&lt;/h2&gt;
&lt;p&gt;“已经执行备份命令”不等于“已经具备恢复能力”。&lt;/p&gt;
&lt;p&gt;完整流程应该是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;生产 MongoDB
      │
      ▼
    Backup
      │
      ▼
独立存储
      │
      ▼
   定期恢复测试
      │
      ▼
确认数据可以恢复
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于运维而言：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Backup
  +
Restore Test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;才构成真正可验证的备份体系。&lt;/p&gt;
&lt;h1&gt;九、MongoDB 索引与性能基础&lt;/h1&gt;
&lt;h2&gt;9.1 为什么需要索引&lt;/h2&gt;
&lt;p&gt;没有索引时，数据库可能需要扫描大量文档：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Collection
 ├── Document 1
 ├── Document 2
 ├── Document 3
 ├── ...
 └── Document N
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果查询：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;db.users.find({ name: &quot;Alice&quot; })
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;没有适合的索引，就可能扫描大量数据。&lt;/p&gt;
&lt;p&gt;建立索引：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;db.users.createIndex({ name: 1 })
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据库可以利用索引快速定位数据。&lt;/p&gt;
&lt;p&gt;MongoDB 官方：
&lt;a href=&quot;https://www.mongodb.com/docs/manual/indexes/&quot;&gt;Indexes&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;9.2 单字段索引&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;db.users.createIndex({ name: 1 })
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示按照 &lt;code&gt;name&lt;/code&gt; 建立索引。&lt;/p&gt;
&lt;h2&gt;9.3 复合索引&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;db.users.createIndex({
  city: 1,
  age: -1
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;字段顺序非常重要。&lt;/p&gt;
&lt;p&gt;索引设计必须结合实际查询：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;经常查询什么？
排序什么？
过滤什么？
查询字段组合是什么？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是“索引越多越好”。&lt;/p&gt;
&lt;h2&gt;9.4 索引的代价&lt;/h2&gt;
&lt;p&gt;索引会提升部分查询性能，但也会带来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;额外磁盘空间
写入成本
内存占用
维护成本
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此需要在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;读性能
写性能
存储空间
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之间进行权衡。&lt;/p&gt;
&lt;h1&gt;十、MongoDB 常见故障排查&lt;/h1&gt;
&lt;h2&gt;10.1 服务无法启动&lt;/h2&gt;
&lt;p&gt;首先：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl status mongod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再查看日志。&lt;/p&gt;
&lt;p&gt;重点检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;配置文件
dbPath
目录权限
端口占用
磁盘空间
日志
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10.2 磁盘空间不足&lt;/h2&gt;
&lt;p&gt;MongoDB 数据库通常会随着数据量增长而扩大。&lt;/p&gt;
&lt;p&gt;查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df -h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据库目录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;du -sh /var/lib/mongodb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果磁盘接近 100%，数据库可能出现写入失败等问题。&lt;/p&gt;
&lt;h2&gt;10.3 查询变慢&lt;/h2&gt;
&lt;p&gt;重点检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;索引
查询条件
返回数据量
排序
并发
磁盘 I/O
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以使用查询分析工具，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;db.users.find({ name: &quot;Alice&quot; }).explain(&quot;executionStats&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重点观察：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;执行计划
扫描文档数量
返回文档数量
执行时间
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10.4 连接问题&lt;/h2&gt;
&lt;p&gt;从：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;客户端
  │
  ▼
MongoDB 端口
  │
  ▼
认证
  │
  ▼
权限
  │
  ▼
数据库
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;逐层排查。&lt;/p&gt;
&lt;p&gt;例如先确认：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -lntp | grep 27017
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再确认网络和认证。&lt;/p&gt;
&lt;h1&gt;十一、Milvus 与向量数据库&lt;/h1&gt;
&lt;h2&gt;11.1 什么是向量数据库&lt;/h2&gt;
&lt;p&gt;Redis 和 MongoDB 主要解决的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Key-Value
Document
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而 Milvus 解决的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Vector Similarity Search
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是&lt;strong&gt;向量相似度搜索&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;例如一段文本经过 Embedding 模型后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;Linux 网络故障排查&quot;
       │
       ▼
Embedding Model
       │
       ▼
[0.13, 0.82, 0.21, ...]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;得到一个高维向量。&lt;/p&gt;
&lt;p&gt;另一段文本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;Linux 网络连接异常怎么办&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以转换成向量。&lt;/p&gt;
&lt;p&gt;虽然两段文本的字面内容不同，但它们的语义可能很接近，因此向量之间的距离也可能较小。&lt;/p&gt;
&lt;p&gt;于是可以进行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Query Vector
      │
      ▼
Vector Database
      │
      ▼
寻找最相似的 Top-K 向量
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是向量相似度搜索。&lt;/p&gt;
&lt;p&gt;Milvus 官方：
&lt;a href=&quot;https://milvus.io/docs&quot;&gt;Milvus Documentation&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;11.2 Milvus 的基本模型&lt;/h2&gt;
&lt;p&gt;Milvus 的核心概念可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Database
   │
   └── Collection
          │
          ├── Vector Field
          ├── Scalar Field
          └── Primary Key
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;documents
├── id
├── text
├── category
└── embedding
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;embedding
    │
    └── [0.12, 0.35, 0.92, ...]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就是向量字段。&lt;/p&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;category
text
id
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;属于标量数据。&lt;/p&gt;
&lt;h2&gt;11.3 为什么普通数据库也能保存向量，却还需要 Milvus&lt;/h2&gt;
&lt;p&gt;理论上，向量可以保存到普通数据库中。&lt;/p&gt;
&lt;p&gt;但是随着数据量增加：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;向量维度
      ×
向量数量
      ×
搜索请求数量
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;相似度检索的计算量会迅速增加。&lt;/p&gt;
&lt;p&gt;因此，向量数据库通常会针对：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;向量存储
向量索引
相似度搜索
Top-K 检索
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进行专门优化。&lt;/p&gt;
&lt;p&gt;Milvus 官方提供多种索引和相似度搜索能力，适合构建大规模向量检索系统。&lt;/p&gt;
&lt;h1&gt;十二、Milvus Linux / Docker 部署&lt;/h1&gt;
&lt;p&gt;Milvus 的部署方式与 Redis、MongoDB 有明显不同。&lt;/p&gt;
&lt;p&gt;Redis / MongoDB 可以直接作为系统服务运行，而 Milvus 很常见的部署方式是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker
Docker Compose
Kubernetes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Milvus 官方当前提供 Docker 和 Docker Compose 部署文档。&lt;/p&gt;
&lt;p&gt;参考：
&lt;a href=&quot;https://milvus.io/docs/install_standalone-docker.md&quot;&gt;Run Milvus in Docker&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;12.1 Docker 部署&lt;/h2&gt;
&lt;p&gt;准备 Docker 环境后，可以使用官方脚本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -sfL \
  https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh \
  -o standalone_embed.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash standalone_embed.sh start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;停止：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash standalone_embed.sh stop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当前 Milvus 官方文档中的 Standalone Docker 部署默认使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Milvus
19530
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时会涉及元数据、存储等相关组件；实际部署结构会随 Milvus 版本演进，因此生产环境应以对应版本官方文档为准。&lt;/p&gt;
&lt;h2&gt;12.2 Docker Compose&lt;/h2&gt;
&lt;p&gt;如果需要更明确地管理组件和数据卷，可以使用 Docker Compose。&lt;/p&gt;
&lt;p&gt;典型结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker Compose
      │
      ├── Milvus
      ├── Metadata Store
      └── Object Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方文档：
&lt;a href=&quot;https://milvus.io/docs/install_standalone-docker-compose.md&quot;&gt;Run Milvus with Docker Compose&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;12.3 Milvus 端口&lt;/h2&gt;
&lt;p&gt;Standalone 部署常见服务端口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;19530 → Milvus 服务
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;某些部署中还会提供 Web UI，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;9091
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -lntp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确认端口映射。&lt;/p&gt;
&lt;h1&gt;十三、Milvus 数据组织与向量搜索&lt;/h1&gt;
&lt;h2&gt;13.1 Collection&lt;/h2&gt;
&lt;p&gt;Collection 可以理解为 Milvus 中的一组数据集合。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;documents
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;内部包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;id
title
content
embedding
category
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;id          → 主键
title       → 标量字段
content     → 标量字段
embedding   → 向量字段
category    → 标量字段
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;13.2 Insert&lt;/h2&gt;
&lt;p&gt;向量经过 Embedding 模型生成后写入 Milvus：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;文本
 │
 ▼
Embedding Model
 │
 ▼
Vector
 │
 ▼
Milvus Collection
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;文档 A
→ [0.12, 0.34, 0.78, ...]

文档 B
→ [0.18, 0.31, 0.75, ...]

文档 C
→ [0.93, 0.12, 0.08, ...]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;13.3 Similarity Search&lt;/h2&gt;
&lt;p&gt;用户输入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Linux 网络连接异常怎么办？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;首先转换成查询向量：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Query
 │
 ▼
Embedding Model
 │
 ▼
Query Vector
 │
 ▼
Milvus
 │
 ├── Document A → 0.92
 ├── Document B → 0.88
 ├── Document C → 0.74
 └── ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后返回 Top-K 结果。&lt;/p&gt;
&lt;p&gt;这也是 RAG（Retrieval-Augmented Generation）系统中非常常见的一种架构。&lt;/p&gt;
&lt;h1&gt;十四、Milvus 的索引与性能基础&lt;/h1&gt;
&lt;p&gt;向量数据库的查询性能与索引方式高度相关。&lt;/p&gt;
&lt;p&gt;基本思想是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;原始向量
   │
   ▼
建立向量索引
   │
   ▼
查询向量
   │
   ▼
快速寻找近似邻居
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见思想包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;精确搜索
近似最近邻搜索（ANN）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际系统会根据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据规模
向量维度
召回率要求
延迟要求
内存
磁盘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;选择合适的索引和参数。&lt;/p&gt;
&lt;p&gt;因此，向量数据库优化并不是简单地：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU 越高越好
内存越大越好
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而需要结合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;索引
数据规模
查询模式
向量维度
Top-K
过滤条件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;综合调整。&lt;/p&gt;
&lt;h1&gt;十五、Milvus 数据安全与运维&lt;/h1&gt;
&lt;p&gt;虽然 Milvus 经常通过 Docker 部署，但它依然是数据库系统，而不是“启动一个容器就结束”。&lt;/p&gt;
&lt;p&gt;运维时需要关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;容器状态
数据卷
日志
端口
存储
元数据
对象存储
备份
版本升级
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;15.1 数据卷&lt;/h2&gt;
&lt;p&gt;容器本身可以删除，但数据库数据不能依赖容器生命周期。&lt;/p&gt;
&lt;p&gt;应该使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker Volume
或
宿主机持久化目录
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host
 │
 └── volumes/
       └── milvus/
             ├── data
             └── ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;否则执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker rm
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等操作时可能造成数据风险。&lt;/p&gt;
&lt;h2&gt;15.2 备份&lt;/h2&gt;
&lt;p&gt;Milvus 的备份不能简单理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker commit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据库备份需要考虑实际的数据存储、元数据和部署模式。&lt;/p&gt;
&lt;p&gt;因此生产环境应该优先采用 Milvus 官方对应版本支持的备份方案，而不是只复制某一个容器目录。&lt;/p&gt;
&lt;h1&gt;十六、Redis、MongoDB、Milvus 对比&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;Redis&lt;/th&gt;
&lt;th&gt;MongoDB&lt;/th&gt;
&lt;th&gt;Milvus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;核心模型&lt;/td&gt;
&lt;td&gt;Key-Value / Data Structure&lt;/td&gt;
&lt;td&gt;Document&lt;/td&gt;
&lt;td&gt;Vector&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;主要数据&lt;/td&gt;
&lt;td&gt;内存数据结构&lt;/td&gt;
&lt;td&gt;BSON 文档&lt;/td&gt;
&lt;td&gt;向量 + 标量&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;典型场景&lt;/td&gt;
&lt;td&gt;缓存、Session、计数、排行榜&lt;/td&gt;
&lt;td&gt;业务文档、内容数据&lt;/td&gt;
&lt;td&gt;向量检索、RAG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;查询特点&lt;/td&gt;
&lt;td&gt;Key / Structure&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;Linux / Docker&lt;/td&gt;
&lt;td&gt;Linux / Docker&lt;/td&gt;
&lt;td&gt;Docker / Compose / K8s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;默认端口&lt;/td&gt;
&lt;td&gt;6379&lt;/td&gt;
&lt;td&gt;27017&lt;/td&gt;
&lt;td&gt;19530&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;td&gt;容器、存储、索引&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;持久化&lt;/td&gt;
&lt;td&gt;RDB / AOF&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;内存过高、热点 Key&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;/p&gt;
&lt;pre&gt;&lt;code&gt;Redis
→ 我要快速拿到数据。

MongoDB
→ 我要灵活地存储和查询文档。

Milvus
→ 我要快速找到“最相似”的向量。
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十七、NoSQL 数据库故障排查方法&lt;/h1&gt;
&lt;p&gt;虽然三种数据库的内部实现完全不同，但运维排障可以使用相似的思路。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                数据库故障
                    │
                    ▼
              1. 服务是否正常？
                    │
                    ▼
              2. 端口是否监听？
                    │
                    ▼
              3. 网络是否连通？
                    │
                    ▼
              4. 是否认证成功？
                    │
                    ▼
              5. 是否有权限？
                    │
                    ▼
              6. 数据是否正常？
                    │
                    ▼
              7. 性能是否正常？
                    │
          ┌─────────┼─────────┐
          ▼         ▼         ▼
        CPU        Memory      Disk
          │         │         │
          └─────────┼─────────┘
                    ▼
                  日志
                    │
                    ▼
                 恢复能力
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;17.1 服务层&lt;/h2&gt;
&lt;p&gt;Linux 下首先看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status xxx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者 Docker：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker ps
docker logs &amp;lt;container&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确认：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;服务是否启动
容器是否退出
是否反复重启
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;17.2 网络层&lt;/h2&gt;
&lt;p&gt;检查监听：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -lntp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从远程客户端测试：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nc -vz &amp;lt;host&amp;gt; &amp;lt;port&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nc -vz 192.168.1.10 6379
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;17.3 认证与权限&lt;/h2&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;端口能访问
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用仍然无法使用数据库
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就需要检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户名
密码
认证机制
数据库
角色
权限
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不要把所有连接问题都归结为“网络不通”。&lt;/p&gt;
&lt;h2&gt;17.4 性能层&lt;/h2&gt;
&lt;p&gt;当数据库响应变慢时，应区分：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
Memory
Disk I/O
Network
Database Query
Connection Pool
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如 Redis：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Memory
Hot Key
Slow Command
Connection
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MongoDB：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Index
Query Plan
Disk
Lock / Concurrency
Connection
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Milvus：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Vector Index
Query Load
Memory
Storage
Component Health
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十八、NoSQL 数据库与 Web 应用&lt;/h1&gt;
&lt;p&gt;实际项目通常不会只使用一种数据库。&lt;/p&gt;
&lt;p&gt;例如一个 AI / Web 应用可能采用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                   Client
                      │
                      ▼
                  API Server
                      │
        ┌─────────────┼─────────────┐
        │             │             │
        ▼             ▼             ▼
      MySQL         Redis        MongoDB
        │             │             │
   业务数据        缓存/Session     文档数据
                      │
                      │
                      ▼
                   Milvus
                      │
                      ▼
                 Vector Search
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进一步结合 RAG：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  用户问题
                     │
                     ▼
               Embedding Model
                     │
                     ▼
                  Milvus
                     │
                  Top-K
                     │
                     ▼
               相关文档内容
                     │
                     ▼
                LLM / Agent
                     │
                     ▼
                  最终回答
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这说明不同数据库并不是简单的竞争关系。&lt;/p&gt;
&lt;p&gt;它们解决的是不同问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;关系数据库
→ 事务与结构化业务数据

Redis
→ 高速缓存与内存数据结构

MongoDB
→ 灵活文档数据

Milvus
→ 向量检索
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;十九、从运维视角理解 NoSQL&lt;/h1&gt;
&lt;p&gt;学习这些数据库时，不应该只记：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;6379
27017
19530
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;真正重要的是理解数据库运行在整个系统中的位置。&lt;/p&gt;
&lt;p&gt;例如 Redis 内存满了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Redis
 │
 └── maxmemory / eviction
       │
       ▼
应用缓存命中率下降
       │
       ▼
MySQL 查询压力增加
       │
       ▼
整体响应变慢
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MongoDB 磁盘满了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MongoDB
   │
   ▼
磁盘空间不足
   │
   ▼
写入失败
   │
   ▼
应用报错
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Milvus 存储异常：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Milvus
   │
   ▼
数据 / 元数据 / 对象存储异常
   │
   ▼
Collection 或搜索异常
   │
   ▼
RAG 检索失败
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此数据库运维真正关注的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据库
   │
   ├── 进程
   ├── 网络
   ├── 磁盘
   ├── 内存
   ├── 配置
   ├── 权限
   ├── 数据
   ├── 性能
   ├── 日志
   └── 备份恢复
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;二十、总结&lt;/h1&gt;
&lt;p&gt;Redis、MongoDB、Milvus 虽然都可以归入广义的 NoSQL / 非关系型数据系统，但它们的设计目标明显不同：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Redis
→ 高性能 Key-Value / 内存数据结构

MongoDB
→ 灵活的文档数据模型

Milvus
→ 大规模向量数据与相似度搜索
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从 Linux 运维角度，三者可以进一步归纳为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;安装
 ↓
服务管理
 ↓
配置
 ↓
网络与端口
 ↓
认证与权限
 ↓
数据存储
 ↓
备份恢复
 ↓
性能监控
 ↓
日志排查
 ↓
故障恢复
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而真正进入生产环境之后，数据库运维的目标并不是单纯让数据库“运行起来”，而是保证：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;可用
可靠
安全
可恢复
可观测
可扩展
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也是从“会使用数据库”走向“具备数据库运维能力”的关键一步。&lt;/p&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/&quot;&gt;Redis Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/&quot;&gt;Redis Persistence&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mongodb.com/docs/&quot;&gt;MongoDB Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mongodb.com/docs/manual/core/backups/&quot;&gt;MongoDB Backup and Restore&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://milvus.io/docs&quot;&gt;Milvus Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>数据库：主流 SQL 数据库系统</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%BB%E6%B5%81-sql-%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%BB%E6%B5%81-sql-%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F/</guid><description>从表、查询、事务、索引到备份恢复，介绍常见关系型数据库的基础使用。</description><pubDate>Sun, 13 Sep 2026 23:31:41 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;本文直接补齐关系型数据库的基本概念和常用操作。&lt;/p&gt;
&lt;p&gt;本篇进一步落到实际数据库系统，重点介绍 Linux 运维中非常常见的 &lt;strong&gt;MySQL 与 PostgreSQL&lt;/strong&gt;。内容覆盖数据库安装与服务管理、用户与权限、备份与恢复、日志、故障排查、性能与索引，以及复制和高可用的基础概念。&lt;/p&gt;
&lt;p&gt;本文关注的是“如何理解和管理数据库系统”，而不是完整的 SQL 教程，因此不会展开大量 SQL 语法，也暂不讨论 Redis、MongoDB 等 NoSQL 数据库。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;MySQL 与 PostgreSQL&lt;/h1&gt;
&lt;p&gt;MySQL 和 PostgreSQL 都属于：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;关系型数据库管理系统（RDBMS）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它们都以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Table
Row
Column
Primary Key
Transaction
Index
SQL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等概念为基础。&lt;/p&gt;
&lt;p&gt;但两者在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL 能力
事务实现
索引类型
扩展机制
权限模型
存储架构
复制
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等方面存在明显差异。&lt;/p&gt;
&lt;p&gt;可以先建立这样的认识：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;关系型数据库
      │
      ├── MySQL
      │
      └── PostgreSQL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它们解决的是相似的问题，但并不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;两个名字不同、完全相同的数据库
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更准确地说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;MySQL 和 PostgreSQL 是两个独立的 DBMS，各自拥有不同的实现和运维体系。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL&lt;/h1&gt;
&lt;h2&gt;MySQL 是什么&lt;/h2&gt;
&lt;p&gt;MySQL 是一种广泛使用的关系型数据库管理系统。&lt;/p&gt;
&lt;p&gt;现代 Linux 环境中，MySQL Server 通常由：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mysqld
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;提供服务。&lt;/p&gt;
&lt;p&gt;MySQL 官方文档将 &lt;code&gt;mysqld&lt;/code&gt; 描述为执行 MySQL Server 核心工作的多线程服务器程序，它负责监听客户端连接并管理数据目录中的数据库和表。&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.4/en/&quot;&gt;MySQL Reference Manual&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MySQL Client
     │
     ▼
  mysqld
     │
     ├── Connection
     ├── SQL
     ├── Transaction
     ├── Buffer
     ├── Log
     └── Storage Engine
             │
             ▼
          Database
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 安装&lt;/h1&gt;
&lt;h2&gt;Debian / Ubuntu&lt;/h2&gt;
&lt;p&gt;例如使用系统的软件包管理器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
sudo apt install mysql-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装完成后可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mysql --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看客户端版本。&lt;/p&gt;
&lt;p&gt;然后检查服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl status mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MySQL 官方 APT 安装文档也以 &lt;code&gt;mysql-server&lt;/code&gt; 软件包和 &lt;code&gt;systemctl&lt;/code&gt; 作为 Debian / Ubuntu 环境中的典型安装与管理方式。&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.4/en/linux-installation-apt-repo.html&quot;&gt;Installing MySQL with APT&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;RHEL 系&lt;/h2&gt;
&lt;p&gt;在 RHEL 系环境中，具体安装方式取决于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发行版版本
MySQL 官方仓库
系统仓库
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际安装前应确认仓库和版本策略。&lt;/p&gt;
&lt;p&gt;安装完成后，服务名称可能是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mysqld
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl status mysqld
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看。&lt;/p&gt;
&lt;p&gt;MySQL 官方文档也明确说明，使用 RPM 系安装时通常由 systemd 管理 MySQL 服务。&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.4/en/using-systemd.html&quot;&gt;Managing MySQL Server with systemd&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 服务管理&lt;/h1&gt;
&lt;p&gt;常见命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl start mysql
sudo systemctl stop mysql
sudo systemctl restart mysql
sudo systemctl status mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;RHEL 系环境中可能使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl start mysqld
sudo systemctl stop mysqld
sudo systemctl restart mysqld
sudo systemctl status mysqld
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;具体服务名要以实际系统为准。&lt;/p&gt;
&lt;p&gt;设置开机启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable mysqld
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 初始安全配置&lt;/h1&gt;
&lt;p&gt;数据库安装完成后，不应该直接认为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“服务启动了 = 可以投入生产”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还需要处理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;管理员账户
密码 / 认证
匿名账户
远程访问
测试数据库
权限
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MySQL 官方安全指南建议遵循最小权限原则，并通过 &lt;code&gt;GRANT&lt;/code&gt; / &lt;code&gt;REVOKE&lt;/code&gt; 控制账户权限，不应随意授予过大的权限。&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.4/en/security-guidelines.html&quot;&gt;MySQL Security Guidelines&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 用户与权限&lt;/h1&gt;
&lt;h2&gt;创建用户&lt;/h2&gt;
&lt;p&gt;MySQL 中使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE USER &apos;app&apos;@&apos;localhost&apos;
IDENTIFIED BY &apos;strong-password&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是数据库账户。&lt;/p&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&apos;localhost&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示这个账户对应的来源主机条件。&lt;/p&gt;
&lt;p&gt;因此 MySQL 的账户概念可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户名
+
主机条件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&apos;app&apos;@&apos;localhost&apos;
&apos;app&apos;@&apos;192.168.1.10&apos;
&apos;app&apos;@&apos;%&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在权限意义上并不等价。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;授予权限&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GRANT SELECT, INSERT, UPDATE
ON appdb.*
TO &apos;app&apos;@&apos;localhost&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据库 appdb
↓
允许 app
↓
SELECT / INSERT / UPDATE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看权限：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SHOW GRANTS FOR &apos;app&apos;@&apos;localhost&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;撤销：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;REVOKE UPDATE
ON appdb.*
FROM &apos;app&apos;@&apos;localhost&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MySQL 官方推荐通过 &lt;code&gt;GRANT&lt;/code&gt;、&lt;code&gt;REVOKE&lt;/code&gt; 等机制管理权限，并强调不要授予超出需要范围的权限。&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.4/en/security-guidelines.html&quot;&gt;MySQL Security Guidelines&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 远程访问&lt;/h1&gt;
&lt;p&gt;很多数据库“连接不上”的问题并不一定是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户名密码错误
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还可能是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;监听地址
端口
防火墙
账户 Host 条件
认证插件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用服务器
192.168.1.10

MySQL
192.168.1.20:3306
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要同时确认：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络可达
+
3306 可访问
+
MySQL 正在监听
+
账户允许该来源连接
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;数据库用户权限和 Linux 网络防火墙是两个不同层次的问题。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;PostgreSQL&lt;/h1&gt;
&lt;h2&gt;PostgreSQL 是什么&lt;/h2&gt;
&lt;p&gt;PostgreSQL 是另一套成熟的开源关系型数据库管理系统。&lt;/p&gt;
&lt;p&gt;它具有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL
Transaction
MVCC
Index
WAL
Replication
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等完整数据库能力。&lt;/p&gt;
&lt;p&gt;官方 PostgreSQL 18 文档将数据库服务器管理划分为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Installation
Server Setup and Operation
Server Configuration
Client Authentication
Database Roles
Backup and Restore
High Availability / Replication
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等章节。&lt;a href=&quot;https://www.postgresql.org/docs/18/&quot;&gt;PostgreSQL 18 Documentation&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;PostgreSQL 安装&lt;/h1&gt;
&lt;h2&gt;Debian / Ubuntu&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
sudo apt install postgresql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看版本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;psql --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl status postgresql
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;PostgreSQL 的 Cluster&lt;/h2&gt;
&lt;p&gt;PostgreSQL 与 MySQL 的一个重要区别，是它经常使用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Database Cluster&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这一概念。&lt;/p&gt;
&lt;p&gt;这里的 Cluster 不一定指：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;多台服务器组成的集群
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;一个 PostgreSQL Server 实例管理的一组数据库及其共享系统对象。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以简单理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PostgreSQL Instance
        │
        ▼
   Database Cluster
        │
   ┌────┼────┐
   ▼    ▼    ▼
 db1   db2   db3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这与 PostgreSQL 的具体目录结构和系统目录管理方式有关。&lt;/p&gt;
&lt;p&gt;因此不要把：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PostgreSQL Cluster
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;和：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PostgreSQL High-Availability Cluster
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;直接画等号。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;PostgreSQL 服务管理&lt;/h1&gt;
&lt;p&gt;使用 systemd 时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl start postgresql
sudo systemctl stop postgresql
sudo systemctl restart postgresql
sudo systemctl status postgresql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;开机启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable postgresql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;具体服务单元名称可能随着发行版和 PostgreSQL 安装方式有所差异。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;PostgreSQL 用户与 Role&lt;/h1&gt;
&lt;p&gt;PostgreSQL 使用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Role（角色）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;管理数据库身份和权限。&lt;/p&gt;
&lt;p&gt;官方文档明确指出：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;PostgreSQL 将“用户”和“组”的概念统一在 Role 中。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一个 Role 可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;登录数据库
拥有对象
拥有权限
继承其他 Role 的权限
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE ROLE app LOGIN PASSWORD &apos;strong-password&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;app
↓
Role

LOGIN
↓
允许登录
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以参考官方 &lt;a href=&quot;https://www.postgresql.org/docs/18/user-manag.html&quot;&gt;Database Roles&lt;/a&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;PostgreSQL 权限&lt;/h1&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GRANT CONNECT
ON DATABASE appdb
TO app;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对表授权：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GRANT SELECT, INSERT, UPDATE
ON TABLE users
TO app;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;撤销：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;REVOKE UPDATE
ON TABLE users
FROM app;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PostgreSQL 权限通常涉及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Database
Schema
Table
Sequence
Function
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等对象。&lt;/p&gt;
&lt;p&gt;因此在排查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;permission denied
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;时，需要先确定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;哪个 Role
+
哪个对象
+
缺少什么权限
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 与 PostgreSQL 权限模型对比&lt;/h1&gt;
&lt;p&gt;两者都有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User / Role
Privilege
Grant
Revoke
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但模型不同。&lt;/p&gt;
&lt;p&gt;可以粗略理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MySQL
↓
Account
(user + host)

PostgreSQL
↓
Role
(Login / Membership / Privilege)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此不能把 MySQL 的权限命令机械搬到 PostgreSQL。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MySQL
&apos;user&apos;@&apos;host&apos;

PostgreSQL
Role
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是两个 DBMS 在权限模型上的明显差异。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库连接&lt;/h1&gt;
&lt;h2&gt;客户端连接数据库&lt;/h2&gt;
&lt;p&gt;MySQL 常见：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mysql -h 127.0.0.1 -P 3306 -u app -p
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PostgreSQL 常见：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;psql -h 127.0.0.1 -p 5432 -U app -d appdb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;连接信息通常包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host
Port
Database
User
Password
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;默认端口&lt;/h1&gt;
&lt;p&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;MySQL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;3306&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;5432&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;MySQL
192.168.1.20:3306

PostgreSQL
192.168.1.20:5432
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际部署时当然可以修改。&lt;/p&gt;
&lt;p&gt;因此排查连接问题时：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;不要假设数据库一定监听默认端口。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;首先应该使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -lntp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确认实际监听情况。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;连接池&lt;/h1&gt;
&lt;p&gt;Web 应用通常不会对每一个 HTTP 请求都重新创建数据库连接。&lt;/p&gt;
&lt;p&gt;更典型的方式是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
     │
     ▼
Connection Pool
     │
 ┌───┼───┐
 ▼   ▼   ▼
 C1  C2  C3
     │
     ▼
    DBMS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;请求：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP Request
    │
    ▼
Application
    │
    ▼
获取连接
    │
    ▼
执行 SQL
    │
    ▼
归还连接
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;连接池过小：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;请求等待连接
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;连接池过大：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据库连接数过多
↓
内存 / CPU / 锁压力增加
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;连接池是应用与数据库之间的重要容量控制点。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库备份&lt;/h1&gt;
&lt;h2&gt;为什么需要备份&lt;/h2&gt;
&lt;p&gt;数据库存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;磁盘损坏
误删
误更新
程序 Bug
人为操作错误
勒索 / 攻击
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等风险。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;数据库必须存在独立于数据库本身正常运行机制之外的备份策略。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;需要区分：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;事务持久性
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;和：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;备份
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;前者解决：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据库崩溃恢复
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后者解决：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;人为 / 逻辑 / 灾难性数据损失
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 备份&lt;/h1&gt;
&lt;h2&gt;mysqldump&lt;/h2&gt;
&lt;p&gt;MySQL 中最常见的逻辑备份工具之一：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mysqldump -u root -p appdb &amp;gt; appdb.sql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;得到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;appdb.sql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后可以恢复：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mysql -u root -p appdb &amp;lt; appdb.sql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以简单理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Database
   │
   ▼
mysqldump
   │
   ▼
SQL Dump
   │
   ▼
恢复
   │
   ▼
Database
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;MySQL 逻辑备份的特点&lt;/h2&gt;
&lt;p&gt;逻辑备份的优势：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;可读
通用
迁移方便
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但缺点也很明显：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据量大时速度较慢
恢复时间可能较长
需要执行大量 SQL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此大型数据库不能只依赖简单的 &lt;code&gt;mysqldump&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;MySQL 官方文档对逻辑备份、恢复以及其他备份方式都有专门说明。&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.4/en/backup-and-recovery.html&quot;&gt;MySQL Backup and Recovery&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 物理备份&lt;/h1&gt;
&lt;p&gt;物理备份更接近：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;复制数据库文件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;导出 SQL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Data Directory
      │
      ▼
Physical Backup
      │
      ▼
Restore
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;物理备份通常更适合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;大型数据库
快速恢复
完整实例迁移
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但它通常要求：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;备份工具
数据库状态
文件一致性
版本兼容
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等条件更加严格。&lt;/p&gt;
&lt;p&gt;MySQL 官方的备份文档同时涵盖逻辑和物理备份方案。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;PostgreSQL 备份&lt;/h1&gt;
&lt;p&gt;PostgreSQL 常见的逻辑备份工具：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pg_dump
pg_dumpall
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pg_dump -U app appdb &amp;gt; appdb.sql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;恢复：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;psql -U app -d appdb &amp;lt; appdb.sql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pg_dump
↓
备份单个数据库

pg_dumpall
↓
备份整个 PostgreSQL Cluster 的逻辑对象
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;PostgreSQL 自定义格式备份&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;pg_dump&lt;/code&gt; 不一定只能输出纯 SQL。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pg_dump -Fc -U app appdb &amp;gt; appdb.dump
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后可以通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pg_restore -U app -d appdb appdb.dump
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进行恢复。&lt;/p&gt;
&lt;p&gt;相比普通 SQL dump：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Custom Format
↓
更适合配合 pg_restore
↓
可以进行更灵活的恢复操作
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;PostgreSQL 物理备份&lt;/h1&gt;
&lt;p&gt;PostgreSQL 还支持基于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Base Backup
+
WAL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的物理备份和恢复体系。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Base Backup
     +
    WAL
     │
     ▼
恢复数据库
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这与 PostgreSQL 的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;WAL（Write-Ahead Logging）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;机制密切相关。&lt;/p&gt;
&lt;p&gt;官方文档对 &lt;a href=&quot;https://www.postgresql.org/docs/18/backup.html&quot;&gt;Backup and Restore&lt;/a&gt; 以及 WAL 归档、基础备份等内容都有详细说明。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 与 PostgreSQL 备份方式对比&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方式&lt;/th&gt;
&lt;th&gt;MySQL&lt;/th&gt;
&lt;th&gt;PostgreSQL&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;mysqldump&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pg_dump&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;全局逻辑备份&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mysqldump&lt;/code&gt; 等&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pg_dumpall&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;tr&gt;
&lt;td&gt;日志恢复能力&lt;/td&gt;
&lt;td&gt;Binlog 等&lt;/td&gt;
&lt;td&gt;WAL&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;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;备份命令只是第一步，真正重要的是“备份能不能恢复”。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;恢复测试&lt;/h1&gt;
&lt;p&gt;一个非常常见的错误是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;每天都有备份
↓
所以数据库安全
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际上更重要的问题是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;备份文件存在吗？
       ↓
完整吗？
       ↓
能恢复吗？
       ↓
恢复需要多久？
       ↓
恢复后的数据到哪个时间点？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以数据库备份一定应该包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Backup
+
Restore Test
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;RPO 与 RTO&lt;/h1&gt;
&lt;p&gt;数据库高可用和灾备中经常出现：&lt;/p&gt;
&lt;h3&gt;RPO&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Recovery Point Objective&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;可以接受最多丢失多少数据。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RPO = 5 min
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;意味着故障时希望：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;最多损失约 5 分钟的数据变化
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;RTO&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Recovery Time Objective&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;希望在多长时间内恢复服务。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RTO = 30 min
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;意味着：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;故障
↓
30 分钟内恢复服务
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RPO
↓
最多丢多少数据

RTO
↓
最多停多久
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 日志&lt;/h1&gt;
&lt;p&gt;MySQL 的日志体系比较丰富。&lt;/p&gt;
&lt;p&gt;常见日志包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Error Log
General Query Log
Slow Query Log
Binary Log
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Error Log&lt;/h2&gt;
&lt;p&gt;记录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;启动错误
崩溃
配置问题
严重异常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;排查数据库：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;启动失败
服务异常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;时，首先就应该关注 Error Log。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Slow Query Log&lt;/h2&gt;
&lt;p&gt;慢查询日志用于记录：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;执行时间超过指定条件的查询。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它非常适合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;慢 SQL 分析
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL
 ↓
执行 8 秒
 ↓
Slow Query Log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后进一步：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EXPLAIN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查执行计划。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Binary Log&lt;/h2&gt;
&lt;p&gt;MySQL Binary Log（Binlog）非常重要。&lt;/p&gt;
&lt;p&gt;它记录数据库中发生的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据修改事件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并广泛用于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;复制
增量恢复
数据同步
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Transaction
     │
     ▼
  Binlog
     │
     ├── Replica
     └── Recovery
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;PostgreSQL 日志&lt;/h1&gt;
&lt;p&gt;PostgreSQL 常见日志用于记录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;启动 / 停止
连接
认证
错误
查询
检查点
恢复
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;具体日志行为由 PostgreSQL 的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;logging_collector
log_statement
log_min_duration_statement
log_min_messages
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等配置控制。&lt;/p&gt;
&lt;p&gt;官方文档中的 &lt;a href=&quot;https://www.postgresql.org/docs/18/runtime-config-logging.html&quot;&gt;Error Reporting and Logging&lt;/a&gt; 对日志配置进行了详细说明。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;PostgreSQL WAL&lt;/h1&gt;
&lt;p&gt;PostgreSQL 非常重要的机制：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;WAL（Write-Ahead Log）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;其基本思想是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据修改
   │
   ▼
先写 WAL
   │
   ▼
之后再处理数据页面
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样数据库崩溃后可以根据 WAL 进行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Crash Recovery
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;WAL 同时还是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Streaming Replication
Point-in-Time Recovery
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等机制的重要基础。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;性能与索引&lt;/h1&gt;
&lt;h2&gt;为什么需要索引&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT *
FROM users
WHERE email = &apos;alice@example.com&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;users
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1000 万行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;没有适当索引时，数据库可能需要扫描大量记录。&lt;/p&gt;
&lt;p&gt;建立索引后，可以缩小查找范围。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Index
↓
减少需要检查的数据
↓
提高某些查询效率
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 索引&lt;/h1&gt;
&lt;p&gt;MySQL 中最常见的索引结构之一是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;B-Tree
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE INDEX idx_users_email
ON users(email);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查询：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT *
FROM users
WHERE email = &apos;alice@example.com&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;优化器可能选择：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Index Lookup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后定位数据。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;PostgreSQL 索引&lt;/h1&gt;
&lt;p&gt;PostgreSQL 也支持：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;B-tree
Hash
GiST
SP-GiST
GIN
BRIN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等不同索引类型。&lt;/p&gt;
&lt;p&gt;其中最常用的仍然是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;B-tree
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE INDEX idx_users_email
ON users(email);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但是 PostgreSQL 的索引体系比简单的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“只有 B+Tree”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更加丰富。&lt;/p&gt;
&lt;p&gt;不同索引类型适合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;等值查询
范围查询
全文搜索
数组
JSON
空间数据
大范围顺序扫描
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等不同场景。&lt;/p&gt;
&lt;p&gt;官方文档：&lt;a href=&quot;https://www.postgresql.org/docs/18/indexes.html&quot;&gt;PostgreSQL Indexes&lt;/a&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;EXPLAIN&lt;/h1&gt;
&lt;p&gt;不能因为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“建立了索引”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就认为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“查询一定变快”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;真正应该观察：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;执行计划（Execution Plan）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;MySQL：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EXPLAIN
SELECT *
FROM users
WHERE email = &apos;alice@example.com&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PostgreSQL：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EXPLAIN
SELECT *
FROM users
WHERE email = &apos;alice@example.com&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Seq Scan
Index Scan
Index Only Scan
Join
Cost
Rows
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等信息。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;全表扫描&lt;/h1&gt;
&lt;p&gt;如果数据库决定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Seq Scan
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Full Table Scan
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不一定表示数据库有问题。&lt;/p&gt;
&lt;p&gt;有时候：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;表很小
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;查询返回大量数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;全表扫描反而可能比使用索引更划算。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;索引优化的核心不是“所有查询都必须走索引”，而是让优化器能够选择合适的访问路径。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;联合索引&lt;/h1&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE INDEX idx_user
ON users(name, age);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以用于某些涉及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name
name + age
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的查询。&lt;/p&gt;
&lt;p&gt;但对于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;只查询 age
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是否能够有效利用这个索引，要结合具体 DBMS 的优化器和执行计划判断。&lt;/p&gt;
&lt;p&gt;因此不要机械记成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;有索引
↓
一定使用
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;慢查询排查&lt;/h1&gt;
&lt;p&gt;数据库查询变慢时，可以形成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;慢查询
   ↓
找到 SQL
   ↓
EXPLAIN
   ↓
查看执行计划
   ↓
是否全表扫描？
   ↓
索引是否合理？
   ↓
数据量是否增长？
   ↓
是否存在锁等待？
   ↓
CPU / Memory / I/O
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样比直接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“给字段加索引”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更加可靠。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库资源&lt;/h1&gt;
&lt;p&gt;数据库性能不仅取决于 SQL。&lt;/p&gt;
&lt;p&gt;还可能受到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
Memory
Disk I/O
Network
Connections
Locks
Cache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;影响。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL 很快
但连接池耗尽
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用仍然可能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;请求超时
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;又例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL 没有问题
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;磁盘 I/O 很慢
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据库仍然可能整体变慢。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;数据库性能问题必须从 SQL、数据库内部状态和操作系统资源三个层次一起看。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 存储引擎&lt;/h1&gt;
&lt;p&gt;MySQL 一个非常重要的概念是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Storage Engine（存储引擎）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;MySQL Server 的通用服务层和具体存储引擎之间存在分层。&lt;/p&gt;
&lt;p&gt;常见存储引擎：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;InnoDB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 InnoDB 是现代 MySQL 中最主要的事务型存储引擎。&lt;/p&gt;
&lt;p&gt;可以简单理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MySQL Server
      │
      ▼
Storage Engine
      │
      ▼
Data / Index
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也是为什么 MySQL 的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;事务
锁
索引
日志
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等行为不能完全脱离存储引擎理解。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;PostgreSQL 的存储体系&lt;/h1&gt;
&lt;p&gt;PostgreSQL 不采用与 MySQL InnoDB 完全相同的“可插拔存储引擎”模型。&lt;/p&gt;
&lt;p&gt;它的核心数据管理由 PostgreSQL 本身的存储和执行架构负责。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MySQL
↓
Storage Engine 是非常重要的架构概念

PostgreSQL
↓
整体数据库引擎架构不同
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也是两者学习时不能简单套模板的地方。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 复制&lt;/h1&gt;
&lt;p&gt;MySQL 可以通过：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Replication&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;让一个服务器从另一个服务器同步数据。&lt;/p&gt;
&lt;p&gt;可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Source
   │
   │ Binlog
   ▼
Replica
   │
   ▼
Replay
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型架构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;          Primary
             │
          Binlog
             │
       ┌─────┴─────┐
       ▼           ▼
   Replica 1   Replica 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以用于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;读扩展
备份辅助
故障切换基础
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Replication 不等于完整高可用。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;还需要处理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;故障检测
角色切换
数据一致性
客户端重新连接
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等问题。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;PostgreSQL Streaming Replication&lt;/h1&gt;
&lt;p&gt;PostgreSQL 常见复制方式：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Streaming Replication&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以简化成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Primary
   │
   │ WAL
   ▼
Standby
   │
   ▼
Replay
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Primary 持续产生：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WAL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Standby 接收并重放 WAL。&lt;/p&gt;
&lt;p&gt;可以构建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Primary
   │
   ├── Standby 1
   └── Standby 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样的复制结构。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;主从复制并不等于高可用&lt;/h1&gt;
&lt;p&gt;这是数据库运维中非常重要的一点。&lt;/p&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Primary
   │
   ▼
Replica
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即使有 Replica：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Primary 挂了
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也不代表：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Replica 自动接管
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为完整高可用还需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;故障检测
+
Leader Election / Failover
+
客户端切换
+
数据一致性
+
脑裂防护
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等机制。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;复制是高可用的基础能力之一，而不是高可用方案本身。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库高可用&lt;/h1&gt;
&lt;p&gt;一个简单的高可用架构可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                 Client
                   │
                   ▼
              Proxy / VIP
                   │
             ┌─────┴─────┐
             │           │
             ▼           ▼
          Primary      Standby
             │           ▲
             │           │
             └── Replication
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Primary
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发生故障：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Failover
   ↓
Standby
   ↓
Promote
   ↓
新的 Primary
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;客户端需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;重新连接
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此一个真正可用的高可用方案一般还需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据库
+
复制
+
故障检测
+
自动 / 半自动切换
+
客户端发现
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 与 PostgreSQL 高可用思路&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方向&lt;/th&gt;
&lt;th&gt;MySQL&lt;/th&gt;
&lt;th&gt;PostgreSQL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;主要复制基础&lt;/td&gt;
&lt;td&gt;Binlog&lt;/td&gt;
&lt;td&gt;WAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;常见复制&lt;/td&gt;
&lt;td&gt;Source / Replica&lt;/td&gt;
&lt;td&gt;Primary / Standby&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;日志&lt;/td&gt;
&lt;td&gt;Binlog&lt;/td&gt;
&lt;td&gt;WAL&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;tr&gt;
&lt;td&gt;高可用&lt;/td&gt;
&lt;td&gt;Replication + Failover&lt;/td&gt;
&lt;td&gt;Streaming Replication + Failover&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;因此两套系统虽然：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;实现方式不同
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但运维思想高度相似：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主库
 ↓
复制日志
 ↓
备用节点
 ↓
故障检测
 ↓
切换
 ↓
恢复服务
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库安全&lt;/h1&gt;
&lt;p&gt;数据库安全不能只考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户名
密码
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还应该包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;监听地址
网络访问控制
数据库用户
权限
认证
TLS
日志
备份安全
密钥管理
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Database
    │
    ├── 不必要的公网暴露
    ├── 弱密码
    ├── 过高权限
    └── 明文传输
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都可能成为安全风险。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库不要直接暴露公网&lt;/h1&gt;
&lt;p&gt;如果没有特殊需求：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Internet
   │
   ▼
Database :3306
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通常不是好的设计。&lt;/p&gt;
&lt;p&gt;更常见：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Internet
   │
   ▼
Nginx
   │
   ▼
Application
   │
   ▼
Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;数据库通常只需要对应用服务器开放，而不是对整个 Internet 开放。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因此数据库运维和 Linux 防火墙、网络管理是直接联系在一起的。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库故障排查&lt;/h1&gt;
&lt;p&gt;当 Web 应用出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Database connection failed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以建立如下思路：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用
 ↓
数据库连接配置
 ↓
Host
 ↓
Port
 ↓
网络
 ↓
防火墙
 ↓
数据库监听
 ↓
用户名 / 密码
 ↓
权限
 ↓
数据库本身
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;典型连接故障&lt;/h1&gt;
&lt;h2&gt;Connection refused&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Connection refused
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;优先检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -lntp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确认数据库端口是否监听。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;3306
5432
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是否存在。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Timeout&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Connection timed out
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更应该关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;路由
防火墙
安全组
网络 ACL
链路
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Authentication failed&lt;/h2&gt;
&lt;p&gt;如果网络：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;正常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;端口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;正常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但认证失败：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Access denied
password authentication failed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么重点关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户名
密码
Host / Source
认证配置
权限
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 日志排障&lt;/h1&gt;
&lt;p&gt;例如 MySQL 启动失败：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;先看 systemd 状态。&lt;/p&gt;
&lt;p&gt;再查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MySQL Error Log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重点关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;配置错误
权限
数据目录
磁盘空间
端口冲突
InnoDB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Disk Full
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能导致：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据库无法写入
日志无法增长
事务失败
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;PostgreSQL 日志排障&lt;/h1&gt;
&lt;p&gt;PostgreSQL 同样可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status postgresql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后查看对应日志。&lt;/p&gt;
&lt;p&gt;重点关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;认证
监听地址
端口
配置文件
WAL
恢复
磁盘
权限
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;database system is starting up
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之类的信息，还需要结合当前数据库的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Recovery
Replication
Startup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;状态判断。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;一个完整的数据库运维排障模型&lt;/h1&gt;
&lt;p&gt;可以把前面的内容整合成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    Web Request
                         │
                         ▼
                    Application
                         │
                         ▼
                 Connection Pool
                         │
                         ▼
                  Database Connection
                         │
          ┌──────────────┼──────────────┐
          │              │              │
          ▼              ▼              ▼
       Network          Port           Auth
          │              │              │
          └──────────────┼──────────────┘
                         ▼
                        DBMS
                         │
              ┌──────────┼──────────┐
              │          │          │
              ▼          ▼          ▼
             SQL      Transaction   Lock
              │          │          │
              └──────────┼──────────┘
                         ▼
                     Optimizer
                         │
                         ▼
                       Index
                         │
                         ▼
                     Data / Cache
                         │
                         ▼
                       Disk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;请求变慢
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就可以逐层判断：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;连接池？
   ↓
网络？
   ↓
数据库连接？
   ↓
锁？
   ↓
SQL？
   ↓
索引？
   ↓
磁盘？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是一看到数据库慢就：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“加 CPU”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“加索引”
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;MySQL 与 PostgreSQL 的对比&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项目&lt;/th&gt;
&lt;th&gt;MySQL&lt;/th&gt;
&lt;th&gt;PostgreSQL&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;code&gt;mysqld&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PostgreSQL server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;默认端口&lt;/td&gt;
&lt;td&gt;&lt;code&gt;3306&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;5432&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;用户模型&lt;/td&gt;
&lt;td&gt;User + Host&lt;/td&gt;
&lt;td&gt;Role&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;常见客户端&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mysql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;psql&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;逻辑备份&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mysqldump&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pg_dump&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;关键日志&lt;/td&gt;
&lt;td&gt;Binlog / Error / Slow&lt;/td&gt;
&lt;td&gt;WAL / Error / Query Logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;常见索引&lt;/td&gt;
&lt;td&gt;B-Tree&lt;/td&gt;
&lt;td&gt;B-tree 等多种&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;复制基础&lt;/td&gt;
&lt;td&gt;Binlog&lt;/td&gt;
&lt;td&gt;WAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;典型复制&lt;/td&gt;
&lt;td&gt;Source / Replica&lt;/td&gt;
&lt;td&gt;Primary / Standby&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;权限管理&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GRANT&lt;/code&gt; / &lt;code&gt;REVOKE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GRANT&lt;/code&gt; / &lt;code&gt;REVOKE&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;服务管理&lt;/td&gt;
&lt;td&gt;systemd&lt;/td&gt;
&lt;td&gt;systemd&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这里最重要的不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;谁更好
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;两者都是成熟的关系型数据库，但具体架构、配置和运维工具不同。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;SQL 数据库系统的完整结构&lt;/h1&gt;
&lt;p&gt;把这篇内容与上一篇的数据库架构结合起来，可以得到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                        Web Application
                              │
                              ▼
                       Connection Pool
                              │
                              ▼
                    ┌─────────┴─────────┐
                    │                   │
                    ▼                   ▼
                  MySQL             PostgreSQL
                    │                   │
             ┌──────┼──────┐      ┌─────┼──────┐
             │      │      │      │     │      │
             ▼      ▼      ▼      ▼     ▼      ▼
            SQL   Txn   Index     SQL   Txn   Index
             │      │      │       │     │      │
             └──────┴──────┘       └─────┴──────┘
                    │                   │
                    ▼                   ▼
                 Storage             Storage
                    │                   │
                    ▼                   ▼
                   Disk                Disk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运维层面则是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                   Database Operations
                           │
      ┌────────────────────┼────────────────────┐
      │                    │                    │
      ▼                    ▼                    ▼
    Install              Security             Backup
      │                    │                    │
      ▼                    ▼                    ▼
  systemd             User / Role         Logical Backup
      │               Privilege            Physical Backup
      ▼                    │                    │
   Config                  ▼                    ▼
      │                Network / TLS         Restore
      ▼                                         │
    Logs                                        ▼
      │                                        RPO/RTO
      ▼
 Troubleshooting
      │
      ├── Connection
      ├── SQL
      ├── Lock
      ├── Index
      ├── CPU
      ├── Memory
      └── I/O
                           │
                           ▼
                      High Availability
                           │
                   ┌───────┴───────┐
                   │               │
                Replication      Failover
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库运维的核心思路&lt;/h1&gt;
&lt;p&gt;学习 MySQL 和 PostgreSQL，不应该只记：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mysql 怎么安装
psql 怎么安装
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更重要的是建立下面这套思维：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据库有没有运行？
        ↓
监听在哪里？
        ↓
谁可以连接？
        ↓
谁拥有什么权限？
        ↓
数据如何备份？
        ↓
备份如何恢复？
        ↓
日志在哪里？
        ↓
SQL 为什么慢？
        ↓
索引是否合理？
        ↓
数据库是否受 CPU / Memory / I/O 限制？
        ↓
主库故障怎么办？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终可以浓缩成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;安装
 ↓
配置
 ↓
权限
 ↓
连接
 ↓
SQL
 ↓
事务
 ↓
索引
 ↓
日志
 ↓
备份
 ↓
恢复
 ↓
复制
 ↓
高可用
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这套知识已经覆盖了 Linux 运维岗位中最常见的数据库基础能力。&lt;/p&gt;
&lt;p&gt;下一篇再继续学习：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NoSQL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就可以自然进入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Redis
MongoDB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等非关系型数据库，而不会和 MySQL / PostgreSQL 的关系型数据库体系混在一起。&lt;/p&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.4/en/&quot;&gt;MySQL 8.4 Reference Manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.4/en/backup-and-recovery.html&quot;&gt;MySQL Backup and Recovery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.postgresql.org/docs/18/&quot;&gt;PostgreSQL 18 Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.postgresql.org/docs/18/backup.html&quot;&gt;PostgreSQL Backup and Restore&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.postgresql.org/docs/18/user-manag.html&quot;&gt;PostgreSQL Database Roles&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>数据库：数据库系统架构</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E6%95%B0%E6%8D%AE%E5%BA%93%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E6%95%B0%E6%8D%AE%E5%BA%93%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84/</guid><description>解释数据库、表、连接、事务、索引以及关系型与非关系型数据库的基本关系。</description><pubDate>Sun, 13 Sep 2026 21:28:23 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Web 应用很少是完全独立运行的。用户请求经过 Web 服务器和应用程序后，通常还需要读取或修改数据库中的数据。&lt;/p&gt;
&lt;p&gt;因此，理解数据库系统不能只停留在“会写 SQL”，还需要知道 &lt;strong&gt;DBMS、数据库、表、连接、事务、索引以及关系型与 NoSQL 数据库&lt;/strong&gt;之间的关系。&lt;/p&gt;
&lt;p&gt;本文从数据库系统的整体架构开始，介绍 DBMS、关系型数据库与 NoSQL、客户端与数据库连接、SQL、事务、ACID、并发控制、索引以及 Web 应用中的数据库访问流程，建立对数据库系统的整体认知。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;数据库系统是什么&lt;/h1&gt;
&lt;p&gt;数据库系统（Database System）可以理解为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;用于组织、存储、管理和访问数据的一整套系统。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一个完整的数据库系统通常不仅包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据库管理系统
客户端 / 应用程序
数据库
用户
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以简单表示为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户
 │
 ▼
Web Application
 │
 ▼
DBMS
 │
 ▼
Database
 │
 ▼
数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如一个 Web 网站可能使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;浏览器
   ↓
Nginx
   ↓
Java / Python 应用
   ↓
MySQL / PostgreSQL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据库位于整个 Web 服务体系的后端。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;DBMS&lt;/h1&gt;
&lt;h2&gt;什么是 DBMS&lt;/h2&gt;
&lt;p&gt;DBMS（Database Management System，数据库管理系统）是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;负责创建、管理、访问和维护数据库的软件系统。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MySQL
PostgreSQL
MariaDB
Oracle Database
Microsoft SQL Server
MongoDB
Redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都属于数据库系统中的具体产品，但它们的模型和能力并不完全相同。&lt;/p&gt;
&lt;p&gt;可以把 DBMS 理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
    │
    │ SQL / API
    ▼
   DBMS
    │
    ├── 连接管理
    ├── 查询解析
    ├── 查询执行
    ├── 事务管理
    ├── 并发控制
    ├── 权限控制
    ├── 缓存
    ├── 日志
    └── 存储管理
    │
    ▼
  Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;数据库是数据本身的组织与存储，而 DBMS 是管理这些数据的软件。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;DBMS 与 Database 的区别&lt;/h2&gt;
&lt;p&gt;这两个概念非常容易混淆。&lt;/p&gt;
&lt;p&gt;可以简单理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Database
↓
数据以及数据组织结构

DBMS
↓
管理 Database 的软件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MySQL
↓
DBMS

my_app
↓
MySQL 中的一个 Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以进一步理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MySQL Server
│
├── Database A
│
├── Database B
└── Database C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不同 DBMS 对：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Database
Schema
Table
Namespace
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等概念的组织方式可能有所不同，因此不能把一种数据库产品的层级结构机械套用到所有数据库上。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库系统的基本架构&lt;/h1&gt;
&lt;p&gt;一个典型 Web 系统可以表示为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  Client
                     │
                     ▼
                Nginx / Apache
                     │
                     ▼
               Web Application
                     │
              Database Connection
                     │
                     ▼
                   DBMS
                     │
                     ▼
                 Database
                     │
                     ▼
                    Data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Browser
   │
   │ HTTP
   ▼
Nginx
   │
   │ Proxy
   ▼
Java Application
   │
   │ JDBC
   ▼
MySQL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
↓
Web 层通信

JDBC
↓
Java 应用访问数据库的接口

MySQL
↓
数据库管理系统
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以数据库并不是直接面对浏览器的。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;数据模型&lt;/h1&gt;
&lt;p&gt;数据库首先需要解决：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;数据应该以什么方式组织？&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;不同数据库采用不同的数据模型。&lt;/p&gt;
&lt;p&gt;常见的有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;关系模型
键值模型
文档模型
列族模型
图模型
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 Web 开发中，最常见的两大类可以先理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;关系型数据库
        +
NoSQL 数据库
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;关系型数据库&lt;/h1&gt;
&lt;h2&gt;什么是关系型数据库&lt;/h2&gt;
&lt;p&gt;关系型数据库（Relational Database）以：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;关系（Relation）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;为核心组织数据。&lt;/p&gt;
&lt;p&gt;实际使用中通常表现为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Database
   │
   ├── Table
   │    ├── Row
   │    └── Column
   │
   └── Table
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如用户表：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;name&lt;/th&gt;
&lt;th&gt;age&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Table
 │
 ├── Column
 │   ├── id
 │   ├── name
 │   └── age
 │
 └── Row
     ├── 1
     ├── Alice
     └── 20
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Table、Row 与 Column&lt;/h2&gt;
&lt;p&gt;关系型数据库最基础的三个概念：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Table
Row
Column
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以简单理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Table
↓
一类数据

Row
↓
一条记录

Column
↓
某种属性
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;users
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是一张用户表。&lt;/p&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;id
name
email
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是列。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1
Alice
alice@example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是一行记录。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Primary Key&lt;/h1&gt;
&lt;p&gt;关系型数据库中的一张表通常需要一种能够唯一标识记录的字段：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Primary Key（主键）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE users (
    id BIGINT PRIMARY KEY,
    name VARCHAR(100)
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;id
↓
Primary Key
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;主键的核心作用是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;唯一标识表中的一条记录。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;id = 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只能对应一个用户。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Foreign Key&lt;/h1&gt;
&lt;p&gt;不同表之间通常存在关系。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;users
orders
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个用户可以拥有多个订单。&lt;/p&gt;
&lt;p&gt;可以设计成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;users
┌────┐
│ id │
└─┬──┘
  │
  │ 1
  │
  │ N
  ▼
orders
┌─────────┐
│ user_id │
└─────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;orders.user_id
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以作为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Foreign Key（外键）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;引用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;users.id
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从而表达：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户
 ↓
订单
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之间的关系。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;SQL&lt;/h1&gt;
&lt;p&gt;关系型数据库通常使用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;SQL（Structured Query Language）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;进行数据定义、查询和修改。&lt;/p&gt;
&lt;p&gt;常见操作：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT
INSERT
UPDATE
DELETE
CREATE
ALTER
DROP
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;SELECT&lt;/h2&gt;
&lt;p&gt;查询：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT * FROM users;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;查询 users 表中的记录
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以只查询部分列：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT id, name
FROM users;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;INSERT&lt;/h2&gt;
&lt;p&gt;插入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;INSERT INTO users (id, name)
VALUES (1, &apos;Alice&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;UPDATE&lt;/h2&gt;
&lt;p&gt;修改：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UPDATE users
SET name = &apos;Bob&apos;
WHERE id = 1;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;DELETE&lt;/h2&gt;
&lt;p&gt;删除：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DELETE FROM users
WHERE id = 1;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要特别注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;不带正确条件的 &lt;code&gt;UPDATE&lt;/code&gt; / &lt;code&gt;DELETE&lt;/code&gt; 可能影响大量记录。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DELETE FROM users;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就是删除表中全部记录。&lt;/p&gt;
&lt;p&gt;因此生产环境执行数据库修改操作时必须谨慎。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;NoSQL&lt;/h1&gt;
&lt;h2&gt;什么是 NoSQL&lt;/h2&gt;
&lt;p&gt;NoSQL 通常泛指：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;不以传统关系模型为核心的数据存储系统。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;NoSQL 并不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“完全不要 SQL”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而更接近：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Not Only SQL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现代 NoSQL 数据库包含很多不同的数据模型。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Key-Value
Document
Column Family
Graph
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;Key-Value&lt;/h1&gt;
&lt;p&gt;键值数据库：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Key
 ↓
Value
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;user:1001
    ↓
Alice
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型数据库：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;非常适合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;缓存
Session
计数器
分布式锁
排行榜
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等场景。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Document Database&lt;/h1&gt;
&lt;p&gt;文档数据库使用类似：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;id&quot;: 1,
  &quot;name&quot;: &quot;Alice&quot;,
  &quot;age&quot;: 20
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样的文档组织数据。&lt;/p&gt;
&lt;p&gt;典型数据库：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MongoDB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它适合某些：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;结构灵活
文档型数据
Schema 变化较快
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的场景。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Column Family&lt;/h1&gt;
&lt;p&gt;列族数据库常用于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;大规模分布式数据
高吞吐写入
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型系统包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cassandra
HBase
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其数据模型与传统关系型数据库不同。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Graph Database&lt;/h1&gt;
&lt;p&gt;图数据库重点描述：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Node
+
Edge
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Alice
 │
 │ 好友
 ▼
Bob
 │
 │ 好友
 ▼
Carol
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型场景：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;社交关系
知识图谱
推荐关系
网络拓扑
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;关系型与 NoSQL 的区别&lt;/h1&gt;
&lt;p&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;NoSQL&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;Schema&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;SQL&lt;/td&gt;
&lt;td&gt;各产品 API / 查询语言&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;事务&lt;/td&gt;
&lt;td&gt;通常支持成熟 ACID&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;取决于模型&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;tr&gt;
&lt;td&gt;典型产品&lt;/td&gt;
&lt;td&gt;MySQL / PostgreSQL&lt;/td&gt;
&lt;td&gt;Redis / MongoDB / Cassandra&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;不能把“关系型 = 单机、NoSQL = 分布式”简单画等号。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;现代关系型数据库同样可以运行在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主从架构
集群
分片
云数据库
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;环境中。&lt;/p&gt;
&lt;p&gt;而 NoSQL 数据库之间的设计差异也非常大。&lt;/p&gt;
&lt;p&gt;因此数据库选型应该根据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据模型
事务要求
查询方式
一致性要求
性能
扩展需求
运维能力
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;综合判断。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库连接&lt;/h1&gt;
&lt;h2&gt;应用为什么需要连接数据库&lt;/h2&gt;
&lt;p&gt;Web 应用要访问数据库，首先需要：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;建立数据库连接。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Java Application
       │
       │ JDBC
       ▼
    Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;连接通常需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host
Port
Database
Username
Password
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host = 127.0.0.1
Port = 3306
Database = app
User = app_user
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;Database Connection&lt;/h1&gt;
&lt;p&gt;一个数据库连接可以简单理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
     │
     │ Connect
     ▼
    DBMS
     │
     ▼
 Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;连接建立后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
     │
     ├── SQL
     │
     ├── Result
     │
     └── Transaction
     │
     ▼
    DBMS
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;为什么需要连接池&lt;/h1&gt;
&lt;p&gt;如果每个 HTTP 请求都：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;创建数据库连接
 ↓
执行 SQL
 ↓
关闭连接
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么大量请求会产生：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;连接建立开销
认证开销
Socket 开销
数据库资源消耗
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1000 Requests
   │
   ├── 建立连接
   ├── 建立连接
   ├── 建立连接
   └── ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此 Web 应用通常使用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Connection Pool（连接池）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;Connection Pool&lt;/h2&gt;
&lt;p&gt;连接池提前创建并维护一些数据库连接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                Connection Pool
               ┌────┬────┬────┐
Application ──►│ C1 │ C2 │ C3 │
               ├────┼────┼────┤
               │ C4 │ C5 │ C6 │
               └────┴────┴────┘
                      │
                      ▼
                     DBMS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;请求到来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP Request
     │
     ▼
Application
     │
     ▼
从连接池获取连接
     │
     ▼
执行 SQL
     │
     ▼
归还连接
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;每次重新建立连接
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;连接池中的重要问题&lt;/h2&gt;
&lt;p&gt;连接池并不是越大越好。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Connection Pool = 1000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不意味着：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;性能一定更好
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为数据库本身也存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
内存
锁
连接数
磁盘 I/O
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等资源限制。&lt;/p&gt;
&lt;p&gt;如果连接池过大：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
   │
   ├── 100 connections
   ├── 100 connections
   └── ...
   ▼
Database
   │
   ▼
资源耗尽
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;反而可能导致数据库压力增加。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;连接池大小需要结合应用并发量、SQL 耗时以及数据库能力进行配置。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;事务&lt;/h1&gt;
&lt;h2&gt;什么是 Transaction&lt;/h2&gt;
&lt;p&gt;事务（Transaction）可以理解为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;一组需要作为一个逻辑整体执行的数据库操作。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如银行转账：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A -100
B +100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不能只执行一半。&lt;/p&gt;
&lt;p&gt;应该：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;开始事务
   │
   ▼
A -100
   │
   ▼
B +100
   │
   ▼
COMMIT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果中间失败：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ROLLBACK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;恢复之前的状态。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;BEGIN、COMMIT 与 ROLLBACK&lt;/h1&gt;
&lt;p&gt;事务可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BEGIN
  │
  ▼
SQL 1
  │
  ▼
SQL 2
  │
  ▼
SQL 3
  │
  ├── 成功 → COMMIT
  │
  └── 失败 → ROLLBACK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;START TRANSACTION;

UPDATE accounts
SET balance = balance - 100
WHERE id = 1;

UPDATE accounts
SET balance = balance + 100
WHERE id = 2;

COMMIT;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果中间发现错误，可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ROLLBACK;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;ACID&lt;/h1&gt;
&lt;p&gt;数据库事务经常使用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ACID&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;描述事务的重要特性。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A → Atomicity
C → Consistency
I → Isolation
D → Durability
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Atomicity&lt;/h2&gt;
&lt;p&gt;原子性：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;一个事务中的操作要么全部成功，要么整体回滚。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A -100
B +100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不能只完成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A -100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;B +100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;失败后仍提交。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Consistency&lt;/h2&gt;
&lt;p&gt;一致性：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;事务执行前后，数据库应该满足定义好的完整性约束和业务规则。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;账户余额
主键唯一
外键约束
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等。&lt;/p&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ACID 中的 Consistency 不只是“所有查询马上看到一样的数据”，而是事务需要把数据库从一个合法状态带到另一个合法状态。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;Isolation&lt;/h2&gt;
&lt;p&gt;隔离性：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;并发执行的事务之间应该按照数据库定义的隔离规则互相影响。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Transaction A
      │
      ├── 修改数据
      │
Transaction B
      │
      └── 同时访问数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据库需要控制：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;并发读写
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;带来的问题。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Durability&lt;/h2&gt;
&lt;p&gt;持久性：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;事务提交成功后，其结果应该具有持久保存的保证。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;COMMIT
  ↓
数据库系统发生重启
  ↓
已提交的数据仍然应该被保留
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;具体保障机制涉及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WAL
Redo Log
Flush
Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等底层机制。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;并发事务&lt;/h1&gt;
&lt;p&gt;现实中的数据库很少只有一个事务。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User A
   │
   ▼
Transaction A

User B
   │
   ▼
Transaction B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两个事务可能同时操作相同数据。&lt;/p&gt;
&lt;p&gt;因此数据库需要：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Concurrency Control（并发控制）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;常见并发问题&lt;/h1&gt;
&lt;h3&gt;Dirty Read&lt;/h3&gt;
&lt;p&gt;事务 A 修改了数据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A
↓
修改
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;事务 B 读取到这个尚未提交的数据。&lt;/p&gt;
&lt;p&gt;如果 A 最后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ROLLBACK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么 B 读到的数据就不存在于最终状态中。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Non-Repeatable Read&lt;/h3&gt;
&lt;p&gt;事务 A 两次读取同一条记录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;第一次
↓
100

第二次
↓
200
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;中间被其他事务修改并提交。&lt;/p&gt;
&lt;p&gt;于是同一个事务中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;同一查询
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;前后得到不同结果。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Phantom Read&lt;/h3&gt;
&lt;p&gt;第一次查询：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;得到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10 行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后另一个事务插入满足条件的新记录。&lt;/p&gt;
&lt;p&gt;再次执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;得到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;11 行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;新增的记录就像：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“突然出现的幻影”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因此称为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Phantom Read&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;事务隔离级别&lt;/h1&gt;
&lt;p&gt;SQL 标准定义了多个事务隔离级别，常见名称为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以粗略理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;隔离性增强
      ↑
      │
READ UNCOMMITTED
      │
READ COMMITTED
      │
REPEATABLE READ
      │
SERIALIZABLE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一般来说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;隔离程度越高，并发事务之间的可见性限制越严格，但并发性能和锁 / 等待代价可能也越高。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;不同数据库的具体实现并不完全一样。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MySQL
PostgreSQL
Oracle
SQL Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对隔离级别的实现细节存在差异，因此实际使用时应该参考具体 DBMS 的文档。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;索引&lt;/h1&gt;
&lt;h2&gt;什么是 Index&lt;/h2&gt;
&lt;p&gt;数据库中的索引可以理解成：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;为了加快数据查找而建立的额外数据结构。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果一张表有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10000000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;条记录。&lt;/p&gt;
&lt;p&gt;查询：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT *
FROM users
WHERE email = &apos;alice@example.com&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果没有合适索引，数据库可能需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;逐行检查
 ↓
Row 1
Row 2
Row 3
...
Row 10000000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种方式通常称为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Full Table Scan（全表扫描）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;有索引时&lt;/h1&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;email
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;有索引。&lt;/p&gt;
&lt;p&gt;数据库可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;查询条件
   ↓
Index
   ↓
定位记录
   ↓
读取数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Table
│
├── id
├── name
└── email

Index(email)
       │
       ▼
   目标记录
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;B+Tree 索引&lt;/h1&gt;
&lt;p&gt;关系型数据库中非常常见的一类索引结构是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;B-Tree / B+Tree 家族&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它适合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;等值查询
范围查询
排序
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT *
FROM users
WHERE id = 100;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT *
FROM users
WHERE age BETWEEN 20 AND 30;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;B+Tree 可以通过树结构减少需要访问的数据范围。&lt;/p&gt;
&lt;p&gt;可以简化理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;             Root
           /      \
         Node     Node
        /  \      /  \
      ...  ...  ...  ...
             │
             ▼
          Target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际数据库实现远比这个模型复杂，但理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;索引
↓
缩小搜索范围
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就足够建立第一层认识。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Hash Index&lt;/h1&gt;
&lt;p&gt;另一类常见思路是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Hash Index&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Hash(Key)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;快速定位。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;email
 ↓
Hash
 ↓
Bucket
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它适合某些：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;等值查询
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但不适合传统意义上的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;范围查询
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WHERE id = 100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;和：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WHERE id BETWEEN 100 AND 200
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对索引结构的需求并不完全一样。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;为什么不是索引越多越好&lt;/h1&gt;
&lt;p&gt;索引能够加快查询，但也有成本。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;INSERT
UPDATE
DELETE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发生时，相关索引也需要维护。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;索引增加
↓
查询可能更快
↓
写入成本增加
↓
占用更多存储
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;索引设计本质上是在查询性能与写入 / 存储成本之间进行权衡。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;组合索引&lt;/h1&gt;
&lt;p&gt;数据库还经常使用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Composite Index（联合索引）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE INDEX idx_user
ON users (name, age);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示索引包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name
age
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两个字段。&lt;/p&gt;
&lt;p&gt;联合索引涉及重要的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;最左前缀原则&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如索引：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(name, age)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通常更适合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WHERE name = &apos;Alice&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WHERE name = &apos;Alice&apos;
  AND age = 20;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而仅仅：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WHERE age = 20;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通常不能充分利用这个联合索引的前导部分。&lt;/p&gt;
&lt;p&gt;具体行为仍取决于 DBMS 的优化器和索引实现。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;索引与执行计划&lt;/h1&gt;
&lt;p&gt;数据库并不会因为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“存在索引”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就一定使用索引。&lt;/p&gt;
&lt;p&gt;数据库通常会通过：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Query Optimizer（查询优化器）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;分析查询。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL
 ↓
Parser
 ↓
Optimizer
 ↓
Execution Plan
 ↓
Executor
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能最终选择：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Index Scan
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可能选择：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Seq Scan
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者其他执行方式。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;判断索引是否真正有效，需要观察执行计划，而不是只看数据库里有没有建立索引。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如 PostgreSQL：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EXPLAIN
SELECT *
FROM users
WHERE email = &apos;alice@example.com&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MySQL 则可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EXPLAIN
SELECT *
FROM users
WHERE email = &apos;alice@example.com&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库查询执行&lt;/h1&gt;
&lt;p&gt;一条 SQL 并不是直接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL
 ↓
Disk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是经过多个步骤。&lt;/p&gt;
&lt;p&gt;可以简化为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL
 │
 ▼
Parser
 │
 ▼
Query Analysis
 │
 ▼
Optimizer
 │
 ▼
Execution Plan
 │
 ▼
Executor
 │
 ▼
Storage Engine / Data
 │
 ▼
Result
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT *
FROM users
WHERE id = 100;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据库可能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;解析 SQL
 ↓
识别 users 表
 ↓
识别 id 条件
 ↓
检查可用索引
 ↓
生成执行计划
 ↓
读取索引 / 数据
 ↓
返回结果
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;Buffer Cache&lt;/h1&gt;
&lt;p&gt;数据库并不会每次都直接访问磁盘。&lt;/p&gt;
&lt;p&gt;通常会在内存中维护大量缓存：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
    │
    ▼
   DBMS
    │
    ▼
Buffer / Page Cache
    │
    ├── Hit → 直接使用
    │
    └── Miss
           │
           ▼
         Disk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此数据库性能通常不仅取决于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还取决于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Memory
Disk
IOPS
Latency
Cache Hit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等因素。&lt;/p&gt;
&lt;p&gt;这也是数据库性能分析比单纯查看 SQL 更复杂的原因之一。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;数据持久化与日志&lt;/h1&gt;
&lt;p&gt;数据库需要解决一个非常重要的问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;系统突然崩溃时，已经提交的数据怎么办？&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因此现代数据库通常会使用某种日志机制。&lt;/p&gt;
&lt;p&gt;例如 PostgreSQL 中的重要机制：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WAL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Write-Ahead Logging&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;核心思想可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;先记录恢复所需的日志
        ↓
再认为相关数据修改可以安全持久化
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;系统崩溃后，可以根据日志进行恢复。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Transaction
   ↓
Log
   ↓
Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是数据库持久化机制中的重要思想。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库备份&lt;/h1&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;事务持久性不等于备份。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;即使数据库具有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ACID
WAL
Crash Recovery
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也不能解决：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;误删
逻辑损坏
勒索
错误 UPDATE
错误 DROP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等问题。&lt;/p&gt;
&lt;p&gt;因此生产环境仍然需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据库备份
+
恢复测试
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完整的数据库运维还需要进一步考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;全量备份
增量备份
日志备份
恢复
RPO
RTO
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;Web 应用访问数据库&lt;/h1&gt;
&lt;p&gt;将前面的概念串起来，一个典型 Web 请求可能是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Browser
   │
   │ HTTP
   ▼
Nginx
   │
   ▼
Web Application
   │
   │ Connection Pool
   ▼
DBMS
   │
   │ SQL
   ▼
Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如用户访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET /users/100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用可能执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT *
FROM users
WHERE id = 100;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据库处理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL
 ↓
Parser
 ↓
Optimizer
 ↓
Index
 ↓
Data
 ↓
Result
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Database
   │
   ▼
Web Application
   │
   ▼
HTTP Response
   │
   ▼
Browser
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库连接与事务&lt;/h1&gt;
&lt;p&gt;实际 Web 应用中，数据库访问通常还会包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP Request
     │
     ▼
Application
     │
     ▼
Get Connection
     │
     ▼
Begin Transaction
     │
     ├── SQL 1
     ├── SQL 2
     └── SQL 3
     │
     ▼
Commit / Rollback
     │
     ▼
Return Connection
     │
     ▼
HTTP Response
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
↓
Application
↓
Connection Pool
↓
Transaction
↓
SQL
↓
Index
↓
Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际上是一整条完整链路。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库常见性能问题&lt;/h1&gt;
&lt;p&gt;数据库出现性能问题时，通常不能只看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CPU
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还应该考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;慢 SQL
索引缺失
索引失效
锁等待
事务过长
连接池耗尽
磁盘 I/O
缓存命中率
数据量增长
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;请求变慢
   │
   ▼
Application
   │
   ▼
等待数据库
   │
   ▼
慢 SQL
   │
   ▼
全表扫描
   │
   ▼
Disk I/O 增加
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种情况下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Web Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;本身可能完全正常。&lt;/p&gt;
&lt;p&gt;真正的瓶颈在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Database
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库故障排查思路&lt;/h1&gt;
&lt;p&gt;可以形成一个基本流程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Web 请求变慢
      │
      ▼
Application
      │
      ▼
数据库连接是否正常？
      │
      ▼
连接池是否耗尽？
      │
      ▼
SQL 是否执行？
      │
      ▼
SQL 是否很慢？
      │
      ▼
EXPLAIN / Execution Plan
      │
      ▼
是否使用合理索引？
      │
      ▼
是否存在锁等待？
      │
      ▼
数据库 CPU / Memory / I/O
      │
      ▼
进一步定位
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也是为什么数据库运维不能只停留在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“会写 SELECT”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而需要同时理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;连接
事务
锁
索引
执行计划
资源
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;关系型数据库与 Web 服务&lt;/h1&gt;
&lt;p&gt;在传统 Web 系统中，一个非常典型的架构是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    Browser
                       │
                       ▼
                    Nginx
                       │
                       ▼
                Application
                       │
                ┌──────┴──────┐
                │             │
                ▼             ▼
          Connection Pool    Cache
                │
                ▼
              DBMS
                │
        ┌───────┴───────┐
        │               │
        ▼               ▼
      Table           Index
        │
        ▼
       Data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Nginx
↓
处理 HTTP / 代理

Application
↓
处理业务逻辑

Database
↓
持久化结构化数据

Cache
↓
减少部分数据库访问
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是常见的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Web + Application + Database&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;基本架构。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;NoSQL 在 Web 系统中的位置&lt;/h1&gt;
&lt;p&gt;NoSQL 数据库也经常出现在 Web 系统中。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
   │
   ├── MySQL
   │      ↓
   │   业务主数据
   │
   └── Redis
          ↓
        Cache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型组合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MySQL / PostgreSQL
↓
核心业务数据

Redis
↓
缓存 / Session / Counter

MongoDB
↓
文档型数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;关系型数据库和 NoSQL 并不是一定互相替代。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;实际系统中经常是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Polyglot Persistence
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即根据不同数据和访问场景选择不同的数据存储系统。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;数据库系统整体模型&lt;/h1&gt;
&lt;p&gt;到这里，可以把数据库系统完整串起来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                         Database System
                                │
             ┌──────────────────┼──────────────────┐
             │                  │                  │
             ▼                  ▼                  ▼
           DBMS              Data Model         Client
             │                  │                  │
       ┌─────┴─────┐       ┌────┼────┐             │
       │           │       │         │             │
  Relational     NoSQL   Table     Document      App
       │           │       │         │             │
       │       ┌───┼───┐   │         │             │
       │       │   │   │   │         │             │
       ▼       ▼   ▼   ▼   ▼         ▼             ▼
      SQL    KV  Doc Graph Row      Data         Connection
       │
       ▼
   Transaction
       │
       ├── Atomicity
       ├── Consistency
       ├── Isolation
       └── Durability
       │
       ▼
      Index
       │
       ▼
 Query Optimization
       │
       ▼
    Data Storage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以进一步浓缩成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
    ↓
Connection
    ↓
DBMS
    ↓
Query
    ↓
Transaction
    ↓
Optimizer
    ↓
Index
    ↓
Storage
    ↓
Data
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;从 Web 运维角度理解数据库&lt;/h1&gt;
&lt;p&gt;对于 Web 运维来说，真正需要建立的并不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“数据库就是一个存数据的地方”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;请求
 ↓
应用
 ↓
数据库连接
 ↓
事务
 ↓
SQL
 ↓
查询优化
 ↓
索引
 ↓
磁盘 / 内存
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;任何一环出现问题，都可能最终表现为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;页面变慢
API 超时
请求失败
数据库连接耗尽
CPU 飙高
I/O 飙高
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;API 响应变慢
       │
       ▼
应用等待 DB
       │
       ▼
数据库查询变慢
       │
       ▼
执行计划异常
       │
       ▼
没有使用合理索引
       │
       ▼
大量 I/O
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此数据库系统实际上是 Web 服务架构中非常核心的一层。&lt;/p&gt;
&lt;p&gt;理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DBMS
关系型 / NoSQL
Connection
Transaction
Index
Query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后，再学习：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MySQL
PostgreSQL
Redis
MongoDB
数据库备份
主从复制
高可用
数据库监控
慢查询
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就会有比较清晰的基础。&lt;/p&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.postgresql.org/docs/&quot;&gt;PostgreSQL Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.mysql.com/doc/&quot;&gt;MySQL Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mongodb.com/docs/&quot;&gt;MongoDB Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/docs/&quot;&gt;Redis Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.iso.org/standard/76583.html&quot;&gt;SQL Standard — ISO/IEC 9075&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Web 服务：Nginx</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/web-%E6%9C%8D%E5%8A%A1nginx/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/web-%E6%9C%8D%E5%8A%A1nginx/</guid><description>Nginx 可以提供静态文件、反向代理、TLS 终止和负载均衡。</description><pubDate>Sun, 13 Sep 2026 11:09:45 GMT</pubDate><content:encoded>&lt;p&gt;Nginx 可以提供静态文件、反向代理、TLS 终止和负载均衡。配置时先确定请求如何匹配站点与路径，再增加缓存、限流等策略，最后通过真实请求和日志验证。&lt;/p&gt;
&lt;h1&gt;安装与配置结构&lt;/h1&gt;
&lt;p&gt;使用发行版认可的软件源安装 Nginx，Debian/Ubuntu 通常使用 &lt;code&gt;apt install nginx&lt;/code&gt;，RHEL 系列通常使用 &lt;code&gt;dnf install nginx&lt;/code&gt;。安装和服务管理需要管理员权限，包安装后是否自动启动取决于发行版。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nginx -v
nginx -V
sudo nginx -T
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-V&lt;/code&gt; 显示编译选项和模块，&lt;code&gt;-T&lt;/code&gt; 检查并输出加载的配置。输出可能包含内部地址或凭据，分享前应审阅。不要假设所有安装都有 sites-enabled，先检查主配置的 include。&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;main&lt;/td&gt;
&lt;td&gt;worker_processes、events、http&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;http&lt;/td&gt;
&lt;td&gt;MIME、日志格式、upstream、server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;server&lt;/td&gt;
&lt;td&gt;监听地址、域名、TLS、location&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;location&lt;/td&gt;
&lt;td&gt;URI 对应的静态文件或代理处理&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;进程通常由 master 管理配置和 worker，worker 处理连接。应用配置一般放入已有 http 上下文加载的文件，不能重复嵌套 http。&lt;/p&gt;
&lt;h1&gt;静态文件与请求匹配&lt;/h1&gt;
&lt;p&gt;以下独立示例要求 &lt;code&gt;/srv/www/demo/index.html&lt;/code&gt; 已存在，worker 用户可读取文件并穿过父目录，TCP 80 可用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {
    listen 80;
    server_name demo.example.com;
    root /srv/www/demo;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;请求 &lt;code&gt;/images/logo.png&lt;/code&gt; 对应 &lt;code&gt;/srv/www/demo/images/logo.png&lt;/code&gt;。&lt;code&gt;root&lt;/code&gt; 在目录后拼接 URI；&lt;code&gt;alias&lt;/code&gt; 替换匹配的 location 路径部分，不能直接互换。&lt;/p&gt;
&lt;p&gt;Nginx 先按监听地址与域名选择 server，再按 URI 选择 location。精确匹配 &lt;code&gt;=&lt;/code&gt;、前缀匹配、正则匹配有不同优先规则；复杂规则应针对真实 URI 测试，不能只按配置书写顺序理解。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo nginx -t
sudo systemctl reload nginx
curl --resolve demo.example.com:80:127.0.0.1 http://demo.example.com/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只有检查成功才执行 reload。核对返回内容和 access/error 日志，再从外部客户端验证。语法正确不保证路径、权限或后端可用。&lt;/p&gt;
&lt;h1&gt;反向代理与负载均衡&lt;/h1&gt;
&lt;p&gt;下面是独立的代理站点示例，两个后端应已运行于本机 8081、8082，并能处理 &lt;code&gt;/api/&lt;/code&gt; 路径：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;upstream demo_backend {
    server 127.0.0.1:8081;
    server 127.0.0.1:8082;
    keepalive 16;
}

server {
    listen 80;
    server_name api.example.com;

    location /api/ {
        proxy_pass http://demo_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection &quot;&quot;;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $remote_addr;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;本例将 Nginx 作为直接接收客户端的可信入口，覆盖客户端提交的 X-Forwarded-For。若前面还有负载均衡器，应限定可信代理地址并配置真实 IP 处理，后端也只能信任约定代理。直接相信客户端自带的转发头会导致来源伪造。&lt;/p&gt;
&lt;h2&gt;proxy_pass 的路径&lt;/h2&gt;
&lt;p&gt;在普通前缀 &lt;code&gt;location /api/&lt;/code&gt; 中：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;配置&lt;/th&gt;
&lt;th&gt;请求 /api/users 的典型上游路径&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;proxy_pass http://demo_backend;&lt;/td&gt;
&lt;td&gt;/api/users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;proxy_pass http://demo_backend/;&lt;/td&gt;
&lt;td&gt;/users&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;带 URI 的 proxy_pass 会替换匹配的前缀。正则 location、变量和 rewrite 场景有额外规则，见&lt;a href=&quot;https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass&quot;&gt;代理模块手册&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;后端选择与故障&lt;/h2&gt;
&lt;p&gt;默认使用加权轮询；&lt;code&gt;least_conn&lt;/code&gt; 按活动连接及权重选择，适用于连接处理时长不一的情况；&lt;code&gt;ip_hash&lt;/code&gt; 提供一定来源粘滞性，但 NAT 聚合和地址变化会影响分布，不能代替可靠的会话存储。&lt;/p&gt;
&lt;p&gt;开源 Nginx 的常见后端故障判断来自实际请求的被动检测，&lt;code&gt;max_fails&lt;/code&gt;、&lt;code&gt;fail_timeout&lt;/code&gt; 与重试条件共同影响行为。不要将所有失败请求无条件转发到下一台：非幂等请求可能已经执行。主动健康检查能力需要核对具体版本、发行版和模块。&lt;/p&gt;
&lt;h1&gt;HTTPS&lt;/h1&gt;
&lt;p&gt;证书需覆盖实际域名，包含所需中间证书链，并与私钥匹配。私钥只授予必要账户读取权限。下面的 server 是独立 HTTPS 示例，使用前替换证书路径并确认文件存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {
    listen 443 ssl;
    server_name demo.example.com;
    ssl_certificate /etc/nginx/certs/demo-fullchain.pem;
    ssl_certificate_key /etc/nginx/certs/demo-key.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    root /srv/www/demo;
    location / {
        try_files $uri $uri/ =404;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;按相同的检查、重载流程应用，再使用 &lt;code&gt;curl --resolve demo.example.com:443:127.0.0.1 https://demo.example.com/&lt;/code&gt; 验证。不要通过 &lt;code&gt;-k&lt;/code&gt; 跳过证书问题。证书续期流程还要包含配置检查、重载和到期监控。&lt;/p&gt;
&lt;p&gt;TLS 在入口终止不意味着入口到后端也已加密；跨不可信网络的上游连接需要单独配置 TLS 和证书验证。&lt;/p&gt;
&lt;h1&gt;缓存与流量控制&lt;/h1&gt;
&lt;h2&gt;浏览器缓存与代理缓存&lt;/h2&gt;
&lt;p&gt;浏览器缓存由 HTTP 响应头控制；代理缓存由 Nginx 保存上游响应。两者可独立启用。&lt;/p&gt;
&lt;p&gt;带内容指纹的静态资源适合较长有效期；会更新的 HTML 需要适当重新验证。不要把所有扩展名相同的资源都设成长缓存，而忽略发布与回退方式。&lt;/p&gt;
&lt;p&gt;代理缓存需要同时设计缓存键、有效期、失效方式和用户隔离。默认不缓存登录、购物车和个性化接口，不为提高命中率随意忽略 Cache-Control 或 Set-Cookie。启用后应记录缓存状态，验证首次请求、重复请求和数据更新后的行为。&lt;/p&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;th&gt;注意事项&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;limit_req&lt;/td&gt;
&lt;td&gt;按键统计请求速率&lt;/td&gt;
&lt;td&gt;burst 与 nodelay 改变突发处理方式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;limit_conn&lt;/td&gt;
&lt;td&gt;按键统计被模块计入的并发连接/请求&lt;/td&gt;
&lt;td&gt;HTTP/2、HTTP/3 并发请求有特定计数语义&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;limit_rate&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;按 IP 限流前先确认真实 IP 来源；共享出口下多个用户可能被合并。阈值应来自容量测量，并明确拒绝状态、重试提示和监控，不直接复制固定数字。&lt;/p&gt;
&lt;h1&gt;日志与性能排查&lt;/h1&gt;
&lt;p&gt;可在 http 上下文定义以下日志格式，再在目标 server 中启用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;log_format timing &apos;$remote_addr &quot;$request&quot; $status &apos;
                  &apos;rt=$request_time upstream=$upstream_addr &apos;
                  &apos;uct=$upstream_connect_time urt=$upstream_response_time&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;access_log /var/log/nginx/demo-access.log timing;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&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;403/404&lt;/td&gt;
&lt;td&gt;实际 server/location、路径、目录索引、权限和安全标签&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;502&lt;/td&gt;
&lt;td&gt;上游监听、连接失败、协议不匹配、进程退出；结合 error 日志&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;504&lt;/td&gt;
&lt;td&gt;连接或读取阶段超时、后端耗时；先定位再调整超时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;499&lt;/td&gt;
&lt;td&gt;客户端提前断开，是线索，不直接等于客户端故障&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;延迟高&lt;/td&gt;
&lt;td&gt;总耗时与上游耗时、CPU、连接数、磁盘和网络&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;无法建立新连接&lt;/td&gt;
&lt;td&gt;文件描述符、worker_connections、系统限制与上游连接占用&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;worker_connections&lt;/code&gt; 是每个 worker 的连接限制之一，并非 RPS。代理还需要上游连接，不能直接将 worker 数乘连接数当成可服务用户数。调整 keepalive、压缩、缓存和缓冲时，一次改变一个有依据的因素，再比较延迟、吞吐量与错误率。&lt;/p&gt;
&lt;h1&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nginx.org/en/docs/beginners_guide.html&quot;&gt;Nginx 入门与管理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nginx.org/en/docs/http/request_processing.html&quot;&gt;请求处理与匹配&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nginx.org/en/docs/http/ngx_http_proxy_module.html&quot;&gt;HTTP 代理模块&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nginx.org/en/docs/http/configuring_https_servers.html&quot;&gt;HTTPS 配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nginx.org/en/docs/http/load_balancing.html&quot;&gt;HTTP 负载均衡&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Web 服务：Web 服务器与 Http 请求处理</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/web-%E6%9C%8D%E5%8A%A1web-%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8E-http-%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/web-%E6%9C%8D%E5%8A%A1web-%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8E-http-%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86/</guid><description>Web 服务通过 HTTP 请求与响应交付网页、文件和接口数据。</description><pubDate>Sun, 13 Sep 2026 11:06:03 GMT</pubDate><content:encoded>&lt;p&gt;Web 服务通过 HTTP 请求与响应交付网页、文件和接口数据。理解请求在哪一层处理，有助于区分网络失败、代理错误与应用异常。&lt;/p&gt;
&lt;h1&gt;请求经过哪些组件&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;客户端 → DNS 解析 → 网络连接与 TLS → Web 入口
                                      ├─ 静态文件
                                      └─ 应用服务 → 数据库等依赖
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是常见 HTTPS 部署路径。DNS 和连接可以复用；HTTP/1.1、HTTP/2 通常运行在 TCP 上，HTTP/3 使用基于 UDP 的 QUIC。不同版本共享方法、状态码等 HTTP 语义，但报文编码不同。&lt;/p&gt;
&lt;p&gt;Web 服务器、反向代理和应用运行环境是角色，不是互斥产品类别。Apache HTTP Server、Nginx 能提供静态资源和反向代理；Tomcat 能直接处理 HTTP，并提供 Java Servlet 应用运行环境。&lt;/p&gt;
&lt;h1&gt;HTTP 请求与响应&lt;/h1&gt;
&lt;p&gt;以下是 HTTP/1.1 的文本形式示意，不表示 HTTP/2 或 HTTP/3 在线路上的编码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET /health HTTP/1.1
Host: app.example.com
Accept: application/json

&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 15

{&quot;status&quot;:&quot;ok&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;示例响应体为 15 个 ASCII 字节，不计展示时的末尾换行。真实响应的长度和消息边界由服务器按协议生成，不应手写一个与内容不符的 Content-Length。&lt;/p&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;th&gt;重试时的考虑&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GET、HEAD&lt;/td&gt;
&lt;td&gt;获取资源；HEAD 不返回响应体&lt;/td&gt;
&lt;td&gt;按语义应安全且幂等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POST&lt;/td&gt;
&lt;td&gt;提交数据或发起处理&lt;/td&gt;
&lt;td&gt;默认不能假定幂等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PUT&lt;/td&gt;
&lt;td&gt;创建或整体替换目标资源&lt;/td&gt;
&lt;td&gt;按语义幂等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PATCH&lt;/td&gt;
&lt;td&gt;局部修改&lt;/td&gt;
&lt;td&gt;是否幂等取决于补丁和应用设计&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DELETE&lt;/td&gt;
&lt;td&gt;删除目标资源关联&lt;/td&gt;
&lt;td&gt;按语义幂等，但多次响应可不同&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OPTIONS&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;/p&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;2xx；200、201、204&lt;/td&gt;
&lt;td&gt;成功、已创建、成功但无响应内容；仍需核对业务结果&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;301、302&lt;/td&gt;
&lt;td&gt;永久或临时重定向；历史客户端可能把 POST 改为 GET&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;307、308&lt;/td&gt;
&lt;td&gt;临时或永久重定向，保留方法&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;304&lt;/td&gt;
&lt;td&gt;条件请求满足缓存复用条件，不是普通跳转&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;400、404&lt;/td&gt;
&lt;td&gt;请求不符合要求，或目标资源未找到/未公开&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;401、403&lt;/td&gt;
&lt;td&gt;认证挑战或拒绝访问；不能简单等同于未登录/已登录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;429&lt;/td&gt;
&lt;td&gt;请求速率受限，结合 Retry-After 和限流策略&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;服务端内部错误，查应用日志&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;502、504&lt;/td&gt;
&lt;td&gt;代理遇到上游异常或等待超时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;503&lt;/td&gt;
&lt;td&gt;暂时无法提供服务，可能是维护、过载或无可用后端&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;状态码由返回响应的组件产生。排查时先确认来自入口代理、应用还是中间网关，再选择对应日志。&lt;/p&gt;
&lt;h1&gt;请求头、缓存与状态&lt;/h1&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;Host / :authority&lt;/td&gt;
&lt;td&gt;标识目标主机，用于虚拟主机等路由&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content-Type&lt;/td&gt;
&lt;td&gt;描述消息内容的媒体类型&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accept&lt;/td&gt;
&lt;td&gt;表达客户端接受的响应类型&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authorization&lt;/td&gt;
&lt;td&gt;携带认证凭据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Location&lt;/td&gt;
&lt;td&gt;指示重定向目标或新建资源位置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache-Control&lt;/td&gt;
&lt;td&gt;控制存储、有效期与重新验证&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ETag / Last-Modified&lt;/td&gt;
&lt;td&gt;为条件请求提供验证依据&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;no-cache&lt;/code&gt; 允许存储，但复用前通常必须验证；&lt;code&gt;no-store&lt;/code&gt; 要求不要存储。&lt;code&gt;private&lt;/code&gt; 限制共享缓存使用，并不意味着传输已经加密。个性化响应不能只因返回 200 就放入共享缓存。&lt;/p&gt;
&lt;h2&gt;Cookie 与会话&lt;/h2&gt;
&lt;p&gt;Cookie 是客户端保存并按域、路径等条件发送的数据。服务端会话通常把状态保存在服务端，通过 Cookie 中的随机会话标识关联用户；两者不是同一个对象。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Set-Cookie: session_id=opaque-value; Path=/; Secure; HttpOnly; SameSite=Lax
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Secure 限制安全连接中的发送，HttpOnly 限制脚本直接读取，SameSite 影响跨站发送。它们各有作用，不能替代认证、授权或完整的 CSRF 防护。登录后应轮换会话标识，退出时使服务端会话失效。&lt;/p&gt;
&lt;p&gt;多实例部署要明确会话存储和过期策略。若会话只存在单台实例内存中，流量切换后可能丢失；共享会话存储或合适的无状态认证需要结合应用实现选择。&lt;/p&gt;
&lt;h1&gt;Apache HTTP Server&lt;/h1&gt;
&lt;p&gt;Apache httpd 通过虚拟主机区分站点，通过模块提供 TLS、代理和访问控制。包名与服务名在不同发行版中可能是 &lt;code&gt;apache2&lt;/code&gt; 或 &lt;code&gt;httpd&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;下面是 Apache 2.4 静态站点配置片段，前提是目标目录已有 index.html、服务用户具有读取权限，并且主配置已经监听 80：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
    ServerName app.example.com
    DocumentRoot /srv/www/app
    &amp;lt;Directory /srv/www/app&amp;gt;
        Require all granted
        Options -Indexes
        AllowOverride None
    &amp;lt;/Directory&amp;gt;
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;配置所在目录、启用站点的方式随发行版变化。先用本机提供的 &lt;code&gt;apachectl configtest&lt;/code&gt; 或 &lt;code&gt;apache2ctl configtest&lt;/code&gt; 检查，再重载对应服务。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl --resolve app.example.com:80:127.0.0.1 http://app.example.com/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确认返回预期文件，同时检查访问日志。此测试只验证本机路径；还需从实际客户端验证 DNS、网络和防火墙。&lt;/p&gt;
&lt;h1&gt;Tomcat 与 Java 应用&lt;/h1&gt;
&lt;p&gt;Tomcat 管理 Servlet 等 Web 组件的加载和请求处理，并不是完整 Jakarta EE 平台。选择版本时，要共同检查 Java 版本、Servlet 规范和应用依赖；Tomcat 9 的 javax 命名空间与 Tomcat 10 及以后采用的 jakarta 命名空间存在迁移差异。&lt;/p&gt;
&lt;p&gt;传统部署可将 WAR 交给指定实例的部署目录，但自动部署方式、上下文路径和生产发布流程由配置决定。&lt;code&gt;myapp.war&lt;/code&gt; 常对应 &lt;code&gt;/myapp&lt;/code&gt;，不能只访问根路径就断言应用未启动。&lt;/p&gt;
&lt;p&gt;部署后检查启动日志、Connector 的监听地址、应用上下文和实际健康端点。位于反向代理后的 Tomcat 一般只开放必要的内部访问范围；管理应用不应默认暴露到公网。&lt;/p&gt;
&lt;h1&gt;用一次请求定位故障&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;curl -v --connect-timeout 5 --max-time 15 https://app.example.com/health
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;替换成实际地址，按失败阶段判断：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;解析失败：检查系统解析器与域名记录。&lt;/li&gt;
&lt;li&gt;连接失败：确认服务监听、访问控制、路由及地址族。&lt;/li&gt;
&lt;li&gt;TLS 失败：核对证书域名、有效期、信任链、SNI 和系统时间。&lt;/li&gt;
&lt;li&gt;HTTP 错误：关联入口和应用日志，核对 Host、路径、认证及依赖。&lt;/li&gt;
&lt;li&gt;返回成功但业务异常：检查响应内容、数据状态和异步任务结果。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通过指定 IP 测试 HTTPS 时，优先用 &lt;code&gt;curl --resolve 域名:443:地址 https://域名/&lt;/code&gt; 保留 Host、SNI 和证书验证。直接改成 IP URL 可能改变虚拟主机选择。&lt;/p&gt;
&lt;h1&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc9110&quot;&gt;RFC 9110：HTTP 语义&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc9111&quot;&gt;RFC 9111：HTTP 缓存&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://httpd.apache.org/docs/2.4/&quot;&gt;Apache 2.4 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tomcat.apache.org/whichversion.html&quot;&gt;Tomcat 版本兼容性&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Linux：网络管理</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E7%BD%91%E7%BB%9C%E7%AE%A1%E7%90%86/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E7%BD%91%E7%BB%9C%E7%AE%A1%E7%90%86/</guid><description>Linux 网络管理包括接口与地址配置、路由、名称解析、访问控制和服务连通性验证。</description><pubDate>Sun, 13 Sep 2026 09:46:16 GMT</pubDate><content:encoded>&lt;p&gt;Linux 网络管理包括接口与地址配置、路由、名称解析、访问控制和服务连通性验证。排障时应沿实际请求路径收集证据，不把一个工具的成功当成整条链路正常。&lt;/p&gt;
&lt;h1&gt;接口、地址与路由&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;ip -br link
ip -br address
ip route
ip -6 route
ip route get 192.0.2.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后一条中的地址是文档示例，使用时替换为真实目标。输出中的接口、下一跳和源地址可以解释请求预计从哪里发出；策略路由、网络命名空间和应用绑定地址可能使实际路径不同。&lt;/p&gt;
&lt;p&gt;接口为 UP 不一定有可用链路；还要观察 LOWER_UP、地址和路由。地址前缀决定本地网段，默认路由只在没有更具体匹配时使用。&lt;/p&gt;
&lt;h2&gt;临时配置与持久配置&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ip address&lt;/code&gt;、&lt;code&gt;ip route&lt;/code&gt; 修改运行时状态，通常不会自动写入持久配置。持久管理可能由 NetworkManager、systemd-networkd、Netplan 或云初始化工具负责；先确认管理者，避免互相覆盖。&lt;/p&gt;
&lt;p&gt;使用 NetworkManager 的系统可先查看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nmcli device status
nmcli connection show
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;远程修改地址、默认路由或 DNS 前，应确认连接名称、现有配置和恢复控制台。修改连接配置后还需激活并重新验证，不能只凭配置文件内容判断已生效。&lt;/p&gt;
&lt;h1&gt;名称解析与应用请求&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;getent ahosts example.com
dig example.com A
curl -v --connect-timeout 5 --max-time 15 https://example.com/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;getent&lt;/code&gt; 经过系统名称服务配置，可能使用 hosts 文件；&lt;code&gt;dig&lt;/code&gt; 主要检查 DNS。二者结果不同并不必然是 DNS 服务器故障。使用 systemd-resolved 时，可用 &lt;code&gt;resolvectl status&lt;/code&gt; 确认各接口的解析设置。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;curl -v&lt;/code&gt; 可区分解析、连接、TLS 和 HTTP 处理阶段。不要默认增加 &lt;code&gt;-k&lt;/code&gt;，否则会跳过证书验证，掩盖实际问题。&lt;code&gt;curl -I&lt;/code&gt; 发送 HEAD 请求，并非所有服务都与 GET 行为一致。&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;ping&lt;/td&gt;
&lt;td&gt;ICMP Echo 是否收到回复及往返时间&lt;/td&gt;
&lt;td&gt;应用端口正常；无回复也不代表主机离线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;traceroute&lt;/td&gt;
&lt;td&gt;探测收到的中间节点响应&lt;/td&gt;
&lt;td&gt;星号就是断点；返回路径与去程一定相同&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ss&lt;/td&gt;
&lt;td&gt;本机 socket、监听地址及状态&lt;/td&gt;
&lt;td&gt;外部一定能访问&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tcpdump&lt;/td&gt;
&lt;td&gt;捕获点和过滤条件下观察到的报文&lt;/td&gt;
&lt;td&gt;包一定到达应用或物理线路另一端&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;curl&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;h1&gt;防火墙体系&lt;/h1&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;Netfilter&lt;/td&gt;
&lt;td&gt;提供包处理挂钩、连接跟踪和 NAT 等能力&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;规则体系与工具&lt;/td&gt;
&lt;td&gt;nftables / nft&lt;/td&gt;
&lt;td&gt;通过表、链和规则组织策略&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;兼容或传统接口&lt;/td&gt;
&lt;td&gt;iptables、ip6tables&lt;/td&gt;
&lt;td&gt;可能使用 legacy 或 nft 后端&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;策略管理服务&lt;/td&gt;
&lt;td&gt;firewalld&lt;/td&gt;
&lt;td&gt;提供 zone、service、运行时及永久配置等抽象&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;不要混用多个管理者随意修改同一套规则。先确认系统、容器平台和云平台分别维护哪些规则。&lt;code&gt;iptables --version&lt;/code&gt; 可辅助识别后端。&lt;/p&gt;
&lt;h2&gt;数据包路径&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;外部访问本机：prerouting → 路由判断 → input → 本地进程
经本机转发：  prerouting → 路由判断 → forward → postrouting
本机发起请求：本地进程 → output → 后续路由处理 → postrouting
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是常见 IP 路径的简化模型。判断规则位置时，先确认流量是访问本机还是经本机转发；容器发布端口可能走转发路径，不能只检查 input。&lt;/p&gt;
&lt;p&gt;iptables 的“表”按处理用途组织，例如 filter 和 nat；nftables 的表是对象容器，基础链通过 hook 和 priority 连接到处理路径。不要把“四表五链”当作所有现代防火墙的完整模型。&lt;/p&gt;
&lt;h2&gt;iptables 的四表五链&lt;/h2&gt;
&lt;p&gt;“四表五链”是面试中常用的 iptables 记忆框架。&lt;strong&gt;表&lt;/strong&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;code&gt;raw&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;在连接跟踪前处理报文&lt;/td&gt;
&lt;td&gt;设置 &lt;code&gt;NOTRACK&lt;/code&gt;，较少直接使用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mangle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;修改报文属性或打标记&lt;/td&gt;
&lt;td&gt;修改 TTL、设置 mark、调整服务质量&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;建立地址或端口转换映射&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DNAT&lt;/code&gt;、&lt;code&gt;SNAT&lt;/code&gt;、&lt;code&gt;MASQUERADE&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;filter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;按条件允许或丢弃报文&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ACCEPT&lt;/code&gt;、&lt;code&gt;DROP&lt;/code&gt;、&lt;code&gt;REJECT&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;传统资料有时还会提到 &lt;code&gt;security&lt;/code&gt; 表，它用于 SELinux 等强制访问控制场景；因此“四表”是常见教学口径，并不是 iptables 支持的全部表。&lt;/p&gt;
&lt;p&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;code&gt;PREROUTING&lt;/code&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;code&gt;INPUT&lt;/code&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;code&gt;FORWARD&lt;/code&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;code&gt;OUTPUT&lt;/code&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;code&gt;POSTROUTING&lt;/code&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;filter&lt;/code&gt; 使用 &lt;code&gt;INPUT&lt;/code&gt;、&lt;code&gt;FORWARD&lt;/code&gt;、&lt;code&gt;OUTPUT&lt;/code&gt;；&lt;code&gt;nat&lt;/code&gt; 主要使用 &lt;code&gt;PREROUTING&lt;/code&gt;、&lt;code&gt;OUTPUT&lt;/code&gt;、&lt;code&gt;POSTROUTING&lt;/code&gt;；&lt;code&gt;mangle&lt;/code&gt; 可出现在五条链；&lt;code&gt;raw&lt;/code&gt; 主要使用 &lt;code&gt;PREROUTING&lt;/code&gt; 和 &lt;code&gt;OUTPUT&lt;/code&gt;。排查规则时先确定流量类型，再选择表和链，否则容易在正确的规则中寻找错误的位置。&lt;/p&gt;
&lt;p&gt;只读查看某张表可以显式指定 &lt;code&gt;-t&lt;/code&gt;，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo iptables -t filter -L -n -v --line-numbers
sudo iptables -t nat -L -n -v --line-numbers
sudo iptables -t mangle -L -n -v --line-numbers
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些命令只能说明当前 iptables 视角下的规则和计数器；如果系统实际由 nftables、firewalld、容器运行时或云平台维护，还要检查对应管理层的配置。&lt;/p&gt;
&lt;h2&gt;只读检查&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;sudo nft list ruleset
sudo iptables -L -n -v
sudo firewall-cmd --get-active-zones
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;按实际使用的工具选择命令。检查接口或来源所属区域、规则顺序、计数器和默认策略。&lt;code&gt;accept&lt;/code&gt; 在某条基础链通过，不保证后续其他链不会丢弃；不能只找到一条允许规则便结束检查。&lt;/p&gt;
&lt;h1&gt;firewalld 开放服务示例&lt;/h1&gt;
&lt;p&gt;假设系统正在使用 firewalld，已确认目标接口属于 &lt;code&gt;public&lt;/code&gt;，业务要求允许该区域来源访问 HTTP，且服务确实监听 TCP 80：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo firewall-cmd --zone=public --list-all
sudo firewall-cmd --zone=public --add-service=http
sudo firewall-cmd --zone=public --query-service=http
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从目标客户端发起 HTTP 请求，确认业务响应，再将同一变更持久化：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --query-service=http
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两次修改分别作用于运行时和永久配置，此处不需要额外 reload。reload 会从永久配置重建运行时状态，可能丢失其他临时修改。若只允许指定来源，应采用相应来源规则，而不是向整个区域开放。&lt;/p&gt;
&lt;h1&gt;NAT 与转发&lt;/h1&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;SNAT&lt;/td&gt;
&lt;td&gt;源地址，可同时转换端口&lt;/td&gt;
&lt;td&gt;内网共享固定出口地址&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;masquerade&lt;/td&gt;
&lt;td&gt;按出口接口地址执行源地址转换&lt;/td&gt;
&lt;td&gt;出口地址动态变化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNAT&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;状态型 NAT 通常为连接建立转换映射，后续报文复用连接跟踪状态。NAT 不等于过滤，也不自动启用路由转发。&lt;/p&gt;
&lt;p&gt;部署 Linux 网关需共同满足：双向路由正确、相应协议的转发开启、forward 策略允许、NAT 规则匹配，并有可行的返回路径。IPv4 可用 &lt;code&gt;sysctl net.ipv4.ip_forward&lt;/code&gt; 检查，IPv6 转发有独立设置。不要在不了解当前拓扑时直接套用网关规则。&lt;/p&gt;
&lt;h1&gt;按症状排查&lt;/h1&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;系统解析配置、DNS 返回码&lt;/td&gt;
&lt;td&gt;对比 getent 与 dig，确认解析器及记录类型&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;tr&gt;
&lt;td&gt;连接被拒绝&lt;/td&gt;
&lt;td&gt;监听地址、端口、主动拒绝规则&lt;/td&gt;
&lt;td&gt;用 ss 和服务日志确认&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TCP 成功但 TLS 失败&lt;/td&gt;
&lt;td&gt;域名、SNI、证书链、时间&lt;/td&gt;
&lt;td&gt;保留证书验证定位原因&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP 502/504&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;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo tcpdump -ni eth0 -c 50 &apos;host 192.0.2.20 and tcp port 8080&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;没有 SYN 时，先确认接口、命名空间和过滤条件，再检查前向路径；有 SYN 无响应时检查本机规则、监听和返回路由；SYN/ACK 发出却没有后续 ACK 时重点核对回程。TLS 加密后的 HTTP 内容不能靠普通抓包直接读取。&lt;/p&gt;
&lt;h1&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man8/ip.8.html&quot;&gt;ip(8)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains&quot;&gt;nftables：配置链&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://firewalld.org/documentation/configuration/runtime-versus-permanent.html&quot;&gt;firewalld：运行时与永久配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://curl.se/docs/manpage.html&quot;&gt;curl 手册&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>网络：应用层</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%BD%91%E7%BB%9C%E5%BA%94%E7%94%A8%E5%B1%82/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%BD%91%E7%BB%9C%E5%BA%94%E7%94%A8%E5%B1%82/</guid><pubDate>Sun, 13 Sep 2026 09:01:56 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;在 TCP/IP 四层模型中，应用层位于最上层，直接面向网络应用和用户需求。&lt;/p&gt;
&lt;p&gt;应用层规定通信双方交换什么数据、数据具有什么含义，以及应该按照什么规则进行交互。&lt;/p&gt;
&lt;p&gt;常见的 HTTP、HTTPS、DNS、DHCP、SSH 等协议都属于这一层。理解应用层之后，TCP/IP 四层模型就形成了一条完整的数据通信链路。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;应用层是什么&lt;/h1&gt;
&lt;p&gt;TCP/IP 四层模型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌────────────────────┐
│      应用层        │
├────────────────────┤
│      传输层        │
├────────────────────┤
│      网际层        │
├────────────────────┤
│    网络接口层      │
└────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;前面已经介绍：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络接口层
↓
如何在当前链路上传输

网际层
↓
如何跨网络寻找目标

传输层
↓
如何在主机之间进行进程通信
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而应用层进一步解决：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;通信双方到底要交换什么信息，以及应该如何理解这些信息。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;浏览器 ↔ Web Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;双方需要约定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;请求是什么格式
响应是什么格式
状态码是什么意思
请求头怎么表示
数据怎么表示
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是应用层协议的作用。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用层
↓
定义通信规则和数据语义

传输层
↓
负责进程之间的数据传输

网际层
↓
负责 IP 寻址和转发

网络接口层
↓
负责具体链路传输
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;应用层与应用程序&lt;/h1&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;应用层协议 ≠ 应用程序本身。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Chrome
Firefox
curl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些是应用程序。&lt;/p&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是应用层协议。&lt;/p&gt;
&lt;p&gt;可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用程序
   │
   ▼
应用层协议
   │
   ▼
TCP / UDP
   │
   ▼
IP
   │
   ▼
Ethernet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Chrome
 ↓
HTTP
 ↓
TCP
 ↓
IP
 ↓
Ethernet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;应用层协议规定“怎么交流”，应用程序则负责利用这些协议完成具体功能。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;协议与数据格式&lt;/h1&gt;
&lt;p&gt;应用层协议通常需要定义：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;消息格式
字段含义
请求方式
响应方式
错误处理
状态
数据编码
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如一个 HTTP 请求：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET /index.html HTTP/1.1
Host: example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里不仅有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;请求方法
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;资源路径
协议版本
请求头
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;服务器必须按照 HTTP 的规则解释这些字段。&lt;/p&gt;
&lt;p&gt;所以：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;应用层协议的核心是建立双方都能够理解的通信语义。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;应用层协议的分类&lt;/h1&gt;
&lt;p&gt;应用层协议种类非常多，可以按用途粗略划分：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Web
├── HTTP
└── HTTPS

名称解析
└── DNS

地址配置
└── DHCP

远程管理
└── SSH

文件传输
├── FTP
└── TFTP

邮件
├── SMTP
├── POP3
└── IMAP

时间同步
└── NTP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;本文重点介绍：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
HTTPS
DNS
DHCP
SSH
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它们在实际 Linux / 运维工作中非常常见。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;HTTP&lt;/h1&gt;
&lt;h2&gt;什么是 HTTP&lt;/h2&gt;
&lt;p&gt;HTTP（Hypertext Transfer Protocol）是 Web 中最重要的应用层协议之一。&lt;/p&gt;
&lt;p&gt;它用于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;客户端
   ↕
服务器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之间交换资源。&lt;/p&gt;
&lt;p&gt;典型场景：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;浏览器
   │
   │ HTTP Request
   ▼
Web Server
   │
   │ HTTP Response
   ▼
浏览器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;HTTP 是一种：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;请求—响应（Request / Response）协议。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;HTTP 请求&lt;/h2&gt;
&lt;p&gt;一个典型 HTTP 请求可以简化为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Request Line
Headers
Blank Line
Body
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET /index.html HTTP/1.1
Host: example.com
User-Agent: curl/8.x
Accept: */*

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET
↓
请求方法

/index.html
↓
目标资源

HTTP/1.1
↓
协议版本
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;HTTP 方法&lt;/h2&gt;
&lt;p&gt;常见 HTTP 方法包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET
POST
PUT
PATCH
DELETE
HEAD
OPTIONS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最常见的有：&lt;/p&gt;
&lt;h3&gt;GET&lt;/h3&gt;
&lt;p&gt;通常用于：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;获取资源。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET /index.html HTTP/1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;POST&lt;/h3&gt;
&lt;p&gt;通常用于：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;向服务器提交数据或触发某种处理。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;POST /login HTTP/1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;请求体可能包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;username
password
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等数据。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;PUT&lt;/h3&gt;
&lt;p&gt;通常用于：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;创建或整体更新某个资源。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3&gt;PATCH&lt;/h3&gt;
&lt;p&gt;通常用于：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;对资源进行部分修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3&gt;DELETE&lt;/h3&gt;
&lt;p&gt;通常用于：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;删除资源。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;HTTP 响应&lt;/h1&gt;
&lt;p&gt;服务器处理请求后会返回：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Response Status
Headers
Blank Line
Body
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234

&amp;lt;html&amp;gt;
...
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;200
↓
状态码

OK
↓
原因短语
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;HTTP 状态码&lt;/h2&gt;
&lt;p&gt;HTTP 状态码通常分为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1xx
2xx
3xx
4xx
5xx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&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;1xx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;信息响应&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;2xx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;请求成功&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3xx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;重定向&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;4xx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;客户端请求问题&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;5xx&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;/p&gt;
&lt;pre&gt;&lt;code&gt;200 OK
201 Created
204 No Content

301 Moved Permanently
302 Found
304 Not Modified

400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found

500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中尤其值得注意：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;4xx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不简单等于：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“网络有问题”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它表示服务器收到了请求，但请求通常存在客户端侧的问题。&lt;/p&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;5xx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通常表示服务器端处理过程中出现问题。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;HTTP Header&lt;/h1&gt;
&lt;p&gt;HTTP 中大量信息通过：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Header（首部）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;传输。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host: example.com
Content-Type: application/json
Content-Length: 123
User-Agent: curl/8.x
Authorization: Bearer ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见作用包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;身份信息
内容类型
内容长度
缓存
压缩
连接控制
认证
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP Message
│
├── Start Line
├── Headers
├── Blank Line
└── Body
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是理解 HTTP 报文结构的重要基础。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;HTTP Body&lt;/h1&gt;
&lt;p&gt;Body 是真正承载内容的区域。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTML
JSON
图片
文件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都可以作为 HTTP Body。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Content-Type: application/json

{
  &quot;name&quot;: &quot;Alice&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Content-Type
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;告诉接收方：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Body 中的数据是什么类型。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;HTTP 与 TCP&lt;/h1&gt;
&lt;p&gt;在传统 HTTP/1.1 和 HTTP/2 部署中，HTTP 通常运行在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之上。&lt;/p&gt;
&lt;p&gt;可以简化成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
 ↓
TCP
 ↓
IP
 ↓
Ethernet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;负责：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Web 通信规则
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;负责：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;可靠传输
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两者是不同层次的协议。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;HTTPS&lt;/h1&gt;
&lt;h2&gt;什么是 HTTPS&lt;/h2&gt;
&lt;p&gt;HTTPS 可以理解为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;HTTP over TLS&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;即：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
 ↓
TLS
 ↓
TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;TLS 提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;加密
身份认证
完整性保护
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
↓
明文应用层协议

HTTPS
↓
HTTP + TLS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;HTTPS 并不是一个与 HTTP 完全无关的新应用层协议，而是使用 TLS 对 HTTP 通信进行保护。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;HTTPS 的基本过程&lt;/h2&gt;
&lt;p&gt;可以简化成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client
   │
   │ TCP Connection
   ▼
Server
   │
   │ TLS Handshake
   ▼
建立安全通道
   │
   ▼
HTTP Request / Response
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
 ↓
建立传输连接

TLS
 ↓
建立安全通信通道

HTTP
 ↓
交换 Web 数据
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;TLS&lt;/h1&gt;
&lt;p&gt;TLS（Transport Layer Security）是一种安全协议，用于在通信双方之间建立安全通道。&lt;/p&gt;
&lt;p&gt;它主要提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;机密性
完整性
身份认证
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;h3&gt;机密性&lt;/h3&gt;
&lt;p&gt;防止通信内容被第三方直接读取。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;明文
 ↓
加密
 ↓
密文
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;完整性&lt;/h3&gt;
&lt;p&gt;防止数据在传输过程中被悄悄修改。&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送数据
 ↓
完整性保护
 ↓
接收端验证
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;身份认证&lt;/h3&gt;
&lt;p&gt;通常通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数字证书
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;帮助客户端验证服务器身份。&lt;/p&gt;
&lt;p&gt;因此浏览器访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;时，会涉及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TLS
+
Certificate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等机制。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;DNS&lt;/h1&gt;
&lt;h2&gt;什么是 DNS&lt;/h2&gt;
&lt;p&gt;DNS（Domain Name System）用于：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;将域名映射为网络中的地址信息。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;www.example.com
        ↓
DNS
        ↓
93.184.216.34
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样用户不需要记住：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;93.184.216.34
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;www.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;为什么需要 DNS&lt;/h1&gt;
&lt;p&gt;人类更容易记住：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;www.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而网络通信需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP Address
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此 DNS 提供了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Domain Name
     ↓
DNS
     ↓
IP Address
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但需要注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;DNS 并不只是简单的“域名转 IP”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它实际上是一个分布式的名称系统。&lt;/p&gt;
&lt;p&gt;DNS 还可以提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A
AAAA
CNAME
MX
NS
TXT
SRV
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等不同类型的记录。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;DNS 查询&lt;/h1&gt;
&lt;p&gt;例如客户端需要解析：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;www.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能会向 DNS 服务器发起：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DNS Query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查询：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;www.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;记录。&lt;/p&gt;
&lt;p&gt;DNS Server 返回：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;93.184.216.34
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以简化成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client
   │
   │ Query
   ▼
DNS Resolver
   │
   │ Answer
   ▼
Client
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;DNS Record&lt;/h1&gt;
&lt;p&gt;常见 DNS 记录：&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;A&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;域名 → IPv4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AAAA&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;域名 → IPv6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CNAME&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;别名&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;邮件服务器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;权威名称服务器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TXT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;文本信息&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SRV&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;/p&gt;
&lt;pre&gt;&lt;code&gt;example.com
   │
   ├── A → 192.0.2.1
   ├── AAAA → 2001:db8::1
   └── MX → mail.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;DNS 的层次结构&lt;/h1&gt;
&lt;p&gt;DNS 并不是一个：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;全世界只有一台服务器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是一个分布式层级系统。&lt;/p&gt;
&lt;p&gt;可以简化为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Root
 │
 ├── .com
 ├── .org
 └── .net
      │
      ▼
example.com
      │
      ▼
www.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Root
↓
根 DNS

TLD
↓
顶级域

Authoritative DNS
↓
权威 DNS
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;DNS 缓存&lt;/h1&gt;
&lt;p&gt;如果每次访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;www.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都从根服务器开始查找，效率会非常低。&lt;/p&gt;
&lt;p&gt;因此 DNS 大量使用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;缓存（Caching）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;第一次查询
   ↓
DNS Resolution
   ↓
得到结果
   ↓
缓存

再次查询
   ↓
直接使用缓存
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DNS 记录通常存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TTL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示缓存可以保留多长时间。&lt;/p&gt;
&lt;p&gt;因此修改 DNS 后并不一定能够立即在所有网络中看到变化。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;DNS 与 TCP / UDP&lt;/h1&gt;
&lt;p&gt;传统 DNS 查询最常见的传输方式是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UDP
53
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但 DNS 也可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
53
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;TCP 在 DNS 中并不是简单的“旧协议”。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;响应过大
区域传送
特定 DNS 场景
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都可能使用 TCP。&lt;/p&gt;
&lt;p&gt;此外，现代 DNS 还存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DoT
DoH
DoQ
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等更现代的传输方式。&lt;/p&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DoT
↓
DNS over TLS

DoH
↓
DNS over HTTPS

DoQ
↓
DNS over QUIC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它们的重点是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;对 DNS 通信本身进行不同形式的传输或加密封装。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;DHCP&lt;/h1&gt;
&lt;h2&gt;什么是 DHCP&lt;/h2&gt;
&lt;p&gt;DHCP（Dynamic Host Configuration Protocol）用于：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;向网络中的主机动态提供网络配置。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如新设备接入网络后，可能需要获得：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP 地址
子网掩码
默认网关
DNS 服务器
租期
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些配置可以通过 DHCP 自动获取。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;DHCP 的基本过程&lt;/h1&gt;
&lt;p&gt;IPv4 DHCP 初始化通常可以概括成经典的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DHCP Discover
       ↓
DHCP Offer
       ↓
DHCP Request
       ↓
DHCP ACK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常被记成：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;DORA&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;即：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Discover
Offer
Request
ACK
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;DHCP Discover&lt;/h2&gt;
&lt;p&gt;新接入网络的客户端可能还没有自己的 IP。&lt;/p&gt;
&lt;p&gt;于是发送：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DHCP Discover
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;寻找 DHCP Server。&lt;/p&gt;
&lt;p&gt;可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client
  │
  │ 我需要网络配置
  ▼
广播 / DHCP Server
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;DHCP Offer&lt;/h2&gt;
&lt;p&gt;DHCP Server 提供一个配置方案：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP
Subnet Mask
Gateway
DNS
Lease Time
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP = 192.168.1.100
Mask = 255.255.255.0
Gateway = 192.168.1.1
DNS = 192.168.1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;DHCP Request&lt;/h2&gt;
&lt;p&gt;客户端表示：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我希望使用这个配置。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;DHCP ACK&lt;/h2&gt;
&lt;p&gt;服务器确认：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;配置正式分配给你。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;于是客户端获得：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP Address
+
其他网络配置
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;DHCP 租约&lt;/h1&gt;
&lt;p&gt;DHCP 并不是永久把 IP 地址交给客户端。&lt;/p&gt;
&lt;p&gt;通常会存在：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lease（租约）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP
192.168.1.100

Lease
8 hours
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;到一定时间后客户端需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;续租
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;否则地址最终可能重新进入地址池。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DHCP
↓
动态地址管理
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;非常适合：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;家庭网络
办公网络
大型局域网
云环境
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;SSH&lt;/h1&gt;
&lt;h2&gt;什么是 SSH&lt;/h2&gt;
&lt;p&gt;SSH（Secure Shell）是一种用于安全远程登录和管理的协议。&lt;/p&gt;
&lt;p&gt;典型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client
   │
   │ SSH
   ▼
Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh user@192.168.1.100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以建立远程 Shell 会话。&lt;/p&gt;
&lt;p&gt;SSH 通常运行在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP 22
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之上。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;SSH 能做什么&lt;/h1&gt;
&lt;p&gt;SSH 不只是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;远程登录
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还可以进行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;远程命令执行
文件传输
端口转发
隧道
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh user@server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;远程执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh user@server &quot;systemctl status nginx&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;scp
rsync
sftp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等工具完成文件传输。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;SSH 认证&lt;/h1&gt;
&lt;p&gt;SSH 常见认证方式包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;密码认证
公钥认证
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;公钥认证可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client
 ├── Private Key
 └── Public Key
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;服务器保存：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;authorized_keys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;客户端通过私钥证明：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;自己拥有对应的身份凭证。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Private Key
↓
必须妥善保护

Public Key
↓
可以放在服务器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在生产环境中，公钥认证通常比单纯密码登录更加适合自动化和安全管理。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;FTP 与其他应用层协议&lt;/h1&gt;
&lt;p&gt;除了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
DNS
DHCP
SSH
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用层还有大量协议。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FTP
SMTP
IMAP
POP3
NTP
SNMP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它们分别解决不同的问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FTP
↓
文件传输

SMTP
↓
发送邮件

IMAP / POP3
↓
获取邮件

NTP
↓
时间同步

SNMP
↓
网络设备管理
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这说明：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;应用层并不等于 Web。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Web 只是应用层中非常重要的一部分。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;应用层协议如何使用传输层&lt;/h1&gt;
&lt;p&gt;不同应用协议可以运行在不同的传输层协议之上。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1
 ↓
TCP

SSH
 ↓
TCP

DNS
 ↓
UDP / TCP

DHCP
 ↓
UDP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以形成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                   应用层
                     │
      ┌──────────────┼──────────────┐
      │              │              │
     HTTP           SSH            DNS
      │              │              │
      └──────┬───────┘              │
             ▼                      ▼
            TCP                    UDP
             │                      │
             └──────────┬───────────┘
                        ▼
                       IP
                        │
                        ▼
                   Ethernet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;应用层协议并不需要自己重新实现 TCP/IP 的底层传输机制，而是建立在传输层提供的能力之上。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;一个完整的 Web 请求&lt;/h1&gt;
&lt;p&gt;假设用户在浏览器中输入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以从应用层开始向下理解。&lt;/p&gt;
&lt;p&gt;首先需要解析：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DNS
 ↓
获得 IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后建立传输连接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果使用 HTTPS，还需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TLS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后才发送：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP Request
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;整个过程可以简化成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户
 ↓
浏览器
 ↓
DNS
 ↓
获得服务器 IP
 ↓
TCP
 ↓
TLS
 ↓
HTTP
 ↓
IP
 ↓
Ethernet
 ↓
服务器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;服务器收到数据后则反过来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet
 ↓
IP
 ↓
TCP
 ↓
TLS
 ↓
HTTP
 ↓
Web Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是整个 TCP/IP 协议栈协同工作的一个典型例子。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;应用层并不是“最上面就没有协议”&lt;/h1&gt;
&lt;p&gt;应用层包含的协议非常多。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Web
├── HTTP
└── HTTPS

DNS
├── DNS
├── DoT
└── DoH

Remote Access
├── SSH
└── RDP

Email
├── SMTP
├── IMAP
└── POP3

Time
└── NTP

Network Management
└── SNMP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它们虽然都是应用层协议，但：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;解决的问题不同
消息格式不同
状态模型不同
传输方式也可能不同
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此学习应用层时，不应该把：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用层 = HTTP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;简单画等号。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP/IP 四层模型&lt;/h1&gt;
&lt;p&gt;现在可以把整个系列完整串起来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────────────────────────┐
│             应用层               │
│ HTTP / DNS / DHCP / SSH / ...     │
└────────────────┬─────────────────┘
                 │
                 ▼
┌──────────────────────────────────┐
│             传输层               │
│          TCP / UDP               │
│       Port / Socket              │
└────────────────┬─────────────────┘
                 │
                 ▼
┌──────────────────────────────────┐
│             网际层               │
│      IPv4 / IPv6 / Routing       │
│         ICMP / ARP               │
└────────────────┬─────────────────┘
                 │
                 ▼
┌──────────────────────────────────┐
│           网络接口层             │
│ Ethernet / MAC / Frame / NIC     │
└──────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每一层解决的问题可以概括成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络接口层
↓
当前链路怎么传？

网际层
↓
数据应该去哪个 IP？

传输层
↓
交给哪个端口？
如何传输？

应用层
↓
双方具体交换什么信息？
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;一次完整通信&lt;/h1&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;浏览器
访问
https://example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以把整个过程浓缩成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                 应用层
                    │
               HTTP / HTTPS
                    │
                    ▼
                 传输层
                    │
                 TCP / UDP
                    │
                    ▼
                 网际层
                    │
                  IP
                    │
                    ▼
               网络接口层
                    │
              Ethernet
                    │
                    ▼
                  网络
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发送过程中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application Data
      ↓
TCP Segment
      ↓
IP Packet
      ↓
Ethernet Frame
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接收过程中则反过来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet Frame
      ↓
IP Packet
      ↓
TCP Segment
      ↓
Application Data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;封装（Encapsulation）与解封装（Decapsulation）。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;从运维角度理解应用层&lt;/h1&gt;
&lt;p&gt;应用层是运维工作中非常容易接触的一层。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网页打不开
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不能简单认为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络断了
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而应该逐层思考：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DNS
↓
域名是否解析？

TCP
↓
端口是否建立连接？

TLS
↓
证书和握手是否正常？

HTTP
↓
状态码是什么？

Application
↓
服务本身是否正常？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DNS 正常
TCP 正常
TLS 正常
HTTP = 502
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;说明问题已经不太可能是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网线
IP
路由
TCP 建连
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而应该继续调查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;反向代理
上游服务
应用程序
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;类似地：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ping 正常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也不能证明：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP 一定正常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ICMP
↓
网际层

HTTP
↓
应用层
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;属于完全不同的层次。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;应用层的整体认知模型&lt;/h1&gt;
&lt;p&gt;可以把应用层浓缩成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                         应用层
                            │
          ┌─────────────────┼─────────────────┐
          │                 │                 │
          ▼                 ▼                 ▼
         Web              DNS              Remote
          │                 │              Management
      HTTP/HTTPS            │                 │
          │                 │                SSH
          │                 │
          └────────┬────────┘
                   ▼
               应用协议
                   │
                   ▼
              定义通信规则
                   │
        ┌──────────┼──────────┐
        │          │          │
        ▼          ▼          ▼
      消息格式    数据语义    交互流程
        │          │          │
        └──────────┼──────────┘
                   ▼
                 TCP/UDP
                   │
                   ▼
                  IP
                   │
                   ▼
               Ethernet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最核心的一点就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;应用层负责定义“通信双方说什么、怎么说、这些数据代表什么”；下面三层则负责把这些数据送到正确的目标。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP/IP 四层模型总结&lt;/h1&gt;
&lt;p&gt;至此，整个 TCP/IP 四层模型可以完整理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用层
↓
定义应用通信协议
↓
HTTP / DNS / DHCP / SSH

传输层
↓
实现进程之间的通信
↓
TCP / UDP / Port

网际层
↓
实现跨网络寻址与转发
↓
IP / Routing / ICMP

网络接口层
↓
实现当前链路上的传输
↓
Ethernet / MAC / Frame / NIC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以进一步浓缩成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用层
↓
“说什么？”

传输层
↓
“交给谁？”

网际层
↓
“到哪台主机？”

网络接口层
↓
“这一跳怎么发送？”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这四层共同构成了一个完整的网络通信体系。&lt;/p&gt;
&lt;p&gt;当浏览器访问一个网站时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
 ↓
TCP
 ↓
IP
 ↓
Ethernet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每一层都只关注自己的职责，同时把结果交给下一层。&lt;/p&gt;
&lt;p&gt;这正是 TCP/IP 分层模型最核心的思想：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;把复杂的网络通信拆分成相对独立的功能层，各层通过明确的接口协同工作。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc9110&quot;&gt;RFC 9110 — HTTP Semantics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc1035&quot;&gt;RFC 1034 / RFC 1035 — Domain Names&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc2131&quot;&gt;RFC 2131 — DHCP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc4251&quot;&gt;RFC 4251 — The Secure Shell (SSH) Protocol Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc8446&quot;&gt;RFC 8446 — TLS 1.3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>网络：传输层</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%BD%91%E7%BB%9C%E4%BC%A0%E8%BE%93%E5%B1%82/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%BD%91%E7%BB%9C%E4%BC%A0%E8%BE%93%E5%B1%82/</guid><pubDate>Sun, 13 Sep 2026 08:58:48 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;如果说网际层解决的是“数据要发到哪台主机”，那么传输层进一步解决的是“数据应该交给主机上的哪个程序，以及多个主机之间如何进行可靠的数据传输”。&lt;/p&gt;
&lt;p&gt;TCP/IP 四层模型中的传输层主要包括 &lt;strong&gt;TCP、UDP、端口、Socket、可靠传输、流量控制、拥塞控制以及连接管理&lt;/strong&gt; 等概念。理解这一层之后，才能继续理解 HTTP、DNS、SSH 等应用层协议为什么能够同时运行在同一台主机上。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;传输层是什么&lt;/h1&gt;
&lt;p&gt;TCP/IP 四层模型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌────────────────────┐
│      应用层        │
├────────────────────┤
│      传输层        │
├────────────────────┤
│      网际层        │
├────────────────────┤
│    网络接口层      │
└────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;理解传输层时，先区分相邻层的职责：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络接口层
↓
Ethernet / MAC / Frame / 网卡

网际层
↓
IP / IP 地址 / 子网 / 路由 / ICMP / ARP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;传输层位于它们之上。&lt;/p&gt;
&lt;p&gt;它主要负责：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机
 ↓
进程之间的通信
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IP 地址定位主机，端口定位主机上的服务或通信端点。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10:80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以拆成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10
↓
目标主机

80
↓
目标端口
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP
↓
找到哪台主机

Port
↓
找到主机上的哪个服务
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;为什么需要传输层&lt;/h1&gt;
&lt;p&gt;假设一台服务器同时运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Web Server
SSH Server
DNS Server
Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它们都使用同一块网卡和同一个 IP 地址。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;服务器
IP = 192.168.1.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但客户端需要区分：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Web
SSH
DNS
Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时候就需要：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Port（端口）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;             192.168.1.10
                    │
       ┌────────────┼────────────┐
       │            │            │
       ▼            ▼            ▼
     :22           :53          :80
      │             │             │
      ▼             ▼             ▼
     SSH           DNS           HTTP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP + Port
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;共同构成了网络通信中的一个重要寻址概念。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;端口&lt;/h1&gt;
&lt;h2&gt;什么是 Port&lt;/h2&gt;
&lt;p&gt;TCP 和 UDP 都使用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;16 bit 端口号&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因此端口范围是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0
~
65535
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;端口号本身只是一个数字。&lt;/p&gt;
&lt;p&gt;真正的含义取决于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;传输协议
+
具体应用
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP 22
TCP 80
TCP 443
UDP 53
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不意味着：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;80 永远只能用于 HTTP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;某个应用协议通常会约定使用某个端口。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;端口范围&lt;/h2&gt;
&lt;p&gt;传统上可以把端口大致理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 ~ 1023
↓
知名端口

1024 ~ 49151
↓
注册端口

49152 ~ 65535
↓
动态 / 私有端口
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中实际系统、IANA 注册以及具体操作系统分配策略可能存在差异。&lt;/p&gt;
&lt;p&gt;IANA 维护官方的 &lt;a href=&quot;https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml&quot;&gt;Service Name and Transport Protocol Port Number Registry&lt;/a&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;源端口与目标端口&lt;/h2&gt;
&lt;p&gt;一次 TCP / UDP 通信通常存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Source Port
Destination Port
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如客户端访问服务器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client
192.168.1.10:50000
       │
       │
       ▼
Server
192.168.1.20:443
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;源 IP   = 192.168.1.10
源端口  = 50000

目标 IP = 192.168.1.20
目标端口 = 443
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是一个方向上的通信可以表示为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10:50000
          ↓
192.168.1.20:443
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;返回方向则相反：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.20:443
          ↓
192.168.1.10:50000
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP 与 UDP&lt;/h1&gt;
&lt;p&gt;传输层最重要的两个协议：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
UDP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它们都属于传输层，但设计目标不同。&lt;/p&gt;
&lt;p&gt;可以先概括为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
↓
面向连接
可靠
有序
字节流

UDP
↓
无连接
尽力交付
数据报
开销较小
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“UDP 不可靠”并不是说 UDP 一定会丢包，而是 UDP 协议本身不提供类似 TCP 的可靠传输、排序和重传机制。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;UDP&lt;/h1&gt;
&lt;h2&gt;UDP 是什么&lt;/h2&gt;
&lt;p&gt;UDP（User Datagram Protocol）是一种无连接的传输层协议。&lt;/p&gt;
&lt;p&gt;RFC 768 定义了 UDP。&lt;/p&gt;
&lt;p&gt;其特点可以概括为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;简单
无连接
数据报
开销低
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;UDP 不负责建立一个类似 TCP 那样的连接状态。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;UDP Datagram&lt;/h2&gt;
&lt;p&gt;UDP 传输的数据单位称为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;UDP Datagram&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application Data
      │
      ▼
UDP Datagram
      │
      ▼
IP Packet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;UDP 首部很简单：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────────┬──────────────────┐
│ Source Port      │ Destination Port │
├──────────────────┼──────────────────┤
│ Length           │ Checksum         │
├──────────────────┴──────────────────┤
│ Payload                              │
└─────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;主要包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;源端口
目标端口
长度
校验和
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;UDP 的特点&lt;/h2&gt;
&lt;p&gt;UDP 不提供 TCP 那样的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;连接建立
可靠重传
顺序保证
流量控制
拥塞控制
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此它更适合某些强调：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;低延迟
简单通信
实时性
应用自行控制可靠性
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的场景。&lt;/p&gt;
&lt;p&gt;常见应用包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DNS
DHCP
实时音视频
部分游戏通信
QUIC 的底层传输
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不过具体协议是否使用 UDP 仍然由协议设计决定。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP&lt;/h1&gt;
&lt;h2&gt;TCP 是什么&lt;/h2&gt;
&lt;p&gt;TCP（Transmission Control Protocol）是一种：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;面向连接的、可靠的、字节流传输协议。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;RFC 9293 是当前 TCP 的主要规范之一。&lt;/p&gt;
&lt;p&gt;TCP 需要维护通信双方的状态。&lt;/p&gt;
&lt;p&gt;可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client
  │
  │ 建立连接
  ▼
Server
  │
  │
  ▼
TCP Connection
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;TCP Segment&lt;/h2&gt;
&lt;p&gt;TCP 传输的数据单位通常称：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TCP Segment&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application Data
      │
      ▼
TCP Segment
      │
      ▼
IP Packet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;TCP 首部比 UDP 复杂得多。&lt;/p&gt;
&lt;p&gt;简化表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────┬─────────────────┐
│ Source Port     │ Dest Port       │
├─────────────────┼─────────────────┤
│ Sequence Number                   │
├───────────────────────────────────┤
│ Acknowledgment Number             │
├───────┬───────┬───────────────────┤
│ Flags │ Window│ ...               │
├───────┴───────┴───────────────────┤
│ Checksum                           │
├───────────────────────────────────┤
│ Urgent Pointer / Options ...       │
├───────────────────────────────────┤
│ Payload                            │
└───────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中非常重要的字段包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Sequence Number
Acknowledgment Number
Flags
Window
Checksum
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP 三次握手&lt;/h1&gt;
&lt;h2&gt;为什么要握手&lt;/h2&gt;
&lt;p&gt;TCP 是面向连接的，因此通信双方需要首先建立连接状态。&lt;/p&gt;
&lt;p&gt;典型过程是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client                          Server
  │                               │
  │ -------- SYN ---------------&amp;gt; │
  │                               │
  │ &amp;lt;------ SYN + ACK ------------ │
  │                               │
  │ -------- ACK ---------------&amp;gt; │
  │                               │
  │          Established          │
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TCP Three-Way Handshake&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;第一次：SYN&lt;/h2&gt;
&lt;p&gt;客户端发送：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SYN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我想建立 TCP 连接。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;其中会携带客户端选择的初始序列号等信息。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client
   │
   │ SYN
   ▼
Server
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;第二次：SYN + ACK&lt;/h2&gt;
&lt;p&gt;服务器收到 SYN 后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Server
   │
   │ SYN + ACK
   ▼
Client
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;我收到了你的请求
+
我也愿意建立连接
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;第三次：ACK&lt;/h2&gt;
&lt;p&gt;客户端收到服务器响应后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client
   │
   │ ACK
   ▼
Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;双方就可以进入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Established
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;状态。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;三次握手到底解决什么&lt;/h2&gt;
&lt;p&gt;不能简单说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“三次握手就是为了确认双方都在线。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它更准确的作用包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;同步双方的初始序列号
确认双向通信能力
建立双方 TCP 状态
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SYN
↓
建立初始状态

SYN + ACK
↓
服务器确认并建立自己的状态

ACK
↓
客户端确认服务器响应
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP 四次挥手&lt;/h1&gt;
&lt;h2&gt;为什么关闭连接需要四步&lt;/h2&gt;
&lt;p&gt;TCP 是全双工通信。&lt;/p&gt;
&lt;p&gt;也就是说：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A → B
B → A
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两个方向可以独立关闭。&lt;/p&gt;
&lt;p&gt;因此关闭连接通常涉及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FIN
ACK
FIN
ACK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型流程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client                          Server
  │                               │
  │ -------- FIN ---------------&amp;gt; │
  │ &amp;lt;-------- ACK --------------- │
  │                               │
  │ &amp;lt;-------- FIN --------------- │
  │ -------- ACK ---------------&amp;gt; │
  │                               │
  │            Closed             │
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TCP 的连接关闭通常被称为“四次挥手”。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;但实际抓包中具体报文可能因为实现和时序有所不同，例如 ACK 可能与其他报文合并，因此不要把“四次”理解成绝对固定的报文数量。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP 序列号与确认号&lt;/h1&gt;
&lt;p&gt;TCP 的可靠传输非常依赖：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Sequence Number
Acknowledgment Number
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送方
Segment 1
Seq = 1000
Length = 500
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么接收方如果完整收到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1000 ~ 1499
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通常会确认下一个希望收到的位置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ACK = 1500
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Seq
↓
“这一段数据从哪里开始”

ACK
↓
“我已经收到哪里，并希望下一个从哪里开始”
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;为什么需要序列号&lt;/h2&gt;
&lt;p&gt;因为网络中的数据包可能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;乱序
丢失
重复
延迟
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如发送：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Segment A
Segment B
Segment C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;网络中可能出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A
C
B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;TCP 可以利用序列号判断：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据顺序
数据范围
重复数据
缺失数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从而实现有序的字节流交付。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP 重传&lt;/h1&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送：

A
B
C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在网络中丢失。&lt;/p&gt;
&lt;p&gt;接收端可能持续确认：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ACK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表明自己还缺少某个位置的数据。&lt;/p&gt;
&lt;p&gt;发送端检测到丢失后，就可能重新发送对应数据。&lt;/p&gt;
&lt;p&gt;可以简化为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A ─────────────►
B ─────X

C ─────────────►

收到情况：
A
缺 B
C

        ↓

重新发送 B
        ↓

B ─────────────►
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是 TCP 可靠传输的重要基础。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP 滑动窗口&lt;/h1&gt;
&lt;p&gt;如果发送方：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送一个
等待 ACK
发送一个
等待 ACK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;效率会非常低。&lt;/p&gt;
&lt;p&gt;因此 TCP 使用窗口机制允许：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;在等待确认之前连续发送多个字节的数据。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送窗口

┌────┬────┬────┬────┬────┐
│ A  │ B  │ C  │ D  │ E  │
└────┴────┴────┴────┴────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以同时存在多个尚未确认的数据。&lt;/p&gt;
&lt;p&gt;收到确认后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌────┬────┬────┬────┬────┐
│ A  │ B  │ C  │ D  │ E  │
└────┴────┴────┴────┴────┘
       ↑
      ACK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;窗口向前滑动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;      ┌────┬────┬────┬────┬────┐
      │ B  │ C  │ D  │ E  │ F  │
      └────┴────┴────┴────┴────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此称为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Sliding Window（滑动窗口）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP 流量控制&lt;/h1&gt;
&lt;h2&gt;为什么需要流量控制&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送方很快
接收方很慢
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果发送方无限制地发送：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送发送发送发送……
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接收方缓冲区最终可能被填满。&lt;/p&gt;
&lt;p&gt;因此接收方需要告诉发送方：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;我现在还能接收多少数据。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;TCP 使用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Receive Window（接收窗口）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;进行流量控制。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;接收窗口&lt;/h2&gt;
&lt;p&gt;可以简单理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Receiver
   │
   │ 告诉 Sender：
   │ 我还能接收 N 字节
   ▼
Sender
   │
   │ 控制发送量
   ▼
Receiver
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送速度
↓
受到接收方处理能力限制
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Flow Control&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;核心解决：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送方
vs
接收方
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;速度不匹配的问题。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP 拥塞控制&lt;/h1&gt;
&lt;p&gt;流量控制解决的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送方 ↔ 接收方
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而拥塞控制关注的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送方
   ↓
网络
   ↓
接收方
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;网络本身是否拥堵。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;为什么需要拥塞控制&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机 A
   ↓
路由器
   ↓
路由器
   ↓
主机 B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果大量发送方同时高速发送：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A ─┐
B ─┼──► Network
C ─┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;中间网络设备可能出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;队列堆积
丢包
延迟增加
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;TCP 因此需要动态调整发送速率。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;拥塞窗口&lt;/h2&gt;
&lt;p&gt;TCP 通过：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Congestion Window（拥塞窗口，cwnd）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;控制在网络中可以同时维持多少未确认数据。&lt;/p&gt;
&lt;p&gt;最终发送端的有效发送窗口通常会受到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;接收窗口 rwnd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;和：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;拥塞窗口 cwnd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;共同限制。&lt;/p&gt;
&lt;p&gt;可以简化理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;实际可发送范围
≈
min(rwnd, cwnd)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;流量控制与拥塞控制的区别&lt;/h1&gt;
&lt;p&gt;这是 TCP 中非常重要的一组概念。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Flow Control
↓
关注接收方

Congestion Control
↓
关注网络
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以画成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Sender
  │
  │
  ▼
Network
  │
  │
  ▼
Receiver

  ↑
  │
流量控制
关注 Receiver 能不能接住

拥塞控制
关注 Network 能不能承受
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;接收方太慢
↓
流量控制

网络太拥堵
↓
拥塞控制
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP 的可靠传输机制&lt;/h1&gt;
&lt;p&gt;把前面的概念放到一起，可以理解 TCP 的可靠性来自多个机制共同作用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
│
├── Sequence Number
├── Acknowledgment
├── Retransmission
├── Sliding Window
├── Flow Control
├── Congestion Control
└── Connection Management
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TCP 的可靠性不是由某一个字段提供，而是一整套机制共同实现的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;UDP 与 TCP 的区别&lt;/h1&gt;
&lt;p&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;/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;数据报&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;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;不提供&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;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;简单&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;tr&gt;
&lt;td&gt;典型场景&lt;/td&gt;
&lt;td&gt;HTTP、SSH 等&lt;/td&gt;
&lt;td&gt;DNS、DHCP、实时通信等&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这里的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP 更可靠
UDP 更简单
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不意味着：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP 一定更快
UDP 一定更快
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;具体性能取决于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络条件
数据规模
应用协议
延迟要求
丢包率
实现方式
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;Socket&lt;/h1&gt;
&lt;h2&gt;什么是 Socket&lt;/h2&gt;
&lt;p&gt;应用程序要使用 TCP / UDP 通信，需要操作系统提供编程接口。&lt;/p&gt;
&lt;p&gt;其中最重要的抽象之一就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Socket&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
    │
    ▼
  Socket
    │
    ▼
TCP / UDP
    │
    ▼
    IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用程序不需要直接操作：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet Frame
MAC
网卡
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是通常通过 Socket API 与传输层通信。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Socket 地址&lt;/h2&gt;
&lt;p&gt;一个 TCP 通信端点可以抽象成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP + Port + Protocol
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
192.168.1.10:443
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UDP
192.168.1.10:53
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10:443/TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;和：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10:443/UDP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是不同的通信端点。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP 连接如何唯一确定&lt;/h1&gt;
&lt;p&gt;一个 TCP 连接通常由：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;源 IP
源端口
目标 IP
目标端口
协议
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些信息共同确定。&lt;/p&gt;
&lt;p&gt;也常称为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Four-Tuple（四元组）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10:50000
        ↓
192.168.1.20:443
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对应：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Source IP      = 192.168.1.10
Source Port    = 50000
Destination IP = 192.168.1.20
Destination Port = 443
Protocol       = TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此同一台服务器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.20:443
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以同时与大量客户端建立 TCP 连接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client A :50000 ──► Server :443
Client B :50001 ──► Server :443
Client C :50002 ──► Server :443
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为每条连接的四元组不同。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;服务器为什么可以同时服务很多客户端&lt;/h1&gt;
&lt;p&gt;假设服务器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.20:443
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;客户端：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A:50000
B:50001
C:50002
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它们分别建立：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A:50000 → 192.168.1.20:443

B:50001 → 192.168.1.20:443

C:50002 → 192.168.1.20:443
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;虽然：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;目标 IP
目标端口
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完全一样，但：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;源 IP
源端口
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不同。&lt;/p&gt;
&lt;p&gt;因此操作系统可以区分这些连接。&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    Server
                 192.168.1.20
                       │
                      :443
                       │
          ┌────────────┼────────────┐
          │            │            │
          ▼            ▼            ▼
       Client A     Client B     Client C
        :50000       :50001       :50002
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是服务器能够同时接受大量连接的基础之一。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP 状态&lt;/h1&gt;
&lt;p&gt;TCP 是有状态协议。&lt;/p&gt;
&lt;p&gt;一个连接在生命周期中会经历不同状态，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;LISTEN
SYN-SENT
SYN-RECEIVED
ESTABLISHED
FIN-WAIT-1
FIN-WAIT-2
CLOSE-WAIT
CLOSING
LAST-ACK
TIME-WAIT
CLOSED
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最重要的可以先掌握：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;LISTEN
↓
等待连接

SYN-SENT / SYN-RECEIVED
↓
建立连接

ESTABLISHED
↓
正常通信

FIN-WAIT / CLOSE-WAIT 等
↓
连接关闭过程

TIME-WAIT
↓
关闭后的特定状态
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -tan
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看 TCP 连接状态。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;LISTEN 是什么&lt;/h1&gt;
&lt;p&gt;服务器程序启动 TCP 服务后，通常会：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;创建 Socket
   ↓
绑定 IP / Port
   ↓
进入 LISTEN
   ↓
等待客户端连接
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以简单表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
    │
    ▼
Socket
    │
    ▼
LISTEN
    │
    ▼
等待 SYN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.0.0.0:80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示某个程序正在监听 TCP 80 端口，并等待连接。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;ESTABLISHED&lt;/h1&gt;
&lt;p&gt;建立连接之后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client
   │
   ▼
Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;双方进入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ESTABLISHED
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示 TCP 连接已经建立，可以进行正常数据传输。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -tan
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ESTAB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Established&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;的缩写。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;TIME_WAIT&lt;/h1&gt;
&lt;p&gt;TCP 连接关闭后，主动关闭的一方可能进入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TIME_WAIT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这并不是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“程序还在运行”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它属于 TCP 连接管理机制的一部分。&lt;/p&gt;
&lt;p&gt;其重要目的之一是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;确保网络中旧的延迟报文不会干扰后续新的连接
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并确保必要的 ACK 重传机制能够正常工作。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TIME_WAIT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;本身并不等于故障。&lt;/p&gt;
&lt;p&gt;在高并发服务器中，如果大量连接同时关闭，可能看到大量：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TIME_WAIT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时应该结合实际连接模式和系统资源进行分析，而不是看到它就认为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“TCP 出问题了”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP 与应用层&lt;/h1&gt;
&lt;p&gt;现在可以把 TCP 放回整个协议栈：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用层
│
├── HTTP
├── SSH
├── DNS
└── ...
      │
      ▼
传输层
│
├── TCP
└── UDP
      │
      ▼
网际层
│
├── IPv4
└── IPv6
      │
      ▼
网络接口层
│
└── Ethernet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以粗略理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
 ↓
TCP
 ↓
IP
 ↓
Ethernet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每一层负责不同的问题。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;一次 TCP 通信的完整过程&lt;/h1&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;客户端
192.168.1.10

服务器
192.168.1.20:80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;客户端访问服务器。&lt;/p&gt;
&lt;p&gt;完整流程可以简化成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  Application
                      │
                      │ HTTP
                      ▼
                    TCP
                      │
                Three-Way
                Handshake
                      │
                      ▼
               TCP Connection
                      │
                      ▼
                   IP Packet
                      │
                      ▼
              Ethernet Frame
                      │
                      ▼
                    网络
                      │
                      ▼
                  服务器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果建立连接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SYN
 ↓
SYN + ACK
 ↓
ACK
 ↓
Established
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后开始传输：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application Data
 ↓
TCP Segment
 ↓
IP Packet
 ↓
Ethernet Frame
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;服务器收到后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet
 ↓
IP
 ↓
TCP
 ↓
Port 80
 ↓
HTTP Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样一个 HTTP 请求最终才能到达：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;具体的服务器进程
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;UDP 通信&lt;/h1&gt;
&lt;p&gt;UDP 会简单很多。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client
192.168.1.10:50000

Server
192.168.1.20:53
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;客户端发送 DNS 查询。&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application Data
      │
      ▼
UDP Datagram
      │
      ▼
IP Packet
      │
      ▼
Ethernet Frame
      │
      ▼
Network
      │
      ▼
Server :53
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP Three-Way Handshake
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也没有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP Connection State
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种连接管理机制。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;传输层的整体认知模型&lt;/h1&gt;
&lt;p&gt;现在可以把这一层浓缩成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                       传输层
                          │
             ┌────────────┴────────────┐
             │                         │
             ▼                         ▼
            TCP                       UDP
             │                         │
      ┌──────┼──────┐                  │
      │      │      │                  │
      ▼      ▼      ▼                  ▼
    连接   可靠性  拥塞控制          数据报
      │      │      │                  │
      │      │      ├── Flow Control   │
      │      │      └── Congestion     │
      │      │                         │
      ▼      ▼                         ▼
  Sequence  ACK                     Port
  Number    Retransmission             │
      │      │                         │
      └──────┴──────────┬──────────────┘
                        ▼
                      Socket
                        │
                        ▼
                     IP Layer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以进一步浓缩成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP
↓
哪台主机

Port
↓
哪个服务 / 通信端点

TCP
↓
可靠的字节流通信

UDP
↓
简单的数据报通信
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而 TCP 的核心机制：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;连接
 ↓
序列号
 ↓
确认
 ↓
重传
 ↓
滑动窗口
 ↓
流量控制
 ↓
拥塞控制
 ↓
连接关闭
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;共同构成了 TCP 的可靠传输体系。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;常见传输层排障思路&lt;/h1&gt;
&lt;p&gt;当出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“网络通，但是服务访问不了”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不能只检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ping
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ping
↓
主要验证 IP 层连通性
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而服务访问还需要检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP / UDP
+
Port
+
Application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以形成这样的排障层次：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用层
  ↓
服务是否正常？

传输层
  ↓
端口是否监听？
连接是否建立？

网际层
  ↓
IP 是否可达？
路由是否正确？

网络接口层
  ↓
网卡 / 链路是否正常？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -lnt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以查看 TCP 监听端口。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -nt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以查看 TCP 连接。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -lun
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以查看 UDP Socket。&lt;/p&gt;
&lt;p&gt;这比单纯执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ping server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;能提供更具体的信息。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP/IP 四层模型中的传输层&lt;/h1&gt;
&lt;p&gt;到这里，可以把四层模型完整串起来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────────────────────┐
│          应用层              │
│   HTTP / DNS / SSH / ...      │
└──────────────┬───────────────┘
               │
               ▼
┌──────────────────────────────┐
│          传输层              │
│        TCP / UDP             │
│        Port / Socket         │
└──────────────┬───────────────┘
               │
               ▼
┌──────────────────────────────┐
│          网际层              │
│    IPv4 / IPv6 / Routing     │
│        ICMP / ARP            │
└──────────────┬───────────────┘
               │
               ▼
┌──────────────────────────────┐
│        网络接口层            │
│ Ethernet / MAC / Frame / NIC │
└──────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以把每一层的问题分别概括成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络接口层
↓
怎么在当前链路上传输？

网际层
↓
数据应该到哪个 IP？

传输层
↓
应该交给哪个端口？
如何传输？

应用层
↓
具体业务数据是什么？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;传输层是连接“网络”和“应用”的关键一层。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它把：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机之间的 IP 通信
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进一步变成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;进程之间的网络通信
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
↓
可靠、有序、面向连接的字节流

UDP
↓
简单、无连接的数据报
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是 TCP/IP 四层模型中传输层最核心的内容。&lt;/p&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc9293&quot;&gt;RFC 9293 — Transmission Control Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc768&quot;&gt;RFC 768 — User Datagram Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml&quot;&gt;IANA Service Name and Transport Protocol Port Number Registry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man7/socket.7.html&quot;&gt;Linux Socket Interface — socket(7)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>网络：网际层</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%BD%91%E7%BB%9C%E7%BD%91%E9%99%85%E5%B1%82/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%BD%91%E7%BB%9C%E7%BD%91%E9%99%85%E5%B1%82/</guid><pubDate>Sun, 13 Sep 2026 08:58:25 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;在 TCP/IP 四层模型中，网际层负责在不同网络之间传递数据，并通过 IP 地址和路由机制实现跨网络通信。&lt;/p&gt;
&lt;p&gt;这一层最核心的概念包括 &lt;strong&gt;IP、IPv4、IPv6、IP 地址、子网、CIDR、路由、下一跳、ICMP 以及 ARP&lt;/strong&gt;。理解这些概念之后，才能真正弄清楚数据包为什么知道“去哪里”、下一跳又是谁。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;网际层是什么&lt;/h1&gt;
&lt;p&gt;TCP/IP 四层模型可以简单表示为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌────────────────────┐
│      应用层        │
├────────────────────┤
│      传输层        │
├────────────────────┤
│      网际层        │
├────────────────────┤
│    网络接口层      │
└────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;前一篇介绍了网络接口层，主要关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet
MAC
Frame
网卡
交换机
物理介质
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而网际层进一步解决：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;数据应该发往哪个网络，以及如何从当前网络到达目标网络。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络接口层
↓
负责当前链路上的传输

网际层
↓
负责跨网络寻址与转发
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机 A
192.168.1.10
    │
    ▼
路由器
    │
    ▼
网络 B
    │
    ▼
主机 B
192.168.2.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10
        ↓
      源 IP

192.168.2.20
        ↓
      目标 IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;网际层根据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;目标 IP
+
路由表
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;决定数据应该往哪里转发。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;IP&lt;/h1&gt;
&lt;h2&gt;什么是 IP&lt;/h2&gt;
&lt;p&gt;IP（Internet Protocol）是 TCP/IP 网络体系中的核心网际层协议。&lt;/p&gt;
&lt;p&gt;它提供一种：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;跨网络传输数据报的统一寻址和转发机制。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;IP 的核心目标不是保证：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;一定送达
一定按顺序到达
一定不重复
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是提供：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;寻址
分组
转发
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些基本能力。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IP 本身并不提供可靠传输。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可靠传输等机制由更上层的协议负责，例如 TCP。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;IP Packet&lt;/h2&gt;
&lt;p&gt;网际层传输的基本数据单位通常称为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IP Packet（IP 数据包）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用数据
   ↓
传输层数据
   ↓
IP Packet
   ↓
Ethernet Frame
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此数据在协议栈中的封装关系可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application Data
       ↓
TCP Segment / UDP Datagram
       ↓
IP Packet
       ↓
Ethernet Frame
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;本文重点关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP Packet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这一层。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;IPv4&lt;/h1&gt;
&lt;h2&gt;IPv4 是什么&lt;/h2&gt;
&lt;p&gt;IPv4 是目前仍然广泛使用的 Internet Protocol 版本。&lt;/p&gt;
&lt;p&gt;IPv4 地址长度为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;32 bit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通常写成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是四个十进制数字：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192 . 168 . 1 . 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每一部分称为一个：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Octet（八位组）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;每个八位组：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;8 bit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;4 × 8 bit
=
32 bit
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;IPv4 地址的二进制形式&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以表示成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;11000000.10101000.00000001.00001010
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;虽然平时通常使用十进制表示，但理解二进制非常重要，因为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;子网掩码
CIDR
网络地址
广播地址
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都与位运算密切相关。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;IPv4 地址结构&lt;/h1&gt;
&lt;p&gt;一个 IPv4 地址并不是简单的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“一个数字”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在实际网络中，它通常可以拆分为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络部分
+
主机部分
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络部分
192.168.1

主机部分
10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP 地址
   │
   ├── Network
   └── Host
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中具体有多少位属于网络部分，由：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;子网掩码
CIDR 前缀长度
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;决定。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;子网掩码&lt;/h1&gt;
&lt;h2&gt;什么是 Subnet Mask&lt;/h2&gt;
&lt;p&gt;IPv4 中经常看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;255.255.255.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样的子网掩码。&lt;/p&gt;
&lt;p&gt;它用于区分：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络部分
主机部分
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP：
192.168.1.10

Mask：
255.255.255.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;转换成二进制：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP
11000000.10101000.00000001.00001010

Mask
11111111.11111111.11111111.00000000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;前 24 bit
↓
网络部分

后 8 bit
↓
主机部分
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;CIDR&lt;/h1&gt;
&lt;h2&gt;什么是 CIDR&lt;/h2&gt;
&lt;p&gt;CIDR（Classless Inter-Domain Routing）使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后面的数字表示网络前缀长度。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;前 24 bit 属于网络前缀。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对应：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;255.255.255.0
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;常见 CIDR&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/8
/16
/24
/25
/26
/27
/28
/30
/32
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都可能在实际网络中出现。&lt;/p&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;8 bit 网络前缀
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;24 bit 网络前缀
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;前缀越长：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络部分越大
主机空间越小
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;前缀越短：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络部分越小
主机空间越大
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;网络地址&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其网络部分是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此对应的网络地址是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.0/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;代表这个子网本身。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;广播地址&lt;/h2&gt;
&lt;p&gt;对于 IPv4 广播型网络：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.0/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对应广播地址通常为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.255
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;前 24 bit
↓
网络部分

后 8 bit
↓
主机部分
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将所有主机位设置为 &lt;code&gt;1&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;11111111
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;255
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络地址
192.168.1.0

广播地址
192.168.1.255
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;主机地址范围&lt;/h2&gt;
&lt;p&gt;对于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.0/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;传统 IPv4 子网划分中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络地址
192.168.1.0

可用主机地址
192.168.1.1
~
192.168.1.254

广播地址
192.168.1.255
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此共有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2^8 = 256
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;个地址。&lt;/p&gt;
&lt;p&gt;通常有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;256
-
2
=
254
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;个传统意义上的可用主机地址。&lt;/p&gt;
&lt;p&gt;不过现代 IPv4 网络还有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/31
/32
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等特殊使用方式，因此不能把：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“减 2”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当成所有 CIDR 前缀的绝对规则。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;子网划分&lt;/h1&gt;
&lt;h2&gt;为什么需要子网&lt;/h2&gt;
&lt;p&gt;如果一个网络包含大量主机：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host 1
Host 2
Host 3
...
Host 5000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;全部放在一个网段中可能并不合理。&lt;/p&gt;
&lt;p&gt;可以进行子网划分：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;大网络
   │
   ├── 子网 A
   ├── 子网 B
   ├── 子网 C
   └── 子网 D
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;控制地址范围
划分网络边界
减少广播域规模
便于路由
便于网络管理
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;子网划分示例&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.0/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要划分成两个子网。&lt;/p&gt;
&lt;p&gt;可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/25
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.0/25
192.168.1.128/25
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一个：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.0
~
192.168.1.127
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第二个：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.128
~
192.168.1.255
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.0/24
       │
       ├── 192.168.1.0/25
       │
       └── 192.168.1.128/25
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;私有 IPv4 地址&lt;/h1&gt;
&lt;p&gt;RFC 1918 定义了用于私有网络的 IPv4 地址空间：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10.0.0.0/8

172.16.0.0/12

192.168.0.0/16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些地址通常用于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;家庭局域网
企业内网
数据中心内部网络
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就是常见的私有 IPv4 地址。&lt;/p&gt;
&lt;p&gt;私有地址本身不能作为公网 Internet 中的普通全局可路由地址使用。&lt;/p&gt;
&lt;p&gt;RFC 1918 对这些地址空间进行了定义：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc1918&quot;&gt;RFC 1918 — Address Allocation for Private Internets&lt;/a&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;公有 IP 与私有 IP&lt;/h1&gt;
&lt;p&gt;可以简单区分：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Private IP
↓
用于私有网络

Public IP
↓
可在 Internet 公共网络中进行全局寻址
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如家庭网络：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;电脑
192.168.1.10
   │
   ▼
路由器
   │
   ▼
公网 IP
   │
   ▼
Internet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是私有地址。&lt;/p&gt;
&lt;p&gt;而路由器外部接口可能具有公网地址。&lt;/p&gt;
&lt;p&gt;这也是后续学习：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NAT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的重要基础。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;IPv4 首部&lt;/h1&gt;
&lt;p&gt;一个 IPv4 Packet 可以简化理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌───────────────────────────┐
│ IPv4 Header               │
├───────────────────────────┤
│                           │
│ Payload                   │
│                           │
└───────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPv4 首部包含很多字段，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Version
IHL
Total Length
Identification
Flags
Fragment Offset
TTL
Protocol
Header Checksum
Source Address
Destination Address
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中比较重要的有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Source Address
Destination Address
TTL
Protocol
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Source Address&lt;/h2&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;数据包的源 IPv4 地址。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Destination Address&lt;/h2&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;数据包的目标 IPv4 地址。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;8.8.8.8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Source
↓
192.168.1.10

Destination
↓
8.8.8.8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这构成了 IP 寻址的核心。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;TTL&lt;/h2&gt;
&lt;p&gt;TTL（Time To Live）用于限制 IPv4 数据包可以经过的路由跳数。&lt;/p&gt;
&lt;p&gt;每经过一个路由器，TTL 通常会：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;减 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TTL = 64
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;经过一个三层转发设备后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TTL = 63
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果最终变成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据包不能继续正常转发。&lt;/p&gt;
&lt;p&gt;这样可以防止由于错误路由造成的数据包无限循环。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Protocol&lt;/h2&gt;
&lt;p&gt;IPv4 首部中的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Protocol
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用于标识 Payload 中承载的上层协议。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
UDP
ICMP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP Packet
 │
 ├── Protocol = TCP
 │
 └── Payload = TCP Segment
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是说，IP 不需要理解 TCP 的具体内容，只需要知道：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Payload 是什么类型
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即可交给对应的上层协议处理。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;IPv6&lt;/h1&gt;
&lt;h2&gt;为什么需要 IPv6&lt;/h2&gt;
&lt;p&gt;IPv4 地址只有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;32 bit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPv6 则使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;128 bit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此可提供巨大的地址空间。&lt;/p&gt;
&lt;p&gt;IPv6 地址通常写成十六进制，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2001:db8::1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个 IPv6 地址由：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;128 bit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;组成。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;IPv6 地址表示&lt;/h2&gt;
&lt;p&gt;例如完整形式：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2001:0db8:0000:0000:0000:0000:0000:0001
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以压缩成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2001:db8::1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;压缩规则允许：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;连续的全 0 分组
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;::
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2001:0db8:0000:0000:0000:0000:0000:0001
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以写成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2001:db8::1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPv6 地址和文本表示方法由 RFC 4291、RFC 5952 等标准定义。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;IPv6 地址类型&lt;/h1&gt;
&lt;p&gt;IPv6 中常见的地址类型包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Unicast
Multicast
Anycast
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;与 IPv4 广播不同：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IPv6 没有传统意义上的广播地址。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;需要向多个主机发送时，IPv6 使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Multicast
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等机制。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;IPv6 首部&lt;/h1&gt;
&lt;p&gt;IPv6 首部相比 IPv4 有明显不同。&lt;/p&gt;
&lt;p&gt;可以简化表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌───────────────────────────┐
│ IPv6 Header               │
├───────────────────────────┤
│                           │
│ Payload                   │
│                           │
└───────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;核心字段包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Version
Traffic Class
Flow Label
Payload Length
Next Header
Hop Limit
Source Address
Destination Address
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Hop Limit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以理解成 IPv4 中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TTL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;类似的跳数限制机制。&lt;/p&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Next Header
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;承担类似于 IPv4 &lt;code&gt;Protocol&lt;/code&gt; 字段的一部分作用，用于指示后续头部或上层协议。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;IPv4 与 IPv6&lt;/h1&gt;
&lt;p&gt;可以简单对比：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;IPv4&lt;/th&gt;
&lt;th&gt;IPv6&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;地址长度&lt;/td&gt;
&lt;td&gt;32 bit&lt;/td&gt;
&lt;td&gt;128 bit&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;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;极大&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;地址发现&lt;/td&gt;
&lt;td&gt;ARP 等&lt;/td&gt;
&lt;td&gt;NDP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TTL 类字段&lt;/td&gt;
&lt;td&gt;TTL&lt;/td&gt;
&lt;td&gt;Hop Limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;首部校验和&lt;/td&gt;
&lt;td&gt;IPv4 Header Checksum&lt;/td&gt;
&lt;td&gt;基本首部不提供同样的 Header Checksum&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IPv4
↓
历史悠久，部署广泛

IPv6
↓
更大的地址空间
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;路由&lt;/h1&gt;
&lt;h2&gt;什么是 Routing&lt;/h2&gt;
&lt;p&gt;有了 IP 地址之后，还需要解决一个问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;数据包应该经过哪条路径？&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Routing（路由）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机 A
192.168.1.10
   │
   ▼
路由器 R1
   │
   ▼
路由器 R2
   │
   ▼
主机 B
192.168.3.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从 A 的角度：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;目标
192.168.3.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不在本地网络中。&lt;/p&gt;
&lt;p&gt;于是 A 需要根据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Routing Table
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;决定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;下一跳
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;路由表&lt;/h1&gt;
&lt;p&gt;路由器以及主机本身都可能拥有路由表。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Destination        Gateway         Dev
192.168.1.0/24     on-link         eth0
192.168.2.0/24     192.168.1.1     eth0
0.0.0.0/0          192.168.1.1     eth0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;目标网络
    ↓
下一跳
    ↓
出口接口
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Linux 中可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ip route
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看路由表。&lt;/p&gt;
&lt;p&gt;后续 Linux 网络管理文章中会详细介绍：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ip route
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及实际路由配置。&lt;/p&gt;
&lt;p&gt;本文主要关注协议原理。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;默认路由&lt;/h1&gt;
&lt;p&gt;路由表中经常看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.0.0.0/0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它表示：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;匹配任意 IPv4 目标地址的默认路由。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.0.0.0/0 via 192.168.1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;如果没有更具体的路由
        ↓
把数据交给
192.168.1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;已知具体路径
↓
使用更具体路由

没有匹配
↓
使用默认路由
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;最长前缀匹配&lt;/h1&gt;
&lt;p&gt;路由表可能同时存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10.0.0.0/8
10.1.0.0/16
10.1.2.0/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果目标是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10.1.2.50
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么三个路由都可能匹配。&lt;/p&gt;
&lt;p&gt;此时使用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;最长前缀匹配（Longest Prefix Match）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;即选择：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更具体。&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;多个路由匹配
      │
      ▼
比较前缀长度
      │
      ▼
选择最长前缀
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这正是 CIDR 和现代 IP 路由紧密结合的重要原因。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;下一跳&lt;/h1&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机 A
192.168.1.10

目标 B
192.168.3.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A 的路由表可能认为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.3.0/24
   ↓
下一跳 192.168.1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;最终目标
↓
192.168.3.20

当前下一跳
↓
192.168.1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这两个概念不能混淆。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;路由解决“下一步往哪里走”，而不是要求每一台设备提前知道完整的端到端路径。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;ARP&lt;/h1&gt;
&lt;h2&gt;ARP 是什么&lt;/h2&gt;
&lt;p&gt;网络接口层负责同一链路上的通信，常见概念包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet
MAC
Frame
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在再来看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就会遇到一个问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;我知道下一跳 IP
↓
但不知道下一跳 MAC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPv4 网络中，这就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ARP（Address Resolution Protocol）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所解决的问题。&lt;/p&gt;
&lt;p&gt;RFC 826 对 ARP 的核心作用进行了定义：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;将协议地址转换为本地网络地址。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.1
      ↓
ARP
      ↓
AA:BB:CC:DD:EE:FF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP 地址
   ↓
ARP
   ↓
MAC 地址
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;ARP Request&lt;/h2&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A
IP  = 192.168.1.10
MAC = AA:AA:AA:AA:AA:AA

B
IP  = 192.168.1.20
MAC = BB:BB:BB:BB:BB:BB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A 想知道：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对应的 MAC。&lt;/p&gt;
&lt;p&gt;A 发送 ARP Request：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;谁是 192.168.1.20？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;由于目标 MAC 尚未知，请求通常发送到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ff:ff:ff:ff:ff:ff
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是 Ethernet 广播地址。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;ARP Reply&lt;/h2&gt;
&lt;p&gt;B 收到 ARP Request 后发现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Target IP
=
192.168.1.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正是自己。&lt;/p&gt;
&lt;p&gt;于是返回：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.20
↓
BB:BB:BB:BB:BB:BB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A 得到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP → MAC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的映射。&lt;/p&gt;
&lt;p&gt;随后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP Packet
↓
Ethernet Frame
↓
Destination MAC = BB:BB:BB:BB:BB:BB
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;ARP Cache&lt;/h2&gt;
&lt;p&gt;主机不会每发送一个 IP Packet 就重新进行 ARP。&lt;/p&gt;
&lt;p&gt;通常会暂时缓存：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP
↓
MAC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;映射。&lt;/p&gt;
&lt;p&gt;Linux 中可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ip neigh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看邻居信息。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.1 dev eth0 lladdr aa:bb:cc:dd:ee:ff REACHABLE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.1
        ↓
aa:bb:cc:dd:ee:ff
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;为什么远程目标不是直接 ARP&lt;/h1&gt;
&lt;p&gt;这是理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ARP
+
路由
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关系的关键。&lt;/p&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机 A
192.168.1.10/24

目标 B
192.168.2.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A 看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.2.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不属于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.0/24
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此它不会直接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ARP 192.168.2.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;目标 IP
   ↓
查路由
   ↓
找到下一跳
192.168.1.1
   ↓
ARP
   ↓
192.168.1.1 的 MAC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet Frame
Dst MAC = 网关 MAC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发给路由器。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ARP 解析的是当前链路上的下一跳，而不是一定解析最终目标主机。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;路由器如何转发 IP Packet&lt;/h1&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A
192.168.1.10
   │
   ▼
R1
   │
   ▼
R2
   │
   ▼
B
192.168.3.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A 首先：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;目标 = 192.168.3.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查自己的路由表：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;下一跳 = R1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ARP
↓
R1 MAC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;封装成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet Frame
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发送给 R1。&lt;/p&gt;
&lt;p&gt;R1 收到后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;剥离链路层封装
        ↓
读取 IP Packet
        ↓
检查目标 IP
        ↓
查路由表
        ↓
确定下一跳
        ↓
重新封装新的链路层帧
        ↓
发送
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是说：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A → R1
R1 → R2
R2 → B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每一跳都可能重新进行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;链路层封装
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但 IP Packet 继续承担：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;端到端目标
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;IP 与 MAC 的关系&lt;/h1&gt;
&lt;p&gt;现在可以把：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP
MAC
ARP
Ethernet
Routing
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之间的关系串起来。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                目标 IP
                   │
                   ▼
                路由表
                   │
                   ▼
                 下一跳 IP
                   │
                   ▼
                  ARP
                   │
                   ▼
                 下一跳 MAC
                   │
                   ▼
            Ethernet Frame
                   │
                   ▼
                 发送
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP
↓
三层寻址

MAC
↓
当前链路寻址

ARP
↓
IPv4 下一跳 IP → MAC

Ethernet
↓
当前链路上的帧传输

Routing
↓
决定下一跳
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;ICMP&lt;/h1&gt;
&lt;h2&gt;什么是 ICMP&lt;/h2&gt;
&lt;p&gt;ICMP（Internet Control Message Protocol）是与 IP 配套的重要控制协议。&lt;/p&gt;
&lt;p&gt;它主要用于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;错误报告
诊断
网络控制信息
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是用来承载普通应用数据。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用数据
↓
TCP / UDP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络控制与诊断
↓
ICMP
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;ping&lt;/h2&gt;
&lt;p&gt;最熟悉的 ICMP 使用场景就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ping 192.168.1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPv4 中通常使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ICMP Echo Request
ICMP Echo Reply
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;过程可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A
 │
 │ Echo Request
 ▼
B
 │
 │ Echo Reply
 ▼
A
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;ping&lt;/code&gt; 能够帮助判断目标是否能够在 IP 层面进行基本的连通性响应。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;但：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ping 通并不意味着应用服务一定正常。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ICMP 可以通信
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不代表：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP 80 一定开放
HTTP 服务一定正常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为它们属于不同层次。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;ICMP 错误消息&lt;/h1&gt;
&lt;p&gt;ICMP 还可以用于通知网络错误。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;目标不可达
TTL 超时
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等。&lt;/p&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Destination Unreachable
Time Exceeded
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都是常见的 ICMP 消息类型。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据包
   ↓
经过多个路由器
   ↓
TTL 不断减少
   ↓
TTL = 0
   ↓
路由器丢弃数据包
   ↓
发送 ICMP Time Exceeded
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;traceroute
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等工具能够工作的基础之一。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;IP 并不可靠&lt;/h1&gt;
&lt;p&gt;到这里可以进一步理解 IP 的设计思想。&lt;/p&gt;
&lt;p&gt;IP 提供的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Best Effort
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;尽力而为的数据报服务。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它不保证：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;一定到达
一定按顺序到达
一定只到达一次
一定不会丢包
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Packet A
Packet B
Packet C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;理论上可能出现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;B
A
C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A
C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可能丢失。&lt;/p&gt;
&lt;p&gt;因此可靠传输通常由：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样的传输层协议提供。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;IPv4 分片&lt;/h1&gt;
&lt;p&gt;IPv4 数据包可能遇到：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;MTU（Maximum Transmission Unit）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;限制。&lt;/p&gt;
&lt;p&gt;例如某条链路能够承载的最大 IP 数据包长度有限。&lt;/p&gt;
&lt;p&gt;如果一个 IPv4 Packet 太大：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Packet
   │
   ▼
超过下一链路 MTU
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在满足条件时，IPv4 可以进行：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fragmentation（分片）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以简单理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;原始 Packet
     │
     ▼
┌────┬────┬────┐
│ F1 │ F2 │ F3 │
└────┴────┴────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;到达目的地后，再进行重组。&lt;/p&gt;
&lt;p&gt;IPv4 首部中的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Identification
Flags
Fragment Offset
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等字段与分片有关。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;IPv6 与分片&lt;/h1&gt;
&lt;p&gt;IPv6 的分片机制与 IPv4 不同。&lt;/p&gt;
&lt;p&gt;IPv6 路由器不会像 IPv4 那样在转发过程中随意对数据包进行分片。&lt;/p&gt;
&lt;p&gt;如果需要分片，通常由发送端通过：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Fragment Extension Header
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进行处理。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IPv4
↓
路由器可能进行分片

IPv6
↓
通常由发送端处理分片
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也是 IPv4 和 IPv6 设计上的重要区别之一。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;网际层的完整通信模型&lt;/h1&gt;
&lt;p&gt;现在可以把前面的概念全部串起来。&lt;/p&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机 A
192.168.1.10/24

目标 B
192.168.3.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A 想向 B 发送数据。&lt;/p&gt;
&lt;p&gt;完整过程可以简化为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用数据
   │
   ▼
传输层数据
   │
   ▼
IPv4 Packet
   │
   │ Destination = 192.168.3.20
   ▼
查询路由表
   │
   ▼
发现目标不在本地网络
   │
   ▼
选择下一跳
   │
   ▼
例如 192.168.1.1
   │
   ▼
ARP 查询
   │
   ▼
得到网关 MAC
   │
   ▼
Ethernet Frame
   │
   ▼
交换机
   │
   ▼
路由器
   │
   ▼
重新进行路由判断
   │
   ▼
下一跳
   │
   ▼
……
   │
   ▼
目标网络
   │
   ▼
主机 B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里真正值得注意的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet
↓
负责一跳

IP
↓
负责跨网络寻址

Routing
↓
决定下一跳

ARP
↓
IPv4 下一跳 IP → MAC

ICMP
↓
网络控制与诊断
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;网络接口层与网际层&lt;/h1&gt;
&lt;p&gt;现在可以把前两层放在一起理解。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────────────────────┐
│          网际层              │
│                              │
│   IP / IPv4 / IPv6           │
│   Routing / ICMP             │
│                              │
└──────────────┬───────────────┘
               │
               ▼
┌──────────────────────────────┐
│        网络接口层            │
│                              │
│   Ethernet / MAC / Frame     │
│   NIC / 双绞线 / 光纤 / Wi-Fi │
│                              │
└──────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以从两个问题来理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网际层
↓
“数据应该去哪个网络、哪个 IP？”

网络接口层
↓
“这一跳应该通过哪个链路、哪个接口发送？”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;和：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MAC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最核心的区别。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;网际层的整体模型&lt;/h1&gt;
&lt;p&gt;最后可以将这一层浓缩成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                       网际层
                          │
        ┌─────────────────┼─────────────────┐
        │                 │                 │
        ▼                 ▼                 ▼
       IP              Routing             ICMP
        │                 │                 │
   ┌────┴────┐            │            诊断 / 控制
   │         │            │
 IPv4      IPv6           │
   │         │            │
   │      128 bit         │
 32 bit                     │
   │                        │
   └──────────┬─────────────┘
              │
              ▼
           IP Packet
              │
              ▼
        下一跳 IP / 路由
              │
              ▼
             ARP
              │
              ▼
         下一跳 MAC
              │
              ▼
       Ethernet Frame
              │
              ▼
        网络接口层
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此，网际层最核心的一条逻辑链可以浓缩成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;目标 IP
   ↓
判断是否本地网络
   ↓
查路由表
   ↓
确定下一跳
   ↓
IPv4 场景下通过 ARP 获取下一跳 MAC
   ↓
交给网络接口层
   ↓
发送 Ethernet Frame
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而在跨网络通信中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP Packet
   ↓
Router
   ↓
重新查路由
   ↓
下一跳
   ↓
重新封装链路层帧
   ↓
继续转发
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IP 负责跨网络寻址，路由负责决定下一跳，链路层负责当前这一跳的实际传输。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;理解这一点之后，下一层的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
UDP
端口
连接
可靠传输
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就有了明确的基础。&lt;/p&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc791&quot;&gt;RFC 791 — Internet Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc8200&quot;&gt;RFC 8200 — IPv6 Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc1918&quot;&gt;RFC 1918 — Private Address Space&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc792&quot;&gt;RFC 792 — Internet Control Message Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc826&quot;&gt;RFC 826 — Address Resolution Protocol&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>网络：网络接口层</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%BD%91%E7%BB%9C%E7%BD%91%E7%BB%9C%E6%8E%A5%E5%8F%A3%E5%B1%82/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%BD%91%E7%BB%9C%E7%BD%91%E7%BB%9C%E6%8E%A5%E5%8F%A3%E5%B1%82/</guid><pubDate>Sun, 13 Sep 2026 07:48:07 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;在 TCP/IP 四层模型中，网络接口层负责让主机能够接入具体的网络，并在相邻节点之间传输数据。&lt;/p&gt;
&lt;p&gt;这一层关注的是最接近网络硬件的一部分：&lt;strong&gt;传输介质、网卡、以太网、MAC 地址、以太网帧以及交换机的基本工作方式&lt;/strong&gt;。理解这一层之后，才能进一步理解 IP 地址、子网和路由。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;网络接口层是什么&lt;/h1&gt;
&lt;p&gt;TCP/IP 四层模型可以简单表示为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌────────────────────┐
│      应用层        │
├────────────────────┤
│      传输层        │
├────────────────────┤
│      网际层        │
├────────────────────┤
│    网络接口层      │
└────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;网络接口层位于最底部，负责：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机
 ↓
接入具体网络
 ↓
通过网络介质传输数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它关注的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据如何真正进入网卡
        ↓
如何封装成链路层帧
        ↓
如何通过网线、光纤或无线介质发送
        ↓
如何被相邻设备接收
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此，这一层与硬件的关系最为密切。&lt;/p&gt;
&lt;p&gt;可以粗略理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网际层
   ↓
“我要把数据发往哪个 IP”
   ↓
网络接口层
   ↓
“这一跳通过什么介质、哪个接口、什么帧发出去”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;网络接口层不是某一个具体协议，而是 TCP/IP 模型中对主机本地网络接入相关机制的抽象。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在不同教材和资料中，这一层也可能被称为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Network Access Layer
Link Layer
网络接入层
链路层
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;本文主要使用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;网络接口层&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这一名称。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;网络通信为什么需要这一层&lt;/h2&gt;
&lt;p&gt;假设主机 A 要向主机 B 发送数据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机 A
  │
  ▼
网络
  │
  ▼
主机 B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上层协议最终会产生：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP Packet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但 IP Packet 本身不能直接通过网线传播。&lt;/p&gt;
&lt;p&gt;还需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP Packet
   ↓
封装
   ↓
链路层帧
   ↓
网卡
   ↓
物理介质
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此可以形成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用数据
   ↓
传输层数据
   ↓
IP 数据包
   ↓
Ethernet Frame
   ↓
网卡
   ↓
网线 / 光纤 / 无线
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;网络接口层真正关心的，就是最下面这部分。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;网络传输介质&lt;/h1&gt;
&lt;p&gt;网络数据最终必须通过某种介质进行传输。&lt;/p&gt;
&lt;p&gt;常见的有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;双绞线
光纤
无线电波
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以简单分为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;有线网络
├── 双绞线
└── 光纤

无线网络
└── 无线电波
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不同介质决定了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;传输距离
带宽
抗干扰能力
部署方式
成本
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等特性。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;双绞线&lt;/h2&gt;
&lt;p&gt;双绞线（Twisted Pair）是以太网中非常常见的传输介质。&lt;/p&gt;
&lt;p&gt;它由多对相互绞合的铜线组成。&lt;/p&gt;
&lt;p&gt;可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;两根铜线
  ╲╱
  ╱╲
  ╲╱
不断绞合
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之所以采用绞合结构，主要是为了降低电磁干扰以及改善传输特性。&lt;/p&gt;
&lt;p&gt;典型网线中通常包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;4 对双绞线
=
8 根导线
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如常见的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cat5e
Cat6
Cat6A
Cat7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等类别。&lt;/p&gt;
&lt;p&gt;这些类别对应不同的传输性能和布线要求。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;双绞线的分类&lt;/h2&gt;
&lt;p&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;Cat5e&lt;/td&gt;
&lt;td&gt;常见千兆以太网&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cat6&lt;/td&gt;
&lt;td&gt;家庭、办公网络&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cat6A&lt;/td&gt;
&lt;td&gt;更高性能的布线环境&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cat7&lt;/td&gt;
&lt;td&gt;更高等级的屏蔽布线场景&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cat8&lt;/td&gt;
&lt;td&gt;数据中心等更高带宽场景&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;不过：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;网线类别并不能简单等价成某一个固定速率。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;实际能够达到的速率还与：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;线缆
长度
接口
收发器
布线环境
连接器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等因素有关。&lt;/p&gt;
&lt;p&gt;因此不要简单记成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cat6 = 某个固定速度
Cat7 = 某个固定速度
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更合理的理解是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;线缆类别规定了相应的电气性能和传输能力，实际网络速率取决于整个链路。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;RJ45 与网络接口&lt;/h2&gt;
&lt;p&gt;我们日常说的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RJ45 网口
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通常指的是常见的 8P8C 模块化连接方式及其接口形态。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;电脑
 │
 ▼
┌─────────┐
│ RJ45口  │
└────┬────┘
     │
     │ 网线
     ▼
┌─────────┐
│ 交换机  │
└─────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“RJ45”在日常使用中经常被用来泛指以太网水晶头和网口，但严格的连接器术语与以太网电气标准并不是一回事。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在学习和实际运维中，理解其作为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;铜缆以太网物理连接
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即可。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;光纤&lt;/h1&gt;
&lt;p&gt;与双绞线不同，光纤使用光信号传输数据。&lt;/p&gt;
&lt;p&gt;可以简单表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;电信号
  ↓
光模块
  ↓
光信号
  ↓
光纤
  ↓
光模块
  ↓
电信号
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见的光纤可以分为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;单模光纤
多模光纤
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;单模光纤&lt;/h2&gt;
&lt;p&gt;单模光纤通常具有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;传输距离长
衰减较低
适合长距离通信
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此常见于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;运营商网络
数据中心互联
园区骨干
城域网络
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等场景。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;多模光纤&lt;/h2&gt;
&lt;p&gt;多模光纤通常用于较短距离的高速通信。&lt;/p&gt;
&lt;p&gt;常见于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;机房
数据中心
园区内部
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等环境。&lt;/p&gt;
&lt;hr /&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;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;很强&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;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;骨干、数据中心、长距离&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;hr /&gt;
&lt;h1&gt;无线介质&lt;/h1&gt;
&lt;p&gt;无线局域网不使用网线作为传输介质，而是利用无线电波进行通信。&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机
 │
 ▼
无线网卡
 │
 ▼
无线电波
 │
 ▼
无线接入点
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如 Wi-Fi。&lt;/p&gt;
&lt;p&gt;因此网络接口层并不意味着：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;必须插网线
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;主机通过某种具体的链路技术接入网络。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个“具体链路”可以是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet
Wi-Fi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等。&lt;/p&gt;
&lt;p&gt;不过本文重点放在最常见的&lt;strong&gt;有线以太网&lt;/strong&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;网卡与网络接口&lt;/h1&gt;
&lt;h2&gt;什么是网卡&lt;/h2&gt;
&lt;p&gt;主机需要通过：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NIC（Network Interface Controller）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;连接网络。&lt;/p&gt;
&lt;p&gt;日常通常直接称为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网卡
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机
 │
 ├── Ethernet 网卡
 ├── Wi-Fi 网卡
 └── 虚拟网卡
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Linux 中，这些网络接口最终会表现为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;eth0
ens33
enp0s3
wlan0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等网络设备。&lt;/p&gt;
&lt;p&gt;具体接口名称会根据发行版、系统配置以及设备命名规则不同而变化。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;网络接口不一定是物理网卡&lt;/h2&gt;
&lt;p&gt;现代 Linux 中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Network Interface
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不一定对应一块真实硬件。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;物理网卡
虚拟网卡
Bridge
VLAN Interface
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都可以表现为网络接口。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;网卡是硬件概念，而网络接口是操作系统中的抽象。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;物理硬件
   ↓
网络设备
   ↓
操作系统网络接口
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后续学习 Linux 网络管理时，会进一步介绍：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ip link
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等工具如何查看和管理这些接口。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;MAC 地址&lt;/h1&gt;
&lt;h2&gt;什么是 MAC 地址&lt;/h2&gt;
&lt;p&gt;以太网网络接口通常具有一个：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;MAC 地址&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;MAC（Media Access Control）地址是链路层使用的重要地址。&lt;/p&gt;
&lt;p&gt;常见的 48-bit Ethernet MAC 地址可以写成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;00:11:22:33:44:55
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以写成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;00-11-22-33-44-55
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;本质上都是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;48 bit
=
6 Byte
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;MAC 地址有什么作用&lt;/h2&gt;
&lt;p&gt;在局域网中，设备需要知道：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;这一帧应该交给哪个网络接口
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此以太网帧中包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Source MAC
Destination MAC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机 A
MAC = AA:AA:AA:AA:AA:AA

主机 B
MAC = BB:BB:BB:BB:BB:BB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A 发送给 B：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Source MAC
↓
AA:AA:AA:AA:AA:AA

Destination MAC
↓
BB:BB:BB:BB:BB:BB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样链路层设备就可以根据 MAC 地址处理该帧。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;MAC 地址并不是永久不变的硬件身份证&lt;/h2&gt;
&lt;p&gt;虽然很多物理网卡出厂时具有一个硬件地址，但操作系统通常可以修改接口使用的 MAC 地址。&lt;/p&gt;
&lt;p&gt;此外：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;虚拟机
容器
虚拟网络接口
无线设备
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;都可能使用人为生成或动态配置的 MAC 地址。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;MAC 地址更应该理解成网络接口在链路层使用的地址，而不是“设备永远不变的身份证”。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;Ethernet&lt;/h1&gt;
&lt;h2&gt;什么是 Ethernet&lt;/h2&gt;
&lt;p&gt;Ethernet（以太网）是现代局域网最常见的链路技术之一。&lt;/p&gt;
&lt;p&gt;IEEE 802.3 系列标准定义了以太网相关的 MAC 与物理层技术。&lt;/p&gt;
&lt;p&gt;可以简化为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;上层数据
   ↓
Ethernet Frame
   ↓
网卡
   ↓
双绞线 / 光纤
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在现代网络中，以太网已经不仅仅是一种“网线通信方式”。&lt;/p&gt;
&lt;p&gt;它包含：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MAC
Frame
Ethernet PHY
物理介质
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等多个方面。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Ethernet Frame&lt;/h1&gt;
&lt;h2&gt;为什么需要帧&lt;/h2&gt;
&lt;p&gt;上层得到的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP Packet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不能直接作为以太网介质上的传输单位。&lt;/p&gt;
&lt;p&gt;因此需要进行封装：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP Packet
   ↓
Ethernet Frame
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;以太网通过 Frame（帧）承载上层数据。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;Ethernet II 帧&lt;/h2&gt;
&lt;p&gt;常见 Ethernet II 帧可以简化表示为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────┬──────────────┬────────────┬──────────────┐
│ 目标 MAC     │ 源 MAC       │ EtherType  │ Payload      │
│ 6 Byte       │ 6 Byte       │ 2 Byte     │              │
└──────────────┴──────────────┴────────────┴──────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际以太网帧还存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FCS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等字段。&lt;/p&gt;
&lt;p&gt;可以更完整地表示为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌────────┬────────┬────────┬──────────────┬──────┐
│Dst MAC │Src MAC │Type    │Payload       │ FCS  │
└────────┴────────┴────────┴──────────────┴──────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Destination MAC&lt;/h2&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这一帧在当前链路上发送给哪个目标接口。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dst MAC = BB:BB:BB:BB:BB:BB
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Source MAC&lt;/h2&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这一帧由哪个接口发送。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Src MAC = AA:AA:AA:AA:AA:AA
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Source MAC
↓
谁发送

Destination MAC
↓
发给谁
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;EtherType&lt;/h2&gt;
&lt;p&gt;EtherType 用于标识：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Payload 中封装的上层协议类型。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IPv4
IPv6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等。&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet Frame
 │
 ├── MAC Header
 │
 ├── EtherType
 │      │
 │      ├── IPv4
 │      └── IPv6
 │
 └── Payload
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此同一种以太网技术能够承载不同的网络层协议。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Payload&lt;/h2&gt;
&lt;p&gt;Payload 就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;以太网帧真正承载的上层数据。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet Frame
   │
   ▼
IPv4 Packet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet Frame
   │
   ▼
IPv6 Packet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet
↓
负责在链路上承载上层数据
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;FCS&lt;/h2&gt;
&lt;p&gt;FCS（Frame Check Sequence）用于帧级错误检测。&lt;/p&gt;
&lt;p&gt;发送端：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据
 ↓
计算校验值
 ↓
FCS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接收端：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;收到帧
 ↓
重新检查
 ↓
判断是否出现传输错误
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;FCS 是链路层错误检测机制，不等于端到端可靠传输。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;MAC 地址的通信类型&lt;/h1&gt;
&lt;p&gt;MAC 地址除了普通的单播地址，还涉及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;单播
组播
广播
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;单播&lt;/h2&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;一个发送者
   ↓
一个目标
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A ─────────► B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Destination MAC 是某一个具体接口的地址。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;广播&lt;/h2&gt;
&lt;p&gt;以太网广播地址通常为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ff:ff:ff:ff:ff:ff
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表示：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;向当前广播域中的所有相关接口发送。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;           ┌── B
           │
A ──► Switch ── C
           │
           └── D
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;广播帧会被交换设备在对应广播域内传播。&lt;/p&gt;
&lt;p&gt;广播是后续理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;广播域
VLAN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等概念的重要基础。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;组播&lt;/h2&gt;
&lt;p&gt;组播表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;一个发送者
   ↓
一组接收者
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;与广播相比：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;广播
↓
所有设备

组播
↓
加入特定组的设备
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在后续学习 IPv4 / IPv6 组播时会进一步展开。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;交换机&lt;/h1&gt;
&lt;h2&gt;交换机做什么&lt;/h2&gt;
&lt;p&gt;交换机是局域网中非常常见的设备。&lt;/p&gt;
&lt;p&gt;传统 Ethernet LAN 中，交换机主要依据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Destination MAC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;决定帧从哪个端口发出。&lt;/p&gt;
&lt;p&gt;可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        ┌───────────┐
        │  Switch   │
        └─────┬─────┘
       ┌──────┼──────┐
       │      │      │
       ▼      ▼      ▼
      PC A   PC B   PC C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;交换机关注的核心对象之一就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;MAC 地址。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;MAC 地址表&lt;/h1&gt;
&lt;p&gt;交换机内部通常维护一张：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;MAC Address Table&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MAC Address         Port
AA:AA:AA:AA:AA:AA   1
BB:BB:BB:BB:BB:BB   2
CC:CC:CC:CC:CC:CC   3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是建立：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MAC
 ↓
Port
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的对应关系。&lt;/p&gt;
&lt;p&gt;因此收到一个帧后，可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Destination MAC
       ↓
查询 MAC Table
       ↓
找到对应端口
       ↓
转发
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;MAC 地址学习&lt;/h2&gt;
&lt;p&gt;交换机并不是一开始就知道所有设备在哪里。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PC A
MAC = AA
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Port 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进入交换机。&lt;/p&gt;
&lt;p&gt;交换机看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Source MAC = AA
Ingress Port = 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是可以学习：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;AA → Port 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;MAC Address Learning&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;随着网络通信不断发生，MAC 地址表会逐渐建立。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;已知单播&lt;/h2&gt;
&lt;p&gt;假设交换机已经知道：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BB → Port 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时收到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Destination MAC = BB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;交换机可以：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;查表
 ↓
Port 2
 ↓
只向 Port 2 转发
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此不会把帧发送到所有端口。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;未知单播&lt;/h2&gt;
&lt;p&gt;如果交换机暂时不知道：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Destination MAC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;位于哪个端口，那么可能会进行：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Flooding（泛洪）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以简单理解成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;未知目标
   │
   ▼
泛洪
   │
   ├── Port 1
   ├── Port 2
   └── Port 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;随后，如果目标主机产生响应，交换机就可以根据响应帧的 Source MAC 学习它的位置。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;广播域&lt;/h1&gt;
&lt;p&gt;理解交换机之后，还需要理解：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;广播域（Broadcast Domain）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;广播帧：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ff:ff:ff:ff:ff:ff
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不会无限传播到整个互联网。&lt;/p&gt;
&lt;p&gt;它通常只会在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;当前二层广播域
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;中传播。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;          Switch
       ┌────┼────┐
       │    │    │
       ▼    ▼    ▼
      A     B    C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 A 发送广播：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A
│
│ Broadcast
▼
Switch
│
├── B
└── C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;B、C 可以收到。&lt;/p&gt;
&lt;p&gt;但广播不会通过普通三层路由器直接转发到另一个广播域。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;交换网络中的广播范围是有限的。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;后续学习 VLAN 时，这个概念会非常重要。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Ethernet、MAC 与交换机之间的关系&lt;/h1&gt;
&lt;p&gt;到这里可以把几个概念串起来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;              Ethernet
                  │
          ┌───────┴───────┐
          │               │
          ▼               ▼
        Frame             MAC
          │               │
          └───────┬───────┘
                  ▼
               Switch
                  │
                  ▼
          MAC Address Table
                  │
                  ▼
              Port
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以从通信过程理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机 A
 │
 │ Ethernet Frame
 │
 │ Src MAC = A
 │ Dst MAC = B
 ▼
交换机
 │
 │ 查 MAC Table
 ▼
目标端口
 │
 ▼
主机 B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MAC
↓
标识链路层接口

Frame
↓
承载数据

Switch
↓
根据 MAC 处理帧

Port
↓
连接具体链路
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;一次完整的以太网通信&lt;/h1&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机 A
MAC = AA:AA:AA:AA:AA:AA

主机 B
MAC = BB:BB:BB:BB:BB:BB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A 要把一个 IP Packet 发送给 B。&lt;/p&gt;
&lt;p&gt;从网络接口层来看，可以简化成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;              IP Packet
                  │
                  ▼
         封装 Ethernet Frame
                  │
        ┌─────────┴─────────┐
        │                   │
        ▼                   ▼
   Src MAC = A         Dst MAC = B
        │
        ▼
      网卡
        │
        ▼
      双绞线
        │
        ▼
     交换机
        │
        │ 查 MAC 地址表
        ▼
     目标端口
        │
        ▼
      双绞线
        │
        ▼
      网卡 B
        │
        ▼
      接收 Frame
        │
        ▼
    取出 IP Packet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就可以看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;上层
↓
IP Packet

网络接口层
↓
Ethernet Frame

物理传输
↓
网卡 + 网线
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;一跳通信&lt;/h1&gt;
&lt;p&gt;网络接口层还有一个非常重要的概念：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;它主要负责相邻节点之间的通信。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A ── Switch ── B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A 发给 B：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A
↓
Switch
↓
B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是本地网络中的通信。&lt;/p&gt;
&lt;p&gt;但如果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A ── Router ── Router ── B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么 A 到 B 并不是一个单独的链路层通信。&lt;/p&gt;
&lt;p&gt;可以理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A → Router 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是一跳；&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Router 1 → Router 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;又是一跳；&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Router 2 → B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还是一跳。&lt;/p&gt;
&lt;p&gt;因此网络接口层主要关注：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;当前这一跳如何把数据交给相邻设备。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;至于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;最终应该走哪条路径
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;则属于网际层的职责。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;网络接口层与网际层的边界&lt;/h1&gt;
&lt;p&gt;这一点对于后续学习非常重要。&lt;/p&gt;
&lt;p&gt;可以先明确划分：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络接口层
│
├── 网卡
├── 双绞线
├── 光纤
├── Wi-Fi
├── Ethernet
├── MAC
├── Frame
└── Switch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网际层
│
├── IPv4
├── IPv6
├── IP 地址
├── 子网
├── CIDR
├── 路由
└── ICMP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;本文&lt;strong&gt;不展开&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ARP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也不讨论：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP 地址
子网
路由
默认网关
ICMP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为这些内容放到后面的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;网际层&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;会更加统一。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;从数据封装看网络接口层&lt;/h1&gt;
&lt;p&gt;把整个 TCP/IP 协议栈放在一起，可以看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用层
   │
   ▼
Application Data
   │
   ▼
传输层
   │
   ▼
TCP Segment / UDP Datagram
   │
   ▼
网际层
   │
   ▼
IP Packet
   │
   ▼
网络接口层
   │
   ▼
Ethernet Frame
   │
   ▼
Physical Medium
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;网络接口层解决的是“数据如何进入具体网络并通过当前链路传输”的问题。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它不负责决定整个互联网的路径。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;网络接口层的整体模型&lt;/h1&gt;
&lt;p&gt;现在可以把这一层浓缩成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    网络接口层
                         │
          ┌──────────────┼──────────────┐
          │              │              │
          ▼              ▼              ▼
       传输介质        网络接口        链路协议
          │              │              │
     ┌────┼────┐      ┌──┴──┐       ┌──┴─────┐
     │    │    │      │     │       │        │
   双绞线 光纤  Wi-Fi  网卡  MAC   Ethernet  Frame
                                           │
                                           ▼
                                        Switch
                                           │
                                           ▼
                                    MAC Address Table
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再进一步缩成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;数据
 ↓
Ethernet Frame
 ↓
网卡
 ↓
物理介质
 ↓
交换机
 ↓
相邻网络设备
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以，这一层最核心的几个概念可以概括为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;介质负责传输比特，网卡负责连接主机与网络，MAC 地址标识链路层接口，Ethernet Frame 承载上层数据，交换机根据 MAC 地址在局域网中转发帧。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;理解这些之后，再往上学习：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网际层
 ↓
IP
 ↓
子网
 ↓
CIDR
 ↓
路由
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就会知道：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP
↓
解决跨网络寻址

MAC
↓
解决当前链路上的交付

Ethernet Frame
↓
真正承载这一跳的数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也正是 TCP/IP 分层模型存在的意义：&lt;strong&gt;不同层负责不同范围的问题，并通过层与层之间的接口协同完成一次完整的网络通信。&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ieee802.org/3/&quot;&gt;IEEE 802.3 Ethernet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml&quot;&gt;IANA EtherTypes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc1122&quot;&gt;RFC 1122 — Requirements for Internet Hosts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Linux：进程与作业管理</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E8%BF%9B%E7%A8%8B%E4%B8%8E%E4%BD%9C%E4%B8%9A%E7%AE%A1%E7%90%86/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E8%BF%9B%E7%A8%8B%E4%B8%8E%E4%BD%9C%E4%B8%9A%E7%AE%A1%E7%90%86/</guid><description>进程是正在运行的程序实例。</description><pubDate>Sun, 13 Sep 2026 07:32:38 GMT</pubDate><content:encoded>&lt;p&gt;进程是正在运行的程序实例。管理进程的关键是确认身份和状态，选择合适的生命周期操作，再验证资源占用与业务是否恢复正常。&lt;/p&gt;
&lt;h1&gt;进程、线程与作业&lt;/h1&gt;
&lt;p&gt;进程拥有地址空间等资源，线程是进程内的执行单元，通常共享这些资源。PID 标识进程，PPID 指向父进程，TID 标识线程；标识可能被复用，操作前应核对启动时间与命令。&lt;/p&gt;
&lt;p&gt;Shell 的作业是它跟踪的一条命令或流水线，可以包含多个进程。&lt;code&gt;jobs&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;系统进程快照&lt;/td&gt;
&lt;td&gt;ps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;动态资源变化&lt;/td&gt;
&lt;td&gt;top、pidstat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;当前 Shell 的后台任务&lt;/td&gt;
&lt;td&gt;jobs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;systemd 管理的服务&lt;/td&gt;
&lt;td&gt;systemctl&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;一个进程内的线程&lt;/td&gt;
&lt;td&gt;ps -L、top -H&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;查找与观察进程&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;ps -eo pid,ppid,user,stat,etime,%cpu,%mem,args --sort=-%cpu
pgrep -a -x nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;pgrep -x&lt;/code&gt; 按进程名精确匹配；应用可能修改进程名，必要时再检查命令行、可执行文件与服务归属。&lt;code&gt;ps&lt;/code&gt; 的 CPU 百分比通常基于进程生命周期统计，与 top 的采样区间含义不同。&lt;/p&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;th&gt;判断方向&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;正在运行或等待 CPU&lt;/td&gt;
&lt;td&gt;结合 CPU 使用率、运行队列判断&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S&lt;/td&gt;
&lt;td&gt;可中断睡眠&lt;/td&gt;
&lt;td&gt;很多正常服务大部分时间处于此状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;不可中断等待，常见于内核资源或 I/O 等待&lt;/td&gt;
&lt;td&gt;检查存储、网络文件系统和内核日志&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;T&lt;/td&gt;
&lt;td&gt;被作业控制信号停止&lt;/td&gt;
&lt;td&gt;确认是否意外暂停，必要时继续运行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;已退出但尚未被父进程回收&lt;/td&gt;
&lt;td&gt;检查父进程，不是继续给僵尸进程发 KILL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;僵尸进程不再执行程序；它保留少量退出记录等待父进程读取。D 状态进程即使收到 KILL，也可能要等到等待条件解除后才能退出。&lt;/p&gt;
&lt;h1&gt;前台、后台与退出状态&lt;/h1&gt;
&lt;p&gt;以下示例只操作自己新建的 &lt;code&gt;sleep&lt;/code&gt; 进程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sleep 30 &amp;amp;
task_pid=$!
jobs -l
ps -p &quot;$task_pid&quot; -o pid,stat,args
wait &quot;$task_pid&quot;
printf &apos;退出状态：%s\n&apos; &quot;$?&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;&amp;amp;&lt;/code&gt; 启动后台任务，&lt;code&gt;$!&lt;/code&gt; 保存最近一个后台任务的 PID，&lt;code&gt;wait&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl+c&lt;/td&gt;
&lt;td&gt;向前台进程组发送 SIGINT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl+z&lt;/td&gt;
&lt;td&gt;通常发送 SIGTSTP，暂停前台作业&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bg %1&lt;/td&gt;
&lt;td&gt;让作业 1 在后台继续&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fg %1&lt;/td&gt;
&lt;td&gt;将作业 1 切到前台&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;需要重连交互会话可使用 tmux；需要长期运行、自动重启和开机启动则使用服务管理器。&lt;/p&gt;
&lt;h1&gt;信号与服务生命周期&lt;/h1&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;TERM&lt;/td&gt;
&lt;td&gt;请求正常退出&lt;/td&gt;
&lt;td&gt;应用可以捕获并执行清理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INT&lt;/td&gt;
&lt;td&gt;交互式中断&lt;/td&gt;
&lt;td&gt;具体行为由应用定义&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HUP&lt;/td&gt;
&lt;td&gt;某些服务用于重载&lt;/td&gt;
&lt;td&gt;不是通用的“重载配置”指令&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;STOP / CONT&lt;/td&gt;
&lt;td&gt;强制暂停 / 继续&lt;/td&gt;
&lt;td&gt;暂停可能持有锁并阻塞其他工作&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KILL&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;处理 systemd 服务应优先使用服务接口，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status nginx
sudo systemctl stop nginx
systemctl is-active nginx
journalctl -u nginx --since &quot;10 minutes ago&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;示例要求系统确实安装该服务。停止后还要确认监听端口和相关任务是否消失；服务可能由 socket、定时器或其他单元再次激活。&lt;/p&gt;
&lt;p&gt;对于独立进程，先核对 PID、属主、启动时间和命令，再发 TERM，等待业务允许的退出时间。仅在确认不能正常退出、已评估未写入数据和锁的影响后考虑 KILL。不要用名称模糊匹配批量终止进程。&lt;/p&gt;
&lt;h1&gt;资源判断与优先级&lt;/h1&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;CPU 持续升高&lt;/td&gt;
&lt;td&gt;top -H、pidstat -u 1&lt;/td&gt;
&lt;td&gt;多线程进程可能超过单个 CPU 的 100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;内存持续增长&lt;/td&gt;
&lt;td&gt;ps、pidstat -r 1、服务指标&lt;/td&gt;
&lt;td&gt;RSS 含共享页，简单相加会重复计算&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I/O 延迟增加&lt;/td&gt;
&lt;td&gt;pidstat -d 1、iostat -xz 1&lt;/td&gt;
&lt;td&gt;区分哪个进程发起请求与哪个设备拥塞&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;文件描述符不足&lt;/td&gt;
&lt;td&gt;/proc/PID/fd、进程 limits&lt;/td&gt;
&lt;td&gt;确认泄漏或业务需求，再调整限制&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;进程反复退出&lt;/td&gt;
&lt;td&gt;服务日志、退出状态、内核 OOM 日志&lt;/td&gt;
&lt;td&gt;先定位原因，单纯重启会隐藏现场&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;nice&lt;/code&gt; 和 &lt;code&gt;renice&lt;/code&gt; 调整普通调度策略下的相对优先级，不是 CPU 使用率上限。资源配额更适合通过 systemd/cgroup 配置，并在变更后观察业务延迟。&lt;/p&gt;
&lt;h1&gt;进程间通信&lt;/h1&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;管道、FIFO&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;Unix socket、网络 socket&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;配合锁协调读写&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;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;/p&gt;
&lt;h1&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man1/ps.1.html&quot;&gt;ps(1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man7/signal.7.html&quot;&gt;signal(7)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/Job-Control.html&quot;&gt;Bash：作业控制&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.freedesktop.org/software/systemd/man/latest/systemctl.html&quot;&gt;systemctl 手册&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>网络：网络分层模型</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%BD%91%E7%BB%9C%E7%BD%91%E7%BB%9C%E5%88%86%E5%B1%82%E6%A8%A1%E5%9E%8B/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E7%BD%91%E7%BB%9C%E7%BD%91%E7%BB%9C%E5%88%86%E5%B1%82%E6%A8%A1%E5%9E%8B/</guid><pubDate>Sun, 13 Sep 2026 07:23:02 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;计算机网络涉及网卡、交换机、路由器、IP、TCP、HTTP 等大量概念。如果把所有内容混在一起学习，很容易只记住一个个协议，却无法理解它们之间的关系。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;网络分层模型&lt;/strong&gt;就是用来解决这个问题的：把复杂的网络通信拆分成多个相对独立的层次，每一层负责不同的问题，并通过明确的接口与上下层协作。&lt;/p&gt;
&lt;p&gt;本文只关注网络分层本身，重点介绍 &lt;strong&gt;OSI 七层模型、TCP/IP 模型、数据封装与解封装、层与层之间的关系，以及实际网络设备和协议大致位于什么位置&lt;/strong&gt;。这些概念足以帮助你理解常见网络故障的排查顺序。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;为什么需要网络分层&lt;/h1&gt;
&lt;p&gt;如果不进行分层，网络通信可以被想象成一个巨大而复杂的系统：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网卡
交换机
路由器
MAC
ARP
IP
ICMP
TCP
UDP
DNS
HTTP
TLS
应用程序
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些技术之间存在大量依赖关系。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
 ↓
TCP
 ↓
IP
 ↓
Ethernet
 ↓
物理介质
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果所有概念都放在同一层理解，就很难回答：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP 和 TCP 是什么关系？

IP 和 MAC 为什么同时存在？

交换机和路由器为什么做的事情不同？

一个数据包从应用程序到网线，经过了什么？

为什么同一个应用可以运行在不同网络上？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是网络体系采用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;分层（Layering）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;的思想。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;网络分层的基本思想&lt;/h1&gt;
&lt;p&gt;网络分层就是把通信过程拆成多个层次。&lt;/p&gt;
&lt;p&gt;每一层：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;负责自己的任务
+
向上层提供服务
+
使用下层提供的服务
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以简单理解为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        应用
         ↑
         │ 使用
         │
      传输层
         ↑
         │ 使用
         │
       网络层
         ↑
         │ 使用
         │
      链路层
         ↑
         │ 使用
         │
      物理层
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每一层不需要知道所有底层实现细节。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;HTTP 不需要知道网卡是如何把比特转换成电信号或无线信号的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;HTTP 更关心：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;请求
响应
方法
状态
头部
数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而底层则负责：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;如何传输这些数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是分层的核心价值。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;分层带来的好处&lt;/h1&gt;
&lt;h2&gt;降低复杂度&lt;/h2&gt;
&lt;p&gt;一个网络通信问题可以拆成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用问题
传输问题
网络问题
链路问题
物理问题
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样比研究整个系统简单得多。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;模块化&lt;/h2&gt;
&lt;p&gt;某一层发生变化时，不一定需要修改整个网络体系。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用层
HTTP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以运行在不同的底层网络之上。&lt;/p&gt;
&lt;p&gt;同样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也不需要知道具体应用是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Web
数据库
SSH
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还是其他程序。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;标准化&lt;/h2&gt;
&lt;p&gt;不同厂商只要遵循相同的协议标准，就可以互相通信。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;厂商 A 的网卡
        ↕
   标准网络协议
        ↕
厂商 B 的交换机
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不需要所有设备都来自同一家厂商。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;便于故障排查&lt;/h2&gt;
&lt;p&gt;分层模型对运维尤其重要。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网站打不开
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不能直接得出：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“网络坏了”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而应该逐层思考：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用层
↓
HTTP 服务正常吗？

传输层
↓
TCP 连接建立了吗？

网络层
↓
IP 路由正常吗？

链路层
↓
网卡 / 交换网络正常吗？

物理层
↓
链路是否真的存在？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也是后续学习网络故障排查时非常重要的思维方式。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;OSI 七层模型&lt;/h1&gt;
&lt;p&gt;最经典的网络分层模型是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;OSI（Open Systems Interconnection）参考模型&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它定义了七个层次：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌────────────────────┐
│ 7  应用层          │
├────────────────────┤
│ 6  表示层          │
├────────────────────┤
│ 5  会话层          │
├────────────────────┤
│ 4  传输层          │
├────────────────────┤
│ 3  网络层          │
├────────────────────┤
│ 2  数据链路层      │
├────────────────────┤
│ 1  物理层          │
└────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从上到下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用
表示
会话
传输
网络
数据链路
物理
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;第一层：物理层&lt;/h1&gt;
&lt;p&gt;物理层：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Physical Layer&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;负责最底层的比特传输。&lt;/p&gt;
&lt;p&gt;它关注的是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;信号
电气特性
光信号
无线信号
连接介质
接口
比特传输
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;铜缆
光纤
无线电波
连接器
信号电平
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;物理层关心的问题类似：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;如何把 0 和 1 变成可以传输的信号？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以简单表示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;比特
 ↓
信号
 ↓
物理介质
 ↓
信号
 ↓
比特
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;第二层：数据链路层&lt;/h1&gt;
&lt;p&gt;数据链路层：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Data Link Layer&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;主要负责：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;在直接相连的网络节点之间传输数据。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这一层通常涉及：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MAC 地址
帧
交换
链路
错误检测
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型的数据单位：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Frame（帧）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ethernet Frame
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;属于这一层非常典型的内容。&lt;/p&gt;
&lt;p&gt;可以简单理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络层数据
    ↓
封装
    ↓
数据链路层帧
    ↓
通过局域网传输
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;第三层：网络层&lt;/h1&gt;
&lt;p&gt;网络层：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Network Layer&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;主要解决：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;不同网络之间的数据转发问题。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这一层的核心概念包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP 地址
路由
路由表
数据包
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型协议：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IPv4
IPv6
ICMP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;网络层数据通常称为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Packet（数据包）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;主机 A
 ↓
路由器
 ↓
路由器
 ↓
主机 B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据能够跨越多个网络，就是网络层解决的重要问题。&lt;/p&gt;
&lt;p&gt;后续会单独介绍：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP 地址
子网
CIDR
路由
路由表
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;第四层：传输层&lt;/h1&gt;
&lt;p&gt;传输层：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Transport Layer&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;主要负责：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;端到端的传输。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;典型协议：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
UDP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它解决的问题包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;端到端通信
端口
可靠传输
顺序
流量控制
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不同协议的设计不同。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TCP
↓
可靠、面向连接

UDP
↓
无连接、开销较低
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;传输层会进一步使用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Port（端口）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;区分同一台主机上的不同网络应用。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.168.1.10:22
192.168.1.10:80
192.168.1.10:443
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;第五层：会话层&lt;/h1&gt;
&lt;p&gt;会话层：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Session Layer&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;主要负责管理应用程序之间的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;会话（Session）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;建立会话
维护会话
恢复会话
结束会话
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 OSI 模型中，它被定义为独立的一层。&lt;/p&gt;
&lt;p&gt;但在今天常见的 TCP/IP 网络栈中：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;会话层通常不会作为一个独立的协议层明显存在。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;很多会话功能实际上由：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用层
传输层
具体协议
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;共同实现。&lt;/p&gt;
&lt;p&gt;因此学习现代互联网协议时，不应该机械地寻找：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“第五层对应某一个具体协议”
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;第六层：表示层&lt;/h1&gt;
&lt;p&gt;表示层：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Presentation Layer&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;主要负责：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;数据表示和转换。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;编码
数据格式
压缩
加密
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其核心思想是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用看到的数据
        ↓
表示层进行转换
        ↓
网络传输数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;传统 OSI 模型将这些功能单独定义为一层。&lt;/p&gt;
&lt;p&gt;但现代互联网协议中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;编码
压缩
加密
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;往往由具体应用协议、库或者独立协议完成，而不是存在一个统一的“表示层协议”。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TLS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;提供加密能力，但不能简单地说：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TLS = OSI 第六层
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为现实协议栈与 OSI 七层模型并不是一一对应的。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;第七层：应用层&lt;/h1&gt;
&lt;p&gt;应用层：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Application Layer&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最接近用户和应用程序。&lt;/p&gt;
&lt;p&gt;常见协议包括：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
HTTPS
DNS
DHCP
SSH
FTP
SMTP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用层负责的是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;具体应用之间如何通信。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如 HTTP 定义：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;请求
响应
方法
状态码
Header
Body
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DNS 定义：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;域名
查询
响应
资源记录
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SSH 定义：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;远程登录
安全通道
认证
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用层
↓
直接服务于具体网络应用
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;OSI 七层模型总览&lt;/h1&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&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;6&lt;/td&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;5&lt;/td&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;4&lt;/td&gt;
&lt;td&gt;传输层&lt;/td&gt;
&lt;td&gt;端到端传输&lt;/td&gt;
&lt;td&gt;Segment / Datagram&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;网络层&lt;/td&gt;
&lt;td&gt;IP、路由&lt;/td&gt;
&lt;td&gt;Packet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;数据链路层&lt;/td&gt;
&lt;td&gt;帧、MAC、局域网&lt;/td&gt;
&lt;td&gt;Frame&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;物理层&lt;/td&gt;
&lt;td&gt;信号、介质、比特&lt;/td&gt;
&lt;td&gt;Bit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;需要注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Segment / Datagram / Packet / Frame / Bit”是常见教学上的数据单位称呼，现实协议栈中具体命名会根据协议有所不同。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;TCP/IP 模型&lt;/h1&gt;
&lt;p&gt;实际互联网并不是直接按照 OSI 七层模型实现的。&lt;/p&gt;
&lt;p&gt;互联网协议体系更常见的是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TCP/IP 模型&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;教材中常见的表达方式有不同版本，其中一种经典的四层划分是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌────────────────────┐
│ 应用层             │
├────────────────────┤
│ 传输层             │
├────────────────────┤
│ 网际层             │
├────────────────────┤
│ 网络接口层         │
└────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以写成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application
Transport
Internet
Network Access
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;OSI 与 TCP/IP 的对应关系&lt;/h1&gt;
&lt;p&gt;可以进行大致映射：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;OSI                         TCP/IP

应用层 ───────┐
表示层 ───────┼────→ 应用层
会话层 ───────┘

传输层 ───────────→ 传输层

网络层 ───────────→ 网际层

数据链路层 ────┐
物理层 ────────┴────→ 网络接口层
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;OSI 7 层
   ↓
更多是参考模型

TCP/IP
   ↓
互联网协议体系中更加实际的模型
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;为什么 OSI 与 TCP/IP 不完全一样&lt;/h1&gt;
&lt;p&gt;OSI 是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;参考模型&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它重点描述：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络功能应该如何分层
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而 TCP/IP 是一个真实存在并长期使用的协议体系。&lt;/p&gt;
&lt;p&gt;所以实际互联网：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
TCP
IP
Ethernet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不会严格按照：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;7 → 6 → 5 → 4 → 3 → 2 → 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分别对应七个独立协议层。&lt;/p&gt;
&lt;p&gt;现代网络协议的实际结构更加灵活。&lt;/p&gt;
&lt;p&gt;因此学习分层模型时：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;不要执着于“每一个协议必须准确属于 OSI 某一层”。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;更重要的是理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;谁负责应用通信？
谁负责端到端传输？
谁负责跨网络转发？
谁负责局域网传输？
谁负责物理信号？
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;数据封装&lt;/h1&gt;
&lt;p&gt;网络分层最重要的概念之一：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Encapsulation（封装）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;假设应用程序产生一段数据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Application Data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;向下经过协议栈时，每一层都可以增加自己的控制信息。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用层
┌────────────────────┐
│ Application Data   │
└────────────────────┘
          ↓
传输层
┌──────────┬─────────┐
│ TCP Header│  Data   │
└──────────┴─────────┘
          ↓
网络层
┌────────────┬──────────────┐
│ IP Header  │ TCP + Data  │
└────────────┴──────────────┘
          ↓
链路层
┌────────┬─────────────────┬──────┐
│ Header │ IP + TCP + Data │ FCS  │
└────────┴─────────────────┴──────┘
          ↓
物理层
          ↓
       比特 / 信号
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个过程就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;逐层封装。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;数据解封装&lt;/h1&gt;
&lt;p&gt;接收端则进行相反过程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;物理层
   ↓
链路层
   ↓
网络层
   ↓
传输层
   ↓
应用层
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以表示成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;比特 / 信号
     ↓
   Frame
     ↓
   Packet
     ↓
 Segment
     ↓
Application Data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;解封装（Decapsulation）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;一个完整通信过程&lt;/h1&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;浏览器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用产生：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP Data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP
 ↓
TCP
 ↓
IP
 ↓
Ethernet
 ↓
物理介质
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发送端：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用数据
   ↓
TCP 封装
   ↓
IP 封装
   ↓
Ethernet 封装
   ↓
物理传输
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接收端：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;物理信号
   ↓
Ethernet 解封装
   ↓
IP 解封装
   ↓
TCP 解封装
   ↓
HTTP 数据
   ↓
浏览器
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是网络分层最直观的体现。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;每一层都在解决什么问题&lt;/h1&gt;
&lt;p&gt;可以把几层最核心的问题简化为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用层
↓
“应用之间怎么交流？”

传输层
↓
“两个程序怎么可靠 / 高效地通信？”

网络层
↓
“数据怎么从一个网络到另一个网络？”

链路层
↓
“相邻节点怎么传输？”

物理层
↓
“比特怎么真正传出去？”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是一种非常适合学习和排障的思维方式。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;地址也具有层次性&lt;/h1&gt;
&lt;p&gt;网络中存在多种不同类型的地址。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MAC 地址
IP 地址
端口
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它们解决的问题不同。&lt;/p&gt;
&lt;p&gt;可以先粗略理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MAC
↓
局部链路中的设备标识

IP
↓
网络层中的主机 / 接口寻址

Port
↓
区分一台主机上的不同应用
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MAC
+
IP
+
Port
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并不是三个重复的概念。&lt;/p&gt;
&lt;p&gt;它们分别服务于不同层次的问题。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;网络设备与分层&lt;/h1&gt;
&lt;p&gt;网络设备也可以从分层角度理解。&lt;/p&gt;
&lt;h2&gt;集线器&lt;/h2&gt;
&lt;p&gt;传统 Hub 主要在物理层工作：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Layer 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它不会理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MAC
IP
TCP
HTTP
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;交换机&lt;/h2&gt;
&lt;p&gt;传统以太网交换机主要工作在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Layer 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MAC 地址
以太网帧
交换表
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现代交换机也可能具备：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Layer 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;路由能力。&lt;/p&gt;
&lt;p&gt;因此不能简单认为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;所有交换机永远只工作在第二层。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;路由器&lt;/h2&gt;
&lt;p&gt;路由器主要关注：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Layer 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;核心工作：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IP
路由
数据包转发
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以简单理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;交换机
↓
主要解决“局域网内部怎么传”

路由器
↓
主要解决“不同网络之间怎么走”
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;防火墙&lt;/h2&gt;
&lt;p&gt;防火墙比较特殊。&lt;/p&gt;
&lt;p&gt;现代防火墙可能同时检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;二层信息
三层 IP
四层 TCP / UDP
甚至应用层内容
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此不应该强行给防火墙贴一个固定的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“第几层设备”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更准确的是看：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;它实际检查和控制哪些协议字段。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;网络分层与故障排查&lt;/h1&gt;
&lt;p&gt;分层模型最实用的地方之一：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;帮助建立故障排查顺序。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;浏览器打不开网站
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以逐层思考。&lt;/p&gt;
&lt;h3&gt;应用层&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Web 服务正常吗？
HTTP 响应是什么？
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;传输层&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;TCP 三次握手成功了吗？
目标端口监听了吗？
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;网络层&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;IP 地址正确吗？
有没有路由？
数据包能到目标吗？
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;链路层&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;网卡是否正常？
交换网络是否正常？
MAC 是否可达？
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;物理层&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;网线是否连接？
光模块是否正常？
链路是否 Up？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“网站打不开”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就会变成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用？
 ↓
传输？
 ↓
网络？
 ↓
链路？
 ↓
物理？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是一上来就：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;“网络有问题”
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;分层不是严格的“盒子”&lt;/h1&gt;
&lt;p&gt;学习网络分层时需要注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;现实协议栈并不是严格互不重叠的五个或七个盒子。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;实际协议可能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;跨层
复用
嵌套
提供多个层次的功能
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TLS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;既和应用通信密切相关，又提供加密和身份认证能力。&lt;/p&gt;
&lt;p&gt;再比如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ICMP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;虽然通常归入网络层相关协议，但在实际实现中与 IP 协议栈关系非常紧密。&lt;/p&gt;
&lt;p&gt;因此学习模型的目的不是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;背协议属于第几层
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;理解不同功能之间的边界和协作关系。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1&gt;OSI 与 TCP/IP 的核心区别&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;对比&lt;/th&gt;
&lt;th&gt;OSI&lt;/th&gt;
&lt;th&gt;TCP/IP&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;7 层&lt;/td&gt;
&lt;td&gt;常见教材模型为 4 层，也有 5 层划分&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;tr&gt;
&lt;td&gt;网络层&lt;/td&gt;
&lt;td&gt;Network Layer&lt;/td&gt;
&lt;td&gt;Internet Layer&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;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;/p&gt;
&lt;pre&gt;&lt;code&gt;OSI
↓
帮助理解“网络应该怎样分层”

TCP/IP
↓
帮助理解“互联网实际上怎样组织协议”
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;数据封装的完整视图&lt;/h1&gt;
&lt;p&gt;把整个过程串起来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送端

Application
    │
    │ Data
    ▼
Transport
    │
    │ Segment / Datagram
    ▼
Network
    │
    │ Packet
    ▼
Data Link
    │
    │ Frame
    ▼
Physical
    │
    │ Bits / Signals
    ▼
==================== 网络 ====================
    │
    │ Bits / Signals
    ▼
Physical
    │
    ▼
Data Link
    │
    ▼
Network
    │
    ▼
Transport
    │
    ▼
Application

接收端
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以概括成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;发送：
上 → 下 → 封装 → 传输

接收：
下 → 上 → 解封装
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;从分层进入后续网络知识&lt;/h1&gt;
&lt;p&gt;建立分层模型之后，后续网络知识就可以按照层次逐步展开。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络分层模型
      │
      ├── 物理 / 链路层
      │      └── 以太网、MAC、ARP、VLAN
      │
      ├── 网络层
      │      └── IP、CIDR、路由、ICMP
      │
      ├── 传输层
      │      └── TCP、UDP、端口
      │
      └── 应用层
             ├── DNS
             ├── DHCP
             ├── HTTP
             └── HTTPS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再往后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;网络基础
   ↓
Linux 网络管理
   ↓
Linux 网络诊断
   ↓
iptables / nftables
   ↓
NAT
   ↓
网络故障排查
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样网络系列就可以做到：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;先建立模型，再逐层学习协议，最后回到 Linux 运维实践。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;外部参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc1122&quot;&gt;RFC 1122 — Requirements for Internet Hosts: Communication Layers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc8200&quot;&gt;RFC 8200 — Internet Protocol, Version 6 (IPv6) Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.iso.org/standard/20269.html&quot;&gt;ISO/IEC 7498-1 — OSI Basic Reference Model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ietf.org/standards/&quot;&gt;IETF — Internet Standards&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Linux：Vim 使用教程</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linuxvim-%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linuxvim-%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</guid><description>Vim 是基于 Vi 发展而来的文本编辑器，用于在终端中查看和修改配置、脚本及文本。</description><pubDate>Sun, 13 Sep 2026 07:12:06 GMT</pubDate><content:encoded>&lt;p&gt;Vim 是基于 Vi 发展而来的文本编辑器，用于在终端中查看和修改配置、脚本及文本。编辑时改变的是内存中的缓冲区，保存后才写入磁盘。系统中的 vi 不一定是完整功能的 Vim，本文以常规 Vim 为例。&lt;/p&gt;
&lt;h1&gt;模式与基本流程&lt;/h1&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;普通模式 Normal&lt;/td&gt;
&lt;td&gt;默认启动状态，其他模式按 Esc 返回&lt;/td&gt;
&lt;td&gt;移动、复制、删除&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;插入模式 Insert&lt;/td&gt;
&lt;td&gt;i、a、o 等&lt;/td&gt;
&lt;td&gt;输入文字&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;可视模式 Visual&lt;/td&gt;
&lt;td&gt;v、V、Ctrl+V&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;执行命令或搜索，回车确认&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;打开、修改与保存&lt;/h2&gt;
&lt;p&gt;在可写的练习目录运行 &lt;code&gt;vim app.conf&lt;/code&gt;。文件不存在时会建立新缓冲区，保存才创建文件。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;按 i，输入 &lt;code&gt;port=8080&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;按 Esc，输入 &lt;code&gt;:w&lt;/code&gt; 并回车，检查底部是否提示写入成功。&lt;/li&gt;
&lt;li&gt;输入 &lt;code&gt;:q&lt;/code&gt; 退出，再用 &lt;code&gt;cat app.conf&lt;/code&gt; 核对落盘内容。&lt;/li&gt;
&lt;/ol&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;:w&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;保存当前缓冲区&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:q&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;关闭当前窗口，未保存修改可能阻止退出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:wq&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;保存并关闭窗口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:x&lt;/code&gt; 或普通模式 ZZ&lt;/td&gt;
&lt;td&gt;有修改时保存，然后关闭窗口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:q!&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;强制关闭窗口；单窗口常见场景中会放弃未保存修改&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:w copy.conf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;写入另一个文件，默认不切换当前文件名&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;:::warning[强制操作的边界]
&lt;code&gt;:w!&lt;/code&gt; 不能绕过系统权限；&lt;code&gt;:q!&lt;/code&gt; 可能丢失修改。保存配置后仍需执行所属程序的配置检查，不能将编辑器写入成功视为服务已生效。
:::&lt;/p&gt;
&lt;h1&gt;移动与输入&lt;/h1&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;h j k l&lt;/td&gt;
&lt;td&gt;左、下、上、右&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0 / ^ / $&lt;/td&gt;
&lt;td&gt;行首 / 第一个非空白字符 / 行尾&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;w / b / e&lt;/td&gt;
&lt;td&gt;下一个词首 / 向后词首 / 词尾&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gg / G&lt;/td&gt;
&lt;td&gt;第一行 / 最后一行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;42G 或 :42&lt;/td&gt;
&lt;td&gt;第 42 行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl+f / Ctrl+b&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;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;小写 w 按 Vim 的 word 规则移动，标点可能形成边界；大写 W 主要按空白分隔的 WORD 移动。&lt;/p&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;i / a&lt;/td&gt;
&lt;td&gt;光标前 / 后&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I / A&lt;/td&gt;
&lt;td&gt;当前行第一个非空白字符前 / 行末&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;o / O&lt;/td&gt;
&lt;td&gt;在当前行下方 / 上方新建一行&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;I 不一定到物理行首；配置文件有缩进时，要区分 I 与 0i。&lt;/p&gt;
&lt;h1&gt;复制、删除与修改&lt;/h1&gt;
&lt;h2&gt;操作符与范围&lt;/h2&gt;
&lt;p&gt;常用组合为“次数 + 操作符 + 移动或文本对象”。d 删除，y 复制，c 删除后进入插入模式。&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;yy / 3yy&lt;/td&gt;
&lt;td&gt;复制当前行 / 从当前行起复制三行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dd / 3dd&lt;/td&gt;
&lt;td&gt;删除当前行 / 从当前行起删除三行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dw&lt;/td&gt;
&lt;td&gt;删除光标到下一个词边界的范围&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ciw&lt;/td&gt;
&lt;td&gt;修改当前词内部&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ci&quot; / ci(&lt;/td&gt;
&lt;td&gt;修改引号 / 括号内文本&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;d$&lt;/td&gt;
&lt;td&gt;删除到行尾&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p / P&lt;/td&gt;
&lt;td&gt;放在光标后 / 前；整行内容则放在当前行下 / 上&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;cw 在非空白字符上通常按 ce 的方式修改到词尾，不宜简单理解为 dw 后进入插入模式。替换完整单词可使用 ciw。&lt;/p&gt;
&lt;p&gt;复制和删除的内容通常进入寄存器，后续删除可能覆盖先前复制的内容。需要保留时用 &lt;code&gt;&quot;ayy&lt;/code&gt; 复制到寄存器 a，再用 &lt;code&gt;&quot;ap&lt;/code&gt; 粘贴。3p 是重复粘贴三次，实际行数由寄存器内容决定。&lt;/p&gt;
&lt;h2&gt;可视选择与剪贴板&lt;/h2&gt;
&lt;p&gt;v 选择字符，V 选择整行，Ctrl+V 选择矩形列。移动光标扩大选区，再用 y、d、c 操作。范围不明确时先用可视模式确认。&lt;/p&gt;
&lt;p&gt;系统剪贴板与 Vim 寄存器不同。支持剪贴板的 Vim 可用 &lt;code&gt;&quot;+y&lt;/code&gt;、&lt;code&gt;&quot;+p&lt;/code&gt;；可用性取决于编译功能和图形环境，SSH 远程 Vim 不会自动获得本地剪贴板访问能力。&lt;/p&gt;
&lt;h2&gt;撤销与重复&lt;/h2&gt;
&lt;p&gt;普通模式下 u 撤销，Ctrl+R 重做，句点 &lt;code&gt;.&lt;/code&gt; 重复上一次可重复的修改。批量操作后先查看结果，发现错误先撤销，再调整范围。句点并不是重复最近任意按键。&lt;/p&gt;
&lt;h1&gt;搜索与替换&lt;/h1&gt;
&lt;h2&gt;搜索&lt;/h2&gt;
&lt;p&gt;输入 &lt;code&gt;/error&lt;/code&gt; 后回车向前搜索，&lt;code&gt;?error&lt;/code&gt; 向后搜索。n 沿最近搜索方向继续，N 沿相反方向继续，并不固定表示向下和向上。&lt;/p&gt;
&lt;p&gt;搜索采用 Vim 正则表达式。查找字面文本可用 &lt;code&gt;/\Vexample.com&lt;/code&gt; 降低特殊字符解释程度，但仍须注意反斜杠。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:set number
:set hlsearch
:set incsearch
:nohlsearch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;前三项分别显示行号、高亮匹配和输入时预览搜索；最后一项暂时清除高亮，不删除搜索模式。&lt;/p&gt;
&lt;h2&gt;替换范围&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;:%s/old_name/new_name/gc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;百分号代表全文，s 表示替换，g 表示每行全部匹配，c 表示逐个确认。省略 g 时默认每行只替换首个匹配。替换端的 &lt;code&gt;&amp;amp;&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:s/old/new/gc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;当前行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:10,20s/old/new/gc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;第 10 到 20 行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:%s/old/new/gc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;全文&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:&apos;&amp;lt;,&apos;&amp;gt;s/old/new/gc&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;/p&gt;
&lt;h1&gt;多文件与常用设置&lt;/h1&gt;
&lt;h2&gt;缓冲区、窗口和标签页&lt;/h2&gt;
&lt;p&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;:e app.conf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打开文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:ls&lt;/code&gt; / &lt;code&gt;:b 2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;列出缓冲区 / 切换到编号 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:split other.conf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;上下分割窗口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:vsplit other.conf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;左右分割窗口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl+w w&lt;/td&gt;
&lt;td&gt;切换窗口&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;比较文件可用 &lt;code&gt;vim -d app.conf app.conf.bak&lt;/code&gt;。不要为了切换文件而使用 &lt;code&gt;:e!&lt;/code&gt;，它会丢弃当前缓冲区的修改。&lt;/p&gt;
&lt;h2&gt;最小配置&lt;/h2&gt;
&lt;p&gt;先在当前会话尝试设置，确认合适后再写入 &lt;code&gt;~/.vimrc&lt;/code&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;syntax on
set number
set incsearch
set hlsearch
set expandtab
set shiftwidth=4
set softtabstop=4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;缩进应服从文件格式。例如 Makefile 的命令行通常需要真实制表符，不能盲目转换为空格。用 &lt;code&gt;:verbose set shiftwidth?&lt;/code&gt; 可以查看设置及来源。&lt;/p&gt;
&lt;h1&gt;配置修改与异常处理&lt;/h1&gt;
&lt;h2&gt;操作闭环&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;确认文件路径和权限，保留原件。&lt;/li&gt;
&lt;li&gt;使用 Vim 编辑；需要提权时，可在已配置 sudo 权限的环境使用 &lt;code&gt;sudoedit /path/to/app.conf&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;保存并比较修改前后的差异，检查是否误改注释或其他配置块。&lt;/li&gt;
&lt;li&gt;使用应用的配置检查命令，通过后按应用要求重载。&lt;/li&gt;
&lt;li&gt;检查服务状态和实际行为，异常时按保留的原件恢复。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Vim 不能判断端口冲突、配置依赖和重载结果，这些检查需要由应用完成。&lt;/p&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;当前是普通模式，按 i 进入插入模式&lt;/td&gt;
&lt;/tr&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;提示交换文件已存在&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;code&gt;vim -r app.conf&lt;/code&gt; 恢复，另存后与磁盘文件比较&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;粘贴缩进错乱&lt;/td&gt;
&lt;td&gt;检查终端括号粘贴支持；旧环境可临时 set paste，完成后 set nopaste&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;出现 ^M 或乱码&lt;/td&gt;
&lt;td&gt;查看 fileformat、fileencoding，确认源格式后再转换&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;恢复并核对之前，不覆盖原文件，不清除唯一的恢复材料。交换文件不保证包含所有未保存内容。&lt;/p&gt;
&lt;h1&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://vimhelp.org/usr_toc.txt.html&quot;&gt;Vim 用户手册&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vimhelp.org/motion.txt.html&quot;&gt;移动命令与文本对象&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vimhelp.org/pattern.txt.html&quot;&gt;搜索与替换&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vimhelp.org/recover.txt.html&quot;&gt;文件恢复&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;本机可运行 &lt;code&gt;vimtutor&lt;/code&gt; 练习，在 Vim 内用 &lt;code&gt;:help&lt;/code&gt; 查阅与安装版本匹配的帮助。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Linux：存储体系</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E5%AD%98%E5%82%A8%E4%BD%93%E7%B3%BB/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E5%AD%98%E5%82%A8%E4%BD%93%E7%B3%BB/</guid><description>从存储介质、协议与设备连接，到分区、RAID、LVM、文件系统和挂载，结合磁盘初始化、扩容与故障定位理解 Linux 存储体系。</description><pubDate>Sun, 13 Sep 2026 06:43:25 GMT</pubDate><content:encoded>&lt;p&gt;Linux 中，设备容量、逻辑卷容量和文件系统可用空间是不同的量。理解它们之间的关系，才能判断新增的容量去了哪里、哪个设备承载了数据，以及故障应从哪一层开始检查。&lt;/p&gt;
&lt;p&gt;本文以本地块存储为主，先建立存储结构，再介绍设备识别、空间管理、挂载和常见故障定位。命令采用现代 Linux 常见工具；修改设备或系统配置的示例使用 &lt;code&gt;sudo&lt;/code&gt;，实际执行前应核对设备、文件系统类型和工具版本。&lt;/p&gt;
&lt;h1&gt;存储体系概览&lt;/h1&gt;
&lt;p&gt;从文件路径向下看，一种常见结构是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;应用访问 /data/report.csv
          │
          ▼
挂载在 /data 的文件系统       组织文件、目录和元数据
          │
          ▼
LVM 逻辑卷（可选）           分配和调整容量
          │
          ▼
RAID 阵列（可选）            按所选级别提供条带化、镜像或校验
          │
          ▼
整盘或分区                  提供可寻址的块空间
          │
          ▼
驱动、控制器与设备连接
          │
          ▼
物理存储设备                实际保存数据
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这不是所有系统都必须遵循的固定流水线。整盘、分区、软件 RAID 设备和 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;特点&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;/dev/sdb1 → XFS → /data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;结构简单&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;软件 RAID 上建立文件系统&lt;/td&gt;
&lt;td&gt;&lt;code&gt;两块盘的分区 → /dev/md0 → XFS → /data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;容错能力取决于 RAID 级别&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LVM 管理文件系统容量&lt;/td&gt;
&lt;td&gt;&lt;code&gt;整盘或分区 → PV → VG → LV → ext4 → /data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;便于分配和扩展容量&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAID 与 LVM 组合&lt;/td&gt;
&lt;td&gt;&lt;code&gt;成员设备 → RAID → PV → VG → LV → XFS → /data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;分别承担阵列管理与容量管理&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;分区表描述设备上的分区位置，不是每次文件读写都要经过的独立存储层。RAID 可以使用整盘或分区，LVM 也可以使用整盘、分区或 RAID 设备；云主机看到的磁盘则可能已经由底层平台完成冗余。&lt;/p&gt;
&lt;p&gt;:::tip[先找到承载数据的设备]
排查 &lt;code&gt;/data&lt;/code&gt; 的问题时，先用 &lt;code&gt;findmnt -T /data&lt;/code&gt; 找到承载这个路径的文件系统，再用 &lt;code&gt;lsblk&lt;/code&gt; 查看设备关系。不要仅凭 &lt;code&gt;/dev/sdb&lt;/code&gt; 这样的名称猜测它的用途。
:::&lt;/p&gt;
&lt;h1&gt;存储介质与设备连接&lt;/h1&gt;
&lt;p&gt;购买或识别一块硬盘时，需要分别回答：&lt;strong&gt;数据存在哪里、主机使用什么命令、通过什么连接传输、设备长什么样且能否安装&lt;/strong&gt;。这些是不同维度，不能用一个“接口类型”概括所有差别。&lt;/p&gt;
&lt;h2&gt;存储介质：HDD 与 SSD&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;HDD（机械硬盘）&lt;/strong&gt; 依靠旋转盘片和磁头存取数据。连续读写时磁头移动较少，顺序吞吐较好；大量分散的小请求会增加寻道和旋转等待。它通常适合容量需求大、随机访问要求相对低的场景。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SSD（固态硬盘）&lt;/strong&gt; 通常使用 NAND 闪存，没有机械寻道过程，随机访问延迟通常更低。控制器负责管理闪存空间和写入回收。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;关注点&lt;/th&gt;
&lt;th&gt;HDD&lt;/th&gt;
&lt;th&gt;SSD&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;随机小块 I/O&lt;/td&gt;
&lt;td&gt;容易受机械延迟限制&lt;/td&gt;
&lt;td&gt;通常明显优于 HDD&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;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;SSD 不等于 NVMe：SSD 可以通过 SATA、SAS 或 PCIe 等方式连接。比较性能时也不能只看标称顺序读写速度，还要看请求大小、读写比例、队列深度和持续负载表现。&lt;/p&gt;
&lt;h2&gt;命令集、协议与主机控制器接口&lt;/h2&gt;
&lt;p&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;ATA 命令集&lt;/td&gt;
&lt;td&gt;存储设备命令集&lt;/td&gt;
&lt;td&gt;SATA 磁盘通常使用 ATA 命令&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SCSI 命令集&lt;/td&gt;
&lt;td&gt;一组存储及其他设备命令集&lt;/td&gt;
&lt;td&gt;可通过 SAS、iSCSI 等不同传输方式使用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NVMe&lt;/td&gt;
&lt;td&gt;面向非易失性存储的协议与规范体系&lt;/td&gt;
&lt;td&gt;包括基础规范、I/O 命令集和传输规范&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AHCI&lt;/td&gt;
&lt;td&gt;SATA 主机控制器的软件编程接口&lt;/td&gt;
&lt;td&gt;驱动通过它操作控制器；它不是硬盘外形或连接器&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;常见的本地 NVMe SSD 通过 PCIe 连接，但 NVMe 并不只支持 PCIe。&lt;a href=&quot;https://nvmexpress.org/specifications/&quot;&gt;NVM Express 规范&lt;/a&gt;还定义了 RDMA、TCP 等传输方式，因此“NVMe 设备”不必然意味着“插在本机 PCIe 插槽中的设备”。&lt;/p&gt;
&lt;p&gt;ATA、SCSI 和 NVMe 的历史与覆盖范围不同。这里按使用时需要判断的问题区分角色，而不是把每套规范都当成只属于某一层。SCSI 架构与 SAS 标准可从 &lt;a href=&quot;https://www.t10.org/&quot;&gt;T10 技术委员会&lt;/a&gt;查阅。&lt;/p&gt;
&lt;h2&gt;总线与互连：SATA、SAS、PCIe&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;th&gt;常见用途&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SATA（Serial ATA）&lt;/td&gt;
&lt;td&gt;面向存储设备的串行接口标准，覆盖物理连接及相关协议层&lt;/td&gt;
&lt;td&gt;HDD、SATA SSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SAS（Serial Attached SCSI）&lt;/td&gt;
&lt;td&gt;面向存储的串行互连，支持扩展器及多路径等能力&lt;/td&gt;
&lt;td&gt;服务器磁盘、存储机箱&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PCIe（PCI Express）&lt;/td&gt;
&lt;td&gt;通用高速串行互连，通过代际和通道数共同决定链路带宽&lt;/td&gt;
&lt;td&gt;NVMe SSD、网卡、GPU 等&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;SATA、SAS 规范本身覆盖多个层面，因此称它们为“存储接口标准”或“存储互连”更准确；PCIe 是通用互连，不是某一种硬盘协议。PCIe 设备还要核对插槽实际提供的代际与通道数，例如物理上能安装，不代表一定能以设备最高带宽运行。&lt;/p&gt;
&lt;p&gt;SAS 控制器通常可以接入 SATA 盘，但仍要确认控制器和背板支持；SATA 控制器不能因此反过来使用 SAS 盘。双端口、多路径和热插拔也需要设备、背板、控制器与软件共同支持，不能仅凭名称推断。&lt;/p&gt;
&lt;h2&gt;外形规格与连接器&lt;/h2&gt;
&lt;p&gt;**外形规格（form factor）**描述尺寸、安装方式等约束，&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;3.5 英寸、2.5 英寸&lt;/td&gt;
&lt;td&gt;常见驱动器外形规格&lt;/td&gt;
&lt;td&gt;盘位、厚度、供电、背板及支持的接口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SATA 数据与电源连接器&lt;/td&gt;
&lt;td&gt;常见 SATA 驱动器分别使用 7 针数据和 15 针电源连接器&lt;/td&gt;
&lt;td&gt;数据连接、供电及背板兼容性&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;M.2&lt;/td&gt;
&lt;td&gt;包含卡形、尺寸和插接等定义的规格&lt;/td&gt;
&lt;td&gt;卡长、键位，以及插槽支持 SATA 还是 PCIe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;U.2&lt;/td&gt;
&lt;td&gt;常用于 2.5 英寸 PCIe/NVMe 驱动器连接，关联 SFF-8639 连接器&lt;/td&gt;
&lt;td&gt;主机端、线缆、背板的布线和支持能力&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AIC（Add-in Card）&lt;/td&gt;
&lt;td&gt;安装在扩展槽中的板卡形态&lt;/td&gt;
&lt;td&gt;PCIe 插槽尺寸、通道、散热；多盘转接卡还可能要求通道拆分&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;例如，M.2 2280 表示常见的 22 mm × 80 mm 卡尺寸，不能据此判断设备采用 SATA 还是 NVMe。键位可以排除部分不兼容组合，但最终应以设备和主板手册为准。&lt;a href=&quot;https://sata-io.org/developers/sata-ecosystem/sata-m2-card&quot;&gt;SATA-IO 的 M.2 说明&lt;/a&gt;也明确指出，M.2 卡形与连接器规格可以承载 SATA、PCIe 等不同接口。&lt;/p&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;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;2.5 英寸 SATA SSD&lt;/td&gt;
&lt;td&gt;NAND 闪存&lt;/td&gt;
&lt;td&gt;ATA&lt;/td&gt;
&lt;td&gt;SATA&lt;/td&gt;
&lt;td&gt;2.5 英寸，SATA 连接器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;M.2 SATA SSD&lt;/td&gt;
&lt;td&gt;NAND 闪存&lt;/td&gt;
&lt;td&gt;ATA&lt;/td&gt;
&lt;td&gt;SATA&lt;/td&gt;
&lt;td&gt;M.2，尺寸与键位按产品规格&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;M.2 NVMe SSD&lt;/td&gt;
&lt;td&gt;NAND 闪存&lt;/td&gt;
&lt;td&gt;NVMe&lt;/td&gt;
&lt;td&gt;PCIe&lt;/td&gt;
&lt;td&gt;M.2，尺寸与键位按产品规格&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.5 英寸 SAS HDD&lt;/td&gt;
&lt;td&gt;磁性盘片&lt;/td&gt;
&lt;td&gt;SCSI&lt;/td&gt;
&lt;td&gt;SAS&lt;/td&gt;
&lt;td&gt;2.5 英寸，SAS 连接器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;U.2 NVMe SSD&lt;/td&gt;
&lt;td&gt;NAND 闪存&lt;/td&gt;
&lt;td&gt;NVMe&lt;/td&gt;
&lt;td&gt;PCIe&lt;/td&gt;
&lt;td&gt;常见为 2.5 英寸，U.2 连接&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这也解释了为什么两块外形相同的 SSD 可能无法互换，而使用相同协议的 SSD 又可能拥有完全不同的外观。&lt;/p&gt;
&lt;h1&gt;块设备与设备识别&lt;/h1&gt;
&lt;h2&gt;设备名称表示什么&lt;/h2&gt;
&lt;p&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;code&gt;/dev/sda&lt;/code&gt;、&lt;code&gt;/dev/sda1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;一个磁盘类设备及其第一个分区&lt;/td&gt;
&lt;td&gt;SATA、SAS、USB 存储或 RAID 逻辑盘都可能出现为 &lt;code&gt;sd*&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/dev/nvme0n1&lt;/code&gt;、&lt;code&gt;/dev/nvme0n1p1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;NVMe 命名空间及其第一个分区&lt;/td&gt;
&lt;td&gt;&lt;code&gt;n1&lt;/code&gt; 表示命名空间；不能直接等同于一块物理盘&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/dev/vda&lt;/code&gt;、&lt;code&gt;/dev/vda1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;常见 virtio 块设备及其分区&lt;/td&gt;
&lt;td&gt;常见于虚拟机，后端由平台决定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/dev/md0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Linux MD 软件阵列设备&lt;/td&gt;
&lt;td&gt;向上仍然表现为块设备&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/dev/vgdata/lvdata&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;LVM 逻辑卷路径&lt;/td&gt;
&lt;td&gt;便于识别所属卷组和逻辑卷&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;设备枚举顺序可能改变。持久挂载通常使用文件系统 UUID；定位物理设备还应结合序列号、WWN、控制器槽位和 &lt;code&gt;/dev/disk/by-id/&lt;/code&gt; 等信息。&lt;/p&gt;
&lt;h2&gt;用 &lt;code&gt;lsblk&lt;/code&gt; 建立设备地图&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS
lsblk -d -o NAME,SIZE,MODEL,SERIAL,TRAN,ROTA
lsblk -f
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一条命令可能得到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NAME                 SIZE TYPE FSTYPE      MOUNTPOINTS
sdb                  100G disk
└─sdb1               100G part LVM2_member
  └─vgdata-lvdata      80G lvm  xfs         /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里 &lt;code&gt;sdb1&lt;/code&gt; 被 LVM 使用，真正承载 XFS 的是 &lt;code&gt;vgdata-lvdata&lt;/code&gt;。不能对 &lt;code&gt;sdb1&lt;/code&gt; 再执行格式化，否则会覆盖下层元数据。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TRAN&lt;/code&gt; 是系统报告的传输类型，&lt;code&gt;ROTA&lt;/code&gt; 表示设备报告的旋转属性；虚拟设备、USB 桥接或硬件 RAID 可能隐藏或改写这些信息。字段为空或 &lt;code&gt;ROTA=0&lt;/code&gt; 都不足以证明底层硬件的完整情况。较旧版本若不支持 &lt;code&gt;MOUNTPOINTS&lt;/code&gt;，可使用 &lt;code&gt;MOUNTPOINT&lt;/code&gt; 并配合 &lt;code&gt;findmnt&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;补充确认分区与标识&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;sudo fdisk -l /dev/sdb
sudo blkid /dev/sdb1
sudo wipefs --no-act /dev/sdb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;fdisk -l&lt;/code&gt; 查看分区布局；&lt;code&gt;blkid&lt;/code&gt; 识别文件系统等元数据；&lt;code&gt;wipefs --no-act&lt;/code&gt; 只列出可识别签名，不擦除数据。签名检查没有结果，也不能证明设备从未使用或没有需要保留的数据。&lt;/p&gt;
&lt;p&gt;字段含义及设备关系的显示限制见 &lt;a href=&quot;https://man7.org/linux/man-pages/man8/lsblk.8.html&quot;&gt;lsblk(8)&lt;/a&gt;。&lt;/p&gt;
&lt;h1&gt;分区与分区表&lt;/h1&gt;
&lt;h2&gt;分区不等于文件系统&lt;/h2&gt;
&lt;p&gt;分区是在块设备上划出的地址范围；分区表记录这些范围的位置、大小和类型。一个分区可以承载文件系统、交换空间、LVM PV 或 RAID 成员元数据。&lt;/p&gt;
&lt;p&gt;例如，&lt;code&gt;parted&lt;/code&gt; 创建分区时指定 &lt;code&gt;xfs&lt;/code&gt;，并不代表已经创建 XFS。创建文件系统还需要单独执行 &lt;code&gt;mkfs.xfs&lt;/code&gt;。整盘也可以直接用于文件系统或 LVM，并不是必须分区。&lt;/p&gt;
&lt;h2&gt;MBR 与 GPT&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;比较项&lt;/th&gt;
&lt;th&gt;MBR&lt;/th&gt;
&lt;th&gt;GPT&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;分区描述&lt;/td&gt;
&lt;td&gt;4 个主分区表项；可用扩展分区容纳逻辑分区&lt;/td&gt;
&lt;td&gt;使用分区项数组，无须扩展分区机制&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;容量范围&lt;/td&gt;
&lt;td&gt;采用 512 字节逻辑扇区时，常见寻址限制约 2 TiB&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;有主、备份头和分区项数组，并有校验机制&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;标识&lt;/td&gt;
&lt;td&gt;传统分区类型编码&lt;/td&gt;
&lt;td&gt;分区类型 GUID、分区唯一 GUID&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;GPT 常见默认分区项数量是 128，但并非其不可改变的理论上限。磁盘容量显示还涉及单位差异：厂商的 TB 通常按十进制计算，TiB 按二进制计算。[^capacity]&lt;/p&gt;
&lt;p&gt;[^capacity]: 1 TB = 10¹² 字节；1 TiB = 2⁴⁰ 字节。一块标称 1 TB 的设备约为 0.91 TiB，分区、文件系统元数据等还会占用空间。&lt;/p&gt;
&lt;h2&gt;UEFI 与 EFI 系统分区&lt;/h2&gt;
&lt;p&gt;UEFI 是固件接口规范，GPT 是分区表方案，二者不是同一种事物。现代 Linux 安装常使用 UEFI 与 GPT，但不要把这种常见组合理解为所有环境下的绝对绑定。&lt;/p&gt;
&lt;p&gt;UEFI 启动通常通过 **EFI 系统分区（ESP）**中的 EFI 程序加载引导器。常见 Linux 安装使用 FAT32 格式的 ESP，挂载到 &lt;code&gt;/boot/efi&lt;/code&gt; 或 &lt;code&gt;/efi&lt;/code&gt;；它与保存系统文件的根文件系统不同，&lt;code&gt;/boot&lt;/code&gt; 也不一定就是 ESP。&lt;/p&gt;
&lt;p&gt;可以检查 &lt;code&gt;/sys/firmware/efi&lt;/code&gt; 是否存在，辅助判断当前系统是否通过 UEFI 启动；容器内看到的结果不能替代宿主机检查。普通数据盘的分区和挂载通常无须修改 ESP。规范定义见 &lt;a href=&quot;https://uefi.org/specifications&quot;&gt;UEFI Specifications&lt;/a&gt;。&lt;/p&gt;
&lt;h1&gt;RAID&lt;/h1&gt;
&lt;p&gt;RAID（Redundant Array of Independent Disks，独立磁盘冗余阵列）把多个成员设备组织为阵列。不同级别在可用容量、性能和容错能力之间做不同取舍；名称中有“冗余”，并不意味着每个级别都具备冗余。&lt;/p&gt;
&lt;h2&gt;硬件 RAID 与 Linux 软件 RAID&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;硬件 RAID&lt;/strong&gt;由专用控制器管理成员盘，通常向 Linux 暴露一个或多个逻辑盘。&lt;code&gt;lsblk&lt;/code&gt; 无法代替控制器管理工具：成员盘状态、槽位、缓存保护和重建进度需要用厂商工具检查。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linux 软件 RAID&lt;/strong&gt;通常由内核 MD 驱动实现，使用 &lt;code&gt;mdadm&lt;/code&gt; 管理。成员设备可以是整盘或分区，阵列设备例如 &lt;code&gt;/dev/md0&lt;/code&gt;。它可以直接承载文件系统，也可以成为 LVM 的下层设备。&lt;/p&gt;
&lt;h2&gt;RAID 0：条带化&lt;/h2&gt;
&lt;p&gt;数据按条带分散到多个成员，多个设备可以并行处理请求。例如两个成员分别保存数据块 &lt;code&gt;A1、A3&lt;/code&gt; 和 &lt;code&gt;A2、A4&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;RAID 0 没有镜像或校验冗余。任一成员失效都可能使整个文件系统不可用，适合可以重建的临时数据，不适合作为需要容错的数据存储。性能收益取决于负载和实现，不能保证简单地按磁盘数量倍增。&lt;/p&gt;
&lt;h2&gt;RAID 1：镜像&lt;/h2&gt;
&lt;p&gt;同一份数据保存在多个成员上。常见的双盘镜像中，两块 1 TB 的盘提供约 1 TB 阵列容量，可容忍其中一块盘故障。&lt;/p&gt;
&lt;p&gt;镜像便于理解，常用于系统盘或容量较小的重要数据卷。读取可能受益于多成员调度，写入需要维护各个副本；镜像数量越多，可用容量比例越低。&lt;/p&gt;
&lt;h2&gt;RAID 5：分布式单校验&lt;/h2&gt;
&lt;p&gt;数据与一份校验信息分布在成员上，通常至少需要三块盘，可容忍一块成员盘故障。等容量成员的近似可用容量为 &lt;code&gt;(N - 1) × S&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;小块随机写可能涉及旧数据、旧校验的读取和更新；全条带写的处理方式不同。重建还会读取其余成员并占用 I/O 资源，因此选型不能只看容量利用率，也要考虑重建期间的性能和再次故障风险。&lt;/p&gt;
&lt;h2&gt;RAID 6：分布式双校验&lt;/h2&gt;
&lt;p&gt;RAID 6 使用两份独立校验信息，通常至少需要四块盘，可容忍任意两块成员盘故障。等容量成员的近似可用容量为 &lt;code&gt;(N - 2) × S&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;相比 RAID 5，它在重建期间保留更多容错余量，但也需要更多校验空间和写入处理。具体性能仍取决于实现、缓存和工作负载。&lt;/p&gt;
&lt;h2&gt;RAID 10：镜像与条带化&lt;/h2&gt;
&lt;p&gt;常见的四盘 RAID 10 先组成两个双盘镜像组，再在镜像组之间条带化：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                   条带化
                /          \
          镜像组 A          镜像组 B
          磁盘 1、2         磁盘 3、4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种布局通常提供总容量的约一半。它保证能容忍任意一块盘故障；多盘同时故障能否继续工作，取决于是否仍为每份数据保留至少一个有效副本。例如磁盘 1 和 3 同时失效仍可能工作，磁盘 1 和 2 同时失效则会丢失镜像组 A。&lt;/p&gt;
&lt;p&gt;RAID 10 常用于随机读写较多、同时需要冗余的场景。Linux MD RAID10 还有不同布局，不能把四盘双镜像的结论不加条件地套到所有实现。&lt;/p&gt;
&lt;h2&gt;容量与容错对比&lt;/h2&gt;
&lt;p&gt;下表假设成员健康且容量相同，&lt;code&gt;N&lt;/code&gt; 为成员数、&lt;code&gt;S&lt;/code&gt; 为单盘容量；忽略元数据开销，热备盘不计入可用容量。RAID 1 按双盘镜像、RAID 10 按常见偶数盘双副本布局比较。&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;RAID 0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;N × S&lt;/code&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;RAID 1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;S&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;双盘镜像可坏 1 块&lt;/td&gt;
&lt;td&gt;简单，容量成本较高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAID 5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(N - 1) × S&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;任意 1 块&lt;/td&gt;
&lt;td&gt;容量与单盘容错折中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAID 6&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(N - 2) × S&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;任意 2 块&lt;/td&gt;
&lt;td&gt;双盘容错，校验开销更高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAID 10&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;N × S / 2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;至少任意 1 块，多盘故障看位置&lt;/td&gt;
&lt;td&gt;随机 I/O 与冗余兼顾&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;:::important[RAID 保护的边界]
RAID 主要应对成员设备故障，无法保留被误删或覆盖的数据，也无法替代独立备份。热备盘可以缩短开始重建前的等待，但不代表重建已经完成，更不会改变阵列原有的校验级别。
:::&lt;/p&gt;
&lt;h2&gt;查看阵列状态&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;cat /proc/mdstat
sudo mdadm --detail /dev/md0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;双盘 RAID 1 的 &lt;code&gt;/proc/mdstat&lt;/code&gt; 中，&lt;code&gt;[UU]&lt;/code&gt; 通常表示两个成员都在；&lt;code&gt;[U_]&lt;/code&gt; 表示缺少一个成员。还需要结合 &lt;code&gt;mdadm --detail&lt;/code&gt; 的阵列状态、活动成员、失败成员和重建进度判断。&lt;/p&gt;
&lt;p&gt;看到 &lt;code&gt;degraded&lt;/code&gt; 时，先确认故障成员与物理槽位的对应关系、其余成员健康状态和备份，再按设备与阵列文档安排更换。不要把 &lt;code&gt;mdadm --create&lt;/code&gt; 当成恢复已有阵列的通用命令。创建、持久组装及成员替换的完整条件见 &lt;a href=&quot;https://man7.org/linux/man-pages/man8/mdadm.8.html&quot;&gt;mdadm(8)&lt;/a&gt; 和 &lt;a href=&quot;https://docs.kernel.org/admin-guide/md.html&quot;&gt;Linux MD 文档&lt;/a&gt;。&lt;/p&gt;
&lt;h1&gt;LVM&lt;/h1&gt;
&lt;p&gt;LVM（Logical Volume Manager，逻辑卷管理器）在块设备之上管理容量，让文件系统不必直接绑定到某一块盘的固定分区。普通线性 LVM 本身不提供冗余；如果一个 LV 跨越多个 PV，丢失其中一个 PV 可能影响整个文件系统。&lt;/p&gt;
&lt;h2&gt;PV、VG 与 LV&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;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;PV&lt;/td&gt;
&lt;td&gt;Physical Volume，物理卷&lt;/td&gt;
&lt;td&gt;将整盘、分区或 RAID 设备交给 LVM 使用&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pvs&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VG&lt;/td&gt;
&lt;td&gt;Volume Group，卷组&lt;/td&gt;
&lt;td&gt;汇集一个或多个 PV 的空间&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vgs&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LV&lt;/td&gt;
&lt;td&gt;Logical Volume，逻辑卷&lt;/td&gt;
&lt;td&gt;从 VG 分配容量，向上提供块设备&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lvs&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;/dev/sdb1（PV） ─┐                 ┌─ lvdata → XFS → /data
                ├─ vgdata（VG） ──┤
/dev/sdc1（PV） ─┘                 └─ lvlogs → ext4 → /srv/logs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;VG 中未分配的空间和文件系统中的可用空间不是同一个量。&lt;code&gt;vgs&lt;/code&gt; 的 &lt;code&gt;VFree&lt;/code&gt; 表示还能分配给 LV 的空间，&lt;code&gt;df&lt;/code&gt; 的 &lt;code&gt;Avail&lt;/code&gt; 表示文件系统内还能使用的空间。&lt;/p&gt;
&lt;h2&gt;查看容量落在哪一层&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;sudo pvs -o pv_name,vg_name,pv_size,pv_free
sudo vgs -o vg_name,vg_size,vg_free
sudo lvs -o lv_name,vg_name,lv_size,segtype,devices
findmnt -T /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;segtype&lt;/code&gt; 有助于识别线性卷、条带卷或精简卷等类型。下面的扩容流程针对普通厚置备 LV；thin pool 还需要单独观察数据区和元数据区，不能仅看 &lt;code&gt;VFree&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;扩容：先准备可分配空间&lt;/h2&gt;
&lt;p&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;VG 已有足够空闲空间&lt;/td&gt;
&lt;td&gt;直接扩 LV&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vgs&lt;/code&gt; 的 &lt;code&gt;VFree&lt;/code&gt; 满足目标增量&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;给现有 VG 新增磁盘&lt;/td&gt;
&lt;td&gt;新设备 → 新 PV → 加入 VG&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pvs&lt;/code&gt; 出现新成员，&lt;code&gt;VFree&lt;/code&gt; 增加&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;原磁盘在平台侧扩大&lt;/td&gt;
&lt;td&gt;系统识别新容量 → 必要时扩大分区 → &lt;code&gt;pvresize&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;原 PV 变大，&lt;code&gt;VFree&lt;/code&gt; 增加&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;例如，确认 &lt;code&gt;/dev/sdc&lt;/code&gt; 是可清空的独立新盘，且未挂载、未被 LVM/RAID/交换空间使用后，可以将&lt;strong&gt;整盘&lt;/strong&gt;加入现有卷组。&lt;code&gt;pvcreate&lt;/code&gt; 会写入 LVM 元数据，不能用于已有数据的设备：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo pvcreate /dev/sdc
sudo vgextend vgdata /dev/sdc
sudo pvs
sudo vgs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里采用整盘 PV，不要再对这块盘创建分区。示例中的设备身份确认方法与&lt;a href=&quot;#%E6%96%B0%E7%A3%81%E7%9B%98%E5%88%9D%E5%A7%8B%E5%8C%96%E7%A4%BA%E4%BE%8B&quot;&gt;新磁盘初始化示例&lt;/a&gt;相同。&lt;/p&gt;
&lt;p&gt;如果平台扩大的是已有磁盘，应先用 &lt;code&gt;lsblk&lt;/code&gt; 确认系统看到了新容量。PV 若在 &lt;code&gt;/dev/sdb1&lt;/code&gt; 上，还需按实际布局扩大分区并让内核识别新边界，最后才运行 &lt;code&gt;sudo pvresize /dev/sdb1&lt;/code&gt;；PV 若直接在整盘上，则对整盘执行 &lt;code&gt;pvresize&lt;/code&gt;。扩大分区时必须保持原起始位置，不能通过重建文件系统“应用”新增空间。具体边界条件见 &lt;a href=&quot;https://man7.org/linux/man-pages/man8/pvresize.8.html&quot;&gt;pvresize(8)&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;扩容：扩大 LV 和文件系统&lt;/h2&gt;
&lt;p&gt;假设 &lt;code&gt;/dev/vgdata/lvdata&lt;/code&gt; 是普通 LV，已挂载到 &lt;code&gt;/data&lt;/code&gt;，VG 至少还有 20 GiB 空闲空间。先确认设备与文件系统类型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;findmnt -T /data -o SOURCE,TARGET,FSTYPE,OPTIONS
sudo lvs /dev/vgdata/lvdata
sudo vgs vgdata
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后扩大 LV：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo lvextend -L +20G /dev/vgdata/lvdata
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;+20G&lt;/code&gt; 表示增加 20 GiB；没有 &lt;code&gt;+&lt;/code&gt; 时表示目标总大小。LV 扩大后，文件系统还需要使用新增空间。&lt;strong&gt;以下两种命令按实际文件系统二选一。&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;XFS&lt;/h3&gt;
&lt;p&gt;XFS 扩容要求文件系统处于挂载状态，使用挂载点作为操作目标：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo xfs_growfs /data
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ext4&lt;/h3&gt;
&lt;p&gt;现代 Linux 上的 ext4 通常支持在线扩容，操作目标是承载文件系统的块设备：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo resize2fs /dev/vgdata/lvdata
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;验证扩容结果&lt;/h3&gt;
&lt;p&gt;最后比较逻辑卷和文件系统大小：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo lvs /dev/vgdata/lvdata
lsblk -f
findmnt -T /data
df -hT /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里预期 LV 和文件系统容量都增加，但 &lt;code&gt;df&lt;/code&gt; 的可用空间不保证恰好增加 20 GiB：文件系统元数据、保留空间及期间的写入都会影响结果。若 &lt;code&gt;lvextend&lt;/code&gt; 成功而文件系统扩容失败，应保留已扩大的 LV，检查原因后重试文件系统扩容，不要用 &lt;code&gt;lvreduce&lt;/code&gt; 回退容量。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lvextend -r&lt;/code&gt; 可以在支持的环境中同时调整文件系统；分两步展示有助于明确哪一层失败。工具行为见 &lt;a href=&quot;https://man7.org/linux/man-pages/man8/lvextend.8.html&quot;&gt;lvextend(8)&lt;/a&gt;、&lt;a href=&quot;https://man7.org/linux/man-pages/man8/xfs_growfs.8.html&quot;&gt;xfs_growfs(8)&lt;/a&gt; 和 &lt;a href=&quot;https://man7.org/linux/man-pages/man8/resize2fs.8.html&quot;&gt;resize2fs(8)&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;缩容与快照的边界&lt;/h2&gt;
&lt;p&gt;扩容和缩容不能简单反向操作。ext4 缩容需要卸载文件系统，按“备份 → 卸载 → 检查 → 缩文件系统 → 缩 LV → 挂载验证”的顺序处理。先缩 LV 可能截断文件系统仍在使用的区域。&lt;/p&gt;
&lt;p&gt;XFS 的缩容能力应以发行版和工具版本正式支持的功能为准；在 RHEL 9 等常见部署中，应按不支持缩容规划，需要更小容量时采用迁移到新文件系统的方式，不把实验性能力作为通用操作方案。&lt;/p&gt;
&lt;p&gt;LVM 快照保存某个时间点的卷视图，可辅助备份或短期回退，但它通常仍与原卷共享底层存储，不能替代独立备份。传统快照的写时复制空间耗尽会使快照失效；精简快照还受 thin pool 数据及元数据容量限制。数据库等应用也需要相应的一致性措施，不能把块层快照自动视为应用一致的备份。&lt;/p&gt;
&lt;p&gt;深入操作可参考 &lt;a href=&quot;https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/configuring_and_managing_logical_volumes/&quot;&gt;LVM 管理文档&lt;/a&gt;。&lt;/p&gt;
&lt;h1&gt;文件系统&lt;/h1&gt;
&lt;p&gt;文件系统在块空间中组织文件内容、目录和元数据。格式化、调整块设备容量、挂载文件系统是不同操作：&lt;code&gt;mkfs&lt;/code&gt; 创建新的文件系统，扩容工具调整已有文件系统，&lt;code&gt;mount&lt;/code&gt; 则把文件系统接入目录树。&lt;/p&gt;
&lt;h2&gt;ext4 与 XFS&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;比较项&lt;/th&gt;
&lt;th&gt;ext4&lt;/th&gt;
&lt;th&gt;XFS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;常见使用&lt;/td&gt;
&lt;td&gt;通用 Linux 文件系统，生态成熟&lt;/td&gt;
&lt;td&gt;通用文件系统，也常用于大容量和并行 I/O 场景&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;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;inode 分配&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;code&gt;mkfs.ext4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mkfs.xfs&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;常见离线检查工具&lt;/td&gt;
&lt;td&gt;&lt;code&gt;e2fsck&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xfs_repair&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;两者都支持日志功能，但日志主要帮助文件系统在异常后恢复一致性，不能保证应用尚未持久化的数据不丢失。文件系统也不存在脱离工作负载的绝对性能排名，选型还要考虑发行版支持、备份工具和恢复需求。&lt;/p&gt;
&lt;p&gt;:::caution[格式化会创建新的文件系统]
对已有数据的设备执行 &lt;code&gt;mkfs&lt;/code&gt; 可能破坏原有文件系统。挂载失败、空间未增加或设备显示异常时，都不应把重新格式化当作修复步骤。
:::&lt;/p&gt;
&lt;h2&gt;FAT32、exFAT 与 NTFS：跨系统交换数据&lt;/h2&gt;
&lt;p&gt;Linux 数据卷常用 ext4 或 XFS，但 U 盘、移动硬盘、Windows 分区和 EFI 系统分区还经常使用 FAT32、exFAT 或 NTFS。选择时除了容量，还要确认目标系统和设备的读写支持。&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;Linux 中的常见类型或驱动名&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FAT32&lt;/td&gt;
&lt;td&gt;广泛兼容的 U 盘、嵌入式设备及常见 ESP&lt;/td&gt;
&lt;td&gt;单个文件最大为 4 GiB − 1 字节；不提供原生 Unix 权限和日志&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vfat&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;exFAT&lt;/td&gt;
&lt;td&gt;需要跨 Windows、macOS、Linux 交换大文件的移动存储&lt;/td&gt;
&lt;td&gt;支持超过 4 GiB 的文件；不提供原生 Unix 权限和文件系统日志，旧设备可能不支持&lt;/td&gt;
&lt;td&gt;&lt;code&gt;exfat&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTFS&lt;/td&gt;
&lt;td&gt;Windows 系统盘和数据盘、与 Windows 共享的磁盘&lt;/td&gt;
&lt;td&gt;支持大文件、ACL 和元数据日志；Linux 下的权限映射及功能取决于驱动和挂载选项&lt;/td&gt;
&lt;td&gt;内核 &lt;code&gt;ntfs3&lt;/code&gt; 或用户态 &lt;code&gt;ntfs-3g&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;FAT32 的单文件限制与整个卷的容量是两回事：即使还有大量空闲空间，也无法保存一个 5 GiB 的文件。exFAT 解决了这类大文件交换需求，但不能因此认为所有只支持 FAT32 的设备都能识别 exFAT。FAT 的格式和 Linux 挂载行为可参考 &lt;a href=&quot;https://docs.kernel.org/filesystems/vfat.html&quot;&gt;Linux VFAT 文档&lt;/a&gt;，exFAT 的能力定义见 &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/fileio/exfat-specification&quot;&gt;Microsoft exFAT 规范&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;FAT32 和 exFAT 不像 ext4 那样持久保存每个文件的 Unix 属主与权限，Linux 通常通过 &lt;code&gt;uid&lt;/code&gt;、&lt;code&gt;gid&lt;/code&gt;、&lt;code&gt;umask&lt;/code&gt; 等挂载选项呈现访问权限。需要 Unix 权限、符号链接等语义的服务数据目录，不宜仅为跨系统兼容而改用这两种格式。&lt;/p&gt;
&lt;p&gt;使用 NTFS 时先确认发行版安装和启用了哪一种驱动；内核 &lt;code&gt;ntfs3&lt;/code&gt; 与 &lt;code&gt;ntfs-3g&lt;/code&gt; 的选项和支持能力不能混用。Windows 休眠或快速启动留下的卷状态可能使读写挂载被拒绝，应回到 Windows 完成正常关闭和必要检查，不用强制挂载绕过保护。内核驱动能力见 &lt;a href=&quot;https://docs.kernel.org/filesystems/ntfs3.html&quot;&gt;NTFS3 文档&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;对已有设备，先用 &lt;code&gt;lsblk -f&lt;/code&gt; 或 &lt;code&gt;blkid&lt;/code&gt; 识别实际类型。缺少驱动或工具时按发行版安装相应支持，不要为解决“无法挂载”直接格式化；可移动存储写入结束后应正常卸载再拔出。&lt;/p&gt;
&lt;h2&gt;Btrfs 与其他常见挂载类型&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Btrfs&lt;/strong&gt; 是 Linux 上另一种本地文件系统，支持写时复制、数据与元数据校验、子卷和快照。它适合需要这些能力且发行版与维护工具支持的场景；快照与原数据共享存储，不等于独立备份。子卷、共享数据和元数据分配还会影响容量统计，不能只按普通分区大小理解，可结合 &lt;code&gt;btrfs filesystem usage &amp;lt;挂载点&amp;gt;&lt;/code&gt; 查看。具体选择与维护边界见 &lt;a href=&quot;https://btrfs.readthedocs.io/en/latest/&quot;&gt;Btrfs 官方文档&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;findmnt&lt;/code&gt; 还可能显示 &lt;code&gt;tmpfs&lt;/code&gt;、&lt;code&gt;nfs&lt;/code&gt; 或 &lt;code&gt;cifs&lt;/code&gt;。这些应与本地磁盘文件系统区分：&lt;code&gt;tmpfs&lt;/code&gt; 使用虚拟内存，可能使用交换空间，卸载或重启后数据不保留；NFS 和 SMB/CIFS 则通过网络访问远端存储。它们不是新建本地数据盘时与 ext4、FAT32 等直接互换的格式选项。&lt;/p&gt;
&lt;p&gt;实际选择可以从用途出发：Linux 服务数据先考虑发行版支持的 ext4/XFS；需要子卷和快照等能力时评估 Btrfs；大文件跨系统交换常考虑 exFAT；兼容旧设备时核实 FAT32；已有 Windows 数据卷通常保留 NTFS 并确认驱动支持。&lt;/p&gt;
&lt;h2&gt;inode、目录项与文件内容&lt;/h2&gt;
&lt;p&gt;以 ext4、XFS 等 Linux 文件系统为例，inode 保存文件类型、权限、属主、时间戳以及数据位置等元数据；目录项建立“名称 → inode”的关系。文件名属于目录内容，不是 inode 内部的文件名字段。不同文件系统的磁盘格式不同，不能把这套布局直接套到 FAT32 等格式上。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/data/report.csv ──目录项──► inode ──► 文件数据
/data/report.bak ──目录项──► 同一个 inode（硬链接）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;删除一个名称不一定立即释放数据：还要看是否存在其他硬链接，以及是否有进程仍然打开这个文件。最后一个名称被删除但文件仍被进程打开时，空间通常要等最后一个引用关闭后才释放。&lt;/p&gt;
&lt;h2&gt;分别检查容量和 inode&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;df -hT /data
df -i /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;df -hT&lt;/code&gt; 查看文件系统类型、容量及使用量，&lt;code&gt;df -i&lt;/code&gt; 查看 inode 使用情况。大量小文件可能让 ext4 的 inode 先于数据空间耗尽；XFS 虽然动态分配 inode，也仍可能受剩余空间及元数据分配限制。&lt;/p&gt;
&lt;p&gt;inode 耗尽时，定位文件数量异常的目录往往比只寻找大文件更有效。配额也可能限制特定用户或项目，即使整个文件系统还有空闲空间，也不代表所有写入都能继续。&lt;/p&gt;
&lt;h1&gt;挂载与持久化配置&lt;/h1&gt;
&lt;h2&gt;挂载点与当前状态&lt;/h2&gt;
&lt;p&gt;挂载把文件系统接到一个目录上。例如把 &lt;code&gt;/dev/sdb1&lt;/code&gt; 挂载到 &lt;code&gt;/data&lt;/code&gt; 后，访问 &lt;code&gt;/data&lt;/code&gt; 就是在访问该文件系统。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo mkdir -p /data
sudo mount /dev/sdb1 /data
findmnt --mountpoint /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;挂载会遮住目录中原有内容，不会自动搬迁或合并这些文件。因此应先检查挂载点是否已被使用、目录中是否有数据。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;findmnt -T /data&lt;/code&gt; 查找承载该路径的文件系统，即使 &lt;code&gt;/data&lt;/code&gt; 并非独立挂载点，也可能返回根文件系统；&lt;code&gt;findmnt --mountpoint /data&lt;/code&gt; 则用于核实 &lt;code&gt;/data&lt;/code&gt; 本身是否已挂载。这一区别在排查“数据写到系统盘”时尤其重要。&lt;/p&gt;
&lt;h2&gt;UUID 与 &lt;code&gt;/etc/fstab&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;手工 &lt;code&gt;mount&lt;/code&gt; 不会自动生成开机挂载配置。&lt;code&gt;/etc/fstab&lt;/code&gt; 描述持久挂载关系，通常使用文件系统 UUID，避免依赖可能变化的设备枚举名称。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo blkid /dev/sdb1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如，XFS 的配置行可以是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UUID=11111111-2222-4333-8444-555555555555 /data xfs defaults 0 0
&lt;/code&gt;&lt;/pre&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;&lt;code&gt;UUID=…&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;文件系统 UUID，不是 GPT 的 &lt;code&gt;PARTUUID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;挂载点&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/data&lt;/code&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;code&gt;xfs&lt;/code&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;code&gt;defaults&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;使用一组默认选项，具体效果还受文件系统及环境影响&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dump 标记&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;不由传统 &lt;code&gt;dump&lt;/code&gt; 调度备份&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;检查顺序&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;不通过传统 fsck 启动检查流程检查 XFS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;非根 ext4 数据卷通常使用末字段 &lt;code&gt;2&lt;/code&gt;，根文件系统常为 &lt;code&gt;1&lt;/code&gt;，还需结合发行版启动机制。磁盘克隆可能复制文件系统 UUID，因此 UUID 也需要避免重复。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;nofail&lt;/code&gt; 适用于允许缺盘时继续启动的数据盘，不应为消除错误而无条件添加。若业务必须依赖 &lt;code&gt;/data&lt;/code&gt;，还应确保服务在挂载失败时不会继续向根文件系统中的同名目录写入；systemd 服务可通过 &lt;code&gt;RequiresMountsFor=/data&lt;/code&gt; 声明挂载依赖。&lt;/p&gt;
&lt;h2&gt;检查配置与实际挂载&lt;/h2&gt;
&lt;p&gt;编辑前备份 &lt;code&gt;fstab&lt;/code&gt;，编辑后先检查其可解析性和可用性：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo findmnt --verify --verbose
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 systemd 系统上，修改后还应让管理器重新加载配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl daemon-reload
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对尚未挂载的新数据卷，可以执行 &lt;code&gt;sudo mount /data&lt;/code&gt;，让 &lt;code&gt;mount&lt;/code&gt; 从 &lt;code&gt;fstab&lt;/code&gt; 读取来源、类型和选项，再用 &lt;code&gt;findmnt --mountpoint /data&lt;/code&gt; 确认结果。&lt;/p&gt;
&lt;p&gt;:::important[配置检查不等于实际挂载成功]
&lt;code&gt;findmnt --verify&lt;/code&gt; 不会真正挂载文件系统；&lt;code&gt;mount -a&lt;/code&gt; 则会尝试挂载符合条件的 fstab 条目，并通常跳过已经挂载的文件系统。因此，&lt;code&gt;mount -a&lt;/code&gt; 没有报错不能证明已有挂载的选项已经更新，也不能保证下次启动的所有依赖都满足。
:::&lt;/p&gt;
&lt;p&gt;对已使用的文件系统，应在合适的维护条件下验证重新挂载或卸载后挂载，不要为了测试配置直接中断业务。配置字段与行为见 &lt;a href=&quot;https://man7.org/linux/man-pages/man5/fstab.5.html&quot;&gt;fstab(5)&lt;/a&gt;、&lt;a href=&quot;https://man7.org/linux/man-pages/man8/mount.8.html&quot;&gt;mount(8)&lt;/a&gt; 和 &lt;a href=&quot;https://man7.org/linux/man-pages/man8/findmnt.8.html&quot;&gt;findmnt(8)&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;卸载与占用检查&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;sudo umount /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;出现 &lt;code&gt;target is busy&lt;/code&gt; 时，先退出位于该挂载点内的工作目录，再检查进程和子挂载：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;findmnt -R /data
sudo fuser -vm /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;让相关应用关闭文件或正常停止后，再重新卸载。&lt;code&gt;umount -l&lt;/code&gt; 的延迟卸载不会立刻结束所有引用，不能把它作为后续格式化或修复已具备安全条件的证明。&lt;/p&gt;
&lt;h1&gt;新磁盘初始化示例&lt;/h1&gt;
&lt;p&gt;目标是在一块&lt;strong&gt;确认可清空的新数据盘&lt;/strong&gt; &lt;code&gt;/dev/sdb&lt;/code&gt; 上建立 GPT 分区和 XFS，并挂载到 &lt;code&gt;/data&lt;/code&gt;。这是一个独立示例，不与其他章节中的 LVM 布局叠加；系统盘、已有 RAID 成员或 PV 不适用。&lt;/p&gt;
&lt;p&gt;示例按常见的 systemd/udev 系统编写，需要 &lt;code&gt;parted&lt;/code&gt;、&lt;code&gt;xfsprogs&lt;/code&gt;、&lt;code&gt;util-linux&lt;/code&gt;，以及用于检查现有 PV 的 &lt;code&gt;lvm2&lt;/code&gt;。命令中的 &lt;code&gt;/dev/sdb&lt;/code&gt; 只是示例设备名，不能据此认定真实机器上的同名设备就是新盘。&lt;/p&gt;
&lt;h2&gt;1. 确认设备身份与挂载点&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS,MODEL,SERIAL
sudo fdisk -l /dev/sdb
sudo wipefs --no-act /dev/sdb
sudo pvs
cat /proc/mdstat
swapon --show
findmnt --mountpoint /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结合序列号、容量、平台分配记录或物理槽位确认目标。若已有分区，还需逐个检查其文件系统签名和用途；设备没有挂载也可能正在被 LVM、RAID、交换空间或其他程序使用。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;findmnt --mountpoint /data&lt;/code&gt; 没有结果仅表示它不是当前挂载点。若目录已经存在，还要检查是否为空；若是符号链接或已有业务数据，先解决路径和迁移问题再继续。&lt;/p&gt;
&lt;p&gt;:::caution[下面的操作会改写目标设备]
&lt;code&gt;mklabel&lt;/code&gt; 会写入新的分区表，&lt;code&gt;mkfs.xfs&lt;/code&gt; 会创建文件系统。只有设备身份、已有用途和数据保留要求都已确认后，才继续执行。发现旧签名或命令拒绝操作时先调查，不添加强制选项绕过保护。
:::&lt;/p&gt;
&lt;h2&gt;2. 创建分区并等待系统识别&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;sudo parted --script /dev/sdb mklabel gpt
sudo parted --script --align optimal /dev/sdb mkpart data xfs 1MiB 100%
sudo partprobe /dev/sdb
sudo udevadm settle
lsblk -o NAME,SIZE,TYPE,FSTYPE /dev/sdb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里的 &lt;code&gt;data&lt;/code&gt; 是 GPT 分区名称，&lt;code&gt;xfs&lt;/code&gt; 是分区创建时的文件系统类型提示，文件系统尚未创建。确认 &lt;code&gt;/dev/sdb1&lt;/code&gt; 已出现且大小符合预期；内核若无法重新读取分区表，应停止并检查占用情况。&lt;/p&gt;
&lt;h2&gt;3. 创建文件系统并临时挂载&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;sudo mkfs.xfs /dev/sdb1
sudo mkdir -p /data
sudo mount /dev/sdb1 /data
findmnt --mountpoint /data -o SOURCE,TARGET,FSTYPE,OPTIONS
df -hT /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预期来源为新分区，类型为 &lt;code&gt;xfs&lt;/code&gt;，目标为 &lt;code&gt;/data&lt;/code&gt;。新文件系统顶层目录通常由 root 拥有，后续应按应用用户分配目录和权限，不能用放开所有权限代替权限规划。&lt;/p&gt;
&lt;h2&gt;4. 保存配置并验证通过 fstab 挂载&lt;/h2&gt;
&lt;p&gt;读取 UUID，并备份、编辑配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo blkid /dev/sdb1
sudo cp --backup=numbered /etc/fstab /etc/fstab.before-data
sudoedit /etc/fstab
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;加入一行，将占位内容替换为实际 UUID：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UUID=&amp;lt;实际文件系统UUID&amp;gt; /data xfs defaults 0 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查配置；以下按 systemd 系统示范：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo findmnt --verify --verbose
sudo systemctl daemon-reload
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;本例是尚未交给业务使用的新文件系统，可以退出该目录后卸载，再只指定挂载点进行挂载，以确认 fstab 条目被实际使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /
sudo umount /data
sudo mount /data
findmnt --mountpoint /data -o SOURCE,TARGET,FSTYPE,OPTIONS
df -hT /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每一步失败都应先处理原因，不继续执行后续步骤。对照来源、类型、挂载点和容量确认结果后，再交给应用使用；不需要通过立即重启来试错。&lt;/p&gt;
&lt;h1&gt;容量、性能与故障定位&lt;/h1&gt;
&lt;p&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;&lt;code&gt;df -hT&lt;/code&gt;、&lt;code&gt;df -i&lt;/code&gt;、配额&lt;/td&gt;
&lt;td&gt;数据空间、inode、配额限制&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;df&lt;/code&gt; 高而 &lt;code&gt;du&lt;/code&gt; 不高&lt;/td&gt;
&lt;td&gt;&lt;code&gt;findmnt&lt;/code&gt;、&lt;code&gt;du -x&lt;/code&gt;、&lt;code&gt;lsof +L1&lt;/code&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;code&gt;lsblk -f&lt;/code&gt;、&lt;code&gt;blkid&lt;/code&gt;、内核日志&lt;/td&gt;
&lt;td&gt;设备、类型、参数、底层 I/O 错误&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;只读或 I/O 错误&lt;/td&gt;
&lt;td&gt;&lt;code&gt;findmnt&lt;/code&gt;、&lt;code&gt;journalctl -k&lt;/code&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;code&gt;lsblk&lt;/code&gt;、&lt;code&gt;pvs&lt;/code&gt;、&lt;code&gt;vgs&lt;/code&gt;、&lt;code&gt;lvs&lt;/code&gt;、&lt;code&gt;df&lt;/code&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;code&gt;iostat&lt;/code&gt;、&lt;code&gt;pidstat&lt;/code&gt;、内核日志&lt;/td&gt;
&lt;td&gt;工作负载变化、排队、重建、设备错误&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;空间不足：容量、inode 与配额&lt;/h2&gt;
&lt;p&gt;假设异常路径位于 &lt;code&gt;/data&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;findmnt -T /data
df -hT /data
df -i /data
sudo du -xhd1 /data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;du -x&lt;/code&gt; 限制在同一个文件系统内统计，避免把嵌套挂载也计算进来；&lt;code&gt;-d1&lt;/code&gt; 先看一层目录，找到占用大的目录后再向下缩小范围。它需要遍历目录，大目录树上可能有明显 I/O 开销。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;容量满&lt;/strong&gt;：检查日志增长、临时文件、保留策略与业务数据，明确数据用途后再清理或扩容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;inode 满&lt;/strong&gt;：关注缓存、会话、队列等大量小文件目录；GNU &lt;code&gt;du --inodes -x -d1 /data&lt;/code&gt; 可辅助查找。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;总空间充足但特定用户写入失败&lt;/strong&gt;：检查用户、组或项目配额；工具取决于文件系统与配额配置。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;No space left on device&lt;/code&gt; 不只表示物理磁盘字节用完；&lt;code&gt;Disk quota exceeded&lt;/code&gt; 则通常应优先检查配额。容器中还可能受自己的可写层、挂载命名空间或平台限制影响。&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;df&lt;/code&gt; 与 &lt;code&gt;du&lt;/code&gt; 为什么不同&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;df&lt;/code&gt; 统计文件系统分配情况，&lt;code&gt;du&lt;/code&gt; 遍历可见目录并统计文件占用，两者口径不同。先确认统计的是同一个文件系统，并考虑权限不足、文件系统元数据和保留空间。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo lsof +L1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结合设备、路径、进程和文件大小判断是否与目标文件系统有关。若日志被删除但服务仍保持文件描述符，应按服务支持的方式重新打开日志，或安排正常重启；再比较 &lt;code&gt;df&lt;/code&gt; 的变化。再次删除路径并不能释放那个已无名称的文件。&lt;/p&gt;
&lt;p&gt;还有一种情况是：应用先向 &lt;code&gt;/data&lt;/code&gt; 写入数据，随后在该目录挂载了另一文件系统。旧数据被遮住，但仍占用原文件系统的空间。检查这些数据需要合适的维护或独立查看方式，不应直接卸载正在使用的业务文件系统。&lt;/p&gt;
&lt;h2&gt;挂载失败或挂载点忙&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;lsblk -f
sudo blkid /dev/sdb1
sudo findmnt --verify --verbose
sudo journalctl -k -b -n 100 --no-pager
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;按错误信息缩小范围：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;设备或 UUID 不存在&lt;/strong&gt;：检查设备是否识别、阵列是否组装、LV 是否激活，以及配置是否引用了旧 UUID。&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;出现 timeout、reset 或 I/O error&lt;/strong&gt;：继续检查控制器、链路、磁盘和阵列，不要只反复尝试挂载。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;没有 systemd 日志的环境可查看 &lt;code&gt;sudo dmesg&lt;/code&gt;。挂载点忙时结合 &lt;code&gt;findmnt -R /data&lt;/code&gt; 和 &lt;code&gt;fuser -vm /data&lt;/code&gt; 定位占用；不要直接强制终止未知业务进程。&lt;/p&gt;
&lt;h2&gt;只读、文件系统错误与修复边界&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;findmnt -T /data -o SOURCE,TARGET,FSTYPE,OPTIONS
sudo journalctl -k -b -n 200 --no-pager
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只读可能来自显式 &lt;code&gt;ro&lt;/code&gt; 配置，也可能是文件系统错误后的保护行为。不同文件系统的反应不一样：ext4 可以按错误策略重新挂载为只读，XFS 遇到严重错误可能进入 shutdown 状态，此时即使挂载选项仍显示 &lt;code&gt;rw&lt;/code&gt;，读写也可能返回错误。&lt;/p&gt;
&lt;p&gt;先确认底层存储健康，再制定备份、维护和修复方案。不要把 &lt;code&gt;mount -o remount,rw&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;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ext4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;e2fsck -fn &amp;lt;设备&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;文件系统应已卸载；挂载状态下的检查结果不可靠&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XFS&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xfs_repair -n &amp;lt;设备&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;文件系统应已卸载；未回放的日志可能阻止完整检查&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;即便是不修改模式，也需要考虑故障盘的读取压力。介质持续报错时应优先考虑数据保护，而不是反复扫描。XFS 的 &lt;code&gt;xfs_repair -L&lt;/code&gt; 会清除日志，可能丢失元数据更新，不应作为默认选项。&lt;/p&gt;
&lt;p&gt;维护条件和恢复限制见 &lt;a href=&quot;https://man7.org/linux/man-pages/man8/e2fsck.8.html&quot;&gt;e2fsck(8)&lt;/a&gt; 与 &lt;a href=&quot;https://man7.org/linux/man-pages/man8/xfs_repair.8.html&quot;&gt;xfs_repair(8)&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;RAID 降级与 LVM 容量异常&lt;/h2&gt;
&lt;p&gt;RAID 降级时先使用 &lt;code&gt;cat /proc/mdstat&lt;/code&gt; 和 &lt;code&gt;mdadm --detail&lt;/code&gt; 确认成员及重建状态；硬件 RAID 则使用控制器工具。重建会增加剩余成员负载，阵列仍可读写不代表冗余已经恢复。&lt;/p&gt;
&lt;p&gt;LVM 容量异常可以逐层比较：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lsblk：磁盘、分区是否已变大？
   ↓
pvs：PV 是否已经识别新增空间？
   ↓
vgs：VG 是否有可分配的空闲空间？
   ↓
lvs：目标 LV 是否已扩大？
   ↓
findmnt + df：是否查看了正确的文件系统，它是否已扩容？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 LV 已经变大而 &lt;code&gt;df&lt;/code&gt; 没变化，通常应检查文件系统扩容步骤；如果 PV 缺失，先检查设备、阵列与连接状态，不能对原设备重新执行 &lt;code&gt;pvcreate&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;I/O 性能：把指标与负载一起看&lt;/h2&gt;
&lt;p&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;IOPS&lt;/td&gt;
&lt;td&gt;每秒完成或处理的 I/O 数量，具体口径取决于工具&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;块大小、并发、链路和设备能力&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;同样是 10,000 IOPS，4 KiB 请求对应的吞吐量约为 39 MiB/s，1 MiB 请求则约为 9.8 GiB/s。因此不能脱离请求大小比较 IOPS，也不能拿顺序大块吞吐量推断数据库随机访问表现。&lt;/p&gt;
&lt;p&gt;安装 &lt;code&gt;sysstat&lt;/code&gt; 后，可持续观察设备与进程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iostat -xz -y 1
pidstat -d 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两条命令可在不同终端运行。&lt;code&gt;iostat&lt;/code&gt; 的 &lt;code&gt;-y&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;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r/s&lt;/code&gt;、&lt;code&gt;w/s&lt;/code&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;code&gt;rkB/s&lt;/code&gt;、&lt;code&gt;wkB/s&lt;/code&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;code&gt;r_await&lt;/code&gt;、&lt;code&gt;w_await&lt;/code&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;code&gt;aqu-sz&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;平均未完成请求数量，旧版本常称 &lt;code&gt;avgqu-sz&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;队列深并不必然异常，要结合延迟与吞吐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;%util&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;统计区间内设备有 I/O 处理的时间比例&lt;/td&gt;
&lt;td&gt;对并行 SSD、RAID，接近 100% 不等于已用尽全部性能&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;%iowait&lt;/code&gt; 是 CPU 时间统计中的一个类别，不是磁盘忙碌率，也不能直接定位哪块盘出现瓶颈。应把设备延迟、队列、吞吐、应用响应时间与正常基线一起比较，并检查是否存在阵列重建、备份扫描、温度节流、链路重置等变化。&lt;/p&gt;
&lt;p&gt;如果需要继续确认设备健康，可按设备类型使用 &lt;code&gt;smartctl -a &amp;lt;设备&amp;gt;&lt;/code&gt; 或 &lt;code&gt;nvme smart-log &amp;lt;控制器设备&amp;gt;&lt;/code&gt;；硬件 RAID 后的磁盘可能需要控制器专用透传参数。健康状态正常也不能排除链路或性能问题。&lt;/p&gt;
&lt;p&gt;指标定义见 &lt;a href=&quot;https://man7.org/linux/man-pages/man1/iostat.1.html&quot;&gt;iostat(1)&lt;/a&gt;。内核请求队列的实现细节可继续阅读 &lt;a href=&quot;https://docs.kernel.org/block/blk-mq.html&quot;&gt;blk-mq&lt;/a&gt;。&lt;/p&gt;
&lt;h1&gt;参考资料&lt;/h1&gt;
&lt;p&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;NVMe&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://nvmexpress.org/specifications/&quot;&gt;NVM Express Specifications&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;基础规范、命令集、PCIe 与网络传输规范&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SATA&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://sata-io.org/developers/sata-ecosystem&quot;&gt;SATA-IO：The SATA Ecosystem&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;SATA 技术及外形生态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SCSI 与 SAS&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.t10.org/&quot;&gt;T10 Technical Committee&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;SCSI 架构、命令集与 SAS 标准&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;固件与分区&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://uefi.org/specifications&quot;&gt;UEFI Specifications&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;UEFI、GPT 与 ESP 定义&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux 存储管理&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/managing_storage_devices/&quot;&gt;RHEL 9：Managing Storage Devices&lt;/a&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;a href=&quot;https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/configuring_and_managing_logical_volumes/&quot;&gt;RHEL 9：Configuring and Managing Logical Volumes&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;卷管理、快照与容量调整&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;软件 RAID&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.kernel.org/admin-guide/md.html&quot;&gt;Linux MD&lt;/a&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;a href=&quot;https://man7.org/linux/man-pages/&quot;&gt;Linux manual pages&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lsblk&lt;/code&gt;、&lt;code&gt;mount&lt;/code&gt;、&lt;code&gt;mdadm&lt;/code&gt;、LVM 与文件系统工具手册&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>Linux：远程管理与安全</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E8%BF%9C%E7%A8%8B%E7%AE%A1%E7%90%86%E4%B8%8E%E5%AE%89%E5%85%A8/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E8%BF%9C%E7%A8%8B%E7%AE%A1%E7%90%86%E4%B8%8E%E5%AE%89%E5%85%A8/</guid><description>远程管理需要同时解决服务器身份确认、用户认证和访问授权。</description><pubDate>Sun, 13 Sep 2026 06:24:34 GMT</pubDate><content:encoded>&lt;p&gt;远程管理需要同时解决服务器身份确认、用户认证和访问授权。SSH 提供加密通道，实际能否安全维护还取决于密钥管理、服务配置、系统权限与网络暴露范围。&lt;/p&gt;
&lt;h1&gt;SSH 与身份认证&lt;/h1&gt;
&lt;p&gt;SSH 是协议，OpenSSH 是常见实现。连接时涉及两类不同密钥：&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;向客户端证明服务器身份&lt;/td&gt;
&lt;td&gt;服务端 /etc/ssh/ssh_host_*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;用户认证密钥&lt;/td&gt;
&lt;td&gt;向服务器证明用户身份&lt;/td&gt;
&lt;td&gt;客户端私钥与服务端 authorized_keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;已知主机记录&lt;/td&gt;
&lt;td&gt;保存客户端信任的服务器公钥&lt;/td&gt;
&lt;td&gt;客户端 ~/.ssh/known_hosts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;首次连接应通过管理控制台、资产记录等可信渠道核对主机指纹。主机密钥变化可能来自重装、地址复用或冒充，应先确认原因；不要直接删除 known_hosts 记录来消除警告。&lt;/p&gt;
&lt;h1&gt;配置公钥登录&lt;/h1&gt;
&lt;p&gt;示例使用 OpenSSH，远端账户为 &lt;code&gt;ops&lt;/code&gt;，地址 &lt;code&gt;server.example.com&lt;/code&gt; 需要替换。先确认本地目标密钥文件不存在，避免覆盖已有密钥。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_ops -C &quot;ops workstation&quot;
ssh-copy-id -i ~/.ssh/id_ed25519_ops.pub ops@server.example.com
ssh -i ~/.ssh/id_ed25519_ops -o IdentitiesOnly=yes ops@server.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;私钥保留在客户端，建议设置口令；只把公钥交给服务器。算法可用性受客户端、服务端版本与组织密码策略影响。没有 ssh-copy-id 时，按服务器管理方式将公钥写入目标账户的 authorized_keys。&lt;/p&gt;
&lt;p&gt;远端 &lt;code&gt;~/.ssh&lt;/code&gt; 通常设置为 &lt;code&gt;700&lt;/code&gt;，&lt;code&gt;authorized_keys&lt;/code&gt; 设置为 &lt;code&gt;600&lt;/code&gt;，并确保属主正确。家目录和路径权限也会影响 OpenSSH 的检查。&lt;/p&gt;
&lt;p&gt;必须新开独立会话验证登录成功，再考虑关闭旧认证方式。已有会话可用并不能证明新的认证配置正确。&lt;/p&gt;
&lt;h2&gt;管理连接配置&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Host prod-app
    HostName app.internal.example
    User ops
    IdentityFile ~/.ssh/id_ed25519_ops
    IdentitiesOnly yes
    ProxyJump bastion

Host bastion
    HostName bastion.example.com
    User ops
    IdentityFile ~/.ssh/id_ed25519_ops
    IdentitiesOnly yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;配置后使用 &lt;code&gt;ssh prod-app&lt;/code&gt;。&lt;code&gt;ProxyJump&lt;/code&gt; 通过跳板机转发连接，一般不需要把私钥复制到跳板机。默认不启用 agent forwarding；被转发到不可信主机的认证代理可能被利用。&lt;/p&gt;
&lt;h1&gt;修改 SSH 服务配置&lt;/h1&gt;
&lt;p&gt;:::warning[保留恢复入口]
修改监听端口或认证策略前，保留当前连接，确认控制台等恢复通道可用，并检查主机防火墙和云安全组。配置重载后，以新会话验证成功再结束旧连接。
:::&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;查看主配置及其 Include 文件，确认是否存在 Match 条件块。&lt;/li&gt;
&lt;li&gt;修改所需选项，避免复制与现有策略冲突的整段配置。&lt;/li&gt;
&lt;li&gt;检查语法和有效配置。&lt;/li&gt;
&lt;li&gt;重载对应服务，再从实际来源地址建立新连接。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;sudo sshd -t
sudo sshd -T
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sshd -t&lt;/code&gt; 检查语法和密钥等基本条件；&lt;code&gt;sshd -T&lt;/code&gt; 输出有效配置。有 Match 条件时，需要用 &lt;code&gt;-C&lt;/code&gt; 提供对应用户、主机和地址条件检查实际匹配结果。&lt;/p&gt;
&lt;p&gt;服务名可能是 &lt;code&gt;ssh&lt;/code&gt; 或 &lt;code&gt;sshd&lt;/code&gt;，以本机单元为准。检查通过后执行对应服务的 &lt;code&gt;systemctl reload&lt;/code&gt;，并查看日志。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PasswordAuthentication no&lt;/code&gt; 不一定关闭键盘交互式认证；PAM、多因素认证与 &lt;code&gt;KbdInteractiveAuthentication&lt;/code&gt;、&lt;code&gt;AuthenticationMethods&lt;/code&gt; 的组合需一并确认。不要在使用多因素认证时盲目禁用其依赖的认证方式。&lt;/p&gt;
&lt;h1&gt;授权与安全策略&lt;/h1&gt;
&lt;h2&gt;账户和文件权限&lt;/h2&gt;
&lt;p&gt;登录成功只证明通过认证，不代表可以访问所有文件。使用专用账户和 sudo 授权需要的管理操作，避免共享私钥和长期共享 root 账户。&lt;/p&gt;
&lt;p&gt;撤销访问时，同时检查公钥、证书、密码、现有会话及自动化凭据。仅设置 nologin 或锁定密码，不应被当成覆盖全部访问途径的撤销方案。&lt;/p&gt;
&lt;h2&gt;SELinux 与 AppArmor&lt;/h2&gt;
&lt;p&gt;传统权限和 ACL 控制基于用户身份的访问；SELinux、AppArmor 等机制还可限制进程能访问哪些资源。传统权限满足后仍可能被安全策略拒绝。&lt;/p&gt;
&lt;p&gt;SELinux 系统可先只读检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;getenforce
ls -Z /srv/www
ps -eZ
sudo ausearch -m AVC -ts recent
sudo restorecon -nRv /srv/www
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后一条只预览标签修复。若默认路径标签错误，确认后再用 &lt;code&gt;restorecon&lt;/code&gt; 应用；自定义路径应先用 &lt;code&gt;semanage fcontext&lt;/code&gt; 建立符合服务用途的持久规则，再恢复标签。不要把关闭 SELinux 或自动接受所有 audit2allow 建议当作常规修复。&lt;/p&gt;
&lt;p&gt;AppArmor 系统可用 &lt;code&gt;aa-status&lt;/code&gt; 查看启用的配置文件，并根据审计日志检查具体规则。两种机制的策略模型不同，不能直接照搬配置命令。&lt;/p&gt;
&lt;h1&gt;网络暴露与审计&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;ss -lntp&lt;/code&gt; 只能证明本机 TCP 监听状态；外部访问还取决于绑定地址、路由、防火墙、NAT 和云安全组。管理端口尽量只对必要来源开放，并从允许及不允许的网络分别验证。&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;/td&gt;
&lt;td&gt;目标地址、路由、安全组、防火墙、监听地址&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connection refused&lt;/td&gt;
&lt;td&gt;目标主机是否到达，端口是否监听，是否被主动拒绝&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permission denied&lt;/td&gt;
&lt;td&gt;用户名、认证方法、实际提交的密钥、服务端日志&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;公钥正确仍失败&lt;/td&gt;
&lt;td&gt;文件属主权限、authorized_keys 选项、有效配置、安全策略&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&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;ssh -v&lt;/code&gt; 查看认证过程；服务端使用对应服务的 journal，或发行版配置的认证日志。共享诊断输出前去除主机、用户名等不必要的信息。&lt;/p&gt;
&lt;h1&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://man.openbsd.org/ssh_config&quot;&gt;OpenSSH 客户端配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://man.openbsd.org/sshd_config&quot;&gt;OpenSSH 服务端配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://man.openbsd.org/sshd&quot;&gt;OpenSSH 服务端命令&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/using_selinux/index&quot;&gt;Red Hat：使用 SELinux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Linux：用户与权限管理</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E7%94%A8%E6%88%B7%E4%B8%8E%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E7%94%A8%E6%88%B7%E4%B8%8E%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86/</guid><description>Linux 通过用户身份、用户组和权限控制资源访问。</description><pubDate>Sun, 13 Sep 2026 05:18:13 GMT</pubDate><content:encoded>&lt;p&gt;Linux 通过用户身份、用户组和权限控制资源访问。排查权限问题时，需要同时确认进程以谁的身份运行、路径各级目录是否可进入，以及是否存在 ACL 或安全策略限制。&lt;/p&gt;
&lt;h1&gt;用户与用户组&lt;/h1&gt;
&lt;p&gt;用户以 UID 标识，组以 GID 标识；用户名只是便于使用的名称。一个用户有一个主组，还可以属于多个附加组。服务通常使用专用账户运行，避免共享管理员身份。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/etc/passwd&lt;/code&gt; 保存本地账户信息，&lt;code&gt;/etc/shadow&lt;/code&gt; 保存受保护的密码相关信息；目录服务中的账户不一定出现在这些文件里。查询系统实际采用的身份信息应使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;id
id alice
getent passwd alice
getent group project
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;id&lt;/code&gt; 不带用户名时显示当前进程的身份；带用户名时查询账户配置。管理员修改附加组后，已有会话通常仍使用原来的组列表，需要重新登录。&lt;/p&gt;
&lt;h2&gt;创建账户与调整组&lt;/h2&gt;
&lt;p&gt;以下示例由管理员执行，假设 &lt;code&gt;alice&lt;/code&gt; 和 &lt;code&gt;project&lt;/code&gt; 尚不存在，且系统提供 shadow-utils：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo groupadd project
sudo useradd -m -s /bin/bash alice
sudo passwd alice
sudo usermod -aG project alice
id alice
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-m&lt;/code&gt; 创建家目录，&lt;code&gt;-aG&lt;/code&gt; 追加附加组。单独使用 &lt;code&gt;usermod -G&lt;/code&gt; 会替换原有附加组。服务账户的创建参数应遵循软件包或发行版约定，不必为其设置交互式密码。&lt;/p&gt;
&lt;p&gt;锁定密码不等于撤销所有访问：SSH 公钥、现有会话和其他认证方式可能仍有效。停用账户时要一起检查授权密钥、会话、计划任务和文件归属；删除账户前先明确数据保留要求。&lt;/p&gt;
&lt;h1&gt;文件与目录权限&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;ls -l&lt;/code&gt; 中的 &lt;code&gt;rwxr-xr--&lt;/code&gt; 对应八进制 &lt;code&gt;754&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;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;r&lt;/td&gt;
&lt;td&gt;读取文件内容&lt;/td&gt;
&lt;td&gt;列出目录中的名称&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;w&lt;/td&gt;
&lt;td&gt;修改文件内容&lt;/td&gt;
&lt;td&gt;配合 x 创建、删除或重命名目录项&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;x&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;/p&gt;
&lt;pre&gt;&lt;code&gt;ls -ld /srv/project
ls -l /srv/project/report.txt
namei -l /srv/project/report.txt
chmod u=rw,g=r,o= /srv/project/report.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后一条命令要求当前用户是文件属主或具备相应权限，将权限设为 &lt;code&gt;640&lt;/code&gt;。更改属主通常需要管理员权限；不要为解决单个文件问题直接递归修改整棵目录。&lt;/p&gt;
&lt;h2&gt;umask 与特殊权限&lt;/h2&gt;
&lt;p&gt;新文件权限由程序请求的权限去掉 &lt;code&gt;umask&lt;/code&gt; 屏蔽的位得到，并非普通算术减法。常见程序请求普通文件 &lt;code&gt;666&lt;/code&gt;、目录 &lt;code&gt;777&lt;/code&gt;；&lt;code&gt;umask 027&lt;/code&gt; 通常得到 &lt;code&gt;640&lt;/code&gt; 和 &lt;code&gt;750&lt;/code&gt;。默认 ACL 会影响这一过程。&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;SUID&lt;/td&gt;
&lt;td&gt;可执行文件按文件属主身份取得有效 UID&lt;/td&gt;
&lt;td&gt;受挂载和安全策略限制；Linux 不按脚本的 SUID 位提升权限&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SGID&lt;/td&gt;
&lt;td&gt;目录中新建对象继承目录所属组&lt;/td&gt;
&lt;td&gt;不会自动授予组写权限&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sticky bit&lt;/td&gt;
&lt;td&gt;共享目录中限制删除或重命名他人文件&lt;/td&gt;
&lt;td&gt;常见于 /tmp；仍需考虑目录属主和特权用户&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ACL&lt;/td&gt;
&lt;td&gt;为指定用户、组设置额外访问规则&lt;/td&gt;
&lt;td&gt;ACL mask 可能限制有效权限&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;使用 &lt;code&gt;getfacl 路径&lt;/code&gt; 查看 ACL，关注输出中的 &lt;code&gt;effective&lt;/code&gt;；不能只看某条 ACL 是否写了 &lt;code&gt;w&lt;/code&gt;。&lt;/p&gt;
&lt;h1&gt;建立共享工作目录&lt;/h1&gt;
&lt;p&gt;假设 &lt;code&gt;project&lt;/code&gt; 组和成员已经存在，&lt;code&gt;/srv/project&lt;/code&gt; 是计划新建的目录，文件系统支持 ACL，系统已安装 &lt;code&gt;setfacl&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo mkdir /srv/project
sudo chown root:project /srv/project
sudo chmod 2770 /srv/project
sudo setfacl -d -m u::rwx,g::rwx,m::rwx,o::--- /srv/project
getfacl /srv/project
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SGID 保证新文件继承 &lt;code&gt;project&lt;/code&gt; 组，默认 ACL 使常规创建的文件保留组协作权限。程序若明确请求更严格的权限，默认 ACL 不能强行扩大权限。&lt;/p&gt;
&lt;p&gt;成员重新登录后，在该目录创建一个测试文件，检查其所属组和 ACL，再由另一位成员验证能否修改。确认成功后删除测试文件。已有文件不会因为目录增加默认 ACL 而自动改变。&lt;/p&gt;
&lt;h1&gt;sudo 与最小授权&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;sudo&lt;/code&gt; 根据策略以其他身份执行命令。通过 &lt;code&gt;sudo -l&lt;/code&gt; 查看当前授权，使用 &lt;code&gt;visudo&lt;/code&gt; 或 &lt;code&gt;visudo -f /etc/sudoers.d/文件名&lt;/code&gt; 编辑规则并检查语法。&lt;/p&gt;
&lt;p&gt;授权应限定需要的操作。允许任意编辑器、Shell，或允许以 root 执行普通用户可修改的脚本，往往等于授予完整管理员权限。规则文件的属主和权限也必须满足 sudo 的要求。&lt;/p&gt;
&lt;h1&gt;权限问题排查&lt;/h1&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;id、namei -l、getfacl&lt;/td&gt;
&lt;td&gt;检查路径搜索权限和 ACL mask&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;加组后仍无权限&lt;/td&gt;
&lt;td&gt;当前会话的 id&lt;/td&gt;
&lt;td&gt;重新登录后再验证，不能只查账户配置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;权限位正确仍拒绝访问&lt;/td&gt;
&lt;td&gt;SELinux/AppArmor 日志、挂载选项&lt;/td&gt;
&lt;td&gt;按策略与路径修复，不使用 chmod 777 绕过&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;无法执行脚本&lt;/td&gt;
&lt;td&gt;解释器、文件格式、x 位、noexec&lt;/td&gt;
&lt;td&gt;分别检查路径、权限和挂载条件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;可写文件无法删除&lt;/td&gt;
&lt;td&gt;父目录权限、sticky bit、只读挂载&lt;/td&gt;
&lt;td&gt;文件内容权限不决定目录项删除权限&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/coreutils/manual/html_node/File-permissions.html&quot;&gt;GNU Coreutils：文件权限&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man5/acl.5.html&quot;&gt;acl(5)：Linux ACL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sudo.ws/docs/man/sudoers.man/&quot;&gt;sudoers 手册&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Linux：软件包管理与常用工具</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E8%BD%AF%E4%BB%B6%E5%8C%85%E7%AE%A1%E7%90%86%E4%B8%8E%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E8%BD%AF%E4%BB%B6%E5%8C%85%E7%AE%A1%E7%90%86%E4%B8%8E%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7/</guid><description>软件包管理器负责安装、升级和跟踪软件及其依赖。</description><pubDate>Sun, 13 Sep 2026 02:20:46 GMT</pubDate><content:encoded>&lt;p&gt;软件包管理器负责安装、升级和跟踪软件及其依赖。日常维护应先确认发行版、软件来源和变更影响，再验证软件是否真正可用。&lt;/p&gt;
&lt;h1&gt;软件包与软件源&lt;/h1&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;Debian、Ubuntu&lt;/td&gt;
&lt;td&gt;.deb、dpkg&lt;/td&gt;
&lt;td&gt;APT：交互使用 apt，脚本通常使用 apt-get&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fedora、RHEL 系列&lt;/td&gt;
&lt;td&gt;.rpm、RPM&lt;/td&gt;
&lt;td&gt;DNF，旧版本系统也可能使用 YUM&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;底层工具管理本地包及安装记录，上层工具结合软件源解析和下载依赖。不同发行版及版本的软件包不能仅凭扩展名通用安装。DNF 4 与 DNF 5 的部分选项和插件行为不同，应以本机版本手册为准。&lt;/p&gt;
&lt;p&gt;软件源决定能安装什么版本、由谁提供维护。使用发行版或软件项目认可的仓库，核对签名密钥来源；HTTPS 和包签名解决不同问题，不能通过关闭签名校验来处理仓库错误。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat /etc/os-release
command -v apt
command -v dnf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;未找到某个命令在这里是正常结果，后续只选择适合当前发行版的一组命令。&lt;/p&gt;
&lt;h1&gt;查询与安装&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;任务&lt;/th&gt;
&lt;th&gt;APT 系统&lt;/th&gt;
&lt;th&gt;DNF 系统&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;搜索软件&lt;/td&gt;
&lt;td&gt;apt search nginx&lt;/td&gt;
&lt;td&gt;dnf search nginx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;查看候选包信息&lt;/td&gt;
&lt;td&gt;apt show nginx&lt;/td&gt;
&lt;td&gt;dnf info nginx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;查看已安装版本&lt;/td&gt;
&lt;td&gt;dpkg-query -W nginx&lt;/td&gt;
&lt;td&gt;rpm -q nginx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;查看包内文件&lt;/td&gt;
&lt;td&gt;dpkg -L nginx&lt;/td&gt;
&lt;td&gt;rpm -ql nginx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;查找已安装文件归属&lt;/td&gt;
&lt;td&gt;dpkg -S /usr/bin/curl&lt;/td&gt;
&lt;td&gt;rpm -qf /usr/bin/curl&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;软件名、包名和可执行文件名不一定一致。查看来源与候选版本后，再安装所需软件。例如安装 &lt;code&gt;curl&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
apt policy curl
sudo apt install curl
curl --version
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;dnf info curl
sudo dnf install curl
curl --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装前阅读事务清单，确认是否要移除、替换或升级其他包。包安装成功只说明包事务完成；对于服务，还需验证配置、监听地址和实际请求。&lt;/p&gt;
&lt;h2&gt;更新与卸载&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;apt update&lt;/code&gt; 更新软件包索引，不升级已安装软件。&lt;code&gt;dnf check-update&lt;/code&gt; 检查可用更新；返回码 &lt;code&gt;100&lt;/code&gt; 表示有更新，不能在自动化中一律当作命令失败。&lt;/p&gt;
&lt;p&gt;升级前查看受影响的服务、兼容性说明和重启要求。数据库等有状态服务还需要可恢复的备份。不要把一次全系统升级当作解决某个依赖问题的默认步骤。&lt;/p&gt;
&lt;p&gt;卸载时先查看即将移除的包和依赖。APT 的 &lt;code&gt;remove&lt;/code&gt; 与 &lt;code&gt;purge&lt;/code&gt; 对包配置的处理不同，但两者都不意味着所有业务数据一定被删除或保留；以软件的数据路径和卸载脚本为准。&lt;/p&gt;
&lt;h1&gt;归档、压缩与文件传输&lt;/h1&gt;
&lt;h2&gt;tar、gzip 与 zip&lt;/h2&gt;
&lt;p&gt;归档把多个对象装入一个文件；压缩减少数据体积。&lt;code&gt;tar&lt;/code&gt; 常用于归档，&lt;code&gt;gzip&lt;/code&gt; 压缩数据流，ZIP 则同时支持多文件封装与压缩。&lt;/p&gt;
&lt;p&gt;假设当前目录包含要归档的 &lt;code&gt;reports/&lt;/code&gt;，且目标文件不存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tar -czf reports.tar.gz reports/
tar -tzf reports.tar.gz
mkdir restore-preview
tar -xzf reports.tar.gz -C restore-preview
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;先查看归档成员，再解压到新目录，检查内容后再使用。不要直接以 root 将不明归档解压到系统目录。&lt;code&gt;gzip 文件&lt;/code&gt; 通常用压缩文件替换原文件；需要保留源文件时可以使用 &lt;code&gt;gzip -c 文件 &amp;gt; 文件.gz&lt;/code&gt;，并避免覆盖已有目标。&lt;/p&gt;
&lt;h2&gt;rsync 与 scp&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;scp&lt;/code&gt; 适合简单复制；现代 OpenSSH 的 scp 默认使用 SFTP 传输。&lt;code&gt;rsync&lt;/code&gt; 适合比较并增量同步，远端通常也需要安装 rsync。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rsync -ani ./reports/ backup@example.com:/srv/backup/reports/
rsync -ai ./reports/ backup@example.com:/srv/backup/reports/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;示例地址需要替换，远端目录应已授权给该用户。&lt;code&gt;reports/&lt;/code&gt; 表示复制目录内容；不带尾部斜杠时通常还会包含该目录名。核对预览中的目标路径，再执行正式同步。&lt;/p&gt;
&lt;p&gt;同步不等于保留历史备份：误改的数据也可能被同步。默认不要增加 &lt;code&gt;--delete&lt;/code&gt;；它会删除目标侧多余文件，需要单独审阅删除清单。&lt;/p&gt;
&lt;h1&gt;会话与辅助工具&lt;/h1&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;tmux&lt;/td&gt;
&lt;td&gt;会话可重连，但不替代服务管理和故障重启&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP 请求检查&lt;/td&gt;
&lt;td&gt;curl&lt;/td&gt;
&lt;td&gt;区分 DNS、连接、TLS 和 HTTP 状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON 筛选&lt;/td&gt;
&lt;td&gt;jq&lt;/td&gt;
&lt;td&gt;先确认字段结构和缺失值处理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;设备与进程 I/O 采样&lt;/td&gt;
&lt;td&gt;sysstat 中的 iostat、pidstat&lt;/td&gt;
&lt;td&gt;连续采样并结合业务负载判断&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;文件传输终端集成&lt;/td&gt;
&lt;td&gt;rz、sz&lt;/td&gt;
&lt;td&gt;需要终端支持相应协议，并非所有 SSH 客户端可用&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;tmux new -s maintenance
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在会话中按 &lt;code&gt;Ctrl+b&lt;/code&gt;，再按 &lt;code&gt;d&lt;/code&gt; 分离；使用 &lt;code&gt;tmux attach -t maintenance&lt;/code&gt; 重新连接。&lt;code&gt;tmux ls&lt;/code&gt; 可确认会话是否仍在。需要开机启动、重启策略和日志管理的长期进程应交给服务管理器。&lt;/p&gt;
&lt;h1&gt;常见问题&lt;/h1&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;仓库签名失败&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;/tr&gt;
&lt;tr&gt;
&lt;td&gt;已安装却找不到命令&lt;/td&gt;
&lt;td&gt;包文件列表、PATH、实际提供命令的子包&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;升级后行为变化&lt;/td&gt;
&lt;td&gt;版本说明、配置差异、服务日志及回退条件&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.debian.org/doc/manuals/debian-reference/ch02.en.html&quot;&gt;Debian：APT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dnf.readthedocs.io/en/latest/command_ref.html&quot;&gt;DNF 命令参考&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/tar/manual/&quot;&gt;GNU tar 手册&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://download.samba.org/pub/rsync/rsync.1&quot;&gt;rsync 手册&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Linux：Shell 自动化脚本</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linuxshell-%E8%87%AA%E5%8A%A8%E5%8C%96%E8%84%9A%E6%9C%AC/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linuxshell-%E8%87%AA%E5%8A%A8%E5%8C%96%E8%84%9A%E6%9C%AC/</guid><description>Bash 脚本把系统命令与条件、循环和函数组合成可重复执行的流程。</description><pubDate>Sun, 13 Sep 2026 02:11:56 GMT</pubDate><content:encoded>&lt;p&gt;Bash 脚本把系统命令与条件、循环和函数组合成可重复执行的流程。它适合文件处理、检查和命令编排；复杂数据模型、大量并发和长期运行的业务逻辑通常更适合 Python、Go 等语言。&lt;/p&gt;
&lt;h1&gt;解释器与执行环境&lt;/h1&gt;
&lt;p&gt;脚本首行的 Shebang 决定直接执行时使用的解释器。&lt;code&gt;#!/usr/bin/env bash&lt;/code&gt; 从 PATH 查找 Bash；固定路径便于控制环境，但要确认目标主机存在该路径。使用数组、双中括号等 Bash 特性时，不要声明为 sh。&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;bash report.sh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bash 读取文件，不要求文件有执行权限&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;./report.sh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;需要执行权限，按 Shebang 启动解释器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;source report.sh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;在当前 Shell 执行，可能改变变量和目录，exit 也可能关闭当前 Shell&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;自动任务不应依赖交互式别名、当前目录或个人启动配置。明确工具路径、输入路径、执行用户和输出位置。&lt;/p&gt;
&lt;h1&gt;输入、变量与数据边界&lt;/h1&gt;
&lt;h2&gt;参数与引用&lt;/h2&gt;
&lt;p&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;$0&lt;/td&gt;
&lt;td&gt;脚本调用名称&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$1、$2&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;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&quot;$@&quot;&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;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;if (( $# != 1 )); then
    printf &apos;用法：%s 文件路径\n&apos; &quot;$0&quot; &amp;gt;&amp;amp;2
    exit 2
fi
input_file=$1
if [[ ! -f &quot;$input_file&quot; || ! -r &quot;$input_file&quot; ]]; then
    printf &apos;文件不存在或不可读：%s\n&apos; &quot;$input_file&quot; &amp;gt;&amp;amp;2
    exit 1
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;普通变量只属于当前 Shell，export 后会由新启动的子进程继承。函数内部用 local 限定变量，固定值可用 readonly。避免复用 HOME、PATH 等系统变量。&lt;/p&gt;
&lt;h2&gt;数组与文本读取&lt;/h2&gt;
&lt;p&gt;文件名列表用数组或逐个参数处理，不把多个路径拼成一个字符串再执行。不要通过 eval 重新解释外部输入。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for item in &quot;$@&quot;; do
    printf &apos;%s\n&apos; &quot;$item&quot;
done

while IFS= read -r line || [[ -n &quot;$line&quot; ]]; do
    printf &apos;%s\n&apos; &quot;$line&quot;
done &amp;lt; &quot;$input_file&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一段保留含空格的参数；第二段保留反斜杠及首尾空白，并处理末尾没有换行的最后一行。这两段是独立处理方式，不是文件名解析的通用替代品。Bash 变量不能保存 NUL 字节。&lt;/p&gt;
&lt;p&gt;数组可写作 &lt;code&gt;files=(&quot;a.txt&quot; &quot;my file.txt&quot;)&lt;/code&gt;，用 &lt;code&gt;&quot;${files[@]}&quot;&lt;/code&gt; 展开。遍历通配符时需要处理无匹配情况，例如循环内检查 &lt;code&gt;[[ -f &quot;$file&quot; ]] || continue&lt;/code&gt;。&lt;/p&gt;
&lt;h1&gt;条件、循环与函数&lt;/h1&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;code&gt;[ -f &quot;$path&quot; ]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;POSIX 文件测试，括号两侧需要空格&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[ -n &quot;$value&quot; ]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bash 字符串测试&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(( count &amp;gt; 0 ))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;整数判断，不支持浮点计算&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[ &quot;$value&quot; =~ ^[0-9]+$ ]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bash 正则匹配，先校验再做数值计算&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;if command; then ...; fi&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;直接使用命令退出状态&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;case 适合固定选项，for 遍历对象，while 根据条件继续。break 结束循环，continue 跳过本次。判断执行用户应用 id 或 Bash 的 EUID，不能信任可被修改的 USER 环境变量。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;case &quot;${1-}&quot; in
    check) printf &apos;执行检查\n&apos; ;;
    help) printf &apos;用法：%s {check|help}\n&apos; &quot;$0&quot; ;;
    *) printf &apos;不支持的操作\n&apos; &amp;gt;&amp;amp;2; exit 2 ;;
esac
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;函数与结果&lt;/h2&gt;
&lt;p&gt;函数用 return 返回退出状态，用标准输出传递文本，用标准错误传递诊断。函数的 $1 等参数属于此次函数调用。命令替换会移除输出末尾换行，不适合保存任意原始数据。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;is_readable_file() {
    local candidate=$1
    [[ -f &quot;$candidate&quot; &amp;amp;&amp;amp; -r &quot;$candidate&quot; ]]
}
if is_readable_file &quot;/etc/hosts&quot;; then
    printf &apos;文件可读\n&apos;
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;错误处理与资源清理&lt;/h1&gt;
&lt;p&gt;零通常表示成功，非零必须结合命令语义判断：grep 的 1 是没有匹配，2 才表示错误。服务进程处于 active 也不等于接口健康，检查脚本应明确报告它实际验证了什么。&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;set -u&lt;/td&gt;
&lt;td&gt;未设置变量展开时报错&lt;/td&gt;
&lt;td&gt;不检测所有空字符串&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;set -e&lt;/td&gt;
&lt;td&gt;部分未处理失败使脚本退出&lt;/td&gt;
&lt;td&gt;if、条件列表等上下文存在例外&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;set -o pipefail&lt;/td&gt;
&lt;td&gt;管道返回最右侧非零状态&lt;/td&gt;
&lt;td&gt;上游 SIGPIPE 等也可能造成非零&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;:::important[显式处理关键步骤]
这些选项不能替代错误分支。尤其不要把所有非零状态统一吞掉，也不要默认失败后重试修改操作。重试必须有次数、超时以及幂等条件。
:::&lt;/p&gt;
&lt;p&gt;Bash 的 &lt;code&gt;((count++))&lt;/code&gt; 在旧值为零时返回非零，可能触发 set -e；计数可使用 &lt;code&gt;count=$((count + 1))&lt;/code&gt;。创建临时文件用 mktemp，并用 trap 清理本次创建的明确路径，不对未经校验的变量执行递归删除。&lt;/p&gt;
&lt;h1&gt;完整示例：生成日志统计&lt;/h1&gt;
&lt;p&gt;以下脚本只读取一个普通文本文件，把统计写到标准输出，不修改源文件。输入格式规定为“时间、级别、消息”，以空白分隔，级别在第 2 字段。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/usr/bin/env bash
set -u
set -o pipefail

if (( $# != 1 )); then
    printf &apos;用法：%s 日志文件\n&apos; &quot;$0&quot; &amp;gt;&amp;amp;2
    exit 2
fi
input_file=$1
if [[ ! -f &quot;$input_file&quot; || ! -r &quot;$input_file&quot; ]]; then
    printf &apos;无法读取：%s\n&apos; &quot;$input_file&quot; &amp;gt;&amp;amp;2
    exit 1
fi

if awk &apos;
    NF &amp;lt; 2 { invalid++; next }
    { total++ }
    $2 == &quot;ERROR&quot; { errors++ }
    END {
        printf &quot;records=%d errors=%d invalid=%d\n&quot;, total, errors, invalid
        if (invalid &amp;gt; 0) exit 2
    }
&apos; &amp;lt; &quot;$input_file&quot;; then
    exit 0
else
    status=$?
    printf &apos;统计未正常完成，状态：%d\n&apos; &quot;$status&quot; &amp;gt;&amp;amp;2
    exit &quot;$status&quot;
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在练习目录准备输入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2026-09-19T10:00:00Z INFO started
2026-09-19T10:01:00Z ERROR timeout
2026-09-19T10:02:00Z ERROR retry
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;先用 &lt;code&gt;bash -n report.sh&lt;/code&gt; 检查语法，再运行 &lt;code&gt;bash report.sh app.log&lt;/code&gt;。预期为 &lt;code&gt;records=3 errors=2 invalid=0&lt;/code&gt;，退出状态为零。分别验证空文件、不可读路径和格式错误行，确认失败不会被误报为成功。此处命令是读者验证步骤，不代表已经在本文环境中执行。&lt;/p&gt;
&lt;h1&gt;配置生成、后台与定时任务&lt;/h1&gt;
&lt;p&gt;Here Document 适合多行文本；分隔符加引号时不做变量展开：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat &amp;lt;&amp;lt;&apos;EOF&apos;
message=$HOME
port=8080
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;若重定向到文件，先确认目标和覆盖策略；生成配置后先校验，再替换生效文件。Bash 的 Here String &lt;code&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/code&gt; 适合把短字符串送到标准输入，会追加换行，不是 POSIX sh 语法。&lt;/p&gt;
&lt;p&gt;后台启动后要用 wait 收集状态，不能把成功启动等同于执行成功。定时运行可选择 cron 或 systemd timer，需定义工作目录、环境、日志、超时及防重入策略。使用 flock 时还应确认所有入口采用同一锁。&lt;/p&gt;
&lt;h1&gt;常见问题&lt;/h1&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;用户、PATH、目录、凭据及交互输入&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;路径含空格就失败&lt;/td&gt;
&lt;td&gt;引号、&quot;$@&quot;、数组，避免解析 ls 输出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;管道失败未上报&lt;/td&gt;
&lt;td&gt;pipefail 和各命令退出码含义&lt;/td&gt;
&lt;/tr&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;调试日志泄露凭据&lt;/td&gt;
&lt;td&gt;bash -x 会展开参数，敏感部分不要跟踪&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/bash/manual/&quot;&gt;Bash 手册&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/Conditional-Constructs.html&quot;&gt;Bash 条件构造&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html&quot;&gt;Bash set 内建命令&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.shellcheck.net/wiki/&quot;&gt;ShellCheck 文档&lt;/a&gt;：常见脚本缺陷及原因。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Linux：文本检索与处理</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E6%96%87%E6%9C%AC%E6%A3%80%E7%B4%A2%E4%B8%8E%E5%A4%84%E7%90%86/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E6%96%87%E6%9C%AC%E6%A3%80%E7%B4%A2%E4%B8%8E%E5%A4%84%E7%90%86/</guid><description>文本处理通常包括定位文件、筛选记录、提取字段、转换和统计。</description><pubDate>Sun, 13 Sep 2026 02:11:15 GMT</pubDate><content:encoded>&lt;p&gt;文本处理通常包括定位文件、筛选记录、提取字段、转换和统计。先确认数据格式与范围，再选择工具，比直接套用一长串管道更可靠。以下示例以 GNU 工具和常见 awk 为基础，其他实现的扩展选项可能不同。&lt;/p&gt;
&lt;h1&gt;选择工具与输入格式&lt;/h1&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;find、locate&lt;/td&gt;
&lt;td&gt;locate 查询索引，可能滞后&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;筛选文本&lt;/td&gt;
&lt;td&gt;grep&lt;/td&gt;
&lt;td&gt;固定字符串和正则表达式分别选择&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;阅读部分内容&lt;/td&gt;
&lt;td&gt;less、head、tail&lt;/td&gt;
&lt;td&gt;不必读完整个大文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;提取字段&lt;/td&gt;
&lt;td&gt;cut、awk&lt;/td&gt;
&lt;td&gt;必须知道分隔方式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;转换文本&lt;/td&gt;
&lt;td&gt;sed、tr&lt;/td&gt;
&lt;td&gt;sed 面向行和模式，tr 面向字符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;排序与统计&lt;/td&gt;
&lt;td&gt;sort、uniq、wc&lt;/td&gt;
&lt;td&gt;注意区域设置、相邻重复和换行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;解析结构化内容&lt;/td&gt;
&lt;td&gt;jq、专用 CSV 工具&lt;/td&gt;
&lt;td&gt;不用正则代替完整解析器&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;管道把上游标准输出送给下游标准输入，错误输出默认不进入管道。处理中途失败时，下游仍可能输出看似正常的结果，必须检查状态和诊断。&lt;/p&gt;
&lt;h1&gt;定位文件与筛选文本&lt;/h1&gt;
&lt;h2&gt;文件搜索&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;find /var/log -type f -name &apos;*.log&apos;
find /var/log -type f -name &apos;*.log&apos; -exec grep -HnF &apos;ERROR&apos; {} +
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;find 查找文件系统对象，grep 搜索内容。通配符加引号避免 Shell 提前展开；-exec 的加号将多个路径分批作为独立参数传入，能保留带空格的文件名。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;find /var/log -type f -mtime -1&lt;/code&gt; 查找不足 24 小时内修改的文件，不等于自然日“今天”。&lt;code&gt;-size +100M&lt;/code&gt; 使用 MiB 单位及取整比较。权限错误意味着结果可能不完整。&lt;/p&gt;
&lt;h2&gt;grep 的匹配方式&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;code&gt;grep -nF &apos;ERROR&apos; app.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;固定字符串搜索并显示行号&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;`grep -nE &apos;ERROR&lt;/td&gt;
&lt;td&gt;WARN&apos; app.log`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -iF &apos;error&apos; app.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;忽略大小写&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -vF &apos;DEBUG&apos; app.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;排除匹配行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -cF &apos;ERROR&apos; app.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;统计匹配行，非字符串出现次数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -nF -C 3 &apos;timeout&apos; app.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;同时显示前后上下文&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -rnF --include=&apos;*.conf&apos; &apos;listen&apos; ./config&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;限定文件类型递归搜索&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;grep 返回 0 表示有匹配，1 表示无匹配，2 表示错误。用 -q 只取状态时还要注意提前退出的行为；不能一概把任何非零值都解释为工具故障。&lt;/p&gt;
&lt;h1&gt;正则表达式&lt;/h1&gt;
&lt;p&gt;以下按扩展正则表达式说明；grep 默认的基本正则在分组等语法上有所不同，优先显式使用 grep -E。&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;^ERROR&lt;/td&gt;
&lt;td&gt;行首 ERROR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;timeout$&lt;/td&gt;
&lt;td&gt;行尾 timeout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[0-9]+&lt;/td&gt;
&lt;td&gt;一个或多个 ASCII 数字&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;colou?r&lt;/td&gt;
&lt;td&gt;u 可有可无&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(ERROR|WARN)&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;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Shell 的 &lt;code&gt;*.log&lt;/code&gt; 是路径通配符；正则 &lt;code&gt;.*\.log$&lt;/code&gt; 表示以 .log 结束的文本。模式默认用单引号传递。固定文本包含点号、方括号等字符时，grep -F 通常更直接。&lt;/p&gt;
&lt;p&gt;不同工具的正则方言、Unicode 和区域设置支持不同，不要默认 grep、sed、awk、PCRE 的表达式完全通用。详见 &lt;a href=&quot;https://www.gnu.org/software/grep/manual/html_node/Regular-Expressions.html&quot;&gt;GNU grep 正则说明&lt;/a&gt;。&lt;/p&gt;
&lt;h1&gt;字段提取与转换&lt;/h1&gt;
&lt;h2&gt;cut 与 awk&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;cut -d &apos;:&apos; -f 1,3 /etc/passwd&lt;/code&gt; 提取简单分隔文本的第 1、3 字段。cut 不理解 CSV 引号、转义和字段内换行；通用 CSV 应使用专用解析器。&lt;/p&gt;
&lt;p&gt;awk 默认以空白划分字段，$0 是整行，$1 起为字段；NF 是字段数，NR 是记录数。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;awk -F &apos;:&apos; &apos;{print $1, $3}&apos; /etc/passwd
awk &apos;NF &amp;lt; 3 {print NR, $0}&apos; app.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第二条只适用于规定至少三列的日志，列数不足也可能是空行或续行，需要结合格式判断。&lt;/p&gt;
&lt;h2&gt;sed 与 tr&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;sed -n &apos;1,20p&apos; app.conf
sed &apos;s/old_name/new_name/g&apos; app.conf
sed &apos;/^[[:space:]]*#/d&apos; app.conf
printf &apos;hello\n&apos; | LC_ALL=C tr &apos;[:lower:]&apos; &apos;[:upper:]&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;sed 默认将结果写到标准输出；s 替换，g 处理行内全部匹配，d 不输出匹配行。替换端的 &amp;amp; 有特殊含义。tr 转换字符集合，不负责替换任意多字符字符串。&lt;/p&gt;
&lt;p&gt;:::warning[修改前先检查范围]
不要使用 &lt;code&gt;sed ... file &amp;gt; file&lt;/code&gt;，重定向可能先清空源文件。先生成独立结果、比较差异并通过应用检查，再替换配置。sed -i 的参数和备份行为在 GNU 与 BSD 实现中不同。
:::&lt;/p&gt;
&lt;h1&gt;排序、去重与统计&lt;/h1&gt;
&lt;p&gt;sort 默认按区域设置进行文本排序，数字使用 -n，逆序加 -r，指定字段可用 -k。需要可重复的字节排序时可为该命令设置 LC_ALL=C。&lt;/p&gt;
&lt;p&gt;uniq 只合并相邻重复行，所以常用 &lt;code&gt;sort values.txt | uniq -c | sort -nr&lt;/code&gt; 计数。它改变顺序，不适合直接用于必须保留原始顺序的记录。&lt;/p&gt;
&lt;p&gt;wc 的 -l 数换行符，-c 数字节，-m 数字符；末行没有换行时，“记录数”与 wc -l 可能不同。中文文本的字节数也通常大于字符数。&lt;/p&gt;
&lt;h1&gt;完整示例：分析访问记录&lt;/h1&gt;
&lt;p&gt;这里主动使用固定三列的简化格式，不假设所有 Nginx 日志都把状态码放在第 9 列。真实 access log 的字段取决于 log_format。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192.0.2.10 / 200
192.0.2.11 /login 200
192.0.2.12 /missing 404
192.0.2.13 /api 500
192.0.2.14 /api 500
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;先检查格式，再统计：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;awk &apos;NF != 3 {print &quot;异常行&quot;, NR, $0}&apos; access.tsv
awk &apos;{print $3}&apos; access.tsv | sort | uniq -c | sort -nr
awk &apos;$3 &amp;gt;= 500 &amp;amp;&amp;amp; $3 &amp;lt; 600 {print}&apos; access.tsv
awk &apos;$3 == 404 {count++} END {print count+0}&apos; access.tsv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预期状态计数为 200 两条、500 两条、404 一条；并列项顺序不作为判断依据。5xx 筛选应输出两个 /api 请求，404 计数为 1。各状态数量之和应为 5，与有效记录总数相符。&lt;/p&gt;
&lt;p&gt;在格式已确认的前提下，&lt;code&gt;awk &apos;{print $2}&apos; access.tsv | sort | uniq -c | sort -nr | head -n 10&lt;/code&gt; 可统计高频路径。结果表示请求次数，不是独立用户数；带查询参数的路径是否归并取决于分析目标。&lt;/p&gt;
&lt;h1&gt;将路径传给其他命令&lt;/h1&gt;
&lt;p&gt;xargs 将标准输入转成命令参数，默认按空白和引号规则解析，不能直接用于任意文件名。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;find ./logs -type f -name &apos;*.log&apos; -print0 | xargs -0 -r wc -l --
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;前提是 ./logs 存在；-print0 与 -0 使用 NUL 分隔，GNU xargs 的 -r 防止空输入时执行。分批执行可能出现多个小计，不能直接当作全局总计。简单场景用 &lt;code&gt;find ... -exec wc -l -- {} +&lt;/code&gt; 也可以。&lt;/p&gt;
&lt;p&gt;涉及删除时，先列出并核对目标；不要把演示性的 xargs rm 或 find -delete 当作默认处理流程。&lt;/p&gt;
&lt;h1&gt;常见问题&lt;/h1&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;awk 统计字段错位&lt;/td&gt;
&lt;td&gt;请求中空格、引号、时区、续行；改用正确格式解析&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;排序结果不同&lt;/td&gt;
&lt;td&gt;LC_ALL、数值选项、字段范围&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;文件名被拆开&lt;/td&gt;
&lt;td&gt;使用 NUL 分隔或 find -exec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;管道给出结果却有错误&lt;/td&gt;
&lt;td&gt;独立检查每一步、标准错误及 pipefail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON 提取不稳定&lt;/td&gt;
&lt;td&gt;用 jq 访问字段，不用 grep 匹配嵌套结构&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/grep/manual/&quot;&gt;GNU grep&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/sed/manual/&quot;&gt;GNU sed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/gawk/manual/&quot;&gt;GNU awk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/findutils/manual/&quot;&gt;GNU Findutils&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/coreutils/manual/&quot;&gt;GNU Coreutils&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jqlang.github.io/jq/manual/&quot;&gt;jq 手册&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Linux：文件与目录管理</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E6%96%87%E4%BB%B6%E4%B8%8E%E7%9B%AE%E5%BD%95%E7%AE%A1%E7%90%86/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E6%96%87%E4%BB%B6%E4%B8%8E%E7%9B%AE%E5%BD%95%E7%AE%A1%E7%90%86/</guid><description>Linux 通过一棵从根目录 / 开始的目录树组织文件。</description><pubDate>Sun, 13 Sep 2026 02:06:57 GMT</pubDate><content:encoded>&lt;p&gt;Linux 通过一棵从根目录 / 开始的目录树组织文件。路径用于定位对象，文件系统负责保存对象，挂载把文件系统接入目录树。目录不一定对应独立磁盘，设备文件也不是普通数据文件。&lt;/p&gt;
&lt;h1&gt;目录布局与路径&lt;/h1&gt;
&lt;h2&gt;常见目录&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://refspecs.linuxfoundation.org/fhs.shtml&quot;&gt;FHS&lt;/a&gt; 定义常见布局约定，发行版和应用可以存在差异。现代系统常采用 usr merge，例如 /bin 链接到 /usr/bin。&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;/etc&lt;/td&gt;
&lt;td&gt;系统和服务配置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/home、/root&lt;/td&gt;
&lt;td&gt;普通用户及 root 的家目录；/root 与根目录 / 不同&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/usr&lt;/td&gt;
&lt;td&gt;用户空间程序、库和共享数据，不是个人文件目录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/usr/local、/opt&lt;/td&gt;
&lt;td&gt;本机管理的软件、附加软件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/var/log、/var/lib、/var/cache&lt;/td&gt;
&lt;td&gt;日志、持久状态、可再生成的缓存&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/tmp、/run&lt;/td&gt;
&lt;td&gt;临时数据、运行时状态；不能作为持久存储&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/dev&lt;/td&gt;
&lt;td&gt;块设备、字符设备等设备节点&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/proc、/sys&lt;/td&gt;
&lt;td&gt;进程、内核、设备和驱动信息接口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/boot&lt;/td&gt;
&lt;td&gt;内核及启动相关文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/mnt、/media&lt;/td&gt;
&lt;td&gt;临时挂载、可移动介质，实际位置依发行版而异&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/srv&lt;/td&gt;
&lt;td&gt;本机服务提供的数据，应用不一定默认采用&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;/tmp 是否清理由系统策略决定，不能假设固定在每次重启时清空。/proc 和 /sys 的许多内容由内核动态生成，修改可写条目可能改变系统行为。&lt;/p&gt;
&lt;h2&gt;绝对路径与相对路径&lt;/h2&gt;
&lt;p&gt;绝对路径从 / 开始，相对路径以当前工作目录为起点。句点表示当前目录，两个句点表示父目录。Bash 中未引用的 ~ 会展开为家目录，而 &lt;code&gt;&quot;~/file&quot;&lt;/code&gt; 通常不会展开；需要引用时用 &lt;code&gt;&quot;$HOME/file&quot;&lt;/code&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pwd
pwd -P
ls -lah
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;pwd 默认可能保留逻辑符号链接路径，pwd -P 显示物理路径。自动化操作用明确路径，并检查 cd 是否成功，避免在错误目录继续执行。&lt;/p&gt;
&lt;h1&gt;文件类型与元数据&lt;/h1&gt;
&lt;h2&gt;识别对象&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ls -l 首字符&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;d&lt;/td&gt;
&lt;td&gt;目录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;l&lt;/td&gt;
&lt;td&gt;符号链接&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;b、c&lt;/td&gt;
&lt;td&gt;块设备、字符设备&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p、s&lt;/td&gt;
&lt;td&gt;命名管道、Unix 域套接字&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;文件扩展名是命名约定，不保证实际内容类型。以句点开头的名称通常被普通 ls 隐藏，这不是权限保护。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ls -ld /etc /etc/hosts
file /etc/hosts
stat /etc/hosts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;file 根据内容及其他信息推测格式，stat 查看大小、权限、所有者、inode 和时间。mtime 是内容修改时间，ctime 是 inode 状态变更时间，不能把 ctime 当作创建时间；atime 的更新受挂载策略影响。创建时间是否可用取决于文件系统和工具支持。&lt;/p&gt;
&lt;h1&gt;查看与查找&lt;/h1&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;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;cat /etc/hosts&lt;/code&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;code&gt;less app.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;/ 搜索，n 继续，q 退出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;开头 / 结尾&lt;/td&gt;
&lt;td&gt;&lt;code&gt;head -n 20 app.log&lt;/code&gt; / &lt;code&gt;tail -n 50 app.log&lt;/code&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;code&gt;tail -F app.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;GNU tail 按文件名跟踪并重试，适合重命名轮转&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;计数&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wc -l app.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;统计换行符，末尾无换行的记录可能不计入&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;tail -f 默认跟踪打开的文件描述符；轮转后可能仍观察旧文件。跟踪输出不完整时，应确认日志实际位置及轮转方式。&lt;/p&gt;
&lt;h2&gt;查找对象&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;find /var/log -type f -name &apos;*.log&apos;
find /var/log -type f -size +100M
find /var/log -type f -mtime -1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;-name 使用文件名通配符，必须引用，防止先由 Shell 展开。GNU find 的 M 以 MiB 为单位并按单位向上取整比较；-mtime -1 表示不足一个 24 小时周期，不是自然日“今天”。权限错误表示未能完整遍历，不应忽略后声称搜索无遗漏。&lt;/p&gt;
&lt;h1&gt;创建、复制、移动与删除&lt;/h1&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;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;mkdir -p project/config&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ls -ld 确认层级&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;创建空文件或更新时间&lt;/td&gt;
&lt;td&gt;&lt;code&gt;touch project/config/app.conf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;stat；已有内容不会清空&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;复制文件&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cp -i app.conf app.conf.bak&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;cmp 或 diff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;保留属性复制目录&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cp -a project project-backup&lt;/code&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;code&gt;mv -i old.conf new.conf&lt;/code&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;code&gt;rmdir empty-dir&lt;/code&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;code&gt;rm -i -- obsolete.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;确认对象确实不再需要&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;cp 和 mv 的目标是已有目录时，会把源放入该目录，不一定覆盖目录本身。GNU 工具的 -- 结束选项解析，适合处理以短横线开头的名称。跨文件系统 mv 需要复制再删除，不应视作原子重命名。&lt;/p&gt;
&lt;p&gt;:::warning[删除与覆盖]
rm 通常不经过回收站。递归操作前确认绝对路径、挂载关系和匹配范围，不把 rm -rf 作为默认方式。交互确认不能代替备份；操作前后目录仍可能被其他程序修改。
:::&lt;/p&gt;
&lt;h2&gt;示例：准备配置副本&lt;/h2&gt;
&lt;p&gt;在独立练习目录执行，所有路径都由本次创建的临时目录限定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;demo_dir=$(mktemp -d)
mkdir -p &quot;$demo_dir/config&quot;
printf &apos;port=8080\n&apos; &amp;gt; &quot;$demo_dir/config/app.conf&quot;
cp -p &quot;$demo_dir/config/app.conf&quot; &quot;$demo_dir/config/app.conf.bak&quot;
printf &apos;port=9090\n&apos; &amp;gt; &quot;$demo_dir/config/app.conf&quot;
diff -u &quot;$demo_dir/config/app.conf.bak&quot; &quot;$demo_dir/config/app.conf&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预期差异只包含端口变化。diff 返回 1 表示存在差异，不是工具故障；真实配置还需应用自己的检查和重载验证。本例保留临时目录便于检查，不执行自动递归清理。&lt;/p&gt;
&lt;h1&gt;链接&lt;/h1&gt;
&lt;h2&gt;硬链接与符号链接&lt;/h2&gt;
&lt;p&gt;inode 保存文件元数据并关联数据；目录项把名称关联到 inode。硬链接增加一个指向同一 inode 的名称，符号链接则是保存目标路径的独立对象。&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;ln source alias&lt;/td&gt;
&lt;td&gt;ln -s target link&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;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;目标被删后可能悬空&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;strong&gt;链接所在目录&lt;/strong&gt;为基准，不是创建时任意工作目录。用 readlink 查看保存的路径，用 readlink -f 解析实际路径；解析成功与文件存在仍应分别确认。&lt;/p&gt;
&lt;h2&gt;使用时的判断&lt;/h2&gt;
&lt;p&gt;多个硬链接不是独立备份。删除所有目录项后，如果进程仍打开文件，空间可能继续占用。符号链接切换也不保证运行中的服务重新读取目标，需按应用机制重载并检查。&lt;/p&gt;
&lt;h1&gt;挂载与空间定位&lt;/h1&gt;
&lt;p&gt;挂载将文件系统接到目录上；原目录已有内容会被遮挡，并未因此删除。不要在未确认挂载成功时把业务数据写入预期挂载点。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;findmnt -T /var/log
df -hT /var/log
df -i /var/log
du -xhd1 /var/log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;df 报告文件系统整体用量，du 汇总可遍历对象占用。GNU du 的 -x 限定同一文件系统。差异可能来自权限、已删除但仍打开的文件、快照、稀疏文件或元数据，不能据此直接认定统计错误。&lt;/p&gt;
&lt;h1&gt;常见问题&lt;/h1&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;路径中每一级目录的搜索权限、文件权限、ACL 和安全策略&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;链接失效&lt;/td&gt;
&lt;td&gt;readlink，确认相对基准与目标存在性&lt;/td&gt;
&lt;/tr&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;写入提示空间不足&lt;/td&gt;
&lt;td&gt;df -h 与 df -i，区分块空间和 inode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;复制后权限异常&lt;/td&gt;
&lt;td&gt;复制选项、执行身份、目标文件系统是否支持属性&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html&quot;&gt;FHS 3.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/coreutils/manual/&quot;&gt;GNU Coreutils&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/findutils/manual/&quot;&gt;GNU Findutils&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man7/path_resolution.7.html&quot;&gt;Linux path_resolution(7)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Linux：终端与 Shell</title><link>https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E7%BB%88%E7%AB%AF%E4%B8%8E-shell/</link><guid isPermaLink="true">https://tamakara.top/posts/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/linux%E7%BB%88%E7%AB%AF%E4%B8%8E-shell/</guid><description>终端提供文本交互界面，Shell 解释命令，程序执行具体操作。</description><pubDate>Sun, 13 Sep 2026 02:05:45 GMT</pubDate><content:encoded>&lt;p&gt;终端提供文本交互界面，Shell 解释命令，程序执行具体操作。本文以 Linux 上的 Bash 为例，说明命令解析、环境配置、输入输出与作业控制；其他 Shell 的语法和启动文件可能不同。&lt;/p&gt;
&lt;h1&gt;终端与命令解释器&lt;/h1&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;显示输出、接收输入，通过伪终端连接程序&lt;/td&gt;
&lt;td&gt;GNOME Terminal、Windows Terminal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shell&lt;/td&gt;
&lt;td&gt;解释命令语言，处理展开、重定向和作业&lt;/td&gt;
&lt;td&gt;Bash、Zsh、Fish&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;命令&lt;/td&gt;
&lt;td&gt;执行具体操作，可以是内建功能或外部程序&lt;/td&gt;
&lt;td&gt;cd、ls、grep&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;TTY 是终端设备接口的通称，桌面终端和 SSH 交互会话通常使用 PTY（伪终端）。Bash 是 Shell 的一种实现，不是终端本身。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;终端模拟器 ←→ PTY ←→ Bash → 内建命令或外部程序
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用 &lt;code&gt;tty&lt;/code&gt; 查看终端设备；无控制终端的任务可能显示“not a tty”。&lt;code&gt;$SHELL&lt;/code&gt; 通常记录登录 Shell，不能据此确定当前解释器；在 Bash 中可用 &lt;code&gt;printf &apos;%s\n&apos; &quot;$BASH_VERSION&quot;&lt;/code&gt; 查看版本。&lt;/p&gt;
&lt;h1&gt;命令解析与查找&lt;/h1&gt;
&lt;h2&gt;参数、引号与展开&lt;/h2&gt;
&lt;p&gt;在 &lt;code&gt;ls -l /var/log&lt;/code&gt; 中，Shell 组织参数，&lt;code&gt;-l&lt;/code&gt; 的含义由 &lt;code&gt;ls&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&apos;$HOME&apos;&lt;/code&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;code&gt;&quot;$HOME&quot;&lt;/code&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;code&gt;$value&lt;/code&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;code&gt;*.log&lt;/code&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;code&gt;&quot;$(date +%F)&quot;&lt;/code&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;pre&gt;&lt;code&gt;report_name=&apos;daily report.txt&apos;
printf &apos;%s\n&apos; &quot;$report_name&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;默认 Bash 中，通配符无匹配时通常保留原样；不要假设它会自动生成空列表。命令替换不适合存放二进制数据。&lt;/p&gt;
&lt;h2&gt;内建命令与 PATH&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;cd&lt;/code&gt;、&lt;code&gt;export&lt;/code&gt;、&lt;code&gt;jobs&lt;/code&gt; 操作当前 Shell 的状态，属于内建命令；外部程序在自己的进程中运行，不能直接改变父 Shell 的工作目录和变量。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type -a ls
type cd
command -v bash
printf &apos;%s\n&apos; &quot;$PATH&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;type -a&lt;/code&gt; 能识别别名、函数、内建命令和程序。外部程序按 &lt;code&gt;PATH&lt;/code&gt; 中以冒号分隔的目录搜索，顺序影响结果；含斜杠的命令，例如 &lt;code&gt;./tool&lt;/code&gt;，按指定路径执行。&lt;/p&gt;
&lt;p&gt;:::tip[命令版本与预期不符]
先查 &lt;code&gt;type -a&lt;/code&gt; 和 &lt;code&gt;PATH&lt;/code&gt;，再查版本。程序移动后可用 &lt;code&gt;hash -r&lt;/code&gt; 清除 Bash 缓存的路径。不要把当前目录或其他用户可写目录放在管理员搜索路径前面。
:::&lt;/p&gt;
&lt;h1&gt;变量与启动环境&lt;/h1&gt;
&lt;h2&gt;变量的作用范围&lt;/h2&gt;
&lt;p&gt;赋值写作 &lt;code&gt;name=value&lt;/code&gt;，等号两边不加空格。普通变量属于当前 Shell，&lt;code&gt;export&lt;/code&gt; 后才会进入之后启动的子进程环境。子进程修改自己的变量，不会反向更新父进程。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;demo_message=hello
bash -c &apos;printf &quot;%s\n&quot; &quot;${demo_message-未设置}&quot;&apos;
export demo_message
bash -c &apos;printf &quot;%s\n&quot; &quot;$demo_message&quot;&apos;
unset demo_message
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两次输出预期分别为“未设置”和“hello”。&lt;code&gt;LANG=C command&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HOME&lt;/td&gt;
&lt;td&gt;用户家目录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PWD、OLDPWD&lt;/td&gt;
&lt;td&gt;当前及上次工作目录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PATH&lt;/td&gt;
&lt;td&gt;可执行程序搜索路径&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LANG、LC_*&lt;/td&gt;
&lt;td&gt;语言、排序、时间等区域设置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SHELL&lt;/td&gt;
&lt;td&gt;通常为登录 Shell 路径&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;交互式与登录 Shell&lt;/h2&gt;
&lt;p&gt;“是否交互”和“是否登录”是两个维度。终端窗口通常启动交互式非登录 Shell，SSH 登录通常启动登录 Shell，&lt;code&gt;bash script.sh&lt;/code&gt; 通常是非交互式 Shell。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bash 启动方式&lt;/th&gt;
&lt;th&gt;主要启动文件&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;登录 Shell&lt;/td&gt;
&lt;td&gt;/etc/profile，然后读取 ~/.bash_profile、~/.bash_login、~/.profile 中第一个存在且可读的文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;交互式非登录 Shell&lt;/td&gt;
&lt;td&gt;~/.bashrc，发行版可能另有系统级文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;普通非交互式 Bash&lt;/td&gt;
&lt;td&gt;按规则使用 BASH_ENV，不应假设读取 ~/.bashrc&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;登录配置常主动加载 &lt;code&gt;~/.bashrc&lt;/code&gt;，但这不是所有环境的固定关系。以 &lt;code&gt;sh&lt;/code&gt; 启动和远程命令还有特殊规则，见 &lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html&quot;&gt;Bash 启动文件&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;别名适合放在交互配置中；服务和定时任务应显式设置环境及工作目录。修改配置后先检查语法，再开新终端验证；&lt;code&gt;source&lt;/code&gt; 会立即执行文件内容，不只是刷新设置。&lt;/p&gt;
&lt;h1&gt;输入输出与命令组合&lt;/h1&gt;
&lt;h2&gt;文件描述符与重定向&lt;/h2&gt;
&lt;p&gt;程序通常通过文件描述符 0 读取标准输入，通过 1 写标准输出，通过 2 写标准错误。它们可以连接终端、文件或管道。&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;command &amp;lt; input.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;从文件读取输入&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command &amp;gt; output.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;创建或截断输出文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command &amp;gt;&amp;gt; output.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;追加标准输出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command 2&amp;gt; error.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;单独保存标准错误&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command &amp;gt; all.txt 2&amp;gt;&amp;amp;1&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;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt; 复制标准输出当时的去向，所以 &lt;code&gt;command 2&amp;gt;&amp;amp;1 &amp;gt; output.txt&lt;/code&gt; 不会把两者都写入文件。&lt;/p&gt;
&lt;p&gt;:::warning[重定向可能先清空文件]
不要写 &lt;code&gt;sort data.txt &amp;gt; data.txt&lt;/code&gt;，应写入独立临时文件，核对后再替换。重定向由当前 Shell 执行，仅给命令加 sudo 不会自动提升重定向权限。
:::&lt;/p&gt;
&lt;h2&gt;管道、条件执行与退出状态&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;a | b&lt;/code&gt; 将 a 的标准输出接到 b 的标准输入，标准错误默认不进入管道。Bash 默认用最后一个命令的状态作为管道状态；启用 &lt;code&gt;set -o pipefail&lt;/code&gt; 后，有失败时返回最右侧非零状态。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$?&lt;/code&gt; 表示刚执行完成的命令或管道状态，应立即读取。零通常代表成功，但非零要结合工具判断，例如 grep 返回 1 表示没有匹配。&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;a &amp;amp;&amp;amp; b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a 返回零才执行 b&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;`a&lt;/td&gt;
&lt;td&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;无论 a 成功与否都继续执行 b&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;示例：统计记录并核对&lt;/h2&gt;
&lt;p&gt;以下示例在临时目录生成演示数据，统计包含固定字符串 ERROR 的行数，不是单词出现次数。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;demo_dir=$(mktemp -d)
printf &apos;%s\n&apos; &apos;INFO started&apos; &apos;ERROR timeout&apos; &apos;ERROR retry failed&apos; &amp;gt; &quot;$demo_dir/app.log&quot;
grep -F &apos;ERROR&apos; &quot;$demo_dir/app.log&quot; | wc -l &amp;gt; &quot;$demo_dir/error-count.txt&quot;
cat &quot;$demo_dir/error-count.txt&quot;
grep -nF &apos;ERROR&apos; &quot;$demo_dir/app.log&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预期计数为 2，最后一条命令列出第 2、3 行作为依据。实际日志应先确认可读，避免把读取失败误判为零条错误。&lt;/p&gt;
&lt;h1&gt;作业与终端操作&lt;/h1&gt;
&lt;h2&gt;前台、后台与暂停&lt;/h2&gt;
&lt;p&gt;作业是当前 Shell 管理的任务，一个管道可能包含多个进程。作业号只在当前 Shell 有意义，PID 则标识系统中的进程。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sleep 120 &amp;amp;
jobs -l
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;根据实际编号用 &lt;code&gt;fg %1&lt;/code&gt; 调回前台，按 &lt;code&gt;Ctrl+Z&lt;/code&gt; 暂停后可用 &lt;code&gt;bg %1&lt;/code&gt; 在后台继续。用 &lt;code&gt;jobs -l&lt;/code&gt; 区分 Running、Stopped、Done，不要把暂停当作结束。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;amp;&lt;/code&gt; 只表示 Shell 不等待，不保证断开连接后继续运行。需要保持交互会话时可使用 tmux，长期服务交给服务管理器。后台任务读取终端时也可能被暂停。&lt;/p&gt;
&lt;h2&gt;常用按键&lt;/h2&gt;
&lt;p&gt;下表以 Bash 默认 Readline Emacs 模式为准；终端或用户配置可能改变映射。&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;Ctrl+C&lt;/td&gt;
&lt;td&gt;通常向前台进程组发送 SIGINT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl+Z&lt;/td&gt;
&lt;td&gt;通常发送 SIGTSTP，暂停前台任务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl+D&lt;/td&gt;
&lt;td&gt;空输入处表示 EOF，Shell 可能因此退出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl+A / Ctrl+E&lt;/td&gt;
&lt;td&gt;到命令行开头 / 末尾&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl+U / Ctrl+K&lt;/td&gt;
&lt;td&gt;删除光标前 / 后的文本&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl+W&lt;/td&gt;
&lt;td&gt;删除光标前的一个词&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl+R&lt;/td&gt;
&lt;td&gt;搜索历史，执行前核对完整命令&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl+L&lt;/td&gt;
&lt;td&gt;重绘显示，不删除历史&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tab&lt;/td&gt;
&lt;td&gt;补全命令或路径&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;终端规范模式下，Ctrl+D 前已有待输入字符时，先把这些字符交给程序，未必立即产生 EOF。它不是终止进程的信号。&lt;/p&gt;
&lt;h1&gt;常见问题&lt;/h1&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;command not found&lt;/td&gt;
&lt;td&gt;检查拼写、安装状态、type -a 与 PATH&lt;/td&gt;
&lt;/tr&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;手动正常，自动任务失败&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;/tr&gt;
&lt;tr&gt;
&lt;td&gt;输入无响应&lt;/td&gt;
&lt;td&gt;检查前台程序；若误触 Ctrl+S 且启用流控，用 Ctrl+Q 恢复&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;子程序读不到变量&lt;/td&gt;
&lt;td&gt;确认变量在启动子程序之前已 export&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/bash/manual/&quot;&gt;GNU Bash Reference Manual&lt;/a&gt;：展开、环境和作业控制。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/Redirections.html&quot;&gt;Bash Redirections&lt;/a&gt;：重定向规则。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/Pipelines.html&quot;&gt;Bash Pipelines&lt;/a&gt;：管道退出状态。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/Readline.html&quot;&gt;Readline&lt;/a&gt;：命令行编辑。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Hello World</title><link>https://tamakara.top/posts/%E6%9D%82%E8%B0%88/hello-world/</link><guid isPermaLink="true">https://tamakara.top/posts/%E6%9D%82%E8%B0%88/hello-world/</guid><pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;严格来讲这并不是第一篇文章，我在上初中时搭建过 WordPress 博客，但是因为时间和精力越来越少，服务器到期后就没有再继续维护了，原来的数据也丢失了。&lt;/p&gt;
&lt;p&gt;这次我采用更易于维护的方式搭建博客，我选择了“Astro + GitHub Pages”的方案，采用了 &lt;a href=&quot;https://github.com/saicaca/fuwari&quot;&gt;Fuwari&lt;/a&gt; 主题并进行二次开发，集成了基于 &lt;a href=&quot;https://giscus.app/zh-CN&quot;&gt;Giscus&lt;/a&gt; 的评论系统。&lt;/p&gt;
&lt;p&gt;我会在这里记录学习笔记、技术实践，以及一些个人思考。我并不期待自己能写出多优秀的文章，我只希望在互联网能有一块属于自己的小角落，用来记录我的成长经历。&lt;/p&gt;
</content:encoded></item><item><title>Markdown Extended Features</title><link>https://tamakara.top/posts/examples/markdown-extended/</link><guid isPermaLink="true">https://tamakara.top/posts/examples/markdown-extended/</guid><description>Read more about Markdown features in Fuwari</description><pubDate>Wed, 01 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;GitHub Repository Cards&lt;/h2&gt;
&lt;p&gt;You can add dynamic cards that link to GitHub repositories, on page load, the repository information is pulled from the GitHub API.&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Fabrizz/MMM-OnSpotify&quot;}&lt;/p&gt;
&lt;p&gt;Create a GitHub repository card with the code &lt;code&gt;::github{repo=&quot;&amp;lt;owner&amp;gt;/&amp;lt;repo&amp;gt;&quot;}&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;::github{repo=&quot;saicaca/fuwari&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Admonitions&lt;/h2&gt;
&lt;p&gt;Following types of admonitions are supported: &lt;code&gt;note&lt;/code&gt; &lt;code&gt;tip&lt;/code&gt; &lt;code&gt;important&lt;/code&gt; &lt;code&gt;warning&lt;/code&gt; &lt;code&gt;caution&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;:::note
Highlights information that users should take into account, even when skimming.
:::&lt;/p&gt;
&lt;p&gt;:::tip
Optional information to help a user be more successful.
:::&lt;/p&gt;
&lt;p&gt;:::important
Crucial information necessary for users to succeed.
:::&lt;/p&gt;
&lt;p&gt;:::warning
Critical content demanding immediate user attention due to potential risks.
:::&lt;/p&gt;
&lt;p&gt;:::caution
Negative potential consequences of an action.
:::&lt;/p&gt;
&lt;h3&gt;Basic Syntax&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;:::note
Highlights information that users should take into account, even when skimming.
:::

:::tip
Optional information to help a user be more successful.
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Custom Titles&lt;/h3&gt;
&lt;p&gt;The title of the admonition can be customized.&lt;/p&gt;
&lt;p&gt;:::note[MY CUSTOM TITLE]
This is a note with a custom title.
:::&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:::note[MY CUSTOM TITLE]
This is a note with a custom title.
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;GitHub Syntax&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;[!TIP]
&lt;a href=&quot;https://github.com/orgs/community/discussions/16925&quot;&gt;The GitHub syntax&lt;/a&gt; is also supported.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; [!NOTE]
&amp;gt; The GitHub syntax is also supported.

&amp;gt; [!TIP]
&amp;gt; The GitHub syntax is also supported.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Spoiler&lt;/h3&gt;
&lt;p&gt;You can add spoilers to your text. The text also supports &lt;strong&gt;Markdown&lt;/strong&gt; syntax.&lt;/p&gt;
&lt;p&gt;The content :spoiler[is hidden &lt;strong&gt;ayyy&lt;/strong&gt;]!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The content :spoiler[is hidden **ayyy**]!

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Expressive Code Example</title><link>https://tamakara.top/posts/examples/expressive-code/</link><guid isPermaLink="true">https://tamakara.top/posts/examples/expressive-code/</guid><description>How code blocks look in Markdown using Expressive Code.</description><pubDate>Wed, 10 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Here, we&apos;ll explore how code blocks look using &lt;a href=&quot;https://expressive-code.com/&quot;&gt;Expressive Code&lt;/a&gt;. The provided examples are based on the official documentation, which you can refer to for further details.&lt;/p&gt;
&lt;h2&gt;Expressive Code&lt;/h2&gt;
&lt;h3&gt;Syntax Highlighting&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/key-features/syntax-highlighting/&quot;&gt;Syntax Highlighting&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Regular syntax highlighting&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;console.log(&apos;This code is syntax highlighted!&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Rendering ANSI escape sequences&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;ANSI colors:
- Regular: [31mRed[0m [32mGreen[0m [33mYellow[0m [34mBlue[0m [35mMagenta[0m [36mCyan[0m
- Bold:    [1;31mRed[0m [1;32mGreen[0m [1;33mYellow[0m [1;34mBlue[0m [1;35mMagenta[0m [1;36mCyan[0m
- Dimmed:  [2;31mRed[0m [2;32mGreen[0m [2;33mYellow[0m [2;34mBlue[0m [2;35mMagenta[0m [2;36mCyan[0m

256 colors (showing colors 160-177):
[38;5;160m160 [38;5;161m161 [38;5;162m162 [38;5;163m163 [38;5;164m164 [38;5;165m165[0m
[38;5;166m166 [38;5;167m167 [38;5;168m168 [38;5;169m169 [38;5;170m170 [38;5;171m171[0m
[38;5;172m172 [38;5;173m173 [38;5;174m174 [38;5;175m175 [38;5;176m176 [38;5;177m177[0m

Full RGB colors:
[38;2;34;139;34mForestGreen - RGB(34, 139, 34)[0m

Text formatting: [1mBold[0m [2mDimmed[0m [3mItalic[0m [4mUnderline[0m
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Editor &amp;amp; Terminal Frames&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/key-features/frames/&quot;&gt;Editor &amp;amp; Terminal Frames&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Code editor frames&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;console.log(&apos;Title attribute example&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- src/content/index.html --&amp;gt;
&amp;lt;div&amp;gt;File name comment example&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Terminal frames&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;echo &quot;This terminal frame has no title&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;Write-Output &quot;This one has a title!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Overriding frame types&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;echo &quot;Look ma, no frame!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;# Without overriding, this would be a terminal frame
function Watch-Tail { Get-Content -Tail 20 -Wait $args }
New-Alias tail Watch-Tail
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Text &amp;amp; Line Markers&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/key-features/text-markers/&quot;&gt;Text &amp;amp; Line Markers&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Marking full lines &amp;amp; line ranges&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// Line 1 - targeted by line number
// Line 2
// Line 3
// Line 4 - targeted by line number
// Line 5
// Line 6
// Line 7 - targeted by range &quot;7-8&quot;
// Line 8 - targeted by range &quot;7-8&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Selecting line marker types (mark, ins, del)&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;function demo() {
  console.log(&apos;this line is marked as deleted&apos;)
  // This line and the next one are marked as inserted
  console.log(&apos;this is the second inserted line&apos;)

  return &apos;this line uses the neutral default marker type&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Adding labels to line markers&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// labeled-line-markers.jsx
&amp;lt;button
  role=&quot;button&quot;
  {...props}
  value={value}
  className={buttonClassName}
  disabled={disabled}
  active={active}
&amp;gt;
  {children &amp;amp;&amp;amp;
    !active &amp;amp;&amp;amp;
    (typeof children === &apos;string&apos; ? &amp;lt;span&amp;gt;{children}&amp;lt;/span&amp;gt; : children)}
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Adding long labels on their own lines&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// labeled-line-markers.jsx
&amp;lt;button
  role=&quot;button&quot;
  {...props}

  value={value}
  className={buttonClassName}

  disabled={disabled}
  active={active}
&amp;gt;

  {children &amp;amp;&amp;amp;
    !active &amp;amp;&amp;amp;
    (typeof children === &apos;string&apos; ? &amp;lt;span&amp;gt;{children}&amp;lt;/span&amp;gt; : children)}
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Using diff-like syntax&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;+this line will be marked as inserted
-this line will be marked as deleted
this is a regular line
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+this is an actual diff file
-all contents will remain unmodified
 no whitespace will be removed either
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Combining syntax highlighting with diff-like syntax&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;  function thisIsJavaScript() {
    // This entire block gets highlighted as JavaScript,
    // and we can still add diff markers to it!
-   console.log(&apos;Old code to be removed&apos;)
+   console.log(&apos;New and shiny code!&apos;)
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Marking individual text inside lines&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;function demo() {
  // Mark any given text inside lines
  return &apos;Multiple matches of the given text are supported&apos;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Regular expressions&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;console.log(&apos;The words yes and yep will be marked.&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Escaping forward slashes&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;echo &quot;Test&quot; &amp;gt; /home/test.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Selecting inline marker types (mark, ins, del)&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;function demo() {
  console.log(&apos;These are inserted and deleted marker types&apos;);
  // The return statement uses the default marker type
  return true;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Word Wrap&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/key-features/word-wrap/&quot;&gt;Word Wrap&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Configuring word wrap per block&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// Example with wrap
function getLongString() {
  return &apos;This is a very long string that will most probably not fit into the available space unless the container is extremely wide&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;// Example with wrap=false
function getLongString() {
  return &apos;This is a very long string that will most probably not fit into the available space unless the container is extremely wide&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Configuring indentation of wrapped lines&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// Example with preserveIndent (enabled by default)
function getLongString() {
  return &apos;This is a very long string that will most probably not fit into the available space unless the container is extremely wide&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;// Example with preserveIndent=false
function getLongString() {
  return &apos;This is a very long string that will most probably not fit into the available space unless the container is extremely wide&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Collapsible Sections&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/plugins/collapsible-sections/&quot;&gt;Collapsible Sections&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// All this boilerplate setup code will be collapsed
import { someBoilerplateEngine } from &apos;@example/some-boilerplate&apos;
import { evenMoreBoilerplate } from &apos;@example/even-more-boilerplate&apos;

const engine = someBoilerplateEngine(evenMoreBoilerplate())

// This part of the code will be visible by default
engine.doSomething(1, 2, 3, calcFn)

function calcFn() {
  // You can have multiple collapsed sections
  const a = 1
  const b = 2
  const c = a + b

  // This will remain visible
  console.log(`Calculation result: ${a} + ${b} = ${c}`)
  return c
}

// All this code until the end of the block will be collapsed again
engine.closeConnection()
engine.freeMemory()
engine.shutdown({ reason: &apos;End of example boilerplate code&apos; })
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Line Numbers&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/plugins/line-numbers/&quot;&gt;Line Numbers&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Displaying line numbers per block&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// This code block will show line numbers
console.log(&apos;Greetings from line 2!&apos;)
console.log(&apos;I am on line 3&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;// Line numbers are disabled for this block
console.log(&apos;Hello?&apos;)
console.log(&apos;Sorry, do you know what line I am on?&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Changing the starting line number&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;console.log(&apos;Greetings from line 5!&apos;)
console.log(&apos;I am on line 6&apos;)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Simple Guides for Fuwari</title><link>https://tamakara.top/posts/guides/guide/</link><guid isPermaLink="true">https://tamakara.top/posts/guides/guide/</guid><description>How to use this blog template.</description><pubDate>Mon, 01 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Cover image source: &lt;a href=&quot;https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/208fc754-890d-4adb-9753-2c963332675d/width=2048/01651-1456859105-(colour_1.5),girl,_Blue,yellow,green,cyan,purple,red,pink,_best,8k,UHD,masterpiece,male%20focus,%201boy,gloves,%20ponytail,%20long%20hair,.jpeg&quot;&gt;Source&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This blog template is built with &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt;. For the things that are not mentioned in this guide, you may find the answers in the &lt;a href=&quot;https://docs.astro.build/&quot;&gt;Astro Docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Front-matter of Posts&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;---
title: My First Blog Post
published: 2023-09-09
description: This is the first post of my new Astro blog.
image: ./cover.jpg
tags: [Foo, Bar]
category: Front-end
draft: false
---
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attribute&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The title of the post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;published&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The date the post was published.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A short description of the post. Displayed on index page.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The cover image path of the post.&amp;lt;br/&amp;gt;1. Start with &lt;code&gt;http://&lt;/code&gt; or &lt;code&gt;https://&lt;/code&gt;: Use web image&amp;lt;br/&amp;gt;2. Start with &lt;code&gt;/&lt;/code&gt;: For image in &lt;code&gt;public&lt;/code&gt; dir&amp;lt;br/&amp;gt;3. With none of the prefixes: Relative to the markdown file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tags&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The tags of the post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;category&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The category of the post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;draft&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If this post is still a draft, which won&apos;t be displayed.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Where to Place the Post Files&lt;/h2&gt;
&lt;p&gt;Your post files should be placed in &lt;code&gt;src/content/posts/&lt;/code&gt; directory. You can also create sub-directories to better organize your posts and assets.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/content/posts/
├── post-1.md
└── post-2/
    ├── cover.png
    └── index.md
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Markdown Example</title><link>https://tamakara.top/posts/examples/markdown/</link><guid isPermaLink="true">https://tamakara.top/posts/examples/markdown/</guid><description>A simple example of a Markdown blog post.</description><pubDate>Sun, 01 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;An h1 header&lt;/h1&gt;
&lt;p&gt;Paragraphs are separated by a blank line.&lt;/p&gt;
&lt;p&gt;2nd paragraph. &lt;em&gt;Italic&lt;/em&gt;, &lt;strong&gt;bold&lt;/strong&gt;, and &lt;code&gt;monospace&lt;/code&gt;. Itemized lists
look like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;this one&lt;/li&gt;
&lt;li&gt;that one&lt;/li&gt;
&lt;li&gt;the other one&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that --- not considering the asterisk --- the actual text
content starts at 4-columns in.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Block quotes are
written like so.&lt;/p&gt;
&lt;p&gt;They can span multiple paragraphs,
if you like.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Use 3 dashes for an em-dash. Use 2 dashes for ranges (ex., &quot;it&apos;s all
in chapters 12--14&quot;). Three dots ... will be converted to an ellipsis.
Unicode is supported. ☺&lt;/p&gt;
&lt;h2&gt;An h2 header&lt;/h2&gt;
&lt;p&gt;Here&apos;s a numbered list:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;first item&lt;/li&gt;
&lt;li&gt;second item&lt;/li&gt;
&lt;li&gt;third item&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note again how the actual text starts at 4 columns in (4 characters
from the left side). Here&apos;s a code sample:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Let me re-iterate ...
for i in 1 .. 10 { do-something(i) }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you probably guessed, indented 4 spaces. By the way, instead of
indenting the block, you can use delimited blocks, if you like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;define foobar() {
    print &quot;Welcome to flavor country!&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(which makes copying &amp;amp; pasting easier). You can optionally mark the
delimited block for Pandoc to syntax highlight it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import time
# Quick, count to ten!
for i in range(10):
    # (but not *too* quick)
    time.sleep(0.5)
    print i
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;An h3 header&lt;/h3&gt;
&lt;p&gt;Now a nested list:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First, get these ingredients:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;carrots&lt;/li&gt;
&lt;li&gt;celery&lt;/li&gt;
&lt;li&gt;lentils&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Boil some water.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dump everything in the pot and follow
this algorithm:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; find wooden spoon
 uncover pot
 stir
 cover pot
 balance wooden spoon precariously on pot handle
 wait 10 minutes
 goto first step (or shut off burner when done)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do not bump wooden spoon or it will fall.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Notice again how text always lines up on 4-space indents (including
that last line which continues item 3 above).&lt;/p&gt;
&lt;p&gt;Here&apos;s a link to &lt;a href=&quot;http://foo.bar&quot;&gt;a website&lt;/a&gt;, to a &lt;a href=&quot;local-doc.html&quot;&gt;local
doc&lt;/a&gt;, and to a &lt;a href=&quot;#an-h2-header&quot;&gt;section heading in the current
doc&lt;/a&gt;. Here&apos;s a footnote [^1].&lt;/p&gt;
&lt;p&gt;[^1]: Footnote text goes here.&lt;/p&gt;
&lt;p&gt;Tables can look like this:&lt;/p&gt;
&lt;p&gt;size material color&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;9 leather brown
10 hemp canvas natural
11 glass transparent&lt;/p&gt;
&lt;p&gt;Table: Shoes, their sizes, and what they&apos;re made of&lt;/p&gt;
&lt;p&gt;(The above is the caption for the table.) Pandoc also supports
multi-line tables:&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;keyword text&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;red Sunsets, apples, and
other red or reddish
things.&lt;/p&gt;
&lt;p&gt;green Leaves, grass, frogs
and other things it&apos;s
not easy being.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;A horizontal rule follows.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Here&apos;s a definition list:&lt;/p&gt;
&lt;p&gt;apples
: Good for making applesauce.
oranges
: Citrus!
tomatoes
: There&apos;s no &quot;e&quot; in tomatoe.&lt;/p&gt;
&lt;p&gt;Again, text is indented 4 spaces. (Put a blank line between each
term/definition pair to spread things out more.)&lt;/p&gt;
&lt;p&gt;Here&apos;s a &quot;line block&quot;:&lt;/p&gt;
&lt;p&gt;| Line one
| Line too
| Line tree&lt;/p&gt;
&lt;p&gt;and images can be specified like so:&lt;/p&gt;
&lt;p&gt;Inline math equations go in like so: $\omega = d\phi / dt$. Display
math should get its own line and be put in in double-dollarsigns:&lt;/p&gt;
&lt;p&gt;$$I = \int \rho R^{2} dV$$&lt;/p&gt;
&lt;p&gt;$$
\begin{equation*}
\pi
=3.1415926535
;8979323846;2643383279;5028841971;6939937510;5820974944
;5923078164;0628620899;8628034825;3421170679;\ldots
\end{equation*}
$$&lt;/p&gt;
&lt;p&gt;And note that you can backslash-escape any punctuation characters
which you wish to be displayed literally, ex.: `foo`, *bar*, etc.&lt;/p&gt;
</content:encoded></item><item><title>Include Video in the Posts</title><link>https://tamakara.top/posts/examples/video/</link><guid isPermaLink="true">https://tamakara.top/posts/examples/video/</guid><description>This post demonstrates how to include embedded video in a blog post.</description><pubDate>Tue, 01 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Just copy the embed code from YouTube or other platforms, and paste it in the markdown file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
title: Include Video in the Post
published: 2023-10-19
// ...
---

&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;https://www.youtube.com/embed/5gIf0_xpFPI?si=N1WTorLKL0uwLsU_&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;YouTube&lt;/h2&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;https://www.youtube.com/embed/5gIf0_xpFPI?si=N1WTorLKL0uwLsU_&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;h2&gt;Bilibili&lt;/h2&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1fK4y1s7Qf&amp;amp;p=1&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded></item></channel></rss>