网络分层 + 端到端路径

  • 网络分层 + 端到端路径
    • 分层模型
      • 链路层 (LINK)
        • 负责:同一链路/局域网内把 IP 包送到下一跳
        • 典型概念:以太网、WIFI、ARP、MAC、MTU
      • 网络层 (IP)
        • 负责:跨网络把包从源 IP 路由到目的 IP
        • 典型概念:IP 地址、路由表、NAT、ICMP、分片
      • 传输层 (Transport)
        • 负责:端到端进程通信,提供端口与可靠性
      • 应用层 (Application)
        • 负责:定义应用语义
    • 端到端路径(一次 HTTPS URL 发生了什么)
      • URL 解析与策略决策(应用层前置)
        • 浏览器先拆 URL:
          • schema:https -> 需要 TLS
          • host:example.com -> 需要 DNS
          • port:默认 443
          • path:/index.html
        • 是否可用缓存
        • 是否复用已有连接
      • DNS 解析:把域名变成 IP
        • 目标:得到服务器的 IP (A=IPv4/AAAA=IPv6)
        • 典型流程
          • 浏览器/OS 先查本地缓存
          • 没命中 -> 向递归解析器发起查询
          • 递归解析器询问:根 -> TLD -> 权威 DNS
          • 返回 IP + TTL
        • TTL 决定缓存时长
        • 同一域名可能返回多个 IP:简单的负载均衡,但是不可控
      • TCP 连接(传输层)
        • 目标:建立一条到服务器IP:443的 TCP 连接
        • 典型流程
          • 客户端选一个临时端口作为源端口
          • 形成 socket 四元组
          • 三次握手完成后,连接进入 ESTABLISHED
        • 连接的唯一标识符是四元组
        • NAT 环境下:srcIP 可能是私网 IP,但是公网会被 NAT 改写
        • RTT 大时,建连成本高:三次握手至少消耗 1 个 RTT
      • NAT:内网 IP 也能访问公网(网络层/链路层交叉)
        • 大多数客户端在 NAT
          • 内网 192.168.x.x:ramdomPort
          • 出口 NAT 把它映射成:公网 IP:另一个 Port
        • NAT 设备维护一张映射表(内网四元组<->公网四元组)
        • 映射有超时:长时间无数据可能被回收
        • 并发连接太多可能端口耗尽
      • TLS 握手:在 TCP 上建立安全通道
        • 目标
          • 验证服务器身份
          • 协商密钥
          • 后续数据用对称加密 + 完整性保护
        • TLS 发生在 TCP 建立之后、HTTP 之前
        • 证书用于“证明对方是它声称的域名“
      • 发送 HTTP 请求并接受响应
        • HTTP 内容
          • 请求行:GET /index.html
          • 头:Host、User-Agent、Accept、Cookie
          • 体:GET 通常无,POST 常见
        • 服务器返回
          • 状态码:200/301/404/500
          • 头:Content-Type、Content-Length、Set-Cookie
          • 体:HTML/JSON/图片等
      • 连接复用与关闭:不是每次都重新握手
        • HTTP/1.1 默认倾向长连接(Keep-Alive)
        • 浏览器有连接池,会复用到同一个 host:port 的连接
    • 关键概念锚点
      • RTT:网络交互的时间单位
        • RTT = 一个来回的延迟
        • 建连/TLS/重传都依赖 RTT
        • 高 RTT 下,交互次数越多越慢
      • 吞吐与 BDP(带宽-时延积)
      • MTU 月 MSS
        • MTU:链路层最大承载
        • MSS:TCP 单段可承载的应用数据最大值
        • 包太大可能被分片或者丢弃
        • 合理 MSS 能减少分片风险,提升稳定性

