跳转至

一次请求的生命周期

学习目标

学完本章后,学习者应该能够:

  1. 说清楚浏览器访问一个接口时,请求经历了哪些步骤。
  2. 理解 DNS、TCP、TLS、HTTP、网关、后端服务、数据库之间的关系。
  3. 知道一个请求失败时,可以从哪些节点排查。
  4. 建立端到端链路思维。

从输入 URL 开始

当用户在浏览器中访问一个地址时,例如:

https://api.example.com/users/me

背后大致会发生:

  1. 浏览器解析 URL。
  2. 查询 DNS,找到域名对应的 IP。
  3. 和目标 IP 建立 TCP 连接。
  4. 如果是 HTTPS,进行 TLS 握手。
  5. 发送 HTTP 请求。
  6. 请求经过网关或负载均衡。
  7. 后端服务接收请求。
  8. 后端执行业务逻辑。
  9. 后端访问数据库、缓存或其他服务。
  10. 后端返回 HTTP 响应。
  11. 浏览器解析响应并展示结果。

简化链路如下:

sequenceDiagram
    participant Browser as 浏览器
    participant DNS as DNS
    participant LB as 网关/负载均衡
    participant API as Go 后端服务
    participant Redis as Redis
    participant DB as 数据库

    Browser->>DNS: 查询 api.example.com
    DNS-->>Browser: 返回 IP
    Browser->>LB: 建立连接并发送 HTTP 请求
    LB->>API: 转发请求
    API->>Redis: 查询缓存
    alt 缓存命中
        Redis-->>API: 返回缓存数据
    else 缓存未命中
        API->>DB: 查询数据库
        DB-->>API: 返回数据
        API->>Redis: 写入缓存
    end
    API-->>LB: 返回响应
    LB-->>Browser: 返回 HTTP 响应

DNS:找到服务在哪里

DNS 负责把域名解析成 IP 地址。

如果 DNS 出问题,常见现象是:

  • 域名无法访问。
  • 某些地区访问失败。
  • 新旧 IP 切换后仍访问旧服务。
  • Kubernetes 集群内服务名解析失败。

排查工具:

dig api.example.com
nslookup api.example.com

TCP:建立可靠连接

HTTP/1.1 和 HTTP/2 通常运行在 TCP 之上。TCP 负责可靠传输。

常见问题:

  • 连接超时。
  • 连接被拒绝。
  • 连接数过多。
  • TIME_WAIT 很多。
  • CLOSE_WAIT 很多。

排查工具:

netstat -ano
ss -ant

后续计算机网络章节会深入 TCP 三次握手、四次挥手、拥塞控制和状态机。

TLS:建立安全通道

HTTPS 会在 HTTP 之前先进行 TLS 握手。

TLS 解决的问题:

  • 加密传输。
  • 身份认证。
  • 防止中间人攻击。

常见问题:

  • 证书过期。
  • 证书域名不匹配。
  • 客户端不信任证书。
  • TLS 版本或加密套件不兼容。

HTTP:表达请求和响应

HTTP 是客户端和服务端沟通的应用层协议。

一个请求通常包含:

  • Method:GETPOSTPUTDELETE
  • Path:请求路径。
  • Query:查询参数。
  • Header:请求元信息。
  • Body:请求体。

一个响应通常包含:

  • Status Code:状态码。
  • Header:响应元信息。
  • Body:响应内容。

例如:

GET /users/me HTTP/1.1
Host: api.example.com
Authorization: Bearer token

网关与负载均衡

请求通常不会直接打到业务服务,而是先经过网关或负载均衡。

它们可能负责:

  • TLS 终止。
  • 路由转发。
  • 负载均衡。
  • 鉴权。
  • 限流。
  • 日志。
  • 跨域处理。
  • 灰度发布。

如果网关配置错误,后端代码完全正确也可能访问失败。

常见现象:

  • 404:路由没匹配到。
  • 502:网关无法连接后端。
  • 503:后端服务不可用。
  • 504:后端处理超时。

后端服务处理请求

Go 后端服务接收到请求后,通常会经历:

  1. 路由匹配。
  2. 中间件处理。
  3. 参数解析。
  4. 参数校验。
  5. 鉴权和权限判断。
  6. 调用业务逻辑。
  7. 访问数据库、缓存、消息队列或其他服务。
  8. 组装响应。
  9. 记录日志和指标。

典型 Go HTTP 处理函数:

func healthHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    _, _ = w.Write([]byte(`{"status":"ok"}`))
}

这里的代码很简单,但真实业务中还会有超时控制、错误处理、日志、指标和链路追踪。

数据库与缓存

很多请求最终都会访问数据。

