计算机基础
计算机网络与协议基础:七层模型、TCP/UDP、HTTP/WebSocket、DNS、CDN 等。
IOS七层模型
应 - 表- 会 - 传 - 网 - 数 - 物
| 层级 | 层名称 (Layer) | 核心作用 (简言之) | 传输数据单元 (PDU) | 典型协议/硬件 |
|---|---|---|---|---|
| 7 | 应用层 (Application) | 最终用户接口,提供网络服务 | 报文 (Message) | HTTP, HTTPS, FTP, DNS |
| 6 | 表示层 (Presentation) | 数据的“翻译官”,负责格式化、加密 | 报文 (Message) | SSL/TLS, JPEG, ASCII |
| 5 | 会话层 (Session) | 建立、管理和终止应用程序间的会话 | 报文 (Message) | RPC, SCP |
| 4 | 传输层 (Transport) | 提供端到端(端口)的可靠/不可靠传输与流控 | 段 (Segment) / 数据报 | TCP, UDP |
| 3 | 网络层 (Network) | 寻址和路由选择,实现主机到主机的通信 | 包 (Packet) | IP, ICMP, 路由器 |
| 2 | 数据链路层 (Data Link) | 物理寻址,在相邻节点间可靠传输帧 | 帧 (Frame) | MAC, ARP, 交换机 |
| 1 | 物理层 (Physical) | 透明地传输原始比特流 | 比特 (Bit) | 网线, 光纤, 集线器 |
TCP
- 网络接口层(对应OSI的物理层和数据链路层)
- 网络层(如IP、ICMP、ARP)
- 传输层(如TCP、UDP、SCTP)
- 应用层(如HTTP、FTP、SMTP、DNS)
TCP与UDP
| 特性 | TCP (Transmission Control Protocol) | UDP (User Datagram Protocol) |
|---|---|---|
| 连接性 | 面向连接(需三次握手建立连接,四次挥手断开) | 无连接(直接发送数据) |
| 可靠性 | 极高。确认、重传、流量控制(滑动窗口)、拥塞控制、校验和 | 低。尽最大努力交付,不保证可靠性,可能丢包或乱序 |
| 传输速度 | 较慢(因为有确认机制、重传、拥塞控制等开销) | 极快(没有冗余的控制机制,发送端全速发送) |
| 首部开销 | 较大(最小 20 字节,包含众多控制字段) | 极小(仅 8 字节) |
| 传输方式 | 面向字节流(没有明显的边界,数据像水流一样) | 面向报文(保留报文边界,一次发送/接收一个完整的数据报) |
| 流量/拥塞控制 | 有(根据网络拥堵情况动态调整发送速度) | 无(网络越堵,丢包越多,但它依然全速发送) |
| 场景 | 准确性优先 HTTP/HTTPS | 时效性优先 游戏、直播 |
TCP 三次握手 传输层
synchronization 同步 acknowledged 确认
- 第一次 SYN Client to Serve
- Synchronize 表示请求建立连接
- 一个序列号ISN s用于后续传输的顺序确认
- 客户端进入
SYN_SENT(同步已发送)状态,等待服务器确认
- 第二次 SYN + ACK Serve to Client
- SYN
- ACK 确认收到
- 服务器初始序列号ISN c
- 确认号 ISN s +1
- 服务器进入
SYN_RCVD(同步已接收)状态
- 第三次 ACK Client to Serve
- ACK
- 确认号ISN s + 1 希望下一个包为ISN s + 1
- 双方进入
ESTABLISHED(连接已建立)
TCP 为什么不是两次握手
存在一个致命缺陷:服务器无法确认客户端是否收到了自己的回复。
如果服务器回复的 SYN+ACK 报文在网络中丢失了,客户端将永远收不到。此时,客户端会认为连接未建立(因为它没收到服务器的确认),而服务器却单方面认为连接已经建立(因为它发出了 SYN+ACK)。服务器会白白等待客户端发送数据,浪费资源。
TCP 四次挥手
TCP 是全双工,两个方向要分别关闭,所以是四次!
- 第一次 FIN = 1 SEQ=u Client to Serve
- FIN finish 客户端想关闭连接
- SEQ sequence
- 客户端进入
FIN_WAIT_I状态
- 第二次 ACK Serve to Client
- ACK = 1
- 我(服务器)收到了该请求,你的数据我都已经接受完了,但我的数据可能没有发完,请你(Client)等待
- 客户端进入
FIN_WAIT_2服务器进入CLOSE_WAIT关闭等待状态
- 第三次 FINServe to Client
- FIN
- 我的数据也发送完了,现在我请求关闭连接。
- 服务器进入
LAST_ACK状态
- 第四次ACK
- 我(客户端)收到你的关闭请求了。连接可以彻底关闭了。
- 客户端进入
TIME_WAIT状态
滑动窗口与流量控制
TCP 拥塞控制