TCP 精讲

  • TCP 精讲
    • TCP 本质:在不可靠 IP 上提供可靠字节流
      • TCP 提供内容
        • 面向连接:双方都维护连接状态(序号、窗口、定时器等)
        • 可靠、有序:丢包重传、乱序重排、去重
        • 字节流:没有消息边界(粘包/拆包的根源)
        • 流量控制:避免把对方接收缓冲打爆(rwnd),端到端
        • 拥塞控制:避免把网络打爆,端到网络
    • 报文段关键字段
      • Sequence Number:本段数据在字节流里的起点序号
      • Acknowledgment Number:我期望收到的下一个收到的序号
      • Flags:SYN/ACK/FIN/RST/PSH/URG
      • Window(rwnd):接收端通告窗口
      • Options:MSS,Window Scale
    • 连接建立:三次握手
      • 标准流程
        • C->S: SYN(seq=x)
        • S->C: SYN+ACK (seq=y,ack=x+1)
        • C->S: ACK (ack=y+1)
      • 为什么必须三次
        • 双方都要确认两件事
          • 对方能收:对方收到了我的东西
          • 对方能发:对方能把东西发回来让我收到
        • 两次握手只能证明客户端 -> 服务端这条路通了;但是服务端无法证明服务端->客户端也通、且客户端确实收到了服务端的回应,第三次 ACK 就是让服务端拿到这个确认(服务端无法确认客户端能收)
        • 如果只有两次握手
          • 服务端回 SYN + ACK 丢失了
          • 服务端仍为连接建立,开始分配连接资源,等待数据
          • 客户端实际上没有收到任何回应,会重试或放弃
        • 三次握手还能防止历史重复 SYN 造成的“幽灵连接“
          • 历史重复 SYN 指的是:某次旧连接尝试时发出的 SYN,由于网络拥塞、路由绕行、链路重传、设备缓存/异常等原因,在很久之后才到达服务器
          • 如果服务器把旧 SYN 当新建连:
            • 服务器会分配资源
            • 如果后续又出现旧 ACK 包,让服务器误以为连接已建立,交付错误的数据
          • 幽灵连接:就是服务端自嗨式建立,客户端不认可
      • 半连接队列与 SYN Flood
        • 服务端收到 SYN 后进入 SYN_RECV,会占用半连接资源(backlog)
        • SYN Flood:大量 SYN 不完成握手 —> 半连接队列被占满 -> 正常连接进不来
        • 典型缓解:SYN cookies、增大 backlog、限速、丢弃策略、前置抗 DDoS
      • 连接关闭:四次挥手、半关闭
        • 主动关闭方 A->B:FIN(不再发了)
        • B -> A:ACK (知道了)
        • B -> A:FIN (我也不再发了)
        • A -> B:ACK (知道了)
      • 为什么常见是四次
        • TCP 是全双工:A 不发 != B 不发
        • B 可能还有数据要发完,所以 ACK 和 FIN 分开
      • 半关闭
        • A 发 FIN 表示 A 的发送方向关闭,但仍然可以接受 B 的数据
        • 工程上常见于“请求发送完但继续接受响应流“的场景
      • RST:不是正常关闭,是异常打断
        • RST(Reset)是 TCP 里面非常硬的控制信号:立刻终止连接/拒绝连接
        • 不是正常的四次挥手关闭,告诉对方:“这条连接不存在/状态不一致,马上停“
        • RST 常见原因
          • 端口没监听
          • 应用崩溃/强制关闭
          • 中间设备丢弃状态后注入 RST
      • TIME_WAIT、CLOSE_WAIT
        • 主动关闭方在发送最后一个 ACK 后进入 TIME_WAIT,并等待 2MSL。
        • 必须 TIME_WAIT
          • 保证对方收到最后 ACK:最后 ACK 丢了,对方重发 FIN;TIME_WAIT 还能再次 ACK
          • 让旧连接的延迟报文过期:避免旧数据混入新连接
        • 为什么是 2MSL
          • MSL = 报文在网络中可能存活的最大时间
          • 等待 2MSL 是为了覆盖对方 FIN 重传 + 我 ACK 再次发送等往返的不确定性。
        • TIME_WAIT 多了怎么办
          • 常见场景:短连接高 QPS
          • 治理思路
            • 优先做连接复用:HTTP Keep-Alive/连接池
            • 调整应用行为:减少主动 close、合并请求、复用长连接
            • 系统参数:允许端口更快复用等
          • 通常是我方主动关 + 短连接
        • CLOSE_WAIT 多是什么
          • CLOSE_WAIT 表示:对方已经 FIN 了,但是我方应用还没有 close
          • 常见原因:应用层忘记关闭连接、连接泄露、线程阻塞导致没有走到 close
          • 通常是我方没关
    • 可靠传输机制:序号、ACK、重传、SACK
      • 序号与累计 ACK
        • TCP 把数据看成连续字节流:每个字节都有序号
        • ACK 是累计的:ack = N 表示 0..N-1 都收到了,下一步要 N
        • 好处:ACK 开销小
        • 坏处:遇到乱序/丢包,单靠累计 ACK 不够精细
      • 重传触发机制
        • 超时重传(RTO):等不到 ACK 就重发(RTO 动态估计,基于 RTT 抖动)
          • TCP 发送一个数据段后,会期待收到 ACK,如果在某个时间窗口没有等到 ACK,TCP 可能认为丢了,于是触发超时重传。
            • 等多久的时间阈值就是 RTO(Retransmission Timeout)。
            • 触发条件:发送后,计时器到期,仍未收到能确认该段的 ACK
            • 行为:重传未确认的数据段
          • RTO 动态估计
            • 网络 RTT 会变,而且会抖动,RTO 必须跟随着链路实际 RTT 变化
          • SRTT + RTTVAR -> RTO
            • 名词解释
              • RTT sample:一次测得的 RTT(从发出某段到收到它对应 ACK 的时间)
              • SRTT (Smoothed RTT):平滑后的 RTT 均值。
              • RTTVAR:RTT 的波动。
            • RTO = SRTT + 4 * RTTVAR
              • SRTT 给出正常情况下 ACK 来回要多久
              • RTTVAR 给出不确定性有多大
              • 乘以 4 是给一个安全幅度:抖动越大,RTO 增长越明显,避免误重传
            • 指数退避:超时一次,RTO 翻倍
            • RTO 重传 vs 快速重传
              • RTO 重传
                • 触发:计时器到期,没等到 ACK
                • 特点:更“保底“,但通常更慢;而且代表网络更糟糕
                • 常伴随:指数退避,cwnd 通常会大幅下降
              • Fast Retransmit (快速重传)
                • 触发:重复 ACK
                • 特点:更快,更轻判拥塞
                • 一半比 RTO 更温和
        • 快速重传(Fast Retransmit):收到多个重复 ACK (典型 3 个)推断某段丢失了,立即重传)
          • RTO 重传局限性
            • 必须等待一段时间没收到 ACK 才重传
            • 在 RTT 较大或 RTO 比较保守时,恢复会很慢
          • 快速重传的思路
            • 不等超时,利用接收端反馈的 ACK 形态更早推断丢包
          • 重复 ACK
            • 如果接收端收到了更后面的段,但是缺了中间某段
              • 不能把乱序段交付给应用
              • 会继续发送同一个累计 ACK,告诉发送端还在等从 1000 开始的那段,后面来的我先缓存
            • ACK 值没前进,但又反复出现的 ACK 就是重复 ACK
          • 3 个重复 ACK 会触发快速重传
            • 收到 3 个重复 ACK 代表某段大概率丢了
            • 立即重传缺口对应的最早未确认段
          • 快恢复
            • 原因
              • 收到快重传代表完了给没有完全堵死(还能持续收到 ACK)
              • 不必像 RTO 那样极度保守把发送速率打到很低
            • Reno 直觉
              • 触发快速重传后,认为发生拥塞 -> 降低 cwnd
              • 但利用重复 ACK 的到来,允许发送端在恢复期间适度继续发,避免完全停摆
              • 当收到新的 ACK 后,退出快恢复,回到拥塞避免阶段
      • SACK(选择确认)
        • 痛点:累计 ACK 信息不够
          • 当出现丢包 + 乱序到达时,累计 ACK 只能不断重复同一个 ACK=N,发送端只知道缺口在 N,不知道
            • 后面哪些段已经到了
            • 究竟丢失了几段,丢失了哪几段
            • 重传时是否把已到达的也重传
          • 目标是把接收端实际收到的乱序块显式告诉发送端
        • SACK 是什么:在 ACK 里带已收到的区间块
          • SACK 是 TCP 的一个 Option,启用后
            • 接收端在 ACK 报文的 TCP Options 中携带若干个 SACK blocks
            • 每个 block 描述一个已经收到的连续字节区间
          • SACK block 的语义
            • SACK block = (Left Edge, Right Edge)
            • 表示接收端已经收到:[LeftEdge, RightEdge) 这个区间
          • ACK 字段仍然存在,表示最左侧连续已收前缀的下一个期待序号
        • 启用流程:SACK Permitted
          • SACK 需要在三次握手时协商
            • 双方在 SYN/SYN+ACK 中携带 SACK Permitted 选项
            • 只要双方都声明支持,后续才会在 ACK 中携带 SACK blocks
      • 乱序与重排
        • 网络层可能乱序,TCP 负责在接收端按序交付给应用
        • 接收端会缓存乱序段,等缺口补齐再交付
    • 滑动窗口
      • 痛点
        • 如果每发一段就必须等 ACK 再发下一段,吞吐会被 RTT 严重限制:链路大部分时间在等回音。
        • 滑动窗口允许发送端在未收到 ACK 前,先发出一批数据,让数据在路上飞,从而把链路利用起来。
        • 窗口 = 允许在途未确认数据的上限;窗口越大,在高 RTT 链路上容易跑满带宽
      • rwnd(receive window,接收窗口,流量控制)
        • 由接收端通告(在 TCP 头的 Window 字段里)
        • 表示接收端缓冲区还剩多少空间
        • 目的:防止发送端把接收端内存撑爆
      • cwnd(congestion window,拥塞窗口,拥塞控制)
        • 由发送端维护
        • 表示发送端认为网络当前能够承受的在途数据量上限
        • 目的:防止把网络打爆
      • swnd(send window,实际发送窗口)
        • 发送端真正允许“在途未确认“的上限
        • 近似于 min(rwnd,cwnd)
      • 发送端视角:窗口如何限制发送
        • 发送端维护两个关键指针
          • SND.UNA:最早未确认的序号(UnACKed)
          • SND.NXT:下一个准备发送的序号(Next to send)
        • 窗口约束可以理解为:
          • 允许发送的序号范围:[SND.UNA, SND.UNA + swnd)
          • 已发送未确认的范围:[SND.UNA, SND.NXT)
          • 还能继续发送的额度:swnd - (SND.NXT - SND.UNA)
        • ACK 到来时发生什么
          • 收到 ACK,把 SND.UNA 往前推进
          • 已确认数据从窗口左边滑出
          • 窗口右边腾出了空间,允许继续发送新的数据
      • 接收端视角:为什么会出现 dupACK/乱序缓存
        • 接收端维护两个关键指针
          • RCV.NXT:下一段按序期望的序号
          • 接收缓冲:可以暂存乱序到达的段
        • 出现乱序
          • 接收端会缓存后到的段,但 ACK 仍然回 RCV.NXT(累计 ACK)
          • 发送端看到重复 ACK (dupACK),可能触发快速重传
      • 窗口、吞吐、RTT
        • 吞吐上限 = 窗口大小/RTT
        • RTT=100ms,窗口=64KB,吞吐=64KB/0.1s=640KB/s
        • BDP(带宽-时延积),窗口需要=BDP 才能跑满带宽
          • 表示一条网络路径在任意时刻在路上飞着的数据量大概有多少,也叫管道容量
          • BDP = 带宽 * 往返时延 (RTT)
          • 想要把链路跑满,发送端需要让“在途未确认数据“接近 BDP
          • 在途未确认数据主要受窗口限制:in_flight <= min(cwnd, rwnd)
          • 要跑满带宽,需要窗口大小 >= BDP
      • 零窗口与窗口探测
        • 如果接收端缓冲满了,会通告 rwnd=0
        • 发送端此时必须停止发送新数据,但是要避免死锁
        • TCP 有 persist timer:周期性发送 Zero Window Probe 探测包
        • 一旦接收窗口恢复,发送端继续发
    • 粘包/拆包
      • 粘包:在发送端 send() 了两条业务消息,接收端一次 recv() 读到了两条合在一起的字节。
      • 拆包:在发送端 send() 了一条业务消息,接收端需要 recv() 多次才能读完
      • TCP 不保证 send 一次就对应端 recv 一次
      • 原因
        • TCP 的抽象是流
          • 像读文件一样读一串字节
          • send():把字节追加到发送缓冲区
          • recv():从接收缓冲区取走当前可读的字节
        • 分段由 TCP 决定,不由应用决定
        • 接收端读取粒度由应用决定
      • 解法
        • 在应用层定义消息边界
        • 长度前缀(Length-Prefixed,最通用)
          • 格式 | 4-byte length (big-endian) | payload bytes… |
          • length 表示 payload 长度
          • 接收端先读满 4 字节得到 length,再继续读满 length 字节
        • 分隔符(Delimiter-Based,适合文本协议)
          • 行协议:以 \r\n 结尾
        • 固定长度(Fixed-Size)
          • 每条消息固定 N 字节
    • 拥塞控制
      • 拥塞不是对端瘦不下,那是流量控制 rwnd,拥塞是网络路径上的队列/链路承载不住
        • 路由器/交换机队列堆积 -> RTT
        • 队列溢出 -> 丢包
        • 丢包/排队抖动 -> 吞吐下降、延迟暴涨
      • 拥塞控制控制的是发送端允许在网络中飞着的未确认数量,cwnd
      • Reno 的两个核心状态变量
        • cwnd:拥塞窗口(发送端认为网络现在能承受的在途数据量)
        • ssthresh:慢启动阈值,决定从指数增长到线性增长的分界点
      • 四个阶段
        • 慢启动
          • 目的:刚开始不知道网络能承受多少,先快速试探
          • 规则:
            • 初始 cwnd 为一个较小值,历史是 1MSS
            • 每收到一个 ACK,cwnd 增加 1MSS
            • 因为一个 RTT 内会收到大约 cwnd/MSS 个 ACK,所以每个 RTT cwnd 近似翻倍
            • 每 RTT 把在路上的包数翻倍,迅速逼近瓶颈带宽
            • 太快可能把队列灌满,引发丢包
        • 拥塞避免
          • 当 cwnd 到达或超过 ssthresh,从慢启动切换到拥塞避免
          • 每 RTT 让 cwnd 大约增加 1 MSS,每个 ACK 增加 MSS*MSS/cwnd
          • 大多数时间连接处于的阶段
        • 快重传:用 dupACK 提前判断丢包,不等 RTO
          • 触发条件
            • 收到 3 个重复 ACK dupACK
            • ACK 号不前进,连续出现多次
        • 快恢复:丢包后减速但不中断,比 RTO 温和
          • 发生快重传后的关键动作
            • 设定新的值
              • ssthresh = cwnd/2
            • cwnd 不回到很小,而是进入快恢复逻辑
            • 当收到能够推进 ACK 的新 ACK,退出快恢复,进入拥塞避免
        • RTO vs dupACK
          • RTO:最严重,认为网络可能很糟
            • ssthresh = cwnd / 2
            • cwnd 下降到很小,经典是 1MSS
            • 回到慢启动(重新探测)
            • RTO 通常会指数退避,导致恢复更慢