常见模式:

  1. 先查 Redis 缓存。
  2. 缓存命中,直接返回。
  3. 缓存未命中,查数据库。
  4. 把数据库结果写入缓存。
  5. 返回响应。

这个模式能提升读取性能,但也带来一致性问题:

  • 数据库更新后缓存如何更新?
  • 缓存删除失败怎么办?
  • 热点 Key 被大量访问怎么办?
  • 缓存雪崩时数据库能否扛住?

这些内容会在数据库与缓存阶段深入学习。

请求失败如何排查

端到端链路越长,失败点越多。排查时可以按路径逐段确认:

阶段 常见问题 排查方向
DNS 域名无法解析 dignslookup
TCP 连接失败 端口、服务监听、防火墙
TLS 证书错误 证书有效期、域名、CA
HTTP 状态码异常 路由、参数、权限、网关
后端服务 处理失败 日志、错误码、panic
数据库 查询慢或失败 慢 SQL、连接池、索引
缓存 命中率低或超时 Redis 状态、热点 Key
外部服务 调用超时 超时配置、重试、降级

常见误区

  • 误区一:访问失败就是后端代码问题。

也可能是 DNS、网关、证书、网络、端口、配置、数据库或缓存问题。

  • 误区二:HTTP 500 就一定是服务器崩了。

500 只表示服务端处理失败,具体原因要看日志和错误链路。

  • 误区三:重试可以解决所有超时。

盲目重试会放大流量,可能把依赖服务彻底打垮。

实战任务

使用当前知识库服务做一次请求链路观察:

步骤一:启动服务。

python -m mkdocs serve
python -m mkdocs serve

步骤二:访问首页。

Invoke-WebRequest -UseBasicParsing http://127.0.0.1:8000/
curl -i http://127.0.0.1:8000/

步骤三:记录。

  • HTTP 状态码。
  • 响应内容大小。
  • 端口监听进程。
  • 如果服务停止,再访问会出现什么错误?

步骤四:思考。

  • 这个请求有没有 DNS?
  • 有没有 TLS?
  • 有没有网关?
  • 它和生产环境的请求链路有什么区别?

面试题

1. 从浏览器输入 URL 到页面返回,中间发生了什么?

参考答案

浏览器会先解析 URL,然后通过 DNS 查询域名对应的 IP。接着和目标地址建立 TCP 连接,如果是 HTTPS,还会进行 TLS 握手。连接建立后,浏览器发送 HTTP 请求,请求可能经过网关或负载均衡,再转发到后端服务。

后端服务接收请求后,会进行路由匹配、参数解析、鉴权、业务处理,可能访问数据库、缓存或其他服务,最后组装 HTTP 响应返回给浏览器。浏览器再解析响应内容并展示页面。

2. DNS、TCP、TLS、HTTP 分别解决什么问题?

参考答案

DNS 解决“域名对应哪个 IP”的问题。TCP 解决“如何在两端之间建立可靠传输连接”的问题。TLS 解决“如何加密传输并验证对方身份”的问题。HTTP 解决“客户端和服务端如何表达请求和响应”的问题。

可以把它们放在一条链路上理解:DNS 找地址,TCP 建连接,TLS 建安全通道,HTTP 传业务语义。

3. 502、503、504 通常分别可能意味着什么?

参考答案

502 通常表示网关从上游服务拿到了无效响应,可能是后端进程崩溃、连接被拒绝、协议不匹配或网关无法正确转发。503 通常表示服务暂不可用,可能是后端实例不可用、过载、维护或没有健康实例。

504 通常表示网关等待上游服务超时,后端可能处理太慢、数据库慢、外部依赖卡住或网络异常。实际排查时要结合网关日志、后端日志和链路追踪判断。

4. 如果一个接口偶发超时,你会从哪些方向排查?

参考答案

可以从请求链路逐段排查:客户端和网关是否有超时日志,后端服务是否有慢请求日志,数据库是否出现慢 SQL,Redis 或外部服务是否有超时,连接池是否耗尽,CPU、内存、GC、锁竞争是否异常。

偶发超时尤其要关注高峰流量、依赖抖动、连接复用、DNS、GC 暂停、慢查询和重试放大。好的排查方式是通过 Trace ID 串起一次具体慢请求,而不是只看平均耗时。

5. 为什么后端服务要记录请求日志和 Trace ID?

参考答案

请求日志用于记录请求发生了什么,包括路径、状态码、耗时、用户、错误信息等。Trace ID 用于把同一次请求在网关、服务、数据库、缓存、消息队列等多个组件中的日志串起来。

没有 Trace ID 时,排查分布式问题很容易变成在大量日志中猜测。记录请求日志和 Trace ID 能显著提高线上问题定位效率,也是可观测性的基础。