握手:现代 API 的隐形成本
Source: Dev.to
发生了什么?
当本地 API 在 20 ms 内响应时,日志没有显示瓶颈,数据库已经优化,代码也很干净。准备上线后,它的响应时间却升到了 400 ms。我们立刻查看日志,重新审视代码,检查数据库,确信问题 一定 出在这里。
我们常常忘记,或者根本没有注意到的是,在 发送第一个字节之前 已经产生了一笔成本。
客户端和服务器需要相互通信。为了安全性和可靠性而进行的通信协商会产生成本,这个成本受网络质量、涉及区域之间的距离以及所使用的传输协议影响。在本地,这个成本几乎感受不到,但在生产环境中我们无法回避它。若被忽视,它会在现代架构中悄然成倍放大。
经过的路径
如果 DNS 解析不在缓存中,请求会经历一个层级过程:
- 客户端查询 根服务器,根服务器指明负责该顶级域(TLD)的服务器。
- TLD 服务器 指向该域的 权威服务器,权威服务器最终返回 IP 地址。
每一步都会产生一次往返通信,可能在连接建立之前就增加延迟。
在传输任何数据之前,TCP 必须在客户端和服务器之间建立可靠连接。这个过程称为 三次握手(three‑way handshake),至少需要一次往返。
如果连接需要安全性,这个成本会进一步上升。TCP 建立后,还需要进行安全协商,TLS 再额外增加一次客户端和服务器之间的通信。
成本已经支付。我们无法消除它,但可以在架构上 摊销 或 降低其影响。
减少损失
这段延迟不是实现上的问题,而是对可靠性和安全性做出正确决策的必然结果。既然无法根除,就要决定 何时、多少次、在哪里 支付这笔成本。
- 连接复用:使用 keep‑alive 和 connection pooling,DNS、TCP 和 TLS 的成本只会支付一次,随后多个请求共享同一通道。
- HTTP/2:允许在单一连接上复用多个请求,减少所需的连接数。收益不在于让网络更快,而在于降低初始成本的支付次数。
- TLS 会话恢复(TLS session resumption):在安全连接中,允许客户端和服务器复用先前 TLS 连接的信息,避免完整的握手过程。
- TLS 终止集中化:将 TLS 终止放在 负载均衡器 或 API 网关,改变成本发生的位置,防止它在内部服务之间不受控制地传播。
- HTTP/3(QUIC):摆脱对 TCP 的依赖,并将 TLS 融入传输层,减少在第一个字节到达前所需的步骤数。在移动端和不稳定网络场景下,这种差异往往决定成败。
- 避免不必要的调用:缓存、数据聚合和削减 fan‑out 并不会加快握手,但可以避免握手的发生。
延迟是我们决定跨越网络多少次的结果。当握手成本被忽视时,它会成倍增长。将其视为架构的一部分后,就可以被控制、摊销,甚至常常被移出关键路径。
参考资料
- System Design – 网络协议与通信
- Optimizing TLS over TCP to Reduce Latency – Cloudflare 博客
- SSL/TLS Recommender – Cloudflare 博客
- What is DNS? – Cloudflare Learning