note · 8,835

计算机基础

计算机网络与协议基础:七层模型、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 确认

  1. 第一次 SYN Client to Serve
    1. Synchronize 表示请求建立连接
    2. 一个序列号ISN s用于后续传输的顺序确认
    3. 客户端进入 SYN_SENT(同步已发送)状态,等待服务器确认
  2. 第二次 SYN + ACK Serve to Client
    1. SYN
    2. ACK 确认收到
    3. 服务器初始序列号ISN c
    4. 确认号 ISN s +1
    5. 服务器进入 SYN_RCVD(同步已接收)状态
  3. 第三次 ACK Client to Serve
    1. ACK
    2. 确认号ISN s + 1 希望下一个包为ISN s + 1
    3. 双方进入 ESTABLISHED(连接已建立)

TCP 为什么不是两次握手

存在一个致命缺陷:服务器无法确认客户端是否收到了自己的回复

如果服务器回复的 SYN+ACK 报文在网络中丢失了,客户端将永远收不到。此时,客户端会认为连接未建立(因为它没收到服务器的确认),而服务器却单方面认为连接已经建立(因为它发出了 SYN+ACK)。服务器会白白等待客户端发送数据,浪费资源。

TCP 四次挥手

TCP 是全双工,两个方向要分别关闭,所以是四次!

  1. 第一次 FIN = 1 SEQ=u Client to Serve
    1. FIN finish 客户端想关闭连接
    2. SEQ sequence
    3. 客户端进入 FIN_WAIT_I状态
  2. 第二次 ACK Serve to Client
    1. ACK = 1
    2. 我(服务器)收到了该请求,你的数据我都已经接受完了,但我的数据可能没有发完,请你(Client)等待
    3. 客户端进入FIN_WAIT_2服务器进入CLOSE_WAIT关闭等待状态
  3. 第三次 FINServe to Client
    1. FIN
    2. 我的数据也发送完了,现在我请求关闭连接。
    3. 服务器进入LAST_ACK状态
  4. 第四次ACK
    1. 我(客户端)收到你的关闭请求了。连接可以彻底关闭了。
    2. 客户端进入TIME_WAIT状态

滑动窗口与流量控制

TCP 拥塞控制

Congestion Window 拥塞窗口 cwnd

Slow Start Threshold 慢启动阈值 ssthresh

  1. 慢启动
    1. 连接刚开始的时候,cwnd发送一个很小的值,指数增长 1-2-4-8……
  2. 拥塞避免
    1. cwnd 增长到一个阈值 ssthresh, 从“指数增长”切换到更保守的“线性增长”cwnd=cwnd+1
  3. 拥塞检测与处理
    1. 检测到超时 这是一个非常严重的拥塞信号 重新进入慢开始 将ssthresh(慢启动阈值)设置为当前 cwnd 的一半 cwnd设为1 重新进入慢启动阶段
    2. 如果 检测到 3 个重复的 ACK , 这是一个相对温和的拥塞信号 , 触发“快速重传”和“快速恢复”
  4. 恢复机制
    1. 快速重传: 检测到 3 个重复的 ACK 立即重传丢失的那个包
    2. 快速恢复: 既然能收到重复 ACK,说明网络还有传输能力,不需要把 cwnd 降回 1
      • “乘法减小”(MD):ssthresh 设置为当前 cwnd的一半 ( ssthresh = cwnd / 2 )。
      • cwnd 也设置为新的 ssthresh 值(而不是降为1)。 (加速递减)
      • 跳过慢启动,直接进入拥塞避免阶段(线性增长)。

UDP

如何让UDP变得可靠:核心机制实现 (在应用层“抄” TCP 的作业)