Congestion Window 拥塞窗口 cwnd
Slow Start Threshold 慢启动阈值 ssthresh
- 慢启动
- 连接刚开始的时候,
cwnd发送一个很小的值,指数增长 1-2-4-8……
- 连接刚开始的时候,
- 拥塞避免
- 当
cwnd增长到一个阈值ssthresh, 从“指数增长”切换到更保守的“线性增长”cwnd=cwnd+1
- 当
- 拥塞检测与处理
- 检测到超时 这是一个非常严重的拥塞信号 重新进入慢开始 将
ssthresh(慢启动阈值)设置为当前cwnd的一半cwnd设为1 重新进入慢启动阶段 - 如果 检测到 3 个重复的 ACK , 这是一个相对温和的拥塞信号 , 触发“快速重传”和“快速恢复”
- 检测到超时 这是一个非常严重的拥塞信号 重新进入慢开始 将
- 恢复机制
- 快速重传: 检测到 3 个重复的 ACK 立即重传丢失的那个包
- 快速恢复: 既然能收到重复 ACK,说明网络还有传输能力,不需要把
cwnd降回 1- “乘法减小”(MD): 将
ssthresh设置为当前cwnd的一半 ( ssthresh = cwnd / 2 )。 - 将
cwnd也设置为新的ssthresh值(而不是降为1)。 (加速递减) - 跳过慢启动,直接进入拥塞避免阶段(线性增长)。
- “乘法减小”(MD): 将
UDP
如何让UDP变得可靠:核心机制实现 (在应用层“抄” TCP 的作业)
要想让 UDP 变得可靠,我们需要在应用层(或者说在 UDP 之上封装一层)解决 UDP 丢包、乱序的问题。具体需要实现以下几个关键机制:
- 序列号 (Sequence Number) 与数据重组
- 痛点: UDP 不保证数据到达的顺序。
- 解决: 在应用层的包头中增加一个序列号(Seq)字段。发送方对每个数据包编号,接收方根据序列号将乱序到达的包重新排序,并丢弃重复的包。
- 确认应答 (ACK - Acknowledgement)
- 痛点: UDP 只管发,不知道对方收没收到。
- 解决: 接收方收到数据后,必须向发送方回传一个带有确认号(ACK)的数据包,告诉发送方“我收到第 X 号包了”。
- 超时重传 (Timeout & Retransmission)
- 痛点: 包在路上丢了怎么办?
- 解决: 发送方在发出一个包后启动一个定时器(RTO, Retransmission TimeOut)。如果超过一定时间还没有收到对应的 ACK,就认为包丢了,自动重新发送该包(ARQ 自动重传请求)。进阶点:可以提一下快速重传(收到三次重复 ACK 立即重传),显得你对细节很把控。
- 滑动窗口 (Sliding Window) 与流量控制
- 痛点: 发送方发得太快,接收方处理不过来,导致缓冲区溢出丢包。
- 解决: 在应用层维护一个发送窗口和接收窗口。接收方在 ACK 中告诉发送方自己剩余的缓冲区大小(窗口大小),发送方根据这个大小动态调整自己的发送速率。
- 前向纠错 (FEC - Forward Error Correction) —— 面试加分项
- 痛点: 重传会带来延迟(至少需要一个 RTT 往返时间),对于极度要求低延迟的场景不可接受。
- 解决: 发送方在发送真实数据时,夹带一些冗余的校验数据。如果接收方只丢失了少量包,可以直接利用收到的包和冗余数据把丢失的包算出来,直接免去了重传的时间。
HTTP
HTTP 与 HTTPS
HTTPS 实际上就是 HTTP over SSL/TLS
在应用层(HTTP) 和 传输层(TCP) 中间增加了安全层
SSL/TLS
使用非对称加密交换密钥 (握手)
使用对称加密进行会话
状态码
1xx (信息性): 表示请求已被接收,继续处理。
2xx (成功): 表示请求已成功被服务器接收、理解、并接受。
- 200 Ok
- 204 No Content 已处理完 但服务器不需要返回任何实体内容
3xx (重定向): 表示需要客户端采取进一步的操作才能完成请求。
- 301 Moved Permanently : 永久重定向
- 302 Found : 临时重定向
- 304 Not Modified : 数据没变 直接用本地缓存
4xx (客户端错误): 表示客户端的请求有语法错误或请求无法实现。
- 400 Bad Request 服务器无法理解客户端的请求,通常是因为语法错误
- 401 Unauthorized 未授权
- 403 Forbidden 禁止访问 可能没有权限
- 404 Not Found 服务器上找不到请求的资源
5xx (服务器错误): 表示服务器未能实现合法的请求。
- 500 Internal Server Error: 服务器内部错误。这是后端开发者最怕看到的,意味着服务器端的代码在执行过程中抛 出了未捕获的异常(Bug),导致程序崩溃。
- 502 Bad Gateway: 网关错误。服务器作为网关或代理,从上游服务器收到了无效的响应。 Nginx 收到了请求并转发给后端的 Java/Go 服务,但后端服务没启动、挂掉了或者根本连不上,Nginx 就会返回 502。
- 503 Service Unavailable: 服务不可用。服务器暂时无法处理请求,通常是因为过载(并发量太大)或正在进行停机维护。
- 504 Gateway Timeout:网关超时 ginx 把请求转发给了后端服务,但是后端服务处理得太慢了(可能是由于慢 SQL 查询或死锁),等了半天没响应,Nginx 失去了耐心,就会向客户端返回 504。
HTTP/1.1 /2 /3
- HTTP/1.1
- 引入长连接 避免每次请求都重新建立TCP
- 基于文本串行传输 在一个TCP连接里 请求必须排队
- HTTP/2
- 引入 二进制分帧 和 多路复用 多个请求帧可以乱序混合发送,再拼接
- 解决了应用层阻塞,却触发了 TCP 层的队头阻塞 如果网络发生丢包,TCP 会暂停向应用层递交所有数据,并等待丢失包的重传。
- HTTP/3
- 改用基于UDP构建QUIC协议 在应用层自己实现了一套可靠机制
- 在 QUIC 中,各个数据流(Stream)是相互独立的。如果 Stream A 丢包了,只会影响 Stream A,不会卡住 Stream B 和 C。
- 握手优化: 传统的 HTTP/2 (TCP + TLS) 需要先进行 TCP 三次握手,再进行 TLS 握手,通常需要 2-3 个 RTT(往返时延)。而 QUIC 将传输层和加密层合并,首次连接只需 1-RTT,恢复曾经建立过的连接甚至可以做到 0-RTT(直接带上数据发车)。
WebSocket
WebSocket 是一种在单个 TCP 连接上进行全双工(Full-duplex)通信的网络协议。
HTTP 的痛点:单向通信 “请求-响应”模式。客户端(比如浏览器)必须主动向服务器发送请求,服务器才能返回数据。服务器永远无法主动给客户端发送信息。
如果你需要获取实时数据(例如股票价格或聊天消息),在没有 WebSocket 的时代,通常只能使用轮询
WebSocket 是如何工作的?
- 握手(Handshake):WebSocket 的建立巧妙地借用了 HTTP 协议。客户端会先发送一个普通的 HTTP GET 请求,但在请求头中会带上特定信息:
Connection: UpgradeUpgrade: websocket- 这等于在告诉服务器:“我们把这个 HTTP 连接升级成 WebSocket 吧!”
- 协议切换:如果服务器支持 WebSocket,它会返回一个
101 Switching Protocols的状态码,表示同意升级。 - 数据传输:握手完成后,HTTP 协议光荣退役。接下来的通信将直接在底层的 TCP 连接上进行,双方可以通过轻量级的“数据帧(Frames)”高效地互传信息。
- 断开连接:任何一方都可以随时发送关闭帧来结束这个连接。
DNS
Domain Name System
- 本地缓存查找
- 浏览器缓存 -> 系统缓存与Host文件 -> 路由器缓存
- 网络的层级查询
- 对 本地DNS 请求递归查询(我只要最终结果)
- 如果本地DNS缓存里没有 进行迭代查询
- 本地DNS拿到IP,存到自己的缓存里,并返回给客户端
CDN
Content Delivery Network,内容分发网络
数据流演练
- 第一步:DNS 解析与 CNAME。 用户在浏览器输入
www.example.com。本地 DNS 服务器去解析时,发现这个域名配置了 CNAME 记录(比如指向了example.cdn.com)。 - 第二步:CDN 全局负载均衡(GSLB)。 这个 CNAME 域名会把解析请求交给 CDN 厂商的 GSLB(全局负载均衡系统)。GSLB 会根据用户的 IP 地址、所属运营商(联通/电信)以及各个 CDN 节点的负载情况,计算出一个离用户最近、状态最好的边缘节点 IP,并把它返回给用户。
- 第三步:访问边缘节点。 用户拿到 IP 后,直接向这个 CDN 边缘节点发起 HTTP 请求。
- 第四步:缓存命中(Cache Hit)。 如果边缘节点上正好有用户想要的这张图片,就直接返回给用户。(加速成功,请求根本没打到你的 Java 后端!)
- 第五步:回源(Origin Pull / Cache Miss)。 如果边缘节点上没有这张图片(或者缓存过期了),节点就会向上游的源站(也就是你维护的真实服务器)发起请求,把图片拉取过来。拉取到之后,边缘节点会把图片缓存在自己本地,然后再返回给用户。下次同地区的其他用户再访问,就能直接命中了。
如何用CDN优化后端系统
在实际项目中,我们通常会结合 CDN 做动静分离。像 HTML、CSS、JS 文件以及用户上传的图片、视频,我们会存放在对象存储(如阿里云 OSS)中,并绑定 CDN 域名进行全网加速。而我的 Java 后端(比如 Spring Boot 接口)只负责处理动态请求(如登录、下单、查询数据库并返回 JSON)。这样可以把 80% 以上的静态流量挡在 CDN 层面,极大地保护了我们的后端服务。
DHCP
流程四步走 - DORA
D - Dsicover客户端发广播 “这里有DHCP服务器吗?我需要一个IP!”O - OfferDHCP服务端在连接池里选择一个IP提供R - Request客户端广播确认A - Acknowleage服务端确认,发送子网掩码、网关、租期等信息发送给客户端。
访问一个网页实际上发生的过程
网络链接与寻址
- URL 解析 检查 URL 是否合法
- DNS 域名解析
- 查浏览器缓存->系统缓存->路由器缓存->ISP DNS 本地服务器递归查询 -> 迭代查询
- 建立 TCP 连接 - 三次握手
- 如果是 HTTPS 协议,在 TCP 握手之后,还会增加一个 TLS/SSL 握手
数据交互
- 发送 HTTP/HTTPS 请求
- 请求行、请求头、请求体
- 服务器处理请求
- 负载均衡 (Load Balancer):如 Nginx,决定将请求分发给哪台具体的应用服务器。
- Web 服务器/应用服务器:如 Tomcat、Netty 或 Gunicorn。它们接收请求,解析协议。
- 业务逻辑处理:后端代码(如 Java Spring Boot, Go, Python Django)执行逻辑,可能涉及查询 数据库 (MySQL/Redis) 或调用其他微服务。
- 生成响应:服务器准备好要返回的数据(通常是 HTML 页面,或者是 JSON 数据)。
- 服务器返回相应
- 状态码、响应头、响应体
浏览器解析与渲染
前端的部分
最后连接会通过 四次挥手 断开,释放资源。
正向代理与反向代理
| 对比维度 | 正向代理 (Forward Proxy) | 反向代理 (Reverse Proxy) |
|---|---|---|
| 代理对象 | 替客户端代理 | 替服务端代理 |
| 隐藏的对象 | 隐藏了真实的客户端 IP | 隐藏了真实的后端服务器 IP |
| 客户端的认知 | 客户端知道自己在通过代理访问 | 客户端不知道有代理,以为它就是真实服务器 |
| 典型代表软件 | VPN客户端、Shadowsocks、Squid | Nginx(负载均衡)、Apache、F5 (硬件) |
| 核心目的 | 突破网络限制、保护个人隐私 | 负载均衡、保护网站服务器安全 |
Nginx
- 反向代理 在公网和核心业务之间建立隔离 安全
- 负载均衡
- 动静分离 拦截静态资源请求,将动态请求放给后端
Kubernets K8s
- 自动恢复(Self-healing): 如果某个运行着你应用的容器崩溃了,或者所在的服务器宕机了,K8s 会瞬间察觉,并在健康的服务器上重新启动一个新的容器,用户几乎无感知。
- 弹性伸缩(Scaling): 双十一流量暴增?只需修改一个配置(甚至配置自动扩容),K8s 就能在几秒钟内把你的应用从 3 个实例扩容到 300 个。流量退去后再自动缩容。
- 负载均衡(Load Balancing): K8s 会自动为你的一组容器分配一个统一的 IP 地址和域名,并将用户的请求均匀地分发到各个容器上。
核心资源
- Pod(豆荚): K8s 中最小的部署单元。K8s 不直接管容器,它管 Pod。一个 Pod 里面可以装一个容器(最常见),也可以装几个关系极其紧密、需要共享网络和存储的容器。
- Deployment(部署): 你的图纸。你在这里声明:“我要运行 Nginx,版本是 1.20,并且我要时刻保持 3 个副本在运行”。K8s 就会照做。Deployment 是高高在上管理这些Pod的“大管家”,它通过自动监控数量、管理发布策略,来保证你的系统永远在线、并且能平滑升级。
- Service(服务): 你的固定门牌号。因为 Pod 随时可能因为重启而改变 IP 地址,Service 提供了一个固定的入口和负载均衡,让内部或外部的用户永远能找到你的应用。
ElasticSearch
正排索引与倒排索引
- 正排索引 通过唯一的 ID(标识)去查找这个文档里包含了哪些内容。
- 倒排索引 提取所有文档中的关键词,建立词汇表,然后记录每个关键词出现在哪些文档中。
Milvus
Milvus 每次刷盘(Flush),都会在底层对象存储(或本地磁盘)生成一个新的数据段(Segment)文件。
- 灾难现场: 如果你有 10 万个用户的总结,每写一条刷一次,就会瞬间产生 10 万个极小(几 KB)的 Segment 文件。
- OOM 触发机制: 为了保证检索效率,Milvus 后台有一个叫做 Compaction(数据合并) 的机制。当它扫描到海量的碎片化小文件时,会疯狂地启动后台合并任务。为了把这 10 万个小文件合并成几个大文件,Milvus 必须把它们重新全部加载进内存进行计算和重组。此时,海量碎片带来的额外开销和并发合并任务,会瞬间刺穿数据节点(DataNode)的内存上限,导致 OOM 崩溃。
索引
FLAT暴力检索类IVF_FLAT将向量空间分成多个簇 分簇检索IVF_SQ8标量化 Float32转换成Int8HNSW图索引类型- 查询速度极快,召回率极
- 构建索引极其耗时,且内存消耗非常庞大
分布式
CAP
- Consistency 一致性
- Availablity 可用性
- “有求必应”。集群中只要有存活的节点,就必须对客户端的请求(读或写)给出正常的响应,绝对不能返回超时或错误。(但不保证返回的数据是最新的)。
- Partition tolerance 分区容错性
- “断网不宕机”。分布式系统部署在不同的机房或服务器上,网络断开或延迟(即“网络分区”)是客观存在、无法避免的。分区容错性是指,即便节点之间失联了,系统作为一个整体依然要能继续对外提供服务。
操作系统
cpu内存访问的流程
- 生成虚拟地址
- 每个进程都有自己独立的虚拟地址空间
- 翻译为物理地址
- 查找高速缓存
- 去 L1、L2、L3 Cache 中查找数据
- 访问主内存