HTTP 与 Web 体系

  • HTTP 与 Web 体系
    • HTTP 基础语义
      • HTTP 是无状态应用层协议:每个请求都自包含信息,状态由 Cookie/Token/Session 等机制在应用层实现
      • HTTP 定义的语义,具体传输方式由 HTTP/1.1、HTTP/2、HTTP/3 决定
      • 方法:语义 + 幂等 + 安全性
        • GET:获取资源,应当安全+幂等
        • HEAD:只要响应头,不要响应体,用作探测/缓存探测
        • POST:提交数据,创建子资源或触发动作,通常非幂等
        • PUT:整体替换/创建指定资源,通常幂等
        • PATCH:部分更新,是否幂等取决于语义设计
        • DELETE:删除资源,通常幂等
        • OPTIONS:探测服务器能力(常用于 CORS 预检)
      • 状态码
        • 1xx:信息(少见)
        • 2xx:成功
          • 200 OK
          • 201 Created 创建成功
          • 204 No Content 成功但无响应体
        • 3xx:重定向
          • 301 永久
          • 302 临时(历史语义混乱)
          • 303 让客户端用 GET 拿
          • 307/308 保持方法不变
        • 4xx:客户端错误
          • 400 参数/格式问题
          • 401 需要认证
          • 403 拒绝
          • 404 不存在
          • 409 冲突
          • 429 限流
        • 5xx:服务器错误
          • 500、502 上游坏/网关问题
          • 503 不可用
          • 504 上游超时
      • Header
        • 通用与内容相关
          • Content-Type:实体类型(json/html…)
          • Content-Length:长度(HTTP/1.1 重要)
          • Content-Encoding:gzip/br 等压缩
          • Accept/Accept-Encoding/Accept-Language:内容协商
          • Host:HTTP/1.1 必须(虚拟主机)
          • Connect:连接管理(HTTP/2 中不再使用)
        • 会话与安全
          • Cookie/Set-Cookie
          • Authorization (Bearer/Basic 等)
          • Origin/Refer:CORS/CSRF 相关
          • Strict-Transport-Security:强制 HTTPS
          • Content-Security-Policy(CSP):前端安全策略
        • 缓存相关
          • Cahce-Control
          • Expires
          • ETag/If-None-Match
          • Last-Modified/If-Modified-Since
          • Vary
          • Age (代理缓存的年龄)
          • Pragma:no-cache (历史兼容)
    • HTTP 缓存
      • 两类缓存:强缓存vs协商缓存
        • 强缓存
          • 命中强缓存时浏览器直接用本地缓存,不走网络
          • 典型控制
            • Cache-Control: max-age=
            • Expires:老机制
        • 协商缓存(发请求但可能不下载)
          • 浏览器发请求带校验文件,服务器判断资源是否变化
          • ETag 流程
            • 响应:ETag: “xxx”
            • 下次请求:If-None-Match: “xxx”
            • 若未变:返回 304 Not Modified
          • Last-Modified 流程
            • 响应:Last-Modified: …
            • 下次请求:If-Modified-Since:…
            • 未变:304
      • Cache-Control 关键指令
        • max-age=N:资源在 N 秒内视为新鲜(强缓存)
        • no-store:绝对不缓存
        • no-cache:可以缓存,但每次使用前必须去服务器验证
        • must-revalidate:过期后必须验证,不能用陈旧副本
        • public:允许被共享缓存(CDN/代理)缓存
        • private:只允许浏览器私有缓存,不允许共享缓存缓存
        • s-maxage=N:给共享缓存的 max-age
      • Vary 存储维度的分桶键
        • Vary 告诉缓存,同一个 URL 的响应会因为某些请求头不同而不同
        • Vary:Accept-Encoding,gzip/br 不同版本要分开缓存
        • Vary:Origin:CORS 常见
        • Vary 过多会让缓存碎片化,命中率下降
      • ETag 的强弱、代理与一致性
        • 强 ETag:字节级一致才算命中
        • 若 ETag (W/):语义上等价即可
    • HTTP/1.1:连接、报文、队头阻塞
      • HTTP/1.1 报文与传输
        • 文本协议:请求行 + 头 + 空行 + body
        • 连接默认与持久化:Keep-Alive (减少握手成本)
        • Chunked Transfer-Encoding:服务端可流式传输,不提前知道 Content-Length
      • HTTP/1.1 的性能问题:应用层 HOL
        • 同一连接上请求/响应按顺序进行
        • 一个慢请求会阻塞后续的请求(队头阻塞)
    • HTTP/2:二进制分帧与多路复用
      • HTTP/2 为什么快
        • 二进制分帧:把大消息拆成帧
        • 多路复用:多个 stream 在同一 TCP 连接上并发交错传输
        • 头部压缩:HPACK(减少重复头部开销)
      • HTTP/2 性能问题:TCP 层 HOL(队头阻塞)
        • TCP 一旦丢包,需要重传并按序交付
        • 丢的那段之前的洞补不上,后续数据即使到了也不能交给上层
        • 结果:一个丢包会让同连接上所有 stream 都受影响
      • HTTP/3/QUIC
        • 核心变化
          • HTTP/3 跑在 QUIC 上,QUIC 基于 UDP
          • QUIC 自己实现可靠传输与拥塞控制
          • 按 stream 提供独立的有序交付,一个 stream 丢包不影响其他 stream 的交付
    • TLS 与 HTTPS
      • 位置与成本
        • HTTPS = TCP 建连后再 TLS 握手,再 HTTP
        • 首次访问慢常见原因:DNS + TCP + TLS 多次 RTT
      • 解决的问题
        • 身份认证:验证连接的是域名的真实服务器
        • 机密性:传输内容加密
        • 完整性:防篡改
      • TLS 握手
        • TLS 1.2
          • ClientHello:客户端支持的版本/套件,随机数,SNI 等
          • ServerHello:选定版本/套件、随机数,让双方对本次会话参数单程一致
          • Certificate:服务器发送证书链,客户端据此验证:链是否可信、域名是否匹配、是否过期,用途是否正确
          • ServerKeyExchange:服务器提供 ECDHE 参数与公钥,客户端通过验证签名,确保密钥协商参数的安全性
          • ServerHelloDone:告诉客户端,材料已经发完
          • ClientKeyExchange:客户端协商参数,客户端发送自己的 ECDHE 公钥,双方据此计算共享 secret
          • ChangeCipherSpec + Finished:双方切换到加密通信并校验握手完整性
      • Web 会话:Cookie/Session/Token
        • Web 会话解决的问题
          • 认证:你是谁
          • 授权:你能做什么
          • 会话保持:登录态怎么持续、怎么过期、怎么注销
          • 安全边界:防窃取、防伪造、防重放、防跨站
        • Cookie:浏览器自动携带的会话容器
          • Cookie 是浏览器保存的一组 key=value,由服务器通过响应头 Set-Cookie 下发。
          • 后续请求中,浏览器会按照规则自动带上 Cookie 头,无需 JS 参与
        • Cookie 关键属性
          • Domain/Path:决定发送范围
            • Domain=example.con:子域也可能携带
            • 不设置 Domain:仅当前 host
            • Path=/api:只对当前路径生效
          • Expires/Max-age:决定生命周期
            • Max-Age=0:立即删除
            • Session Cookie:不设过期时间,随浏览器进程结束而清理
          • Secure:只在 HTTPS 发送
          • HttpOnly:禁止 JS 读取
            • 有 HttpOnly 的 cookie,JS 读取不到
            • 不能防止 CSRF
          • SameSite:控制跨站请求是否携带
            • Strict:几乎不跨站携带
            • Lax:默认常用
            • None:允许跨站携带,必须同时设置 Secure
      • Session:服务端保存状态,客户端只存门票
        • Session 的典型模式
          • 服务端维护 session_id -> session_data
          • 客户端用 Cookie 存 session_id
          • 每次请求:浏览器自动带 cookie -> 服务端查 session store -> 识别用户
      • Token(尤其是 JWT):把身份证明带在请求里
        • Token 的核心模式
          • 服务端签发 token 给客户端
          • 客户端后续请求带 token
          • 服务端验证 token 来识别用户
        • JWT 结构
          • JWT=header.payload.signature
          • header:算法等元信息
          • payload:claims 声明
          • signature:服务端用密钥签名
      • Refresh Token 与 Access Token
        • Access Token:短有效期,每次用于请求
        • Refresh Token:长有效期,用于换取新的 Access Token
    • 安全边界:XSS、CSRF、会话固定、重放
      • XSS(跨站脚本)
        • 若 token/cookie 可以被 JS 读取,xss 可以直接窃取并盗用
        • cookie 用 HttpOnly + Secure
        • CSP 减少脚本注入
        • 输入输出编码 + 模板转义
      • CSRF 跨站请求伪造
        • CSRF 利用浏览器自动携带 cookie
        • 攻击者诱导用户在登录态下访问恶意页面,发起跨站请求到受害站点
        • 防护手段
          • SameSite Cookie (优先)
          • CSRF Token(表单/请求头携带,服务端校验)
          • 检查 Origin/Rerfer
    • 同源策略与 CORS
      • 痛点
        • 浏览器安全模型默认假设:不同站点之间互不信任
        • 浏览器用同源策略(Same-Origin Policy,SOP)限制一个网页脚本能读取另一个来源的资源内容
        • 业务需要跨域调用 API,有了 CORS(CrossOrigin Resource Sharing):在 SOP 的基础上提供一个受控的放行机制。
      • Orgin 源是什么:同源的三元组
      • 同源策略具体限制
        • 跨源读被禁止
          • JS 用 fetch 请求 https://xxx.com,请求可能能发出去,但是浏览器会阻止 JS 读取响应,除非响应满足 CORS 规则
        • 跨源写/发送很多情况下是允许的
          • 可以提交,因此 CSRF 能成立,请求可以发出去,但是页面读取不到 bank.com 的响应内容
        • 部分资源加载天然跨源允许
          • 浏览器允许加载这些资源
      • CORS 本质:服务器声明允许,浏览器执行拦截
        • 浏览器在请求带上 Origin
        • 服务器在响应返回 Access-Control-* 头
        • 浏览器据此决定:是否把响应暴露给 JS
      • CORS 两种请求路径:简单请求 vs 预检请求
        • 简单请求
          • 方法是 GET/HEAD/POST
          • Content-Type 只能是三种之一
            • application/x-www-form-urlencoded
            • multipart/form-data
            • text/plain
          • 请求头只能是 CORS-safelistedhead,不能随意加自定义头
        • 预检请求
          • 不满足简单请求条件,浏览器会先发送一个 OPTIONS 请求,询问服务器是否允许
          • 预检请求携带关键头
            • Origin: https://a.com
            • Access-Control-Request-Method:PUT
            • Access-Control-Request-Headers:x-token(将要携带的自定义头列表)
          • 服务器如果允许,需要在 OPTIONS 响应返回
            • Access-Control-Allow-Origin
            • Access-Control-Allow-Methods
            • Access-Control-Allow-Headers
            • Access-Control-Max-Age(预检缓存多久)
          • 通过后,浏览器才会发真实请求
        • CORS 响应头:每个头怎么用
          • Access-Control-Allow-Origin
            • 指定允许的 Origin
            • 可以是精确 Origin 或者 * (允许任意源),如果要带 Cookie/凭证,不能用 *
          • Access-Control-Allow-Methods
            • 允许的方法列表:GET/POST
            • 主要用于预检响应
          • Access-Control-Allow-Headers
            • 允许的自定义请求头列表
            • 必须覆盖预检中 Access-Control-Request-Headers 请求到的那些头
          • Access-Control-Allow-Credentials
            • true 表示允许携带凭证,例如 Cookie
            • 配合前端请求 credentials: ‘include’
          • Access-Control-Expose-Headers
            • 默认情况下,JS 能够读取的响应头很有限,如果希望暴露,必须显式添加
          • Vary: Origin
            • 按 Origin 分桶缓存
    • DNS 解析
      • 基础对象
        • 记录类型
          • A(IPv4)
          • AAAA(IPv6)
          • CNAME(别名)
          • NS(权威)
        • 解析角色
          • Stub resolver(客户端/OS)
          • Recursive resolver(递归解析器:运营商/公司 DNS/公共 DNS)
          • Authoritative server (权威 DNS)
    • 正向代理、反向代理、透明代理与隧道
      • 代理:本质上是位于客户端与服务端之间的一种中间节点,代表一侧发起连接、转发数据、并可能施加策略
      • 承担职责
        • 路由/转发:把请求送到正确上游
        • 安全控制:鉴权、WAF、访问控制
        • 性能优化:连接复用、压缩、缓存、限流
        • 可观测性:日志、指标、追踪、采样
        • 协议转换:HTTP <-> grpc 等
      • 正向代理
        • 正向代理站在客户端一侧,客户端明确知道自己在用代理,由代理代表客户端访问外部资源
      • 反向代理
        • 反向代理站在服务端一侧,对外它像真正的服务器入口,对内把请求转发到后端服务
        • 反向代理常用原因
          • 隐藏后端拓扑:外部只有一个入口
          • 统一 TLS 终止:证书集中管理
          • 统一流量治理:限流、熔断、灰度、路由、鉴权
          • 连接复用:对外维持大量连接、对内复用少量连接
          • 观测与审计:同一日志/指标/链路追踪
        • 透明代理
        • 隧道:Connect 到底干了什么
          • 隧道:代理不解析上层协议,只做字节透传。
          • HTTP Connect 隧道流程
            • 客户端先对代理发 CONNECT
              • 客户端 -> 代理
                • CONNECT bank.com:443 HTTP/1.1
                • Host: back.com:443
            • 代理建立到目标的 TCP 连接
              • 代理 -> bank.com:443:发起 TCP 连接
              • 代理回客户端
                • HTTP/1.1 200 Connect Established
            • 隧道建立,字节透传
              • 客户端与 bank.com 的 TLS 握手数据会被原封不动地通过代理转发,代理看不懂也不需要看懂
              • TLS 会话在客户端<->目标服务器之间建立
    • 负载均衡:L4 vs L7、算法、会话保持、健康检查
      • 目标
        • 扩展性:把流量分散到多台实例,提高吞吐
        • 高可用:实例故障自动摘除,流量不中断或快速恢复
        • 性能:就近、减少重连、减少排队、提升尾延迟
        • 治理:灰度、限流、熔断、路由、可观测
      • 边界
        • LB 解决的是把请求推送到谁,不解决业务正确性
        • LB 层任何自动重试/超时,都可能改变业务语义
      • L4 与 L7 的区别
        • L4 LB(传输层):基于 IP/端口/连接做转发
          • 优点:性能高,对协议透明
          • 缺点:无法基于 URL/Header 做路由
          • 常见实现:内核转发、四层 VIP、DSR、NAT 模式等
          • 适合长连接:WebSocket、MQ、数据库连接等
        • L7 LB(应用层):理解 HTTP,按照 Host/Path/Header/Cookie 路由
          • 常见常见:API Gateway、Ingress、CDN 回源入口
      • 负载均衡算法
        • Round Robin(轮询)
          • 依次分发到每个后端
          • 适合:请求耗时相近、后端同质、短连接
          • 问题
            • 后端性能差异大时不均衡
            • 长连接场景下连接一旦分配就会粘住,RR 也会失衡
        • Weighted Round Robin
          • 按权重分配(机器规格不同,冷热分层)
          • 适合:异构机器,逐步扩容
          • 问题:权重需要维护;负载时间随时间变化时仍然不准
        • Least Connections(最少连接)
          • 连接数最少的后端连接
          • 适合:长连接、连接数与负载相关的业务
          • 问题:
            • 连接数不等于负载
            • 需要 LB 维护连接计数状态
        • Least Request/Least Load(最少请求/最小负载)
          • 按当前活跃请求数或综合指标选择
          • 适合:请求耗时差异大,尾延迟敏感
          • 问题:实现复杂、依赖观测准确性;指标延迟可能导致震荡
        • Random/Power of Two Choices(随机/二选一)
          • 随机挑两个后端,选最优者
          • 优点:简单且实际效果接近最优,分布更稳定,大规模下能显著降低热点概率
          • 适合:大规模集群、需要避免中心化状态
        • Consistent Hash(一致性 hash)
          • 按 key 映射到固定节点
          • 适合:
            • 需要缓存命中(本地 cache)
            • 会话保持(不想引入共享 session)
            • 分片存储(按 key 分片)
          • 关键性质:节点增减时迁移量小
          • 问题:
            • 热点 key 会压垮单节点(热点拆分/虚拟节点)
            • 节点故障时 key 重映射会引发抖动。
      • 会话保持
        • 为什么需要 sticky
          • 后端有状态
          • 本地缓存必须命中
          • WebSocket/长连接绑定到某实例
        • 常见 sticky 手段
          • Source IP hash
            • 按客户端 IP 做 hash 选节点
            • 优点:简单
            • 缺点:
              • NAT/代理下大量用户共享同一出口 IP -> 严重倾斜
              • 用户换网 IP 变化导致漂移
          • Cookie 粘性
            • LB 注入 cookie ,后续按照 cookie 路由
            • 优点:比 IP 稳定
            • 缺点:跨域,隐私策略,cookie 清理,灰度/回源复杂
          • 一致性哈希(按 userId/会话键)
        • 工程风险
          • 降低容错:节点挂了,该节点的用户都受影响
          • 产生热点:某些用户/租户流量大->单节点热
          • 扩缩容抖动:重新分配导致缓存冷启动、延迟尖刺
        • 推荐的替代方案
          • 应用无状态 + 共享 session (Redis)
          • 把状态外置(DB/Cache),实例可以随时替换
          • 长连接常见:连接层 sticky 不可避免,要做好限流与迁移策略
      • 健康检查
        • L4 健康检查
          • 探测 TCP 能否 connect 成功
          • 优点:便宜、通用
          • 缺点:应用假活时仍然会通过(线程池满、依赖挂)
        • L7 健康检查
          • 请求 /healthz 或 /readyz
          • 可检查
            • 进程存活
            • 是否可接新流量
            • 关键依赖是否可用
        • 设计要点
          • liveness vs readliness 分离
            • liveness:进程是否需要重启
            • readliness:是否接流量
          • 避免健康检查过重
            • 如果每秒大量探测并且检查依赖,会把依赖也打挂
          • 阈值与抖动控制
            • 连续 N 次失败才摘除
            • 连续 M 次成功才恢复
          • 慢启动与预热
            • 新实例启动后先不接流量,预热缓存/JIT,再标 ready
    • 网络排障
      • L3/L4 基础联通与路径
        • ping
          • 测试的是什么
            • ping 用的是 ICMP Echo Request/Echo Reply
            • 发 Echo Request(带序号 seq、时间戳等)
            • 对端回 Echo Reply
            • 测量往返时延 RTT
          • 查看延迟
            • 看 avg 和 min/max
          • 抖动
            • RTT 的波动程度
            • stddev(标准差) 大,说明网络队列/无线/拥塞波动明显
          • 丢包
            • packet loss > 0 说明有包没有收到回包
        • tracerout/mtr 的原理
          • traceroute:用 TTL 把路径探测出来
            • IP 包里有 TTL,每过一跳路由器把 TTL - 1
            • 当 TTL 变为 0,路由器丢包并回 ICMP Time Exceeded
            • traceroute 依次发 TTL=1,2,3 的探测包
            • 可以看到每一跳的地址与该跳的 RTT
            • 每一跳显式的 RTT 是你->该跳->你的往返,不是单程,也不是该跳->下一跳的延迟
          • mtr:traceroute + ping 的结合
            • mtr 会对每一跳持续发探测包并统计
              • 丢包率
              • 最快/平均/最慢 RTT
              • 抖动
            • mtr 更适合定位抖动/偶发丢包/拥塞点
          • 用 traceroute 看路径与绕路