第 18 章 计算机网络实践
系统设计的绝大多数系统都建立在网络通信之上。请求为什么会超时、连接为什么会堆积、重试为什么会放大故障、为什么有的场景选 TCP 有的场景选 UDP,本质上都离不开网络基础。本章不追求把协议细节讲成教材,而是聚焦系统设计工程师最常用的网络判断框架。
网络分层与通信基础
网络分层的意义在于把复杂通信拆成职责明确的层次。无论是常见的 OSI 七层模型,还是工程上更常用的 TCP/IP 分层,真正重要的都不是把每一层背下来,而是理解“链路层负责本地传输、网络层负责寻址与转发、传输层负责端到端通信、应用层负责具体语义”。只要这个边界清楚,排查问题时就能更快判断故障到底出在路由、连接、协议还是业务本身。
系统设计里常见的应用层协议很多,如 HTTP、HTTPS、RPC、DNS、SMTP、SSH、WebSocket 等。它们并不是孤立存在的,而是建立在传输层和网络层之上。因此,面试里问“浏览器输入一个 URL 后发生了什么”,本质上是在考你能否把域名解析、TCP 建连、TLS 握手、HTTP 请求、负载均衡、缓存命中和页面渲染串成一条链路。
理解请求路径的第一步,是把“名字”和“地址”区分开。用户输入的是域名,真正通信需要的是 IP 和端口;应用关心的是 URL、Header、Body 和状态码,内核和网卡关心的是报文、连接状态、队列和重传。系统设计中的很多中间层,例如代理、网关、CDN 和 Service Mesh,正是通过在不同层插入能力来实现路由、缓存、安全和治理。
还要注意,一个应用请求通常会穿过多级网络设备和软件组件:本机协议栈、出口 NAT、四层或七层负载均衡、反向代理、应用网关、服务实例。延迟和故障可能出现在其中任何一段。所以讨论网络性能时,不能只盯着“服务端代码是不是慢”,还要考虑解析、建连、加密、拥塞、重试和中间层转发开销。
TCP、UDP 与连接管理
TCP 是面向连接、可靠、按序的字节流协议;UDP 是无连接、尽力而为的数据报协议。这个区别几乎所有人都会背,但系统设计更关心“为什么这里必须要连接语义”“为什么这里宁可接受丢包也不愿接受高延迟”。例如交易请求、数据库连接、控制平面通信更适合 TCP;语音视频、实时游戏、部分监控或探测流量则更可能偏向 UDP。
TCP 的可靠性来自一整套机制:三次握手建立连接、序列号保证顺序、确认与重传保证交付、滑动窗口实现流量控制、拥塞控制约束发送速率。面试中经常被问到“为什么是三次握手不是两次”“为什么挥手通常是四次”“TIME_WAIT 有什么作用”。这些问题的核心都在于:连接状态不是一句“建好了”就结束,而是双方都要对序列空间和关闭状态达成一致,避免旧报文污染新连接。
TIME_WAIT 经常被误解为“系统有问题”。实际上它是主动关闭一方的正常状态,用于等待旧报文自然消失并确保最后一个 ACK 有重传机会。真正值得警惕的是 CLOSE_WAIT 过多,因为这通常意味着对端已经关闭连接,而本地应用迟迟没有执行关闭逻辑。线上排查时,TIME_WAIT 大量堆积先看连接模型和短连接风暴,CLOSE_WAIT 大量堆积则优先排查代码是否存在连接泄漏。
TCP 还有几个系统设计里特别常见的概念。粘包不是 TCP “把消息粘住了”,而是因为 TCP 只提供字节流,不保留应用消息边界,所以应用层必须靠长度字段、分隔符或固定协议头自行拆包。KeepAlive 负责探测连接是否存活,但它不等于应用层心跳,因为内核看到连接活着,不代表业务线程、依赖服务或上游逻辑一定可用。真正严肃的分布式系统通常会同时使用 TCP 连接保活和业务语义心跳。
UDP 的价值则在于低开销和更少的连接约束。它适合广播、DNS 查询、实时媒体和部分自定义协议。如果业务既想要 UDP 的低时延,又想要可靠性,就只能在应用层自己补上序号、确认、重传、流控甚至拥塞控制,这也是 QUIC 这类协议的重要思路:保留 UDP 的部署灵活性,同时在更高层重新实现可靠连接语义。
HTTP、HTTPS 与应用层协议
HTTP 是最常见的应用层协议,本质是请求-响应语义在网络中的标准表达。理解 HTTP,关键不是死记各种 Header,而是理解三个层面:方法语义、连接复用、缓存与状态。GET、POST、PUT、DELETE 等方法不仅仅是语法差异,更关系到幂等性、可缓存性以及重试时是否安全。系统设计里谈 API 网关、重试策略和幂等保障时,这些语义非常重要。
HTTP/1.1 引入持久连接后,不再要求每个请求都重新建立 TCP 连接,明显减少了握手成本。HTTP/2 则进一步提供多路复用、头部压缩和更高效的连接利用率。HTTP/3 基于 QUIC,把传输层的部分可靠性和拥塞控制能力上移,减少队头阻塞问题。理解这些演进,能帮助你解释为什么同样的服务在协议升级后会表现出不同的延迟特征。
HTTPS 则是在 HTTP 之下增加 TLS,加密数据并提供服务端身份认证。对系统设计来说,HTTPS 不只是“更安全”,它还意味着额外的握手、证书管理、加解密开销和终止点选择。很多系统会在 CDN、负载均衡或 API Gateway 层终止 TLS,再用内网协议转发;也有更严格的场景会选择端到端加密。这背后是安全性、性能和运维复杂度之间的平衡。
HTTP keep-alive 和 TCP keepalive 也经常被混淆。前者强调连接复用,希望多个请求共享同一条连接,减少重复建连和握手开销;后者强调存活探测,希望确认底层连接没有悄悄失效。把这两个概念分清,你才能解释为什么客户端连接池、服务端空闲连接回收、代理层超时和心跳策略必须协同设计。
除了 HTTP,系统内部还大量使用 RPC 协议。RPC 更强调方法调用和服务契约,通常配合二进制序列化获得更紧凑的编码和更高的吞吐;REST 更强调资源表达和通用语义,更适合对外开放接口。系统设计中选 RPC 还是 REST,关键看调用对象、演进方式、调试便利性和生态要求,而不是简单争论“哪种更高级”。
DNS、CDN 与代理
DNS 负责把域名解析成 IP 地址,是用户请求链路里最早的关键环节之一。系统设计里讨论 DNS,不应只停留在“把域名变成 IP”。更重要的是理解它对可用性和流量调度的影响:本地缓存、递归解析、权威 DNS、TTL、就近解析、故障切换都会影响最终用户实际访问到哪里。
CDN 本质上是把静态资源、部分动态内容甚至边缘计算能力尽量前移,缩短用户与内容之间的物理和网络距离。它能降低源站带宽压力、减少跨地域时延、吸收突发流量,并承担缓存、TLS 终止、访问控制等职责。系统设计里如果面对图片、视频、下载包、热点页面或公共 API 分发,CDN 几乎都是必须考虑的层。
代理分为正向代理和反向代理。正向代理更偏向客户端侧的出口控制与访问转发;反向代理则位于服务端入口,承担负载均衡、缓存、TLS 终止、限流、鉴权、灰度发布等职责。面试里问代理,很多时候其实是在问网关和流量治理。你需要说明代理并不是“多了一跳而已”,而是通过这层插入统一控制面和可观测能力。
DNS、CDN 和代理组合起来,构成了用户访问大规模互联网服务的第一道基础设施。一次请求可能先经过本地 DNS 缓存,命中 CDN 边缘节点;未命中时再回源到反向代理;代理再把流量分配到后端服务集群。理解这条路径,有助于分析“为什么用户明明访问同一个域名,却落到不同机房”“为什么回源带宽飙升”“为什么某些地区访问特别慢”等问题。
常见网络问题排查
网络排查最怕一上来就猜。更可靠的方法是沿请求路径逐层缩小范围:名字是否能解析、路由是否可达、端口是否监听、连接是否建立、TLS 是否成功、应用是否返回、返回是否被代理或缓存改写。把问题拆开后,工具才有意义。
最常用的基础工具包括:
ping:快速验证 ICMP 可达性,但不能证明某个业务端口一定正常。traceroute:定位路径中的跳点和潜在路由异常。netstat或ss:查看监听端口、连接状态和收发队列。lsof -i:确认端口被哪个进程占用。tcpdump:抓包确认请求是否真的发出、是否有重传、RST、握手失败等问题。curl、wget、nc:从应用层或传输层主动构造请求,缩短定位路径。
几类高频现象特别值得掌握。第一,连接超时不一定是服务没启动,也可能是 DNS、路由、防火墙、安全组、监听地址或 SYN 队列问题。第二,请求慢不一定是网络慢,可能是 TCP 重传、TLS 握手过多、连接池复用差,或者代理层重试放大。第三,服务端连接数高不一定危险,但如果伴随大量 SYN_RECV、TIME_WAIT、CLOSE_WAIT,就要进一步区分是攻击、流量模型还是代码资源泄漏。
系统设计里,网络问题经常和容量、超时、重试、幂等耦合在一起。一次小规模丢包如果触发客户端无节制重试,就可能从局部波动演变成系统性故障。理解网络,不只是为了抓包,更是为了设计更稳健的重试策略、超时预算、连接池策略和服务降级机制。
本章小结
网络基础不是系统设计的附属知识,而是所有分布式系统的共同地基。只要系统跨机器运行,就一定会面对寻址、连接、超时、重传、缓存、代理和流量治理问题。
这一章最重要的结论是:
- 分层模型帮助你把复杂问题定位到正确层次,而不是笼统地说“网络有问题”。
- TCP 与 UDP 的选择,本质上是可靠性、时延、状态管理和复杂度的取舍。
- HTTP、HTTPS 与 RPC 的差异,直接影响 API 设计、连接复用和系统开销。
- DNS、CDN 与代理决定了请求如何被分发、缓存和治理。
- 排查网络问题时,要沿链路逐层验证,不要把所有异常都归因于应用代码。
本章面试题与追问
-
OSI 七层模型和 TCP/IP 分层模型在工程上最大的意义是什么? 追问:排查一次接口超时时,你会优先从哪几层入手?
-
TCP 和 UDP 的本质区别是什么? 追问:为什么实时音视频常用 UDP,而交易请求通常更适合 TCP?
-
为什么 TCP 建连通常是三次握手? 追问:如果只有两次,会在哪些场景下带来歧义或风险?
-
TIME_WAIT 和 CLOSE_WAIT 分别说明了什么? 追问:如果机器上 CLOSE_WAIT 特别多,你会优先排查哪里?
-
什么是 TCP 粘包? 追问:应用层一般通过哪些方式恢复消息边界?
-
HTTP keep-alive 和 TCP keepalive 有什么区别? 追问:为什么应用层往往还要额外设计心跳机制?
-
HTTPS 相比 HTTP 多了哪些核心能力和代价? 追问:TLS 终止放在 CDN、负载均衡还是应用侧,各自有什么权衡?
-
RPC 和 REST 的差异是什么? 追问:内部高频服务调用和对外开放 API,为什么常常会选不同风格?
-
DNS、CDN 和反向代理分别解决什么问题? 追问:如果某地区用户访问明显变慢,你会如何沿这三层排查?
-
遇到“能 ping 通但接口连不上”的问题,你会怎么定位? 追问:哪些工具能帮助你区分是端口监听、握手失败还是应用层超时?