尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

网络与操作系统篇 · Java 架构师面试备考文档

网络与操作系统篇 · Java 架构师面试备考文档 对应 2 周计划:D5 | 优先级: 高频 | 大厂一面必考,TCP/HTTP 是经典送命题〇、设计哲学:网络与 OS 为什么这么设计?(先读这节)一句话主线:底层设计都在和「不可靠」作斗争——网络会丢包、会乱序、会拥塞;CPU 和 IO 速度差万倍。所以 TCP 用确认重传换可靠、HTTP 不断演进换并发、epoll 用事件驱动换海量连接、虚拟内存用隔离换安全。图 0 · 四大设计动机四大设计动机 → 对应机制① 为什么 TCP 可靠IP 网络会丢包乱序还被用作不可靠→ 序号ACK重传→ 握手确认双向通用开销换正确② 为什么 HTTP 演进1.0 短连接太慢队头阻塞卡住→ keep-alive/多路复用→ QUIC 绕开 TCP为并发不断优化③ 为什么 epollselect 每轮遍历全部O(n) 扛不住万连接→ 红黑树就绪链表→ 只返回就绪的事件驱动 O(1)各机制的设计思路(为什么):为什么 TCP 要三次握手:网络不可靠,客户端发的连接请求可能迷路后又突然到达。两次握手只能让服务端确认客户端能发,却无法确认客户端能收——服务端白白分配资源等一个根本没收到的连接。三次才双向确认收发能力,同时用 seq/ack 同步初始序号。为什么 HTTP/2 用多路复用:HTTP/1.1 一个 TCP 连接同一时刻只能处理一个请求(队头阻塞),并发靠开多个连接(浪费)。多路复用把请求拆成帧、在同一条连接上交错传输,彻底解决应用层队头阻塞。为什么 HTTP/3 换 UDP(QUIC):HTTP/2 仍跑在 TCP 上,TCP 一个包丢了整个连接的所有流都要等重传(传输层队头阻塞)。QUIC 在 UDP 上自己实现可靠拥塞控制,丢包只影响单个流,还能 0-RTT 建连、IP 变化不断连。为什么 epoll 比 select 快:select 每次调用都要把全部 fd 从用户态拷到内核态、再全量遍历(O(n));epoll 用红黑树管理 fd、就绪事件进链表,只把就绪的返回给应用(O(1)),万级连接也不退化。一、TCP 协议Q1: TCP 三次握手?图 1 · 三次握手时序(双向确认收发能力)客户端服务端① SYN, seqx② SYNACK, seqy, ackx1③ ACK, acky1连接建立 ✓② 是 SYNACK 合并发送,所以总共 3 次而非 4 次答案要点:1. 客户端 → 服务端:SYN1, seqx(请求建立连接)2. 服务端 → 客户端:SYN1, ACK1, seqy, ackx1(同意并确认)3. 客户端 → 服务端:ACK1, seqx1, acky1(确认收到,连接建立)深追问(必问):为什么是三次不是两次?→ 防止失效的连接请求突然到达服务端造成资源浪费;两次握手无法确认客户端收到了服务端的 SYN(同步序列编号)。三次才能同时确认双方收发能力为什么不是四次?→ 三次已足够确认双向能力,四次多余SYN 洪水攻击?→ 服务端收到 SYN 后进入 SYN_RECV 半连接状态,攻击者伪造大量 SYN 不回复 ACK,耗尽半连接队列;防护:SYN Cookie、缩短超时、增大队列Q2: TCP 四次挥手?答案要点:1. 主动方 → 被动方:FIN1(不再发数据)2. 被动方 → 主动方:ACK(确认收到 FIN)3. 被动方 → 主动方:FIN1(被动方数据也发完了)4. 主动方 → 被动方:ACK,进入 TIME_WAIT(等待 2MSL)深追问(必问):为什么挥手要四次?→ 被动方收到 FIN 时可能还有数据要发,ACK 和 FIN 不能合并为什么 TIME_WAIT 要等 2MSL?(必背)MSL:报文最大生存时间(默认 2 分钟,Linux 常为 30s-60s)保证最后 ACK 能到达(丢失则被动方重发 FIN)让旧连接报文在网络中消失,防止影响新连接大量 TIME_WAIT 怎么处理?→ 服务端调小 TIME_WAIT 超时、开启 reuse/quickack 参数、避免短连接频繁创建(连接池)Q3: TCP 与 UDP 区别?| 维度 | TCP | UDP ||---|---|---|| 连接 | 面向连接(三次握手) | 无连接 || 可靠性 | 可靠,确认重传 | 不可靠,尽最大努力 || 有序性 | 有序 | 无序 || 传输方式 | 字节流(粘包问题) | 报文(边界清晰) || 速度 | 慢 | 快 || 应用 | HTTP/FTP/SMTP | DNS/视频/语音/游戏 |深追问:粘包/拆包是什么?怎么解决?TCP 字节流无边界,多个包粘在一起(粘包)或被拆开(拆包)解决:固定长度、分隔符(如 \n)、消息头声明长度(最常用,如 Netty LengthFieldBasedFrameDecoder)为什么 UDP 视频不卡?→ 丢包不重传,实时性优先Q4: TCP 可靠传输机制?答案要点:确认应答 ACK 超时重传滑动窗口(流量控制):接收方窗口大小控制发送速率拥塞控制:慢开始(指数增长)、拥塞避免(线性)、快重传、快恢复序号机制保证有序深追问:流量控制 vs 拥塞控制?→ 前者是端到端(接收方能力),后者是网络中间(网络负载)重传机制:超时重传、快速重传(收到 3 个重复 ACK)、SACK(选择性确认)二、HTTP 协议Q5: HTTP 1.0/1.1/2/3 区别?图 2 · HTTP 演进:每一代解决什么问题1.0短连接每次建连1.1keep-alive 复用2多路复用(解应用层阻塞)3QUIC/UDP(解传输层阻塞)演进主线:减少连接开销 → 解决并发阻塞 → 绕开 TCP 本身的限制| 版本 | 关键特性 ||---|---|| HTTP/1.0 | 短连接,每次请求建立/断开 TCP || HTTP/1.1 | 持久连接(keep-alive 默认开启)、管线化(有限)、Host 头、分块传输 || HTTP/2 | 多路复用(单连接并发请求)、二进制分帧、头部压缩 HPACK、服务端推送 || HTTP/3 | 基于 QUIC(UDP),0-RTT,解决队头阻塞 |深追问(必问):HTTP/1.1 队头阻塞?→ 一个请求响应慢,后续请求排队等待HTTP/2 解决了应用层队头阻塞,但TCP 层队头阻塞仍在(丢包导致整个流暂停)HTTP/3 为什么用 UDP?→ QUIC 在应用层实现可靠传输,避免 TCP 队头阻塞,连接迁移(IP 变化不断连)Q6: HTTPS 握手过程?答案要点:1. 客户端发送 ClientHello(支持的加密套件、随机数)2. 服务端返回 ServerHello(选定算法、随机数) 证书(Cerificate) ServerHelloDone3. 客户端验证证书(信任链、域名、有效期)→ 生成 pre-master secret,用证书公钥加密发送4. 双方用三个随机数生成会话密钥5. 客户端发送 Finished,服务端验证后也发 Finished6. 之后用对称密钥加密通信深追问(必问):为什么混合加密?→ 非对称(RSA/ECDHE)安全但慢,对称(AES)快;用非对称协商密钥,用对称传输数据证书作用?→ 防中间人攻击,证明服务端身份;CA 信任链:根证书→中间证书→站点证书如何验证证书?→ 检查有效期、域名匹配、CA 签名(用 CA 公钥验签)、吊销状态(CRL/OCSP)Q7: GET 与 POST 区别?GET:幂等、可缓存、参数在 URL(长度限制)、用于查询POST:非幂等、不可缓存、参数在 body、用于提交安全:GET 参数暴露在日志/历史记录,敏感信息用 POST深追问:幂等是什么?→ 同一请求执行多次结果相同;GET/PUT/DELETE 幂等,POST 非幂等状态码速记:200 OK、201 Created、301 永久重定向、302 临时重定向、304 Not Modified(缓存)、400 参数错误、401 未认证、403 无权限、404 不存在、500 服务器错误、502 网关错误、503 服务不可用、504 网关超时Q8: 浏览器输入 URL 到页面展示全过程?答案要点(必背八股):1.DNS 解析:浏览器缓存 → 系统 hosts → 本地 DNS → 根/顶级/权威 DNS 迭代查询2.TCP 连接:三次握手(HTTPS 加 TLS 握手)3.发送 HTTP 请求:请求行/头/体4.服务器处理:经负载均衡 → 应用 → 返回响应5.浏览器渲染:解析 HTML 构建 DOM、解析 CSS 构建 CSSOM、合成渲染树、布局、绘制6.资源加载:CSS 阻塞渲染、JS 阻塞解析(可 defer/async)、图片懒加载深追问:DNS 用 TCP 还是 UDP?→ 查询用 UDP(53),区域传输用 TCPCDN 原理?→ 内容分发,就近节点缓存,回源;调度用 DNS 或 Anycast三、操作系统Q9: 进程、线程、协程区别?| 维度 | 进程 | 线程 | 协程 ||---|---|---|---|| 资源 | 独立内存空间 | 共享进程内存 | 共享线程栈 || 调度 | 操作系统 | 操作系统 | 用户态自行调度 || 切换成本 | 高 | 中 | 极低 || 通信 | IPC(管道/共享内存/消息队列) | 共享内存锁 | 语言层面 |深追问:为什么协程切换快?→ 用户态切换,不涉及内核态/系统调用;Java 21 虚拟线程就是 JVM 实现的协程进程间通信方式?→ 管道、消息队列、共享内存、信号量、信号、Socket进程 vs 线程崩溃影响?→ 进程隔离,一个进程崩不影响其他;线程共享,一个线程崩溃(如 OOM)可能拖垮整个进程Q10: 虚拟内存与分页?答案要点:虚拟内存:每个进程有独立虚拟地址空间,通过页表映射物理内存好处:隔离、按需分配、可超物理内存(磁盘交换)页面置换算法:FIFO、LRU、LFU、Clock(改进版 LRU)深追问:缺页中断?→ 访问的页不在内存,触发缺页,从磁盘加载(慢)内存映射 mmap 是什么?→ 文件/匿名内存映射到进程地址空间,零拷贝基础之一Q11: IO 模型与 NIO?答案要点(5 种):1. 阻塞 IO(BIO):同步阻塞,线程等待2. 非阻塞 IO(NIO):同步非阻塞,轮询3. IO 多路复用:select/poll/epoll,一个线程监控多个连接4. 信号驱动 IO5. 异步 IO(AIO):完成通知图 3 · select 全量遍历 vs epoll 只给就绪select / poll每次遍历全部 fdO(n),1 个就绪也要扫完epoll红黑树管理全部fd就绪链表只返回这些事件驱动 O(1)深追问(必问):select/poll/epoll 区别?(大厂高频)select:文件描述符数组有上限(1024),每次都要遍历全部、内核拷贝 fd 集合poll:链表无上限,但仍全量遍历、效率 O(n)epoll:红黑树 就绪链表,事件驱动回调,只返回就绪的 fd,O(1),Linux 独有epoll 的 LT 和 ET?→ 水平触发(默认,有数据就通知)/ 边缘触发(状态变化才通知,需一次读完)Netty 为什么快?→ NIO 多路复用 零拷贝 内存池 无锁串行设计(单线程处理一个 Channel 的事件)Q12: 死锁?答案要点(4 条件):1. 互斥:资源排他2. 持有并等待:持有一个等另一个3. 不可剥夺:资源不能强抢4. 循环等待:形成环深追问:如何避免?→ 破坏任一条件:一次性申请所有资源、按序加锁(全局有序)、超时释放、银行家算法死锁排查?→ jstack 查看 BLOCKED 线程 锁信息;数据库死锁看 innodb 错误日志、show engine innodb status四、Linux 常用命令(架构师必会)top # CPU/内存/负载,按 1 看每核 free -h # 内存使用 df -h / du -sh * # 磁盘容量 ps -ef | grep java # 进程 netstat -tlnp # 端口监听(ss -tlnp 更高效) lsof -i:8080 # 端口占用 tail -f app.log # 实时日志 grep ERROR app.log | head -50 find / -name *.log # 文件查找 awk {print $1} access.log | sort | uniq -c | sort -rn # 日志分析 vmstat 1 # 系统整体状态 iostat -x 1 # 磁盘 IO sar -n DEV 1 # 网络流量 curl -v http://localhost:8080/api # 接口调试五、漫画 · 三次握手打电话(理解为什么三次)三次握手 打个电话确认能说能听① 小明拨打明喂?听得到吗?(SYN)② 小红回应红听得到!你呢?(SYNACK)③ 小明确认明听得到!(ACK)④ 连接建立双方确认:明能说能听 ✓红能说能听 ✓双向能力都验证⑤ 为什么不能两次两次:小红不知道小明听不听得到→ 白等一个根本没收到的连接⑥ 额外好处同步初始序号seq/ack 对得上防失效连接省服务端资源六、考前速记(10 条)1. 三次握手防失效连接;四次挥手因为被动方可能还有数据2. TIME_WAIT 2MSL:保证 ACK 到达 旧报文消失3. 粘包解决:长度头 / 分隔符 / 固定长度4. HTTP/2 多路复用解决应用层队头阻塞;HTTP/3 基于 QUIC(UDP) 解决传输层5. HTTPS:非对称协商密钥 对称传输数据;证书防中间人6. GET 幂等可缓存,POST 非幂等7. 进程/线程/协程:切换成本递增,协程用户态调度8. select 1024 上限全遍历;epoll 红黑树就绪链表 O(1),LT/ET9. Netty:多路复用 零拷贝 内存池 无锁串行10. 死锁四条件:互斥/持有等待/不可剥夺/循环等待;jstack 排查七、易错点提醒「三次握手」第 2 次是 SYNACK 合并(所以是 3 次不是 4 次)HTTP/2 队头阻塞在 TCP 层仍在,HTTP/3 才彻底解决TIME_WAIT 是主动关闭方进入的,不是被动方select 上限 1024 是 fd 数量,不是连接数DNS 默认 UDP 但区域传输(主从 - 同步)是 TCP八、深挖 · 面试官连环追问 源码级原理源码级 · TCP 与 IO:TCP 三次握手在内核实现(tcp_v4_conn_request),半连接队列syn_table存待确认连接;SYN Flood 靠tcp_syncookies用算法生成 seq 代替队列。epoll 内核用红黑树存监听 fd、rdllist存就绪 fd;LT(水平触发)是默认,ET(边缘触发)必须一次性读净(while read读到 EAGAIN),否则事件丢失。零拷贝:sendfile/splice在内核态直接挪数据,避免用户态拷贝;Netty 用FileRegion走零拷贝。连环追问:TIME_WAIT 出现在主动关闭方,为什么不能跳过?→ 否则旧连接残留报文可能被新连接误收;高并发短连接建议tcp_tw_reuse 连接池。为什么 UDP 没有粘包?→ UDP 是报文边界清晰,粘包是 TCP 字节流特性。惊群问题?→ epoll 的 ET 模式 EPOLLEXCLUSIVE可避免唤醒多个等待线程。常见陷阱:select的 1024 是 fd 数量上限(Linux 默认),不是连接数;海量连接必须 epoll。九、大厂真题话术(照着背)真题 1(腾讯/字节):TCP 为什么三次握手,不是两次?第一句:两次不行——Server 无法确认 Client 收得到自己的包,会建出半开连接,被洪水攻击拖垮。展开:三次本质是双方各自确认对方的收发能力;SYN 带序列号,ACK 确认,第三次 Client 回 ACK 才双向就绪。带节奏:挥手要四次是因为 TCP 全双工,关闭得两边各自 FIN,被动方可能还有数据要发。真题 2(阿里):epoll 和 select 区别?ET 和 LT 怎么选?第一句:select 每次遍历全部 fd,1024 上限,海量连接 O(N) 慢;epoll 用红黑树 就绪链表,只返回就绪的,复杂度 O(1)。展开:LT 水平触发(没处理完下次还通知,安全但低效);ET 边缘触发(只通知一次,必须循环读到 EAGAIN,效率高但容易漏)。带节奏:我们网络框架用 ET 非阻塞循环读,配合 EPOLLEXCLUSIVE 避免惊群。真题 3(美团):TIME_WAIT 是什么?太多怎么办?第一句:主动关闭方最后等 2MSL,确保最后 ACK 到达、旧报文消失,防端口复用串数据。展开:高并发短连接会堆大量 TIME_WAIT;可启用tcp_tw_reuse(客户端)或调小tcp_max_tw_buckets,但别瞎开tcp_tw_recycle(已废弃,NAT 下会丢包)。带节奏:根治是改用长连接/连接池,而不是硬清 TIME_WAIT。真题 4(字节):零拷贝是什么?你哪里用过?第一句:减少数据在内核态/用户态间的冗余拷贝和上下文切换,sendfile 最典型。展开:传统 readwrite 4 拷贝 4 切换,sendfile 降到 2-3 次;Java 用 FileChannel.transferTo,Kafka/Netty 都靠它提吞吐。带节奏:mmap 也算一种零拷贝思路,适合文件随机读。十、易错点提醒(高频踩坑清单)⚠️粘包/拆包是 TCP 字节流特性,UDP 是报文边界清晰、不会粘包;应用层必须自己定界(长度/分隔符)。⚠️select的 1024 是 fd 数量上限(Linux 默认),不是连接数;海量连接必须 epoll。⚠️ET 模式必须读到 EAGAIN 才停,否则剩余数据不会被再通知,会丢数据。⚠️不要乱开tcp_tw_recycle(已废弃),NAT 环境下会导致丢包;用tcp_tw_reuse或连接池。⚠️惊群:多进程/多线程 accept 同一监听 socket 会同时被唤醒,用 EPOLLEXCLUSIVE 或 SO_REUSEPORT 分摊。
返回列表