网络运维面试题里,网络部分几乎是绕不开的第一关。不管你面的是应用运维、系统运维还是SRE方向,面试官只要聊到网络,三五个问题就能大致判断出你平时是只背过八股,还是真在半夜两点处理过“服务突然连不上”的故障。我这些年面过不少场,也以面试官身份参与过筛选,慢慢发现一个规律:网络题答得好的人,排障时往往又快又稳,因为他们脑子里有一条清晰的数据包路径;答得磕磕绊绊的人,遇到问题容易靠重启和猜。这篇内容我打算把网络篇拆成两个部分来讲,这是第一篇,重点放在分层模型、TCP协议行为、HTTP协议细节和DNS解析链路上。适合正在准备面试的朋友系统复习,也适合已经工作但想补齐网络底子的同行对照着查漏补缺。下面所有内容都围绕真实面试场景和线上排障经验展开,不堆概念,尽量把每道题背后的“为什么”讲透。
1. 网络题为什么总被放在面试第一轮
1.1 面试官问网络题时到底在考什么
很多人以为网络题考的是记忆力,比如TCP三次握手有哪几个标志位、HTTP 502和504有什么区别。这些当然要会,但面试官真正想看的不是这个。我做过面试记录,发现网络题的回答质量通常反映三件事:第一,你有没有分层排查的意识;第二,你知不知道协议设计背后的取舍;第三,你调过哪些参数、踩过哪些坑。举个例子,同样是问“TCP为什么需要三次握手”,背标准答案的人会说“为了防止已失效的连接请求突然又传到服务端”。这个答案没错,但它只是教科书上的防御性解释。真正有经验的人会补一句:三次握手更大的意义在于双方互相确认序列号初始值,保证后续数据传输的可靠性,而且第三次握手让服务端确认客户端确实收到了自己的SYN-ACK。这两种回答的差距不在对错,而在理解深度。
我印象很深的一次是帮一个朋友做模拟面试,他工作三年,平时主要做业务发布和监控配置。问到“TCP四次挥手为什么比握手多一次”时,他愣了几秒,然后说“因为要等对方把话说完”。这个回答虽然口语化,但方向是对的。沿着这个方向继续追问“TIME_WAIT为什么要等2MSL而不是马上释放”,他就接不上了。后来我给他补的时候发现,他之前一直把TIME_WAIT当成“要优化的坏东西”,以为调小就完事。这个误解很典型,也正好说明网络面试题的真正价值:它会逼你去理解协议行为和服务端资源之间的关系,而不是死记状态名。
从面试官视角看,网络题还有一个隐性作用,就是看你对“不确定问题”的处理方式。比如问“从浏览器输入URL到页面展示,中间发生了什么”,这道题几乎可以无限展开。有人从DNS讲到TCP握手、TLS握手、HTTP请求、负载均衡、反向代理、应用处理、浏览器渲染,一口气讲五分钟;也有人只讲三段就没了。面试官不一定要求你讲全,但会观察你讲的内容里有没有层次、有没有重点、有没有实际踩坑经验。所以准备网络面试,重点不是背更多题,而是把一条数据包路径真正走通。
1.2 高频考点分布与回答策略
我把近几年常见网络面试题按出现频率和准备优先级整理成了一张表,方便对照。频率的高低基于我个人参与面试和同行交流的观察,仅供参考,不同公司侧重点会有差异。
| 考点方向 | 出现频率 | 典型问法 | 回答时建议展开的角度 |
|---|---|---|---|
| 分层模型 | 高 | 一次HTTP请求经过哪些层 | 封装解封装、每层设备、排障时怎么用 |
| TCP三次握手 | 高 | 为什么不是两次或四次 | 序列号确认、半连接队列、SYN攻击 |
| TCP四次挥手 | 高 | TIME_WAIT的作用与调优 | 主动关闭方、2MSL、端口复用风险 |
| TCP与UDP对比 | 高 | 为什么DNS用UDP、HTTP/3用UDP | 连接开销、拥塞控制、可靠传输补偿 |
| HTTP状态码 | 高 | 502/504/499区别 | 网关层行为、后端超时、客户端取消 |
| HTTP版本演进 | 中 | HTTP/1.1和HTTP/2关键差异 | 队头阻塞、多路复用、服务端推送 |
| DNS解析链路 | 中 | 域名怎么变成IP | 递归查询、缓存层级、TTL |
| 常用排障命令 | 中 | 服务连不上怎么查 | ss/netstat、traceroute、curl时序 |
| 负载均衡与代理 | 中 | 四层和七层代理区别 | 转发依据、连接保持、真实IP传递 |
回答策略上,我的建议是“先给结论,再讲原因,最后补经验”。比如问TCP与UDP的区别,先说“核心区别是TCP面向连接、保证可靠有序,UDP无连接、不保证顺序和可达”,然后展开两者在开销和拥塞控制上的差异,最后补一句“实际选型要看业务对丢包的容忍度,像DNS这种一次请求一次应答的场景用UDP可以减少握手开销,而音视频通话宁可丢几帧也不愿等重传,所以也偏向UDP”。这样答既有结构,又不至于像背书。
还有一点要提醒:面试官如果追问“你实际调过什么参数”,不要硬编。可以诚实说“我主要用过和排查过哪些,更深的没动过”。网络参数调优的影响面很大,面试官更看重你知道边界在哪里,而不是盲目改内核参数。下面从分层模型开始,把每条链路拆开讲。
2. 分层模型与数据包流转:从应用层到网线
2.1 OSI七层与TCP/IP四层的实战对应关系
面试里问分层模型,如果只是复述“物理层、数据链路层、网络层、传输层、会话层、表示层、应用层”,基本只能拿到及格分。真正加分的回答是把它和实际协议、设备、排障命令对应起来。我的习惯是直接讲TCP/IP四层模型,因为线上环境几乎都按这个来理解:网络接口层、网络层、传输层、应用层。OSI的会话层和表示层在TCP/IP里通常被归到应用层,比如TLS握手可以勉强算会话层,但实际排查时我们更关心它发生在哪个端口、哪个进程。
拿一个nginx服务来举例。客户端发起HTTPS请求,数据从应用层开始,先被HTTP协议封装成请求报文,加上请求行、请求头、请求体;然后交给TLS层加密,再进入传输层,TCP头部会带上源端口、目的端口、序列号、确认号、窗口大小等字段;接着到网络层,IP头部加上源IP、目的IP、TTL、协议号;最后到网络接口层,加上以太网帧头和帧尾,通过网卡发出去。服务端收到后反着解封装,每一层剥掉自己的头部,交给上一层。这个过程听起来简单,但排障时分层意识非常值钱。
我遇到过一个典型的“应用层现象、网络层根因”的案例。某服务调用外部接口偶发超时,应用日志只写“connection timeout”,看起来像对方服务慢。后来用traceroute一看,中间某一跳延迟明显抖动,丢包率在高峰期能到8%左右。继续用mtr跑了十分钟,确认是某段链路拥塞导致的间歇性丢包,而不是对方应用处理慢。如果没有分层意识,很容易把问题甩给上游接口,来回扯皮很久。分层模型的实际价值就在这里:它给你一个逐层排除的路径,而不是一上来就翻应用代码。
还有一个小技巧,回答分层题时可以主动提“排障时从下往上还是从上往下,取决于现象”。如果是“完全连不上”,优先从网络层和传输层查,比如IP通不通、端口通不通;如果是“能连上但慢或报错”,优先看应用层和传输层状态,比如HTTP状态码、TCP重传、连接队列。这个顺序不是固定的,但能体现你的判断逻辑。面试官通常会对这种“有条件的结论”印象不错,因为它说明你不是在背模型,而是在用模型。
2.2 一次请求的封装与解封装过程详解
把封装过程讲细一点,面试里如果被要求“描述一个数据包从客户端到服务端的完整过程”,可以按这个顺序展开。假设客户端IP是10.0.1.10,服务端IP是10.0.2.20,服务端口是443,客户端随机端口是49152。应用层构造HTTP请求,假设请求体大小是200字节。TCP层加上20字节头部(不含选项),其中源端口49152、目的端口443、序列号假设为1001、确认号为1、窗口大小65535、标志位PSH和ACK置位。网络层加上20字节IP头部,源IP10.0.1.10、目的IP10.0.2.20、TTL通常64、协议号6表示TCP。数据链路层加上14字节以太网头部和4字节帧校验序列,帧头里源MAC是客户端网卡MAC,目的MAC是网关MAC(因为目的IP不在同一网段,需要先发给网关)。
这里有一个参数值得展开:MSS,也就是最大报文段长度。TCP建立连接时,双方会在SYN和SYN-ACK里协商MSS,常见值是1460字节,计算方式是MTU 1500减去IP头部20字节和TCP头部20字节。如果链路中间有PPPoE或VXLAN封装,MTU会变小,MSS也要相应调小,否则容易出现“小包正常、大包卡死”的现象。我碰到过一次容器环境里请求偶发卡住,最后查到是overlay网络MTU是1450,而应用侧没感知,超过1420左右的数据包被丢弃。后来在服务端把MSS clamp到1400,问题消失。这个案例说明,封装解封装不只是理论,MTU和MSS不匹配会直接体现在业务超时上。
解封装过程在服务端反过来走:网卡收到帧,检查目的MAC是不是自己或广播,是则去掉帧头帧尾,交给网络层;网络层检查目的IP是不是自己,是则去掉IP头部,根据协议号6交给TCP;TCP根据目的端口443找到监听进程,按序列号重组数据,去掉TCP头部,把HTTP报文交给应用层;应用层解析请求行和请求头,交给后端处理。如果中间经过负载均衡或反向代理,解封装可能只到某一层。四层负载均衡通常拆到TCP层,根据IP和端口转发,不改应用层内容;七层负载均衡会拆到HTTP层,能根据URL或Header做路由,但需要重新封装TCP连接。面试里如果问“四层和七层代理的区别”,从解封装深度切入会比背“四层快、七层灵活”更有说服力。
3. TCP三次握手与四次挥手:状态机背后的真实问题
3.1 三次握手每一步到底在解决什么
三次握手的过程大家都知道:客户端发SYN,服务端回SYN-ACK,客户端再回ACK。但面试里真正拉开差距的是“每一步解决什么问题”。第一步客户端发SYN,携带自己的初始序列号client_isn,同时告诉服务端“我想建立连接,我的起始序号是这个”。第二步服务端回SYN-ACK,携带自己的初始序列号server_isn,同时确认客户端的SYN,确认号是client_isn+1。第三步客户端回ACK,确认号是server_isn+1,同时自己的序列号变成client_isn+1。到这里双方都确认了两件事:对方的接收能力正常,对方的初始序列号自己已经知道。
为什么不能是两次?如果只有前两步,服务端发完SYN-ACK就认为连接建立了,但此时它并不知道客户端有没有收到自己的SYN-ACK。假如这个SYN-ACK在网络里丢了,客户端还在等,服务端却已经开始维护连接资源,这就是半连接。三次握手的第三次ACK让服务端确认“客户端确实收到了我的序列号,并且愿意继续”。从资源角度看,服务端在收到SYN后会把连接放进半连接队列(syn queue),收到ACK后才移到全连接队列(accept queue)。半连接队列的大小由内核参数控制,常见的是net.ipv4.tcp_max_syn_backlog,全连接队列则和应用程序的listen backlog有关。这两个队列是面试里很值得主动提的点,因为它们直接关联线上问题。
我见过一个比较典型的故障:某服务在流量高峰时大量连接超时,但CPU和带宽都不高。查ss -s发现syn recv状态的连接数很高,全连接队列溢出计数在增长。最后定位到两个原因叠加:一是tcp_max_syn_backlog偏小,二是应用侧accept速度跟不上,导致全连接队列满后新连接被丢弃或重置。调整时不能只调一个参数,还要看应用是不是用了多进程/多线程accept,以及是否开了syncookies。syncookies在SYN队列满时可以临时缓解,但它会限制一些TCP选项的使用,属于应急手段而非常态方案。面试里如果能把三次握手和队列、syncookies串起来讲,基本能说明你确实处理过连接层问题。
还有一个常被追问的点是SYN flood攻击。攻击者大量发SYN但不回第三次ACK,把半连接队列占满,正常用户连不进来。防御手段包括调大队列、开启syncookies、限制单位时间内的SYN速率、用四层清洗设备等。回答时注意不要展开成安全专题,点到为止即可,重点是说明“三次握手的资源分配时机”和“半连接队列是攻击面”之间的关系。
3.2 四次挥手与TIME_WAIT的两难取舍
四次挥手比三次握手多一次,原因在于TCP是全双工的,两个方向需要分别关闭。假设客户端主动关闭:第一次客户端发FIN,表示“我没有数据要发了”,但还可以接收;第二次服务端回ACK,表示“知道了”,此时客户端进入FIN_WAIT_2,服务端进入CLOSE_WAIT;第三次服务端处理完剩余数据后发FIN,表示“我也没有数据要发了”;第四次客户端回ACK,然后进入TIME_WAIT,等待2MSL后彻底关闭。服务端收到ACK后直接进入CLOSED。
TIME_WAIT是面试里被问得最多、也最容易答偏的点。它的作用有两个:第一,确保最后一个ACK能到达对方。如果这个ACK丢了,对方会重发FIN,处于TIME_WAIT的一方还能再回一次ACK。第二,让本次连接产生的旧数据包在网络中消散,避免它们被后续使用相同四元组的新连接误收。等待时间2MSL,MSL是报文最大生存时间,Linux上通常按60秒处理,所以TIME_WAIT默认持续60秒。这个值可以通过net.ipv4.tcp_fin_timeout调整,但它影响的是FIN_WAIT_2的超时,不是TIME_WAIT本身。真正控制TIME_WAIT时长的是内核编译时的TCP_TIMEWAIT_LEN,用户态一般改不了。很多人把tcp_fin_timeout当成TIME_WAIT调优参数,这是个常见误解。
线上遇到大量TIME_WAIT,先别急着调参数。TIME_WAIT多通常说明这台机器是主动关闭方,而且短连接很多。比如反向代理到后端、爬虫客户端、频繁调外部API的服务,都容易积累TIME_WAIT。如果数量在几万以内,且端口没有耗尽,一般不需要处理。真正需要关注的是TIME_WAIT把本地端口占满,导致无法发起新连接。这时候可以考虑开启net.ipv4.tcp_tw_reuse,允许将TIME_WAIT状态的套接字用于新的出站连接。注意它只对出站连接有效,而且需要时间戳选项配合。tcp_tw_recycle在新版内核里已经移除,不要再提。更根本的方案是改用长连接、连接池,或者让服务端主动关闭连接,把TIME_WAIT压力转移到服务端。但服务端如果也扛不住,就要综合评估。
我曾经处理过一个案例:某服务调用第三方接口,QPS不高,但每隔一段时间就报“Cannot assign requested address”。查ss -tan state time-wait发现本地TIME_WAIT接近三万,端口范围是32768到60999,大约两万八千个端口,已经接近耗尽。根因是每次请求都新建连接且不复用,响应又慢,TIME_WAIT堆积。短期开了tcp_tw_reuse缓解,长期改成HTTP长连接加连接池,问题彻底消失。这个案例说明,TIME_WAIT本身不是故障,端口耗尽才是。面试里如果被问“TIME_WAIT怎么优化”,先反问或判断“是数量多还是端口耗尽”,会比直接背参数更专业。
3.3 状态排查命令与关键字段解读
面试里经常问“怎么查看TCP连接状态”,很多人只说netstat -an。现在更推荐ss,因为它直接从内核空间读,速度快,字段也更清晰。常用命令有这几个:
# 查看所有TCP连接及状态 ss -tan # 按状态统计数量 ss -tan state established | wc -l ss -tan state time-wait | wc -l # 查看监听端口及对应的全连接队列情况 ss -lnt # 查看更详细的TCP内部信息,包括重传、队列溢出 ss -sss -lnt的输出里,Send-Q和Recv-Q在监听套接字上有特殊含义:Send-Q表示全连接队列的最大长度,Recv-Q表示当前已完成三次握手但还没被应用accept的连接数。如果Recv-Q持续接近Send-Q,说明应用accept不过来,全连接队列快满了。这个细节在排查“连接超时但服务端CPU不高”时非常有用。与之对应,半连接队列的情况可以通过ss -s里的synrecv计数或者netstat -s里的“SYNs to LISTEN sockets dropped”来看。
还有一个命令组合是查看重传和异常:
# 查看TCP重传统计 netstat -s | grep -i retrans # 查看各状态连接数汇总 ss -s # 查看某个端口的连接分布 ss -tan '( sport = :8080 or dport = :8080 )'重传率高通常意味着链路质量差或对端处理慢,但也要排除网卡丢包和缓冲区不足。我一般会结合ip -s link看网卡错误计数,用ethtool -S看驱动层统计,再决定是查网络还是查应用。面试里如果被问“服务响应慢怎么排查”,能从ss状态、重传、队列溢出讲到应用accept,会比单纯说“看日志”更有层次。
4. TCP与UDP的选型:对比题怎么答出深度
4.1 面向连接与无连接的本质代价
TCP和UDP的对比是网络面试的保留题。标准答案通常是:TCP面向连接、可靠、有序、有流量控制和拥塞控制;UDP无连接、不可靠、不保证顺序、开销小。这些都对,但只答到这里很难出彩。我习惯从“代价”角度讲:TCP的可靠性不是免费的,它用序列号、确认、重传、窗口、拥塞控制换来有序可靠,代价是头部更大、建立连接有延迟、拥塞时主动降速。UDP把这些问题交给应用层,头部只有8字节,发出去就不管了,延迟低但可能丢、可能乱序、可能重复。
从头部开销看,TCP头部基础20字节,带选项可到60字节;UDP固定8字节。别小看这十几字节差异,在大量小包场景下会放大。比如DNS查询,一个请求可能就几十字节,如果用TCP,三次握手加四次挥手的开销远超查询本身,所以DNS默认用UDP,只有响应超过512字节或做区域传送时才改用TCP。这个设计不是随便定的,而是权衡了“查询小、要求快、可重试”这三个特点。
从拥塞控制看,TCP遇到丢包会降速重传,这在文件传输和网页加载里是合理的,因为丢一个包重传的代价小于整体拥塞崩溃。但实时音视频不一样,丢一帧可以靠编码补偿,等重传反而造成卡顿。所以实时通信多用UDP,再在应用层做前向纠错、抖动缓冲、按需重传。面试里如果能结合具体业务讲“为什么这里选UDP”,比单纯背特性表更有说服力。
4.2 典型协议的选型逻辑与参数调优
拿几个常见协议举例。DNS用UDP 53端口做常规查询,响应超过512字节或DNSSEC场景会用到TCP 53,区域传送也用TCP。DHCP用UDP 67/68,因为客户端还没有IP地址,无法建立TCP连接,只能广播。NTP用UDP 123,时间同步对延迟敏感,丢一个包可以等下一个周期。HTTP/3基于QUIC,底层用UDP,把可靠传输、拥塞控制、加密都放到用户态实现,目的是减少连接建立延迟并解决TCP层的队头阻塞。这些例子说明,协议选型不是“TCP更可靠所以都用TCP”,而是看业务对延迟、丢包、连接开销的容忍度。
参数调优方面,TCP侧常关注的有somaxconn(全连接队列上限)、tcp_max_syn_backlog(半连接队列上限)、tcp_tw_reuse、tcp_keepalive_time等。UDP侧常关注接收缓冲区,因为UDP没有重传,缓冲区满了直接丢包,应用层可能感知不到。可以调net.core.rmem_max和net.core.rmem_default,但要注意内存占用。还有net.ipv4.udp_mem,控制UDP内存页的上限。我遇到过一次日志采集Agent用UDP发数据,高峰期丢包严重,查下来是接收端socket缓冲区太小,调大后明显改善。但调大缓冲区只是缓兵之计,根本方案还是加确认机制或改用TCP。
面试里如果被问“UDP怎么实现可靠传输”,可以提几个关键机制:应用层序列号、确认与重传、滑动窗口、拥塞控制。QUIC就是典型代表,它在UDP上实现了类似TCP的可靠性和TLS加密,还支持多路复用和连接迁移。回答时不用展开QUIC全部细节,点出“把可靠性从内核搬到用户态,换取更灵活的拥塞控制和更低的连接建立延迟”即可。
5. HTTP协议与状态码:从背题到定位故障
5.1 请求响应报文里藏着哪些排障线索
HTTP面试题通常从“输入URL到页面展示”开始,然后追问HTTP版本差异、状态码、Header字段。我的建议是不要只背字段含义,要结合排障场景讲。比如Content-Length和Transfer-Encoding这两个头,看起来是协议细节,实际经常导致线上问题。Content-Length表示报文体的字节数,如果它和实际发送的字节数不一致,接收方可能一直等剩余数据,表现为请求挂起。Transfer-Encoding: chunked表示分块传输,每块前面带长度,最后以0结束。如果代理层对chunked处理不一致,可能出现截断或额外等待。
Host头也很关键。HTTP/1.1要求请求必须带Host,因为同一个IP可能承载多个域名,虚拟主机靠Host区分。如果Host缺失或错误,服务端可能返回400或路由到错误的后端。Connection头控制连接是否保持,HTTP/1.1默认keep-alive,HTTP/1.0默认close。代理层如果错误地改写了Connection头,可能导致长连接失效,表现为频繁建连、延迟升高。
HTTP/1.1和HTTP/2的核心差异也常被问到。HTTP/1.1的keep-alive虽然复用了TCP连接,但同一个连接上的请求是串行的,前一个响应没回来,后一个只能等,这就是应用层队头阻塞。HTTP/2引入二进制分帧和多路复用,同一个连接上可以并行交错多个请求和响应,还支持头部压缩和服务器推送。但HTTP/2底层还是TCP,TCP层的丢包重传仍会阻塞所有流,所以HTTP/3换到QUIC(基于UDP)来解决传输层队头阻塞。回答这条演进线时,抓住“队头阻塞从应用层转移到传输层,再被QUIC解决”这个主线,会比零散罗列特性清晰得多。
5.2 状态码背后的服务端行为与典型案例
状态码题里,502、504、499是运维面试的高频三兄弟。502 Bad Gateway表示网关或代理从上游收到了无效响应,常见原因包括上游进程挂了、上游返回了不符合HTTP协议的内容、上游连接被重置。504 Gateway Timeout表示网关等待上游响应超时,通常是上游处理太慢或网络不通。499是nginx自定义的状态码,表示客户端在服务端返回响应之前主动关闭了连接,常见于客户端超时时间设置得比服务端处理时间短。
我处理过一个502的案例。某服务通过nginx反向代理到后端,白天偶尔出现少量502,夜间几乎没有。查nginx error log发现“upstream prematurely closed connection while reading response header from upstream”。继续查后端日志,发现后端在某些请求下会主动关闭连接,原因是线程池满了之后触发了拒绝策略。表面看是502,根因是后端线程池配置不合理。这类问题如果只看状态码,很容易误判为网络抖动。我的排查习惯是:502先看上游进程和端口是否存活,再看上游返回内容是否合法,最后看连接是否被中间层重置;504先看上游处理耗时和超时配置;499先看客户端超时设置和服务端响应时间分布。
还有一个容易被忽略的点是状态码和日志级别的对应。有些框架把4xx记为WARN,5xx记为ERROR,但如果客户端大量499,日志里可能只有访问日志没有错误日志,容易漏掉。面试里如果被问“怎么定位502”,能说出“先区分是网关自身问题还是上游问题,再看error log里的上游地址和错误原因”,基本就够了。
6. DNS解析链路与网络排查命令实战
6.1 一个域名从输入到IP的完整链路
DNS解析是网络面试里容易被低估的考点。很多人只知道“域名解析成IP”,但面试官如果追问“解析过程经过哪些环节”,答不全就会显得基础不牢。完整链路大致是这样:浏览器先查自身缓存,然后查操作系统hosts文件和DNS缓存,再向本地DNS服务器(通常是运营商DNS或内网DNS)发起递归查询。本地DNS如果没有缓存,会从根域名服务器开始迭代查询:根服务器返回顶级域服务器地址,顶级域服务器返回权威DNS服务器地址,权威DNS返回最终IP。本地DNS拿到结果后缓存一段时间,TTL由权威DNS设置,然后返回给客户端。
这里有几个细节值得展开。递归查询和迭代查询的区别:客户端到本地DNS通常是递归查询,意思是“你帮我查到底”;本地DNS到根、顶级域、权威DNS是迭代查询,每一层只告诉你下一层去哪问。TTL决定缓存多久,TTL太短会增加权威DNS压力,太长会导致变更生效慢。线上做域名切换时,通常提前把TTL调小,切换完成后再调回来。这个操作看起来简单,但如果没有提前做,紧急切换时可能要等很久。
DNS还分授权和非授权应答。如果本地DNS直接返回缓存结果,标志位里授权应答为0;如果它是从权威服务器查到的,授权应答为1。用dig命令可以看到这个标志。面试里如果被问“怎么判断DNS解析是否生效”,可以说用dig看ANSWER SECTION和AUTHORITY SECTION,再结合不同地域的递归DNS分别验证,避免只查本地缓存造成误判。
6.2 高频命令与真实排查记录
网络排障命令不在多,而在组合使用。我常用的几个:
# 查看域名解析结果和耗时 dig example.com +stats # 指定DNS服务器查询,排除本地缓存干扰 dig @8.8.8.8 example.com # 跟踪到目标地址的路由,看哪一跳异常 traceroute -n example.com # 持续探测路径质量,观察丢包和延迟抖动 mtr -n --report example.com # 查看HTTP请求各阶段耗时 curl -o /dev/null -s -w "dns:%{time_namelookup} connect:%{time_connect} tls:%{time_appconnect} first_byte:%{time_starttransfer} total:%{time_total}\n" https://example.com # 查看端口连通性 nc -zv example.com 443curl的耗时拆解特别实用。time_namelookup是DNS解析耗时,time_connect是TCP握手耗时,time_appconnect是TLS握手完成耗时,time_starttransfer是首字节时间,time_total是总耗时。如果DNS耗时高,查DNS;如果connect高,查网络链路或服务端握手队列;如果starttransfer高但connect正常,查服务端处理;如果total高但starttransfer正常,查响应体传输。这个拆解能把“慢”定位到具体阶段,比笼统说“网络慢”有用得多。
我处理过一个“接口偶发超时”的案例,现象是每小时出现几次,每次持续几秒。用curl拆解发现,正常请求total在200ms左右,异常请求time_namelookup偶尔跳到3秒以上。继续用dig对比多个DNS服务器,发现内网DNS在高峰期响应慢,原因是上游转发超时。后来把内网DNS改成多级缓存加并发查询,问题缓解。这个案例说明,DNS问题不一定表现为“解析失败”,也可能表现为“解析慢”,而慢解析会拖慢整个请求链路。
7. 开放场景题:给你一个故障现象怎么往下查
7.1 从现象到根因的排查框架
网络面试最后往往会给一个开放场景,比如“用户反馈网站访问慢,你怎么排查”。这类题没有标准答案,面试官看的是你的排查路径是否清晰、是否知道每一步验证什么。我通常用“先定界、再分层、后验证”的框架。先定界:是全部用户慢还是部分用户慢,是全部页面慢还是某个接口慢,是持续慢还是偶发慢。这个信息决定后续方向。如果只有部分地域慢,优先查链路和DNS;如果只有某个接口慢,优先查该接口依赖的服务;如果是偶发慢,优先看监控和日志的时间分布。
再分层:从客户端到服务端,依次看DNS解析、TCP连接、TLS握手、HTTP请求、服务端处理、数据库或下游依赖、响应传输。每一层都有对应的验证手段。DNS用dig或curl耗时拆解;TCP连接用nc或ss看握手和队列;TLS握手用openssl s_client看证书和协议版本;HTTP层看状态码和响应头;服务端看应用日志和线程池;下游看依赖调用耗时;传输看响应体大小和压缩。后验证:改一个变量,观察现象是否变化。比如换一个DNS服务器、换一个客户端网络、绕开代理直连后端,通过对比缩小范围。
这个框架听起来普通,但在面试里能讲出“每一步验证什么、如果异常说明什么”,就已经超过大多数候选人了。我面过一些人,问“网站慢怎么查”,对方从“看CPU”开始讲,讲了一堆监控指标,但没有回到网络链路。不是说CPU不重要,而是没有定界就容易在错误的方向上浪费精力。
7.2 两个典型场景的推演过程
第一个场景:某服务调用方反馈“偶尔连接超时”,服务端监控显示CPU和内存正常。推演过程:先看超时发生的频率和时间点,发现集中在每天上午十点左右,持续几分钟。用ss -s看服务端连接状态,发现那个时间段syn recv数量升高,全连接队列溢出计数增长。查应用日志,发现十点左右有批量任务启动,大量请求涌入。根因是瞬时并发超过全连接队列容量,应用accept速度跟不上。处理方式是调大somaxconn和tcp_max_syn_backlog,同时给批量任务加限流,错峰执行。这个场景的关键是把“超时”从网络层拉到传输层队列,再关联到应用行为。
第二个场景:某内网服务A调用服务B,A侧日志显示“connection reset by peer”,B侧日志没有请求记录。推演过程:先用tcpdump在A侧抓包,看reset是B发的还是中间设备发的。如果reset包的TTL和B的正常响应TTL一致,大概率是B发的;如果不一致,可能是中间防火墙或负载均衡。继续查B的监听队列和连接数,发现B的进程在重启,重启期间旧连接被重置。再查重启原因,是健康检查失败触发了自动重启,而健康检查失败是因为B依赖的数据库连接池耗尽。最终根因在数据库连接池,但现象表现为网络层的reset。这个场景说明,网络层错误不一定根因在网络层,抓包和日志对照很重要。
面试里遇到这类开放题,不用急着给答案,可以先确认几个关键信息,比如“超时是连接超时还是读超时”“是所有请求还是部分请求”“最近有没有变更”。提问本身也是加分项,说明你有排查习惯而不是上来就猜。我个人在实际操作中的体会是,网络问题最怕“想当然”,看到超时就调超时时间,看到502就重启上游,往往掩盖了真正的问题。把链路走一遍,把每一层的证据留下来,比任何单一命令都可靠。
这个系列的网络篇先到这里,后面还会整理传输层参数调优、代理与负载均衡、容器网络这些更偏实战的内容。如果你正在准备面试,建议把上面的命令在自己的测试环境里跑一遍,尤其是ss -lnt看队列、curl拆耗时、dig对比解析这几组,跑过和只看过是完全不同的手感。