diff --git a/docs/networking/cdn.md b/docs/networking/cdn.md
new file mode 100644
index 0000000..e5c558b
--- /dev/null
+++ b/docs/networking/cdn.md
@@ -0,0 +1,200 @@
+# CDN(Content Delivery Network)
+
+!!! note "把资源复制到全世界一堆服务器上,用户就近获取——互联网上最基础的加速手段"
+
+---
+
+## 核心概念
+
+1. **边缘节点** — CDN 在全球部署的缓存服务器,用户就近访问
+2. **回源** — 边缘节点缓存未命中时,去源站拉取文件
+3. **智能 DNS** — 根据用户地理位置将请求导向最近的边缘节点
+4. **静态资源加速** — 图片、JS、CSS、视频等不变的内容最适合上 CDN
+5. **DDoS 防护** — 攻击流量被分散到全球边缘节点吸收
+
+---
+
+## 详解
+
+### 没有 CDN 的世界
+
+所有用户都直接访问源站服务器:
+
+```mermaid
+graph TD
+ S[源站服务器 上海]
+ A[用户A 上海 5ms] --> S
+ B[用户B 北京 30ms] --> S
+ C[用户C 广州 50ms] --> S
+ D[用户D 纽约 200ms] --> S
+ E[用户E 伦敦 250ms] --> S
+```
+
+所有流量挤在一台服务器上,远距离用户体验差,服务器扛不住。
+
+### 有 CDN 之后
+
+```mermaid
+graph TD
+ S[源站 上海]
+ E1[边缘节点 上海]
+ E2[边缘节点 北京]
+ E3[边缘节点 纽约]
+ E4[边缘节点 伦敦]
+ S --> E1
+ S --> E2
+ S --> E3
+ S --> E4
+ A[用户A] --> E1
+ B[用户B] --> E2
+ D[用户D] --> E3
+ E[用户E] --> E4
+```
+
+每个用户都就近访问最近的边缘节点,不直接打源站。
+
+### CDN 工作流程
+
+```mermaid
+sequenceDiagram
+ participant U as 用户
+ participant DNS as 智能 DNS
+ participant E as CDN 边缘节点
+ participant S as 源站
+ U->>DNS: 请求 cdn.example.com/logo.png
+ DNS->>U: 解析到最近的边缘节点 IP
+ U->>E: GET /logo.png
+ alt 缓存命中
+ E->>U: 200 OK + 图片(直接返回)
+ else 缓存未命中
+ E->>S: GET /logo.png(回源)
+ S->>E: 200 OK + 图片
+ Note over E: 存一份缓存
+ E->>U: 200 OK + 图片
+ end
+```
+
+关键点:**第一次请求会慢一点(回源),之后就快了。**
+
+### CDN 缓存了什么?
+
+| 适合放 CDN | 不适合放 CDN |
+|-----------|-------------|
+| 图片(logo、banner、产品图) | 用户个人数据 |
+| JS / CSS 文件 | 实时交易数据 |
+| 视频、音频 | 登录接口 |
+| 字体文件 | 搜索接口 |
+| 软件安装包、APK | 任何需要实时性的内容 |
+
+简单判断标准:**内容不怎么变 + 所有人看到的一样 + 可以缓存 → 适合 CDN。**
+
+### CDN 核心能力
+
+#### 1. 加速
+
+```
+没 CDN:用户(伦敦)→ 上海源站 = 250ms
+有 CDN:用户(伦敦)→ 伦敦边缘节点 = 8ms
+```
+
+#### 2. 减轻源站压力
+
+```
+100 万用户 → 99 万次命中边缘节点 → 源站只处理 1 万次回源
+```
+
+**99% 的流量被边缘节点消化掉了。**
+
+#### 3. 防 DDoS
+
+```
+攻击者打 100Gbps 流量 → 分散到全球几百个边缘节点吸收 → 源站几乎无感
+```
+
+#### 4. HTTPS 终止
+
+边缘节点处理 TLS 握手,到源站可以用 HTTP(内网更快):
+
+```
+用户 ←── HTTPS ──→ CDN 边缘节点 ←── HTTP ──→ 源站
+ 安全 信任内网,可以明文
+```
+
+### 缓存策略
+
+```nginx
+# Nginx 源站告诉 CDN 怎么缓存
+
+# 静态资源缓存 1 天
+Cache-Control: max-age=86400
+
+# 带版本号的资源缓存 1 年
+Cache-Control: max-age=31536000, immutable
+# 例如 /js/app.v3.2.1.js ← 文件名带版本,变了就是新文件
+
+# 别缓存
+Cache-Control: no-cache
+
+# 先检查源站有没有更新
+Cache-Control: max-age=300, must-revalidate
+```
+
+CDN 缓存分层:
+
+```mermaid
+graph LR
+ U[用户] --> E[边缘节点
缓存1]
+ E --> R[区域节点
缓存2]
+ R --> S[源站
原始文件]
+```
+
+---
+
+## 实际配置
+
+### 阿里云 CDN
+
+```bash
+# 1. 控制台添加加速域名
+# 加速域名:cdn.example.com
+# 回源地址:origin.example.com
+
+# 2. DNS 配置 CNAME
+# cdn.example.com → cdn.example.com.w.alikunlun.com
+
+# 3. 缓存规则
+# /static/* → 缓存 30 天
+# /images/* → 缓存 7 天
+# /api/* → 不缓存
+```
+
+### Cloudflare
+
+```bash
+# 1. 把域名的 NS 改成 Cloudflare 的
+# 2. 自动开启 CDN
+# 3. 拖个滑块选安全级别
+# 完事。
+```
+
+---
+
+## 常见陷阱
+
+!!! warning "缓存一致性问题"
+ 更新了 logo.png,但 CDN 还缓存旧的,用户看到旧 logo。解决方案:(1)文件名带版本号 `/logo.v2.png`;(2)调用 CDN API 强制清除缓存;(3)设置较短的 `max-age` 等自然过期。
+
+!!! warning "CDN 服务商挂了全挂"
+ 过度依赖单一 CDN 有中心化风险。重要业务考虑多 CDN 冗余或回源降级方案。
+
+---
+
+## 练习题
+
+??? question "CDN 的智能 DNS 是怎么知道用户在哪里的?"
+ ??? success "答案"
+ CDN 的 DNS 服务器会根据**请求来源 IP 的地理位置**(通过 IP 地理位置数据库)来决定返回哪个边缘节点的 IP。这个过程对用户完全透明,用户只需解析域名,CDN 的 DNS 自动帮你选最近的节点。
+
+??? question "Cache-Control: immutable 是什么意思?"
+ ??? success "答案"
+ `immutable` 告诉浏览器:这个资源永远不会改变,不需要向源站发起条件请求(If-Modified-Since/ETag 验证)。适用于文件名带版本号的静态资源(如 `/app.v2.js`),版本变了就是新 URL,所以内容一定是新的。
diff --git a/docs/networking/connection-pooling.md b/docs/networking/connection-pooling.md
new file mode 100644
index 0000000..869dc62
--- /dev/null
+++ b/docs/networking/connection-pooling.md
@@ -0,0 +1,165 @@
+# 连接池复用
+
+!!! note "预先把连接建好放着,谁要用谁借,用完别关——高频场景下最简单有效的优化"
+
+---
+
+## 核心概念
+
+1. **连接池** — 一批预先建好的连接集合,用时借出,用完归还而非关闭
+2. **HTTP/1.1 Keep-Alive 复用** — 同一 TCP 连接上串行处理多个请求
+3. **HTTP/2 多路复用** — 一个 TCP 连接上并行处理多个请求/响应
+4. **池化参数** — 最大连接数、最小空闲数、超时时间等关键配置
+
+---
+
+## 详解
+
+### 没有连接池的世界
+
+每次请求都要:建 TCP 连接 → TLS 握手 → 发数据 → 四次挥手关掉。
+
+```mermaid
+sequenceDiagram
+ participant C as 客户端
+ participant S as 服务器
+ loop 每次请求
+ C->>S: TCP 三次握手
+ C->>S: TLS 握手(HTTPS)
+ C->>S: GET /api/data
+ S->>C: 200 OK + 数据
+ C->>S: TCP 四次挥手
+ end
+```
+
+就像每次出门买菜都要:解锁 → 开门 → 走出去 → 锁门,回来再解锁 → 开门 → 走进去 → 锁门。一天买十次菜,光开关门就累死了。
+
+### 有连接池的世界
+
+```mermaid
+sequenceDiagram
+ participant P as 连接池
+ participant S as 服务器
+ Note over P: 启动时建好 50 个连接
+ participant C as 请求
+ C->>P: 借连接 A
+ C->>S: GET /api/data(复用连接 A)
+ S->>C: 200 OK
+ C->>P: 还连接 A
+ C->>P: 借连接 B
+ C->>S: GET /api/user(复用连接 B)
+ S->>C: 200 OK
+ C->>P: 还连接 B
+```
+
+### 两个层次的复用
+
+#### HTTP/1.1 连接复用(Keep-Alive)
+
+```mermaid
+sequenceDiagram
+ participant C as 客户端
+ participant S as 服务器
+ Note over C,S: TCP 连接(建一次)
+ C->>S: 请求1
+ S->>C: 响应1
+ C->>S: 请求2(同一个连接)
+ S->>C: 响应2
+ C->>S: 请求3(同一个连接)
+ S->>C: 响应3
+```
+
+**但同一时刻只能有一个请求在跑**(队头阻塞)。浏览器默认开 6 个连接弥补:
+
+```
+连接1: 请求1 → 响应1 (串行)
+连接2: 请求2 → 响应2 (串行)
+连接3: 请求3 → 响应3 (串行)
+连接4: 请求4 → 响应4 (串行)
+连接5: 请求5 → 响应5 (串行)
+连接6: 请求6 → 响应6 (串行)
+ ↑
+ 6 个连接之间是并行的
+```
+
+#### HTTP/2 多路复用
+
+一个 TCP 连接上同时跑多个请求/响应,通过帧编号区分:
+
+```
+TCP 连接(就一个)
+├── 请求1 的第1帧 ──┐
+├── 请求2 的第1帧 ──┼── 混在一起发,到了对端自动分拣
+├── 请求1 的第2帧 ──┤
+├── 请求3 的第1帧 ──┤
+├── 请求2 的第2帧 ──┘
+```
+
+不再需要多个 TCP 连接来并行,一根连接全部搞定。
+
+### 关键配置参数
+
+| 参数 | 说明 | 过大 | 过小 |
+|------|------|------|------|
+| 最大连接数 | 池子最多同时借出多少个 | 内存和 fd 浪费 | 请求排队等连接 |
+| 最小空闲 | 池子里至少保留多少个待命 | 空闲资源浪费 | 高并发时来不及建连 |
+| 连接超时 | 借不到连接最多等多久 | 请求长时间挂起 | 高峰期大量失败 |
+| 空闲回收 | 超过多久没用就释放 | 占着不用浪费资源 | 频繁重建连接 |
+
+---
+
+## 代码示例
+
+### Python requests
+
+```python
+from requests.adapters import HTTPAdapter
+
+adapter = HTTPAdapter(
+ pool_connections=10, # 连接到不同目标服务器的池子数
+ pool_maxsize=20, # 每个池子最多保持 20 个连接
+)
+session.mount('https://', adapter)
+```
+
+### Go
+
+```go
+client := &http.Client{
+ Transport: &http.Transport{
+ MaxIdleConns: 100, // 最大空闲连接
+ MaxIdleConnsPerHost: 10, // 每个主机最多保留 10 个空闲连接
+ IdleConnTimeout: 90 * time.Second,
+ },
+}
+```
+
+### Java Apache HttpClient
+
+```java
+PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
+cm.setMaxTotal(200); // 总连接池大小
+cm.setDefaultMaxPerRoute(20); // 每个目标服务器最多 20 个连接
+```
+
+---
+
+## 常见陷阱
+
+!!! warning "连接池打满导致延迟飙升"
+ 池子大小为 10,但同时来了 50 个请求,40 个在排队等连接。解决方案:合理调大池子,或用 HTTP/2 多路复用减少对连接数的需求。
+
+!!! warning "僵尸连接"
+ 服务器端已经关闭了连接,但客户端不知道,下次复用时发现连接已死 → 报错。解决方案:开启连接健康检查、设置合理的空闲超时、使用 TCP keepalive。
+
+---
+
+## 练习题
+
+??? question "连接池大小设为多少合适?"
+ ??? success "答案"
+ 没有万能值,取决于场景。一般经验值:**最大连接数 = 服务端能承受的并发数**,**空闲连接数 = 平均并发请求数的 20-50%**。高 IO 等待的场景(如调外部 API)可以设大一些,CPU 密集的场景设小一些。监控连接池的借出/归还速率来动态调整。
+
+??? question "HTTP/2 的多路复用还需要连接池吗?"
+ ??? success "答案"
+ 连接池仍然有用。HTTP/2 解决了单个连接上的并行问题,但连接池提供了**容错**(一个连接挂了可以切到另一个)和**负载均衡**(多连接分散压力)的能力。此外,Go 的 `http.Transport` 本身就是连接池实现。
diff --git a/docs/networking/cors.md b/docs/networking/cors.md
new file mode 100644
index 0000000..ac9ff1d
--- /dev/null
+++ b/docs/networking/cors.md
@@ -0,0 +1,235 @@
+# 跨域(CORS)
+
+!!! note "浏览器的同源策略看的是'协议+域名+端口'三元组,不是'同一台机器'——只要有一个不一样就跨域"
+
+---
+
+## 核心概念
+
+1. **同源策略** — 浏览器的安全基石,不同源的请求一律先拦住
+2. **Origin 三元组** — 协议 + 域名 + 端口,三者必须完全一致才算同源
+3. **CORS** — 跨源资源共享,服务器通过响应头告诉浏览器"允许谁来访问"
+4. **预检请求** — 非简单请求浏览器先发 OPTIONS 探路,确认安全后才发真正请求
+
+---
+
+## 详解
+
+### 同源的定义
+
+浏览器判断跨域的标准不是"是不是同一台机器",而是:
+
+```
+源(Origin)= 协议 + 域名 + 端口
+
+https://example.com:443
+ ↑ ↑ ↑
+协议 域名 端口
+
+三个都一样 → 同源 → 没问题
+任何一个不一样 → 跨域 → 浏览器拦截
+```
+
+### 常见的"同一台主机但跨域"情况
+
+#### 1. 协议不同
+
+```
+页面:http://localhost:3000 (HTTP)
+请求:https://localhost:3000 (HTTPS)
+
+http ≠ https → 跨域!
+```
+
+#### 2. 端口不同
+
+```
+页面:http://localhost:3000 (前端)
+请求:http://localhost:8080 (后端 API)
+
+3000 ≠ 8080 → 跨域!
+```
+
+前后端分离开发时极其常见。
+
+#### 3. 域名写法不同
+
+```
+页面:http://example.com
+请求:http://www.example.com
+
+example.com ≠ www.example.com → 跨域!
+```
+
+#### 4. 子域名不同
+
+```
+页面:https://app.example.com (前端)
+请求:https://api.example.com (后端 API)
+
+app.example.com ≠ api.example.com → 跨域!
+```
+
+### 图示
+
+```mermaid
+graph TD
+ subgraph 同源 ✅
+ A1["https://example.com:443"]
+ A2["https://example.com:443"]
+ A1 --- A2
+ end
+ subgraph 跨域 ❌
+ B1["https://app.example.com:443"]
+ B2["https://api.example.com:443"]
+ B1 --- B2
+ end
+ subgraph 跨域 ❌
+ C1["http://localhost:3000"]
+ C2["http://localhost:8080"]
+ C1 --- C2
+ end
+ subgraph 跨域 ❌
+ D1["http://example.com:80"]
+ D2["https://example.com:443"]
+ D1 --- D2
+ end
+```
+
+### 为什么要拦截?
+
+```mermaid
+sequenceDiagram
+ participant You as 你
+ participant Bank as bank.com
+ participant Evil as evil.com
+ Note over You,Bank: 你登录了银行网站,浏览器存了 cookie
+ You->>Evil: 访问恶意网站
+ Evil->>Bank: 请求 bank.com/api/transfer(冒充你转账)
+ Note over Bank: 浏览器同源策略拦截!
+ Note over Bank: evil.com 的请求被阻止 😅
+```
+
+**同源策略 = 浏览器替你守门,不同源的请求一律先拦住。**
+
+### 解决方案
+
+#### 方案 1:后端设置 CORS 响应头(最常用)
+
+```python
+# Python Flask
+from flask import Flask
+from flask_cors import CORS
+
+app = Flask(__name__)
+CORS(app) # 允许所有来源
+
+# 或精确控制
+CORS(app, origins=["https://app.example.com"])
+```
+
+```go
+// Go 标准库
+func corsMiddleware(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Access-Control-Allow-Origin", "https://app.example.com")
+ w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS")
+ w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
+ if r.Method == "OPTIONS" {
+ w.WriteHeader(http.StatusNoContent)
+ return
+ }
+ next.ServeHTTP(w, r)
+ })
+}
+```
+
+```nginx
+# Nginx
+add_header Access-Control-Allow-Origin "https://app.example.com";
+add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
+add_header Access-Control-Allow-Headers "Content-Type, Authorization";
+```
+
+#### 方案 2:前端开发代理
+
+```javascript
+// Vite 开发服务器配置
+export default {
+ server: {
+ proxy: {
+ '/api': {
+ target: 'http://localhost:8080',
+ changeOrigin: true,
+ }
+ }
+ }
+}
+```
+
+浏览器看到的请求始终在 `localhost:3000`,同源,不触发跨域。
+
+#### 方案 3:Nginx 反向代理(生产环境)
+
+```nginx
+server {
+ listen 80;
+ server_name app.example.com;
+
+ location / {
+ root /usr/share/nginx/html;
+ try_files $uri $uri/ /index.html;
+ }
+
+ location /api/ {
+ proxy_pass http://localhost:8080;
+ # 对浏览器:请求的是 app.example.com/api → 同源 ✅
+ }
+}
+```
+
+### 简单请求 vs 预检请求
+
+| 类型 | 条件 | 行为 |
+|------|------|------|
+| 简单请求 | GET/POST/HEAD + 简单 Header | 浏览器直接发,看响应头判断 |
+| 预检请求 | PUT/DELETE/自定义 Header 等 | 浏览器先发 OPTIONS 探路,确认后再发 |
+
+预检请求流程:
+
+```mermaid
+sequenceDiagram
+ participant C as 浏览器
+ participant S as 服务器
+ C->>S: OPTIONS /api/data(预检)
+ S->>C: 204 No Content
+ Note over S: Access-Control-Allow-Origin: https://app.example.com
+ Note over S: Access-Control-Allow-Methods: PUT, POST, GET
+ C->>C: 确认允许
+ C->>S: PUT /api/data(真正的请求)
+ S->>C: 200 OK
+```
+
+网络面板里一个请求出现两次——**第一次是 OPTIONS 预检**,不是 bug。
+
+---
+
+## 常见陷阱
+
+!!! warning "Access-Control-Allow-Origin 不能设为 * 同时带 Cookie"
+ 如果请求携带 Cookie(`withCredentials: true`),`Access-Control-Allow-Origin` 不能是 `*`,必须指定具体来源。否则浏览器会拒绝。
+
+!!! warning "忘记处理 OPTIONS 预检请求"
+ 很多后端框架默认不处理 OPTIONS 方法,导致预检请求返回 405 Method Not Allowed。需要显式添加 OPTIONS 处理逻辑。
+
+---
+
+## 练习题
+
+??? question "为什么 WebSocket 不受同源策略限制?"
+ ??? success "答案"
+ WebSocket 连接一旦建立,就是全双工通信,不受 CORS 限制。但建立连接的**握手阶段**(HTTP Upgrade 请求)仍然受同源策略影响。所以 WebSocket 的安全性依赖服务器端的身份验证,而不是浏览器的同源策略。
+
+??? question "如果后端设置了 Access-Control-Allow-Origin: *,前端 withCredentials: true 会怎样?"
+ ??? success "答案"
+ 浏览器会拒绝。规范明确要求:当请求携带凭据(Cookie、HTTP Auth)时,`Access-Control-Allow-Origin` 不能是通配符 `*`,必须是具体的源。这是为了防止任意网站都能通过你浏览器里的 Cookie 访问受保护资源。
diff --git a/docs/networking/domain-sharding.md b/docs/networking/domain-sharding.md
new file mode 100644
index 0000000..3bd3002
--- /dev/null
+++ b/docs/networking/domain-sharding.md
@@ -0,0 +1,142 @@
+# 域名分片(Domain Sharding)
+
+!!! note "HTTP/1.1 时代的聪明 hack——用多个子域名骗浏览器多开连接,绕过同域名 6 连接限制"
+
+---
+
+## 核心概念
+
+1. **浏览器连接限制** — 同一域名最多同时开 6 个 TCP 连接
+2. **域名分片** — 用多个子域名指向同一服务器,每个域名都能开 6 个连接
+3. **缓存碎片化** — 不同域名的缓存独立,可能重复下载相同资源
+4. **HTTP/2 淘汰** — 多路复用从根本上解决了这个问题,域名分片已无必要
+
+---
+
+## 详解
+
+### 它要解决什么问题
+
+浏览器对**同一域名**最多同时开 6 个 TCP 连接,这是硬限制。一个页面要加载 30 个资源:
+
+```
+只用一个域名 www.example.com:
+
+连接1: req1 → req7 → req13 → req19 → req25
+连接2: req2 → req8 → req14 → req20 → req26
+连接3: req3 → req9 → req15 → req21 → req27
+连接4: req4 → req10 → req16 → req22 → req28
+连接5: req5 → req11 → req17 → req23 → req29
+连接6: req6 → req12 → req18 → req24 → req30
+
+30 个资源 ÷ 6 个连接 = 每个连接排队 5 轮
+```
+
+每个连接上是**串行的**,请求排队等响应。
+
+### 域名分片的思路
+
+用多个子域名指向同一台服务器:
+
+```mermaid
+graph TD
+ A[www.example.com] --> D[源站服务器]
+ B[img1.example.com] --> D
+ C[img2.example.com] --> D
+ E[img3.example.com] --> D
+
+ F[每个域名 6 个连接] --> G[3 × 6 = 18 个并行连接]
+```
+
+```
+3 个子域名 × 6 个连接 = 18 个并行连接
+18 个连接同时下载,30 个资源几轮就完了
+```
+
+### 分片前后对比
+
+**不分片(1 个域名,6 个连接):**
+
+```
+连接1: ████ req1 ████ req7 ████ req13 ████ req19 ████ req25
+连接2: ████ req2 ████ req8 ████ req14 ████ req20 ████ req26
+连接3: ████ req3 ████ req9 ████ req15 ████ req21 ████ req27
+连接4: ████ req4 ████ req10 ████ req16 ████ req22 ████ req28
+连接5: ████ req5 ████ req11 ████ req17 ████ req23 ████ req29
+连接6: ████ req6 ████ req12 ████ req18 ████ req24 ████ req30
+ ↑ 很长
+```
+
+**分片后(3 个域名,18 个连接):**
+
+```
+img1 连接1-6: ████ 1 ████ 7 ████ 13 ████ 19 ████ 25
+img2 连接1-6: ████ 2 ████ 8 ████ 14 ████ 20 ████ 26
+img3 连接1-6: ████ 3 ████ 9 ████ 15 ████ 21 ████ 27
+ ↑ 快多了
+```
+
+### 实现方式
+
+前端 HTML 里只需把资源 URL 的域名换掉:
+
+```html
+
+
+
+
+
+```
+
+服务器端不用改动,所有子域名 DNS 解析到同一台机器就行。
+
+### 域名分片的代价
+
+| 代价 | 说明 |
+|------|------|
+| **DNS 解析开销** | 每个子域名都要单独解析,5-50ms |
+| **TLS 握手开销** | 每个新域名要单独做 TLS 握手 |
+| **缓存碎片化** | 不同域名的缓存独立,不能共享,可能重复下载 |
+
+### 为什么现在不需要了
+
+| | HTTP/1.1 + 域名分片 | HTTP/2 |
+|---|---|---|
+| 并行方式 | 多个 TCP 连接 | 一个 TCP 连接内多路复用 |
+| 开 30 个连接 | 需要 5 个子域名骗浏览器 | 不需要,一根连接全搞定 |
+| 额外开销 | 每个子域名 DNS + TLS | 只有一次 |
+| 缓存 | 每个子域名独立缓存 | 统一缓存 |
+
+---
+
+## 演进路线
+
+```mermaid
+graph TD
+ A[HTTP/1.0 无 Keep-Alive
每个请求一个连接] --> B[HTTP/1.1 + Keep-Alive
一个连接串行复用]
+ B --> C[域名分片
多域名骗浏览器多开连接]
+ C --> D[HTTP/2 多路复用
一个连接真正并行]
+ D --> E[HTTP/3 QUIC
连 TCP 队头阻塞都干掉]
+```
+
+---
+
+## 常见陷阱
+
+!!! warning "不要在 HTTP/2 上使用域名分片"
+ HTTP/2 的多路复用让域名分片变成了负优化——多了 DNS 和 TLS 开销,还破坏了缓存统一性。如果你的站点已经上了 HTTP/2,应该去掉域名分片。
+
+!!! warning "分片数量不是越多越好"
+ 3-4 个子域名通常就够了。过多子域名意味着更多 DNS 查询和 TLS 握手,反而拖慢加载速度。
+
+---
+
+## 练习题
+
+??? question "如果一个网站同时有 HTTP/1.1 和 HTTP/2 的用户,域名分片还有意义吗?"
+ ??? success "答案"
+ 需要权衡。HTTP/1.1 用户能从分片中获益(更多并行连接),但 HTTP/2 用户会受额外 DNS/TLS 开销之苦。建议直接升级到 HTTP/2 全站覆盖,而不是为少数 HTTP/1.1 用户保留分片。
+
+??? question "浏览器对同一域名 6 个连接的限制是怎么来的?"
+ ??? success "答案"
+ 这是浏览器厂商的**经验值**,不是协议规定。2000 年代初期,6 个连接被认为是在"并行效率"和"服务器负载"之间的平衡点。这个限制在 HTTP/2 时代已经过时,但浏览器仍然保持兼容。
diff --git a/docs/networking/go-build-strip.md b/docs/networking/go-build-strip.md
new file mode 100644
index 0000000..e81acf7
--- /dev/null
+++ b/docs/networking/go-build-strip.md
@@ -0,0 +1,172 @@
+# Go 编译标志 -s
+
+!!! note "剥离调试信息让二进制缩小 20-30%,生产发布必备,但代价是调试和排查困难"
+
+---
+
+## 核心概念
+
+1. **`-s` 标志** — 剥离符号表(函数名、变量名等调试符号)
+2. **`-w` 标志** — 剥离 DWARF 调试信息(gdb/lldb 所需的详细信息)
+3. **`-s -w` 组合** — 体积最小化,最适合发布部署
+4. **`-ldflags`** — 可在剥离的同时注入编译时变量(版本号、构建时间等)
+
+---
+
+## 详解
+
+### 基本用法
+
+```bash
+# 普通编译
+go build -o myapp main.go
+
+# 剥离符号表
+go build -s -o myapp main.go
+
+# 剥离调试信息
+go build -w -o myapp main.go
+
+# 同时剥离(最常用)
+go build -s -w -o myapp main.go
+```
+
+### -s 和 -w 的区别
+
+| 标志 | 剥离内容 | 效果 |
+|------|----------|------|
+| `-s` | 符号表 | 体积减小,panic 时看不到完整函数路径 |
+| `-w` | DWARF 调试信息 | 体积减小,无法用 gdb 调试 |
+| `-s -w` | 全部剥离 | 体积最小,最适合发布 |
+
+### 实际体积对比
+
+```bash
+go build -o app_normal main.go
+go build -s -o app_stripped main.go
+
+ls -lh app_normal app_stripped
+# -rwxr-xr-x 1 user staff 1.8M app_normal
+# -rwxr-xr-x 1 user staff 1.2M app_stripped
+# 省了约 30% 的体积
+```
+
+实际节省取决于程序复杂度,一般能**减少 20%-30%**。
+
+### panic 输出变化
+
+**有符号表(正常编译):**
+
+```
+goroutine 1 [running]:
+main.processData(0x10a0c00, 0x3)
+ /home/user/app/main.go:42 +0x1a5 ← 完整路径
+main.main()
+ /home/user/app/main.go:15 +0x89
+```
+
+**剥离符号表后(-s):**
+
+```
+goroutine 1 [running]:
+main.processData(0x10a0c00, 0x3)
+ main.go:42 +0x1a5 ← 只有文件名,没有完整路径
+main.main()
+ main.go:15 +0x89
+```
+
+函数名还在,但完整源码路径丢失。出问题时调试稍麻烦。
+
+### 对调试工具的影响
+
+```bash
+# 有 DWARF
+gdb ./app_normal
+(gdb) break main.processData # ✅ 可以设断点
+
+# 剥离 DWARF
+gdb ./app_stripped
+(gdb) break main.processData # ❌ 找不到符号
+```
+
+```bash
+# go tool pprof
+# 正常二进制
+(pprof) top
+ flat flat% sum% cum cum%
+ 1.2s 45.2% 45.2% 1.2s 45.2% runtime.mallocgc ← 有函数名
+
+# 剥离后
+(pprof) top
+ flat flat% sum% cum cum%
+ 1.2s 45.2% 45.2% 1.2s 45.2% 0x4a3b20 ← 只有地址
+```
+
+### 生产环境最佳实践
+
+结合 `-ldflags` 在剥离的同时注入构建信息:
+
+```makefile
+# Makefile
+VERSION := $(shell git describe --tags --always)
+BUILD_TIME := $(shell date -u '+%Y-%m-%dT%H:%M:%SZ')
+
+# 发布版
+build-release:
+ go build -ldflags="-s -w -X main.Version=$(VERSION) -X main.BuildTime=$(BUILD_TIME)" \
+ -o bin/app .
+```
+
+```go
+// main.go
+var (
+ Version string
+ BuildTime string
+)
+
+func main() {
+ fmt.Printf("Version: %s, Built: %s\n", Version, BuildTime)
+}
+```
+
+### 使用场景决策
+
+| 场景 | 用 `-s -w`? | 原因 |
+|------|-------------|------|
+| 生产环境部署 | ✅ | 体积小,不需要调试符号 |
+| CI/CD 构建产物 | ✅ | 减少传输和存储开销 |
+| 嵌入式 / IoT | ✅ | 存储空间宝贵 |
+| 本地开发调试 | ❌ | 需要完整调试信息 |
+| 性能分析(pprof) | ❌ | 需要符号表才能看到函数名 |
+| 排查线上 panic | ❌ | 需要完整路径定位代码 |
+
+### 语言对比
+
+| 语言 | 类似功能 |
+|------|----------|
+| C/C++ | `strip` 命令、`-s` 编译选项 |
+| Rust | `strip = true` in Cargo.toml |
+| Java | ProGuard / R8 混淆和精简 |
+| Go | `-s -w` 编译标志 |
+
+---
+
+## 常见陷阱
+
+!!! warning "线上出了 panic 但看不到完整堆栈"
+ 生产二进制用了 `-s`,panic 堆栈只有文件名没有完整路径。解决方案:保留符号表文件(`-w` 但不用 `-s`),或者用 `go tool addr2line` 通过地址反查行号。
+
+!!! warning "pprof 数据无法解读"
+ 剥离符号表后 pprof 只显示地址,无法定位到具体函数。线上排查性能问题时非常痛苦。建议线上至少保留 `-w`(只剥离 DWARF),不要用 `-s`。
+
+---
+
+## 练习题
+
+??? question "为什么 -s 能省 20-30% 的体积?符号表占那么多吗?"
+ ??? success "答案"
+ 符号表 + DWARF 调试信息确实可以占很大比例。DWARF 包含了每个函数的行号信息、变量类型、作用域等详细调试数据,对于大型程序来说体积相当可观。Go 的 runtime 本身也有很多符号信息。实际比例取决于程序复杂度和依赖数量。
+
+??? question "如果我用了 -s -w 但线上出了问题,怎么排查?"
+ ??? success "答案"
+ (1)如果有构建时生成的 debug info 备份,可以用 `go tool addr2line` 反查;(2)可以通过 `go tool pprof` 的 raw 模式看到地址;(3)如果保留了 `-w`(没用 `-s`),panic 堆栈仍然有函数名,只是没有行号;(4)最稳妥的做法是生产环境用 `-w` 但不用 `-s`,保留符号表。
diff --git a/docs/networking/http-connection-cost.md b/docs/networking/http-connection-cost.md
new file mode 100644
index 0000000..a216bcf
--- /dev/null
+++ b/docs/networking/http-connection-cost.md
@@ -0,0 +1,106 @@
+# HTTP 连接资源消耗
+
+!!! note "理解单个 HTTP 连接的真实资源开销,才能在百万并发场景下做出正确的架构决策"
+
+---
+
+## 核心概念
+
+1. **TCP 连接内存** — 内核为每个连接分配发送/接收缓冲区和控制块,约 3-10 KB
+2. **线程开销** — 传统模型每连接一个线程(~1 MB),协程模型仅需几 KB
+3. **TLS 会话** — HTTPS 连接额外消耗 50-100 KB 内存
+4. **文件描述符** — 每个连接占一个 fd,受系统 ulimit 限制
+5. **临时端口** — 客户端端口上限 65535,高并发时需要多端口或多 IP
+
+---
+
+## 详解
+
+### 单个 TCP 连接的内核开销
+
+操作系统为每个 TCP 连接分配的资源:
+
+| 资源 | 大约消耗 | 说明 |
+|------|----------|------|
+| 内核内存 | 3-10 KB | 发送/接收缓冲区 + TCP 控制块 |
+| 文件描述符 | 1 个 fd | 受 ulimit 限制 |
+| CPU | — | 三次握手 + 协议栈处理 |
+| 临时端口 | 1 个 | 客户端端口,上限 65535 |
+
+### 服务器侧的连接模型差异
+
+| 模型 | 每连接内存 | 比喻 |
+|------|-----------|------|
+| 线程模型(Java BIO) | ~1 MB(线程栈) | 每人占一条泳道(1米宽) |
+| 协程模型(Go/async) | ~4 KB | 每人只占一把椅子 |
+| 异步事件驱动(Nginx) | ~2 KB | 几乎不占位置 |
+
+### 百万并发的真实数字
+
+| 指标 | 单连接 | × 1,000,000 |
+|------|--------|-------------|
+| 内核内存 | ~10 KB | **~10 GB** |
+| 线程(传统模型) | ~1 MB | **~1 TB(不可行)** |
+| 协程(Go/async) | ~4 KB | **~4 GB(可行)** |
+| TLS 内存(HTTPS) | ~50 KB | **~50 GB** |
+| 文件描述符 | 1 | **100 万(需调 ulimit)** |
+
+### 形象比喻
+
+**传统线程模型 — 泳池:**
+
+```
+每个连接 = 一个人占一条泳道(1 米宽)
+100 万人 → 需要 100 万条泳道 → 1000 公里宽的泳池
+物理上不可能 🤯
+```
+
+**异步/事件驱动模型 — 叫号系统:**
+
+```
+人来了不占泳道,坐在池边等叫号
+有数据来了才临时下水
+每个人只占一把椅子(几 KB)
+100 万人 → 100 万把椅子 → 大概几百 MB ✅
+```
+
+**高速公路收费站:**
+
+| 模型 | 比喻 | 100 万车 |
+|------|------|----------|
+| 线程模型 | 每辆车配一个专属收费员 | 需要 100 万个收费员 |
+| 异步模型 | 一个收费员 + 叫号系统 | 一个收费员 + 一块显示屏 + 几 GB 内存 |
+
+---
+
+## 撑住百万并发的关键手段
+
+| 手段 | 说明 |
+|------|------|
+| **Epoll / Kqueue** | 不为每个连接开线程,一个线程监控百万 fd |
+| **连接池复用** | HTTP/1.1 Keep-Alive、HTTP/2 多路复用,少建新连接 |
+| **轻量协程** | Go goroutine、Rust async、Python asyncio |
+| **负载均衡** | L4 LB 分散到几十台机器 |
+| **内核调优** | `ulimit -n 1048576`、调整 TCP 缓冲区大小 |
+
+---
+
+## 常见陷阱
+
+!!! warning "误区:连接池越大越好"
+ 池子里每个连接都占内存和 fd。配得合理比配得大更重要。连接池打满时新请求排队,延迟飙升。
+
+!!! warning "别忽视 TLS 开销"
+ HTTPS 场景下 TLS 会话缓存每个连接 50-100 KB,百万并发下可能吃掉 50 GB 内存。考虑在 CDN 边缘终止 TLS。
+
+---
+
+## 练习题
+
+??? question "Go 的 goroutine 初始栈大小是多少?和 Java 线程相比如何?"
+ ??? success "答案"
+ Go goroutine 初始栈大小为 **2 KB**(可动态增长到 1 GB),Java 线程默认栈大小为 **1 MB**。这意味着在相同内存下,Go 能创建的并发单元数量是 Java 的约 500 倍。
+
+??? question "为什么操作系统对客户端临时端口有限制?"
+ ??? success "答案"
+ 客户端端口是 16 位整数,理论上限 65535。每个 TCP 连接需要一个唯一的四元组(源IP:源端口:目标IP:目标端口),如果一个客户端对同一服务器发起大量连接,端口很快耗尽。解决方案包括使用多 IP、连接池复用、HTTP/2 多路复用等。
diff --git a/docs/networking/http-handshake.md b/docs/networking/http-handshake.md
new file mode 100644
index 0000000..f4bac61
--- /dev/null
+++ b/docs/networking/http-handshake.md
@@ -0,0 +1,133 @@
+# HTTP 握手
+
+!!! note "HTTP 本身没有应用层握手,但底层的 TCP 和 TLS 各自有独立的握手流程"
+
+---
+
+## 核心概念
+
+1. **TCP 三次握手** — 所有 HTTP 连接建立前的基础,客户端与服务器确认彼此收发能力
+2. **TLS 握手** — HTTPS 场景下在 TCP 之上完成密钥协商和证书验证
+3. **HTTP/2 SETTINGS 交换** — 应用层的"半个握手",双方协商连接参数
+4. **QUIC 握手** — HTTP/3 将传输层和加密层合二为一,一次握手同时完成建连和加密
+
+---
+
+## 详解
+
+### TCP 三次握手
+
+每次 HTTP 通信之前,底层都要先完成 TCP 三次握手:
+
+```mermaid
+sequenceDiagram
+ participant C as 客户端
+ participant S as 服务器
+ C->>S: SYN(我要连接)
+ S->>C: SYN-ACK(收到,我也准备好了)
+ C->>S: ACK(确认,开始传数据)
+```
+
+| 阶段 | 方向 | 标志位 | 作用 |
+|------|------|--------|------|
+| 第一次 | 客户端 → 服务器 | SYN | 客户端发起连接请求 |
+| 第二次 | 服务器 → 客户端 | SYN-ACK | 服务器确认并回应 |
+| 第三次 | 客户端 → 服务器 | ACK | 客户端确认,连接建立 |
+
+三次握手的本质是**双方各确认一次收发能力**,确保连接可靠。
+
+### TLS 握手(HTTPS)
+
+在 TCP 握手之后、HTTP 请求之前完成:
+
+| TLS 版本 | 握手耗时 | 说明 |
+|----------|----------|------|
+| TLS 1.2 | 2-RTT(两个来回) | 需要两次往返完成密钥协商 |
+| TLS 1.3 | 1-RTT(一个来回) | 优化了握手流程 |
+| TLS 1.3 0-RTT | 0-RTT | 恢复会话时无需额外往返 |
+
+TLS 握手完成的事:
+
+- **证书验证**:确认服务器身份,防止中间人攻击
+- **密钥协商**:生成对称加密密钥
+- **加密套件确定**:双方商定使用的加密算法
+
+### HTTP/1.0 和 HTTP/1.1
+
+这两个版本**没有应用层握手**——TCP 连上、TLS 握完,直接发 HTTP 请求。
+
+```http
+# TCP 连接建立后,直接发请求
+GET /index.html HTTP/1.1
+Host: example.com
+```
+
+### HTTP/2 的 SETTINGS 交换
+
+HTTP/2 在连接建立后有一个应用层初始化过程:
+
+```mermaid
+sequenceDiagram
+ participant C as 客户端
+ participant S as 服务器
+ Note over C,S: TCP + TLS 握手完成
+ C->>S: SETTINGS 帧(我的能力参数)
+ S->>C: SETTINGS 帧(我的能力参数)
+ C->>S: SETTINGS ACK
+ S->>C: SETTINGS ACK
+ Note over C,S: 可以开始发送请求了
+```
+
+双方通过 SETTINGS 帧交换参数,如最大并发流数、窗口大小等。这不算严格的"握手",但起到类似的协商作用。
+
+### HTTP/3 (QUIC)
+
+HTTP/3 基于 QUIC 协议,QUIC 运行在 UDP 之上:
+
+```mermaid
+graph LR
+ A[QUIC] --> B[内置 TLS 1.3]
+ A --> C[内置可靠传输]
+ A --> D[多路复用]
+ A --> E[0-RTT 恢复]
+```
+
+- QUIC 把传输层握手和 TLS 1.3 握手**合二为一**
+- 首次连接只需 **1-RTT**
+- 恢复连接可达 **0-RTT**
+- 解决了 TCP 的队头阻塞问题(单个流丢包不影响其他流)
+
+---
+
+## 各层握手对比
+
+| 层级 | 协议 | 有握手? | 耗时 |
+|------|------|----------|------|
+| 传输层 | TCP | ✅ 三次握手 | 1-RTT |
+| 安全层 | TLS 1.2 | ✅ 密钥协商 | 2-RTT |
+| 安全层 | TLS 1.3 | ✅ 密钥协商 | 1-RTT |
+| 应用层 | HTTP/1.x | ❌ 无 | — |
+| 应用层 | HTTP/2 | 半个(SETTINGS) | ~0.5-1 RTT |
+| 传输+安全 | HTTP/3 (QUIC) | ✅ 内置 TLS 1.3 | 1-RTT / 0-RTT |
+
+---
+
+## 常见陷阱
+
+!!! warning "误区:认为 HTTPS 只多了一次握手"
+ HTTPS 的额外开销不仅是 TLS 握手本身。如果 CDN、代理层多,TLS 握手可能要打好几次。理解每一层的握手才能优化延迟。
+
+!!! warning "0-RTT 并非免费"
+ TLS 1.3 的 0-RTT 恢复虽然快,但存在**重放攻击**风险。0-RTT 发送的数据不能保证幂等性,因此不适合做敏感操作(如支付)。
+
+---
+
+## 练习题
+
+??? question "为什么 TCP 握手是三次而不是两次?"
+ ??? success "答案"
+ 两次握手无法防止**已失效的连接请求**到达服务器。如果客户端的旧 SYN 延迟到达,服务器会误以为是新请求并建立连接,白白浪费资源。三次握手让客户端有最后一次确认的机会,丢弃过期请求。
+
+??? question "HTTP/2 的 SETTINGS 交换和 TCP 三次握手有什么区别?"
+ ??? success "答案"
+ TCP 三次握手发生在传输层,目的是建立可靠的字节流通道。HTTP/2 的 SETTINGS 交换发生在应用层,目的是协商 HTTP 协议参数(如最大并发流、窗口大小等)。TCP 握手解决的是"能不能通信",SETTINGS 解决的是"怎么高效通信"。
diff --git a/docs/networking/http-keepalive.md b/docs/networking/http-keepalive.md
new file mode 100644
index 0000000..6c0ad8b
--- /dev/null
+++ b/docs/networking/http-keepalive.md
@@ -0,0 +1,137 @@
+# HTTP Keep-Alive
+
+!!! note "建一次连接,连续发多个请求,不用每次重新握手——HTTP/1.1 最重要的默认优化"
+
+---
+
+## 核心概念
+
+1. **Keep-Alive** — TCP 连接建立后不立即关闭,允许在同一连接上发送多个 HTTP 请求
+2. **Connection 头** — 通过 `Connection: Keep-Alive` 或 `Connection: close` 控制连接生命周期
+3. **队头阻塞** — Keep-Alive 连接上的请求严格串行,后一个请求必须等前一个响应返回
+4. **演进路线** — 从无 Keep-Alive → Keep-Alive → HTTP/2 多路复用 → HTTP/3 QUIC
+
+---
+
+## 详解
+
+### 没有 Keep-Alive(HTTP/1.0)
+
+一个请求一个连接,用完即弃:
+
+```mermaid
+sequenceDiagram
+ participant C as 客户端
+ participant S as 服务器
+ loop 每个请求
+ C->>S: TCP 三次握手
+ C->>S: TLS 握手(HTTPS)
+ C->>S: GET /resource
+ S->>C: 200 OK
+ C->>S: TCP 四次挥手断开
+ end
+```
+
+一个网页通常有几十个资源(HTML、CSS、JS、图片……),每个都走一遍握手流程。**光握手就比传数据花的时间还多。**
+
+### 有 Keep-Alive(HTTP/1.1 默认)
+
+建一次连接,连续发多个请求:
+
+```mermaid
+sequenceDiagram
+ participant C as 客户端
+ participant S as 服务器
+ Note over C,S: TCP 连接(就这一次)
+ C->>S: GET /index.html
+ S->>C: 200 OK + HTML
+ C->>S: GET /style.css(同一个连接)
+ S->>C: 200 OK + CSS
+ C->>S: GET /app.js(还是同一个)
+ S->>C: 200 OK + JS
+ C->>S: GET /logo.png
+ S->>C: 200 OK + PNG
+ Note over C,S: 全部搞完,最后才断开
+```
+
+### 协议层面的协商
+
+服务器通过响应头声明 Keep-Alive 参数:
+
+```http
+HTTP/1.1 200 OK
+Connection: Keep-Alive
+Keep-Alive: timeout=5, max=100
+```
+
+| 字段 | 含义 |
+|------|------|
+| `Connection: Keep-Alive` | 告诉客户端:这个连接可以复用 |
+| `timeout=5` | 空闲超过 5 秒没新请求,关闭连接 |
+| `max=100` | 单连接最多处理 100 个请求,之后强制关闭 |
+
+客户端也可以主动声明:
+
+```http
+GET /page.html HTTP/1.1
+Host: example.com
+Connection: Keep-Keep-Alive
+```
+
+不想复用时:
+
+```http
+HTTP/1.1 200 OK
+Connection: close
+```
+
+### 队头阻塞问题
+
+Keep-Alive 解决了频繁握手,但引入了队头阻塞:
+
+```mermaid
+sequenceDiagram
+ participant C as 客户端
+ participant S as 服务器
+ C->>S: 请求1
+ Note over C,S: 必须等响应1完全返回
+ S->>C: 响应1
+ C->>S: 请求2(才能开始)
+ S->>C: 响应2
+ C->>S: 请求3
+ S->>C: 响应3
+```
+
+请求 2 必须等请求 1 的响应**完全返回**后才能发出。浏览器用**多开 6 个连接**来弥补——一条收银通道排队太慢,所以超市开了 6 个收银台,但每个收银台内部还是串行的。
+
+### 演进路线
+
+```mermaid
+graph TD
+ A[HTTP/1.0 无 Keep-Alive
一请求一连接] -->|加 Connection 头| B[HTTP/1.1 默认 Keep-Alive
一个连接串行多个请求]
+ B -->|多开 6 个连接弥补| C[浏览器并行连接
缓解队头阻塞]
+ C -->|彻底重构| D[HTTP/2 多路复用
一个连接上真正并行]
+ D -->|连 TCP 队头阻塞都干掉| E[HTTP/3 QUIC
基于 UDP 的多路复用]
+```
+
+---
+
+## 常见陷阱
+
+!!! warning "空闲连接占用资源"
+ Keep-Alive 连接在空闲时仍然占内存和 fd。如果客户端长时间不发新请求,服务器应该主动关闭。合理设置 `timeout` 参数。
+
+!!! warning "服务器已关连接但客户端不知道"
+ 服务器因超时关闭了连接,但客户端下次复用时才发现连接已死 → 报错。需要开启连接健康检查或设置合理的超时。
+
+---
+
+## 练习题
+
+??? question "HTTP/1.1 默认 Keep-Alive,为什么浏览器还要开 6 个连接?"
+ ??? success "答案"
+ 因为 HTTP/1.1 的 Keep-Alive 存在队头阻塞——同一连接上的请求严格串行。开 6 个连接可以并行处理 6 个请求,大幅提升页面加载速度。HTTP/2 的多路复用解决了这个问题,一个连接就够了。
+
+??? question "Keep-Alive 的 timeout 和 max 有什么区别?"
+ ??? success "答案"
+ `timeout` 控制的是**时间**——空闲多久后关闭连接。`max` 控制的是**请求数**——单连接处理多少个请求后关闭。两者取先触发的那个。例如 `timeout=5, max=100` 表示:空闲 5 秒或处理 100 个请求后关闭。
diff --git a/docs/networking/index.md b/docs/networking/index.md
new file mode 100644
index 0000000..32757e6
--- /dev/null
+++ b/docs/networking/index.md
@@ -0,0 +1,19 @@
+# 计算机网络
+
+!!! note "从 HTTP 协议到底层连接管理,覆盖面试和实战中的核心网络知识"
+
+---
+
+## 文章目录
+
+| 文章 | 核心内容 |
+|------|----------|
+| [HTTP 握手](http-handshake.md) | TCP 三次握手、TLS 握手、HTTP/2 与 HTTP/3 的连接建立 |
+| [HTTP 连接资源消耗](http-connection-cost.md) | 单连接资源开销、百万并发的真实数字与应对策略 |
+| [连接池复用](connection-pooling.md) | 预建连接、借还机制、HTTP/1.1 与 HTTP/2 的复用差异 |
+| [HTTP Keep-Alive](http-keepalive.md) | Keep-Alive 原理、队头阻塞、演进路线 |
+| [Keep-Alive 使用场景](keepalive-scenarios.md) | 何时启用、何时关闭、生产环境最佳实践 |
+| [域名分片](domain-sharding.md) | HTTP/1.1 时代的 hack,HTTP/2 后的淘汰 |
+| [CDN](cdn.md) | 边缘节点、缓存策略、加速原理与配置 |
+| [跨域 CORS](cors.md) | 同源三元组、CORS 响应头、预检请求 |
+| [Go 编译标志 -s](go-build-strip.md) | 剥离调试信息、体积优化、生产发布 |
diff --git a/docs/networking/keepalive-scenarios.md b/docs/networking/keepalive-scenarios.md
new file mode 100644
index 0000000..cb41e3e
--- /dev/null
+++ b/docs/networking/keepalive-scenarios.md
@@ -0,0 +1,161 @@
+# Keep-Alive 使用场景
+
+!!! note "99% 的场景都该用 Keep-Alive,关键是配好超时时间和最大请求数"
+
+---
+
+## 核心概念
+
+1. **高频请求** — 同一客户端短时间内多次请求同一服务器,Keep-Alive 省掉大量握手开销
+2. **高延迟网络** — 移动端/跨地域场景下,每次握手的延迟代价更高
+3. **资源受限** — 空闲连接太多时反而有害,需要缩短超时或关闭 Keep-Alive
+4. **安全隔离** — 某些敏感场景需要每次请求走独立连接
+
+---
+
+## 详解
+
+### 建议启用 Keep-Alive 的场景
+
+#### 1. 高频请求同一服务器
+
+```mermaid
+graph LR
+ A[前端页面] -->|请求 30 个资源| B[CDN/源站]
+ C[微服务 A] -->|链式调用| D[微服务 B]
+ D -->|继续调用| E[微服务 C]
+```
+
+最常见的场景。前端页面加载、微服务间调用、API 连续请求等,几乎没有任何理由关掉 Keep-Alive。
+
+#### 2. 移动端 / 高延迟网络
+
+移动端网络延迟高,每次 TLS 握手可能要 100-300ms:
+
+| 场景 | 无 Keep-Alive | 有 Keep-Alive |
+|------|--------------|---------------|
+| 30 次请求 × 150ms 握手 | **4.5 秒**光握手 | **150ms**只握手一次 |
+
+**省了 4 秒多,体感天差地别。**
+
+#### 3. 短间隔批量请求
+
+爬虫批量抓取、定时轮询、WebSocket 建立前的 HTTP 握手等,1000 个请求:
+
+| 方案 | 每个请求耗时 | 总耗时 |
+|------|-------------|--------|
+| 无 Keep-Alive | 60ms(50ms 握手 + 10ms 传输) | 60 秒 |
+| 有 Keep-Alive | 10ms(0ms 握手 + 10ms 传输) | 10 秒 |
+
+#### 4. 内部服务间通信
+
+微服务之间的 RPC 调用、数据库连接、Redis 连接等,连接池 + Keep-Alive 是标配。
+
+### 不建议使用 Keep-Alive 的场景
+
+#### 1. 一次性 / 低频请求
+
+偶尔请求一次,几分钟甚至几小时才来一次:
+
+```
+用户一天登录一次,查一次个人信息就不用了
+每天凌晨跑一次定时任务,拉一次数据
+```
+
+Keep-Alive 连接空等着白白占内存。不过现代服务器默认超时 5-15 秒会自动释放,实际影响不大。
+
+#### 2. 连接数是瓶颈时
+
+极端场景下,空闲连接太多反而有害:
+
+```
+10000 个空闲 Keep-Alive 连接 × 10KB = 100MB 内存
+文件描述符吃掉 10000 个
+新请求反而因为资源不够被拒绝
+```
+
+这时候应该**缩短超时时间**,而不是关掉 Keep-Alive:
+
+```nginx
+keepalive_timeout 5; # 空闲 5 秒就释放
+keepalive_requests 1000; # 单连接最多处理 1000 个请求就回收
+```
+
+#### 3. 安全隔离
+
+银行转账等敏感操作,每次操作用全新连接,确保上一次的上下文不会残留。多租户 SaaS 也要隔离,A 租户的连接不能被 B 租户复用。
+
+#### 4. 大文件传输
+
+下载 2GB 文件,一个连接独占十几分钟。如果连接池只有 10 个,其他请求全部排队等这个下载完。
+
+```python
+# 正确做法:下载用独立连接,业务用连接池
+download_session = requests.Session()
+download_session.headers['Connection'] = 'close' # 下载完就关
+
+api_session = requests.Session() # 默认 Keep-Alive
+```
+
+---
+
+## 决策参考
+
+| 条件 | Keep-Alive | Connection: close |
+|------|-----------|-------------------|
+| 同一客户端高频请求 | ✅ | |
+| 请求间隔 < Keep-Alive 超时 | ✅ | |
+| 移动端 / 高延迟网络 | ✅ | |
+| 微服务内部通信 | ✅ | |
+| 偶尔请求一次 | 无所谓(让服务器默认超时就好) | |
+| 单次大文件下载 | | ✅ |
+| 连接数已达上限 | 缩短超时 | |
+| 安全隔离要求 | | ✅ |
+| 公共 API 防滥用 | 缩短超时 + 限制次数 | |
+
+---
+
+## 生产环境配置建议
+
+### Nginx
+
+```nginx
+# 后端代理(微服务间)—— 激进复用
+proxy_http_version 1.1;
+proxy_set_header Connection "";
+keepalive_timeout 60s;
+keepalive_requests 1000;
+
+# 面向公网 —— 适度保守
+keepalive_timeout 10s;
+keepalive_requests 100;
+```
+
+### Java Tomcat
+
+```xml
+
+```
+
+---
+
+## 常见陷阱
+
+!!! warning "公共 API 忘记限制连接数"
+ 不限制 Keep-Alive 超时和最大请求数,一个恶意客户端可以长期霸占连接。应该设置 `keepalive_timeout` 和 `keepalive_requests` 上限。
+
+!!! warning "大文件和小请求混用同一连接池"
+ 大文件传输独占连接时间过长,导致小请求排队。应该分离:大文件用独立连接(`Connection: close`),小请求用连接池复用。
+
+---
+
+## 练习题
+
+??? question "如果你的 API 网关同时服务移动端和 Web 端,Keep-Alive 配置应该怎么考虑?"
+ ??? success "答案"
+ 移动端延迟高,Keep-Alive 收益大,超时可以设长一些(如 30 秒)。Web 端延迟低但并发高,超时可以短一些(如 10 秒)。可以按来源区分配置,或者取一个折中值(10-15 秒),配合 `keepalive_requests` 限制单连接最大请求数。
+
+??? question "为什么说 Keep-Alive 的 '99% 场景都该用'?那 1% 是什么?"
+ ??? success "答案"
+ 那 1% 主要是:(1)安全隔离要求极高的场景(如金融交易),每次连接必须独立;(2)连接数是硬瓶颈的极端高并发场景;(3)超大文件传输会独占连接。除此之外,默认开启是正确选择。
diff --git a/mkdocs.yml b/mkdocs.yml
index eb6c285..4b83bc9 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -127,6 +127,17 @@ nav:
- 部署与 CI/CD: qiniu-cloud/deployment-cicd.md
- 安全·认证·数据: qiniu-cloud/security-auth-data.md
- 简历技术要点: qiniu-cloud/resume-tech-points.md
+ - 计算机网络:
+ - networking/index.md
+ - HTTP 握手: networking/http-handshake.md
+ - HTTP 连接资源消耗: networking/http-connection-cost.md
+ - 连接池复用: networking/connection-pooling.md
+ - HTTP Keep-Alive: networking/http-keepalive.md
+ - Keep-Alive 使用场景: networking/keepalive-scenarios.md
+ - 域名分片: networking/domain-sharding.md
+ - CDN: networking/cdn.md
+ - 跨域 CORS: networking/cors.md
+ - Go 编译标志 -s: networking/go-build-strip.md
- AI:
- ai/index.md
- Skill 编写最佳实践: ai/skill-best-practices.md