要想让 UDP 变得可靠,我们需要在应用层(或者说在 UDP 之上封装一层)解决 UDP 丢包、乱序的问题。具体需要实现以下几个关键机制:

  1. 序列号 (Sequence Number) 与数据重组
    • 痛点: UDP 不保证数据到达的顺序。
    • 解决: 在应用层的包头中增加一个序列号(Seq)字段。发送方对每个数据包编号,接收方根据序列号将乱序到达的包重新排序,并丢弃重复的包。
  2. 确认应答 (ACK - Acknowledgement)
    • 痛点: UDP 只管发,不知道对方收没收到。
    • 解决: 接收方收到数据后,必须向发送方回传一个带有确认号(ACK)的数据包,告诉发送方“我收到第 X 号包了”。
  3. 超时重传 (Timeout & Retransmission)
    • 痛点: 包在路上丢了怎么办?
    • 解决: 发送方在发出一个包后启动一个定时器(RTO, Retransmission TimeOut)。如果超过一定时间还没有收到对应的 ACK,就认为包丢了,自动重新发送该包(ARQ 自动重传请求)。进阶点:可以提一下快速重传(收到三次重复 ACK 立即重传),显得你对细节很把控。
  4. 滑动窗口 (Sliding Window) 与流量控制
    • 痛点: 发送方发得太快,接收方处理不过来,导致缓冲区溢出丢包。
    • 解决: 在应用层维护一个发送窗口和接收窗口。接收方在 ACK 中告诉发送方自己剩余的缓冲区大小(窗口大小),发送方根据这个大小动态调整自己的发送速率。
  5. 前向纠错 (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 是如何工作的?

  1. 握手(Handshake):WebSocket 的建立巧妙地借用了 HTTP 协议。客户端会先发送一个普通的 HTTP GET 请求,但在请求头中会带上特定信息:
    • Connection: Upgrade
    • Upgrade: websocket
    • 这等于在告诉服务器:“我们把这个 HTTP 连接升级成 WebSocket 吧!”
  2. 协议切换:如果服务器支持 WebSocket,它会返回一个 101 Switching Protocols 的状态码,表示同意升级。
  3. 数据传输:握手完成后,HTTP 协议光荣退役。接下来的通信将直接在底层的 TCP 连接上进行,双方可以通过轻量级的“数据帧(Frames)”高效地互传信息。
  4. 断开连接:任何一方都可以随时发送关闭帧来结束这个连接。

DNS

Domain Name System

  1. 本地缓存查找
  • 浏览器缓存 -> 系统缓存与Host文件 -> 路由器缓存
  1. 网络的层级查询
  • 对 本地DNS 请求递归查询(我只要最终结果)
  • 如果本地DNS缓存里没有 进行迭代查询
  1. 本地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服务端确认,发送子网掩码、网关、租期等信息发送给客户端。

访问一个网页实际上发生的过程

网络链接与寻址

  1. URL 解析 检查 URL 是否合法
  2. DNS 域名解析
    1. 查浏览器缓存->系统缓存->路由器缓存->ISP DNS 本地服务器递归查询 -> 迭代查询
  3. 建立 TCP 连接 - 三次握手
  4. 如果是 HTTPS 协议,在 TCP 握手之后,还会增加一个 TLS/SSL 握手

数据交互

  1. 发送 HTTP/HTTPS 请求
    1. 请求行、请求头、请求体
  2. 服务器处理请求
    • 负载均衡 (Load Balancer):如 Nginx,决定将请求分发给哪台具体的应用服务器。
    • Web 服务器/应用服务器:如 Tomcat、Netty 或 Gunicorn。它们接收请求,解析协议。
    • 业务逻辑处理:后端代码(如 Java Spring Boot, Go, Python Django)执行逻辑,可能涉及查询 数据库 (MySQL/Redis) 或调用其他微服务。
    • 生成响应:服务器准备好要返回的数据(通常是 HTML 页面,或者是 JSON 数据)。
  3. 服务器返回相应
    1. 状态码、响应头、响应体

浏览器解析与渲染

前端的部分

最后连接会通过 四次挥手 断开,释放资源。

正向代理与反向代理

对比维度正向代理 (Forward Proxy)反向代理 (Reverse Proxy)
代理对象客户端代理服务端代理
隐藏的对象隐藏了真实的客户端 IP隐藏了真实的后端服务器 IP
客户端的认知客户端知道自己在通过代理访问客户端不知道有代理,以为它就是真实服务器
典型代表软件VPN客户端、Shadowsocks、SquidNginx(负载均衡)、Apache、F5 (硬件)
核心目的突破网络限制、保护个人隐私负载均衡、保护网站服务器安全

Nginx

  1. 反向代理 在公网和核心业务之间建立隔离 安全
  2. 负载均衡
  3. 动静分离 拦截静态资源请求,将动态请求放给后端

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转换成Int8
  • HNSW图索引类型
    • 查询速度极快,召回率极
    • 构建索引极其耗时,且内存消耗非常庞大

分布式

CAP

  • Consistency 一致性
  • Availablity 可用性
    • “有求必应”。集群中只要有存活的节点,就必须对客户端的请求(读或写)给出正常的响应,绝对不能返回超时或错误。(但不保证返回的数据是最新的)。
  • Partition tolerance 分区容错性
    • “断网不宕机”。分布式系统部署在不同的机房或服务器上,网络断开或延迟(即“网络分区”)是客观存在、无法避免的。分区容错性是指,即便节点之间失联了,系统作为一个整体依然要能继续对外提供服务。

操作系统

cpu内存访问的流程

  1. 生成虚拟地址
    1. 每个进程都有自己独立的虚拟地址空间
  2. 翻译为物理地址
  3. 查找高速缓存
    1. 去 L1、L2、L3 Cache 中查找数据
  4. 访问主内存