运维常见题-网站维护

目录
本文所引用的核心资料与数据,均由 DeepSeek V4 Flash 辅助生成。为确保内容的可靠性,笔者已对大部分关键论点进行了人工复核与校验。但鉴于大模型的固有局限,本文仍可能存在认知偏差或未尽准确之处。若您在阅读中发现存疑或矛盾之处,欢迎反馈讨论,笔者将及时核实与修正。

🤔 简述 HTTP/1.0、1.1、2、3 区别?

  • HTTP 协议经历了四代演进,每一代解决前一代的核心痛点:连接复用、并发能力、传输效率。

    • HTTP/1.0(1996,RFC 1945)

      • 特点:每个请求/响应使用一个独立的 TCP 连接,请求完成后连接立即关闭(短连接)
      • 问题:一次页面加载需要多个资源(HTMLCSSJS、图片),每个资源都要新建 TCP 连接,TCP 握手(尤其 HTTPSTLS 握手)开销巨大
      • 其他:无 Host 头(同一 IP 上无法在 HTTP 层区分多个域名,即虚拟主机);缓存控制简陋(仅有 Expires/Pragma/Last-Modified,无 Cache-Control/ETag
    • HTTP/1.11997 首版 RFC 20681999 定稿 RFC 2616,现为 RFC 9110/9111/9112

      • 持久连接(Keep-Alive :默认复用同一个 TCP 连接发送多个请求,解决频繁握手问题
      • Host:支持一个 IP 上部署多个域名(虚拟主机)
      • 管线化(Pipelining):客户端可以连续发送多个请求而不必等前一个响应——但由于响应必须按请求顺序返回(FIFO),一个慢响应会阻塞后面的所有响应(队头阻塞),实际很少启用
      • 其他chunked 传输编码、更完善的缓存控制(Cache-ControlETag
      • 核心问题:队头阻塞(Head-of-Line Blocking) ——同一连接上的请求必须串行处理,一个响应慢,后续全等
    • HTTP/22015RFC 7540,现为 9113

      • 二进制分帧:把 HTTP 消息拆成二进制帧(HEADERSDATA 等),替代 HTTP/1.1 的纯文本格式
      • 多路复用(Multiplexing :多个请求/响应可以在同一个 TCP 连接上并行交错传输,解决了应用层的队头阻塞
      • 头部压缩(HPACK :压缩首部(请求和响应两侧),减少重复头部传输
      • 服务器推送(Server Push :规范层面仍保留(RFC 9113 §8.4),但 Chrome 106(2022-09)Firefox(2022)已移除实现、Safari 从未实现,实际未普及;HTTP/3 无此功能,业界替代是 103 Early HintsRFC 8297
      • 流优先级RFC 7540 的依赖-权重方案已被 RFC 9218Extensible Prioritization2022)取代(原方案"并不成功")
      • 局限:虽然解决了应用层队头阻塞,但 TCP 层队头阻塞仍然存在——TCP 保证数据有序,一个 TCP 包丢失会导致后续所有包等待重传,即使它们属于不同的请求流
    • HTTP/3(2022,RFC 9114)

      • 传输层改用 QUIC 协议(RFC 9000,承载于 UDP 之上)替代 TCP
      • 解决 TCP 层队头阻塞:QUIC 在用户空间实现可靠传输和有序交付,但丢失的包只影响它所在的流,其他流不受影响
      • 0-RTT 连接恢复:基于 TLS 1.3 会话恢复票据(PSK),第二次连接可免握手直接发送数据(注意 0-RTT 有重放风险,RFC 9001
      • 连接迁移:QUIC 用连接 ID 标识连接,IP 地址变化(如 Wi-Fi 切到移动网络)连接不中断
      • 内建 TLS 1.3:加密是 QUIC 的强制部分,没有明文 HTTP/3
      • 头部压缩用 QPACKRFC 9204)而非 HPACK(应对乱序到达的首部)
      • 部署现状:W3Techs 2026-08 数据显示约 40% 的网站已支持 HTTP/3
    • 四代对比速览

      • 1.0:短连接,一请求一连接
      • 1.1:持久连接,但有队头阻塞
      • 2:多路复用(解决应用层队头阻塞),基于 TCP
      • 3:多路复用 + 解决传输层队头阻塞,基于 UDP/QUIC
  • 协助记忆

    • 一代一痛点:1.0 连接费(短连接)→ 1.1 连接省(持久连接)但排队(队头阻塞)→ 2 并行(多路复用)但堵在 TCP3 换路(QUIC/UDP)彻底不堵
    • 队头阻塞有两个层面:应用层(HTTP/1.1FIFO)和传输层(TCP 包丢失重传) ——— HTTP/2 解决前者,HTTP/3 解决后者
  • 进阶思考

    • 为什么 HTTP/2 多路复用后还要升级到 HTTP/3

      • HTTP/2 解决的是应用层队头阻塞——多个请求可以在一个 TCP 连接上并行,不需要按序等待。但 TCP 本身有传输层队头阻塞:TCP 保证数据按序交付,如果某一个 TCP 段丢失,接收方必须等待该段重传才能继续处理后续数据,即使这些数据属于完全不同的请求流。在丢包率高的弱网环境(移动网络)这个问题尤其严重。HTTP/3QUICUDP)解决了这个问题——每个流独立处理,一个流的丢包不影响其他流
    • HTTP/3 用了 UDP,可靠性和顺序性怎么保证?

      • QUICUDP 之上自己实现了可靠传输和有序交付——它有类似 TCP 的序号、确认、重传机制,但作用域是"流"而不是整个连接。每个流独立编号、独立确认、独立重传,所以一个流的丢包只重传该流的数据,不影响其他流。这也是 QUIC 解决队头阻塞的本质:把 TCP 的"全局有序"变成 QUIC 的"流内有序"

🤔 HTTP 有哪些常见的状态码?

  • HTTP 状态码是服务器在响应中返回的三位数字,用于告知客户端请求的处理结果。按首位数字分为五类:1xx(信息)、2xx(成功)、3xx(重定向)、4xx(客户端错误)、5xx(服务器错误)。

    • 1xx:信息性响应

      • 100 Continue:客户端可以继续发送请求体
      • 101 Switching Protocols:协议切换(如升级到 WebSocket
      • 103 Early Hints:提前发送提示(如预加载资源链接),配合 301/308 重定向场景做性能优化
      • 日常运维很少直接见到 1xx,多由协议层内部处理
    • 2xx:成功

      • 200 OK:请求成功,最常见
      • 201 Created:资源创建成功(常用于 POST 创建资源)
      • 202 Accepted:请求已接受但尚未处理完成(异步任务)
      • 204 No Content:请求成功但无内容返回(常用于 DELETE、以及 POST/PUT 的"成功无内容"场景)
    • 3xx:重定向

      • 301 Moved Permanently:永久重定向,后续请求应使用新 URL(默认允许缓存,受 Cache-Control 控制)
      • 302 Found:临时重定向,后续请求仍用原 URL
      • 303 See Other:方法强制改为 GETSHOULD use GETRFC 9110 §15.4.4)——常用于表单提交后重定向到结果页
      • 304 Not Modified:资源未修改,可使用缓存(配合 If-Modified-Since / ETag
      • 307 Temporary Redirect:临时重定向,且保留请求方法和请求体
      • 308 Permanent Redirect:永久重定向,且保留请求方法和请求体
      • 方法语义完整图谱301/302MAY 改方法)→ 303SHOULDGET)→ 307/308(必须保留方法)
    • 4xx:客户端错误

      • 400 Bad Request:请求语法错误,服务器无法或不愿处理
      • 401 Unauthorized:未认证(未登录或凭据无效)。注意:401 是"没证明你是谁",403 是"不让进"
      • 403 Forbidden:服务器理解请求但拒绝处理/授权——常因权限不足,但也可能是未认证、IP 封禁、WAF 拦截;未认证时服务器也可能返回 403 而非 401(如不想暴露资源存在性)
      • 404 Not Found:资源不存在,最常见
      • 405 Method Not Allowed:请求方法不被允许(如对只读接口发 POST
      • 408 Request Timeout:请求超时
      • 409 Conflict:请求与当前资源状态冲突(如版本冲突)
      • 410 Gone:资源已永久删除(区别于 404 的"不存在",410 是"曾经存在但没了")
      • 413 Content Too Large:请求体过大(RFC 9110 新名,旧名 Payload Too Large 仍广泛使用)
      • 429 Too Many Requests:请求过多,触发限流(RFC 6585 定义,常配合 Retry-After 头)
    • 5xx:服务器错误

      • 500 Internal Server Error:服务器内部错误,通用错误码
      • 501 Not Implemented:服务器不支持请求的方法
      • 502 Bad Gateway:网关/代理收到上游服务器的无效响应(Nginx 作为反向代理时常见)
      • 503 Service Unavailable:服务暂时不可用(过载、维护中),常配合 Retry-After 头,通常过一段时间会恢复
      • 504 Gateway Timeout:网关/代理等待上游响应超时
  • 协助记忆

    • 五位分类1 信、2 成、3 转、4 客户错、5 服务器错

    • 易混三对

      • 301 vs 308:都是永久,但 301 方法可能变(POST→GET),308 保留方法
      • 302 vs 307:都是临时,302 方法可能变,307 保留方法
      • 401 vs 403``:401 是"你是谁",403 是"不让进"(注:403 不要求已认证,是"拒绝授权")
    • 502 vs 503 vs 504502 是上游答了但答错(无效响应)、503 是自己没空(过载)、504 是上游没答(超时)

  • 进阶思考

    • 301308 到底有什么区别?什么时候用哪个?

      • 核心区别是请求方法是否保留。301(和 302)在重定向时,很多浏览器和客户端会把 POST 请求改为 GET 请求(RFC 使用 MAY,历史行为普遍存在);303 明确要求改用 GET308(和 307)明确要求保留原方法和请求体。实践中:永久迁移且希望客户端用新 URL 重新发起 GET 请求,用 301API 场景希望 POST/PUT 的请求体和方法原样转发到新地址,用 308。现代 WebAPI 重定向推荐 308/307 以保证语义一致
    • 反向代理场景,502503504 分别对应什么排查方向?

      • 502(Bad Gateway):上游服务器响应了但响应无效——如上游进程崩溃返回空响应、返回了非法响应格式。排查上游应用是否挂了、端口是否监听。
      • 503(Service Unavailable):本机(代理)或上游过载/维护——如后端连接数打满、限流触发。排查后端负载、连接池。
      • 504(Gateway Timeout):上游没有及时响应——如后端处理超时、慢查询。排查后端应用延迟、数据库慢查询。
      • 一句话502 是上游答了但答错,503 是没空, 504 是没答

🤔 浏览器访问域名经历了哪些流程?

  • 从在地址栏输入域名到页面显示,浏览器经历了一条完整的链路:URL 解析 → DNS 解析 → TCP 连接 → TLS 握手(HTTPS)→ HTTP 请求 → 服务器处理 → HTTP 响应 → 浏览器渲染。每一步都有对应的可排查点。

    • 第一步URL 解析

      • 浏览器解析输入的 URL,拆分成协议(https)、域名(www.example.com)、端口(默认 443)、路径(/index.html)、查询参数等
      • 判断协议是否合法、域名格式是否正确
    • 第二步DNS 解析(把域名变成 IP

      • 按缓存层级逐级查找:浏览器缓存 → 系统解析器(hosts 文件、系统缓存、DNS 服务器的相对顺序由操作系统决定 ——— Windows 通常是 hostsDNS Client 缓存 → DNS 服务器,Linuxnsswitch.conf 默认 files dns 通常 hosts 优先)
      • 客户端向递归 DNS 服务器发起递归查询;递归解析器对根 DNS → 顶级域 DNS.com)→ 权威 DNSexample.comNS)的逐级查询称为迭代查询(浏览器本身不逐级问根服务器)
      • 细节:现代浏览器和系统可能启用 DNS-over-HTTPSDoHRFC 8484),DNS 查询走 HTTPS 加密通道
    • 第三步TCP 连接(三次握手)

      • 拿到 IP 后,浏览器与服务器建立 TCP 连接:SYNSYN-ACKACKRFC 9293
      • 涉及 TCP 相关优化:Fast OpenTFO)、连接复用(keep-alive);若启用 HTTP/3TCP+TLS 合并为 QUIC 一次握手
    • 第四步TLS 握手(HTTPS 专属)

      • HTTPS 下进行 TLS 握手(以 TLS 1.3 为主,现行规范 RFC 9846):

        • 客户端发送 ClientHello(支持的加密套件、TLS 版本、key_share 密钥共享)
        • 服务器返回 ServerHello(含密钥共享)、证书;证书在加密消息中发送(EncryptedExtensionsCertificateCertificateVerifyFinished
        • 客户端验证证书(信任链、域名匹配、有效期)
        • 双方确认,握手完成,开始加密通信
      • 注:TLS 1.2 流程是"独立的密钥交换回合(ECDHE 等)",TLS 1.3 把密钥共享直接放进 ClientHello/ServerHello,更快更简洁

      • TLS 1.3 首次握手 1-RTT、会话恢复 0-RTT(注意 0-RTT 有重放攻击风险,规范要求默认禁用,浏览器默认不开 early data

    • 第五步:发送 HTTP 请求

      • 浏览器构造 HTTP 请求(方法、URL、头部、cookie),通过已建立的加密通道发送
      • 经过 CDN 时,请求先到最近的 CDN 节点,CDN 命中缓存则直接返回,未命中则回源
    • 第六步:服务器处理

      • 请求到达服务器(或反向代理 Nginx),经过:负载均衡 → Web 服务器 → 应用代码 → 数据库/缓存查询
      • 服务器生成响应(状态码、响应头、响应体)
    • 第七步HTTP 响应返回

      • 服务器返回响应:状态码(200/404/500 等)、响应头(Content-TypeCache-ControlSet-Cookie 等)、响应体(HTML
      • 浏览器判断状态码2xx 正常渲染,3xx 跟随重定向(重新走流程),4xx/5xx 显示错误页
    • 第八步:浏览器渲染

      • 解析 HTML 构建 DOM
      • 解析 CSS 构建 CSSOM
      • DOM + CSSOM 合并生成渲染树(Render Tree) (注:Render TreeWebKit/Blink 的实现术语,非统一 Web 标准定义,GeckoFrame tree
      • 布局(Layout/Reflow) :计算每个元素的几何位置
      • 绘制(Paint) :绘制到屏幕
      • 合成(Composite) :把各层合并呈现 ——— transform/opacity 动画只触发合成,不触发重排重绘
      • 脚本与样式对渲染的影响<script>parser-blocking(阻塞 DOM 解析进而阻塞渲染,除非 async/defer<script type="module"> 默认 defer),但现代浏览器有预加载扫描器提前并行下载脚本(下载并行、执行阻塞);CSSrender-blocking 但不阻塞 DOM 构建
      • JavaScript 执行修改 DOM/CSSOM 会触发重排(Reflow)和重绘(Repaint
  • 协助记忆

    • 八步链路:拆 URL → 查 DNS → 连 TCP → 握 TLS → 发请求 → 服务器处理 → 收响应 → 渲染页面
    • “三握一握”TCP 三次握手 + TLS 一次握手(HTTPS 专属)
    • 渲染五步DOM(结构)→ CSSOM(样式)→ Render Tree(合并)→ Layout + Paint(画出来)→ Composite(合成呈现)
    • 排查口诀:访问慢,先看 DNS 快不快,再看 TCP/TLS 握多久,再看服务器响应时间,最后看渲染卡不卡
  • 进阶思考

    • 为什么 HTTPS 站点首次访问比 HTTP 慢?慢在哪?

      • HTTP 只需 TCP 三次握手(1RTT);HTTPS 除了 TCP 还要 TLS 握手 ——— TLS 1.2 需要 2RTTTLS 1.3 需要 1RTT(首次),加上 TCP 总共 2~3RTT 才能发出第一个请求。RTT 越大(物理距离越远),差距越明显。优化手段:TLS 1.3 会话恢复(0-RTT,需权衡重放风险)、HTTP/3QUICTCP+TLS 合并为一次握手)、连接复用与 TFO。在 HTTP/3 或连接复用场景下 HTTPSHTTP 差距已不明显,但全新连接下 HTTPS 仍多约 1RTT
    • 输入域名后浏览器直接显示"无法访问此网站",最可能是哪一步出了问题?

      • 按经验上最常见的顺序:一是 DNS 解析失败(域名拼错、DNS 服务器故障、本地 hosts 被改)——浏览器提示"找不到服务器 IP 地址";二是 TCP 连接失败(服务器宕机、端口不通、防火墙拦截)——— 提示"连接超时"或"连接被拒绝";三是 TLS 握手失败(证书过期、不受信任)——提示"您的连接不是私密连接";四是服务器返回 5xx 错误(有响应但处理失败)。浏览器通常给出具体错误提示,根据提示即可定位到是哪一步

🤔 HTTP 请求头和响应头有哪些内容?

  • HTTP 头部(Header)是请求/响应中"键值对"形式的元数据,用于传递请求上下文、内容描述、缓存策略、认证信息等。现代分类(RFC 9110)不再使用传统的"通用头/实体头"分类,头部按用途分为请求头、响应头、表示头、内容头等;本文按常见场景组织,仍会说明新旧分类对应关系。

    • 请求行 / 状态行结构(头部之前)

      • 请求行GET /index.html HTTP/1.1(方法 + 路径 + 版本)
      • 状态行HTTP/1.1 200 OK(版本 + 状态码 + 原因短语)
    • 请求头(客户端 → 服务器)

      • Host:目标主机和端口(HTTP/1.1 必需,虚拟主机依据)
      • User-Agent:客户端标识(浏览器/版本/操作系统)
      • Accept:客户端可接受的内容类型(如 text/htmlapplication/json
      • Accept-Encoding:客户端支持的压缩算法(gzipbrzstd —— 2024-2025 主流浏览器已支持)
      • Accept-Language:客户端语言偏好
      • Content-Type / Content-Length:请求体类型和长度(POST/PUT 时;注意这属于"表示头/内容头",同一字段在请求和响应中含义一致)
      • Authorization:认证凭据(Bearer tokenBasic
      • Cookie:客户端携带的 cookieRFC 6265 定义,注意不是 RFC 9110
      • Referer:来源页面 URL(注意拼写是 Referer 而非 Referrer
      • Origin:跨域请求的来源(协议+域名+端口,CORS 用)
      • X-Forwarded-For:经过代理时的原始客户端 IP(非标准头,事实标准;标准替代为 ForwardedRFC 7239
    • 响应头(服务器 → 客户端)

      • Content-Type / Content-Length:响应体类型和长度
      • Set-Cookie:服务器设置 cookie(RFC 6265 定义,含 Secure、HttpOnly、SameSite 等属性)
      • Location:重定向目标地址(3xx 响应;也用于 201 Created 返回新资源地址)
      • Cache-Control:响应缓存策略(RFC 9111 定义)
      • ETag:资源版本标识(配合 If-None-Match 缓存验证;也配合 If-Match 做乐观并发控制)
      • Last-Modified:资源最后修改时间(配合 If-Modified-Since)
      • Expires:缓存过期时间(HTTP/1.0 遗留,被 Cache-Control 取代)
      • Server:服务器软件信息
      • Date:响应时间
      • Access-Control-Allow-Origin:CORS 允许的跨域来源
      • Retry-After:多久后重试(配合 429/503)
      • Strict-Transport-Security:强制 HTTPS(HSTS,RFC 6797)
    • 传统分类与新分类的对应(旧文档常见,帮助理解)

      • 传统四分类:通用头、请求头、响应头、实体头
      • RFC 9110 已同时废弃"通用头"和"实体头"概念,重构为:请求头、响应头、表示头(Representation,描述资源表示,如 Content-Type、ETag、Last-Modified)、内容头(Content,描述消息内容,如 Content-Length)、验证器字段(Validator,ETag/Last-Modified 单独归为验证器)
      • 旧教材把 ETag 归入实体头是简化说法,严格按 RFC 2616 ETag 是响应头
    • 常见安全响应头(现代 Web 标配)

      • CSP(Content-Security-Policy) :内容安全策略,限制资源加载来源
      • X-Content-Type-Options: nosniff:禁止 MIME 嗅探
      • X-Frame-Options / frame-ancestors:点击劫持防护
      • Referrer-Policy:控制 Referer 发送策略
      • Permissions-Policy:限制浏览器功能权限
      • COOP/COEP/CORP:跨源隔离相关头
  • 协助记忆

    • 请求头记一组HostUAAccept 家族、CookieAuthorization——“你是谁、要什么、带什么”
    • 响应头记一组Content-TypeSet-CookieLocationCache-ControlETag ——— “给你什么、让你存什么、跳去哪”
    • 排查缓存问题看这四个Cache-ControlETagLast-ModifiedExpires
    • 区分两个"内容"Content-Type(媒体类型)≠ Content-Length(字节长度)
  • 进阶思考

    • CookieAuthorization 都能传递身份信息,有什么区别?

      • 机制不同。Authorization 是请求头,每次请求由客户端代码显式携带(如 Bearer token),无状态、常用于 APICookie 是浏览器自动管理的状态机制——服务器 Set-Cookie 后,浏览器自动在后续请求中带上对应域名的 cookie,有状态、常用于 Web 会话。Cookie 会自动附加到同域请求(不受代码控制),Authorization 需要代码显式添加。安全上:Authorization 适合 API tokenCookie 需配合 Secure/HttpOnly/SameSite 防窃取
    • Nginx 反代场景,如何保证后端能看到真实客户端 IP

      • Nginx 在转发请求时把客户端真实 IP 写入 X-Forwarded-ForX-Real-IP 头,后端应用从这些头读取。但 X-Forwarded-For 是可伪造的——客户端可以直接构造这个头。安全做法:在 Nginx 层用 set_real_ip_from + real_ip_header 处理,或在信任的代理边界重写 X-Forwarded-For(不要直接信任客户端传入的值)。这是反代场景的常见安全坑

🤔 网站显示中文乱码会是什么原因?

  • 中文乱码的根本原因是编码不一致——网页的字节是按 A 编码写入的,但浏览器用 B 编码解读,导致字节序列被错误解码。排查方向就是找出"写入编码"和"读取编码"哪里对不上。

  • 编码机制速览(先理解再排查)

    • UTF-8:现代标准,兼容 ASCII,中文字符占 3 字节,全栈默认。2025-2026UTF-8 已占全网超 98%,且 Encoding 标准已把 UTF-8 定为新协议的强制编码
    • GBK / GB2312:中文传统编码,中文字符占 2 字节,旧系统常见(注意 GBKGB2312 的超集,现行国标是 GB18030
    • 乱码的本质:同一串字节,用不同编码解读得到不同字符
  • 常见原因一HTML 文件内部声明与实际编码不符

    • HTML 文件实际以 UTF-8 保存,但 <meta charset="GBK"> 声明为 GBK(或反过来)——浏览器按声明解码,乱码
    • 注意 file 命令的局限:file 能可靠识别 UTF-8/UTF-16(靠 BOM 和字节特征),但对 GBK 等东亚双字节编码通常只报含糊的 “ISO-8859 text” 或 “data"。排查 GBK 更可靠的方式:用 iconv -f GBK -t UTF-8 文件 和 iconv -f UTF-8 -t GBK 文件 双向试转,看哪个方向能转出正常文字;或用 chardet / uchardet 检测
    • 修复:统一文件保存编码和 meta 声明
  • 常见原因二HTTP 响应头 charsetmeta 声明冲突

    • HTTP 响应头 Content-Type: text/html; charset=UTF-8HTMLmeta 声明不一致时,HTTP 头的优先级更高
    • 排查curl -I <url> 查看响应头 charsetcurl -s <url> | head -20 查看 meta 声明
    • 修复:让两者一致(改 Nginx/应用配置或改 meta
    • 补充:还有更高优先级的 BOM ——— 文件开头的 UTF-8 BOM 优先级高于包括 HTTP 头在内的一切声明。这是"改了 meta 还是乱码"的另一个隐蔽原因
    • meta 声明必须位于文件前 1024 字节内才生效
  • 常见原因三:数据库存储编码与连接编码不一致

    • 数据库表是 UTF-8,但应用连接数据库时用了错误的连接字符集(如 latin1),导致"存进去是乱码"或"读出来是乱码”
    • 机制(MySQL:服务器按 character_set_client 解释客户端发来的字节,再转 character_set_connection,最后转目标列字符集;读出的结果由 character_set_results 决定
    • 排查SHOW VARIABLES LIKE 'character_set%' 查看各字符集配置
    • 修复:连接时 SET NAMES utf8mb4(同时设置 client/connection/results 三个变量);建库时 CREATE DATABASE ... DEFAULT CHARACTER SET utf8mb4
    • 注:MySQL 8.0+ 默认即 utf8mb4,旧的 utf8utf8mb3)已废弃、未来大版本移除
  • 常见原因四:编码被二次转换

    • 数据经过多个环节时,某个环节做了一次错误的编码转换
    • 是否可逆取决于原始字节是否被改写:纯显示层乱码(字节仍是原始 UTF-8,只是被按 GBK 显示)可逆 ——— 著名例证是"锟斤拷" (UTF-8 替换符被按 GBK 显示);只有经真实转码(如 iconv 转错后落库)才不可逆
  • 常见原因五:页面完全没有编码声明

    • HTTP 头无 charsetHTML 内也无 meta 声明时,浏览器按默认(现代浏览器默认 UTF-8)尝试解码,非 UTF-8 字节就会乱码
    • 这比"用户改了浏览器设置"常见得多——排查时先确认页面是否有编码声明,而不是去查浏览器设置
  • 协助记忆

    • 一句话:乱码 = 写的时候用 A 编码,读的时候用 B 编码,对不上
    • 读取侧优先级(从高到低) :HTTPcharsetBOMmeta 声明 → 默认 UTF-8
    • 写入侧检查:文件实际编码(iconv 双向试转)、数据库/连接字符集
    • 排查命令:curl -I 看响应头、iconv -f X -t Y 文件 试转换、chardet 检测
    • utf8mb4 记住:MySQLemoji 必须用 utf8mb4 而非 utf8
  • 进阶思考

    • HTTP 响应头 charsetHTML meta charset 哪个生效?

      • HTTP 响应头的 Content-Type: text/html; charset=xxx 优先级更高——浏览器先看 HTTP 头,如果 HTTP 头没有明确 charset,才看 HTML 内的 meta 声明。但注意 BOM 优先级最高:文件开头的 UTF-8 BOM 会覆盖包括 HTTP 头在内的一切声明。所以"改了 meta 还是乱码"要查两个地方:HTTP 头里的旧 charset、文件是否带 BOM
    • 数据库已经是 UTF-8,为什么页面还乱码?

      • 存储编码和连接编码是两回事。表字符集是 UTF-8 只保证数据以 UTF-8 存,但写入时服务器按 character_set_client(连接时声明的客户端字符集)解释应用发来的字节——如果连接用的还是 latin1GBK,写入时就错了。MySQL 排查:character_set_server(服务器默认)、character_set_database(当前库)、character_set_client/connection/results(连接链路)。统一 SET NAMES utf8mb4 + 建库指定 utf8mb4 通常能解决

🤔 网站访问很慢,该如何排查?

  • 网站访问慢的排查要遵循"分层定位"思路:把一次访问拆成多个阶段,先定位慢在哪一层(DNS?网络?服务器?数据库?),再针对该层深入。不要一上来就盯着服务器 CPU——很多"网站慢"其实是网络或前端问题。

    • 第一步:先量化"慢"在哪——用 curl 计时

      • curl -o /dev/null -s -w 'DNS: %{time_namelookup}s\nTCP: %{time_connect}s\nTLS: %{time_appconnect}s\nTTFB:%{time_starttransfer}s\nTotal: %{time_total}s\n' https://example.com

      • 重要:这些变量是"从 curl 启动到该阶段完成的累计时间",不是各阶段本身耗时。要算阶段耗时需做差:

        • DNS 解析耗时 = time_namelookup
        • TCP 握手耗时 = time_connecttime_namelookup
        • TLS 握手耗时 = time_appconnecttime_connect
        • 服务器处理时间 = time_starttransfertime_appconnect(近似)
      • TTFB(time_starttransfer) :从 curl 启动到收到第一个字节的累计时间,包含 DNS 查询 + TCP 握手 + TLS 握手 + 服务器处理(MDN 定义)

      • 判断方法DNS 差值长 → DNS 问题;TCP 差值长 → 网络问题;DNS/TCP/TLS 各阶段差值都正常但 TTFB 仍长 → 服务器处理慢;Total 长但 TTFB 正常 → 响应体传输慢(带宽/大文件)

    • 第二步:按阶段定位

      • DNSdig + time = 2 example.com 看解析耗时,dig @8.8.8.8 example.com 对比公共 DNS;检查本地 DNS 服务器、递归解析器、上游权威、DNSSEC;考虑 DoH/DoT。注意:智能 DNS/CDN 解决的是"解析到哪个节点"的调度准确性,不直接加速解析耗时本身
      • 网络慢pingRTTmtr 看中间链路是否有丢包或高延迟节点;跨地域访问考虑 CDN2025 新坑:HTTP/3UDP,部分网络对 UDPQoS 限速/防火墙拦截——如果 time_connect 长但 ping 正常,可怀疑 UDP 被限速
      • 服务器响应慢(TTFB 高) :进入服务器端排查(第三步)
      • 传输慢(TotalTTFB 长) :响应体太大、带宽不足、压缩未开(gzip/brotli)、大图片未优化
    • 第三步:服务器端深入

      • Nginx 层

        • 先确认日志格式包含耗时字段:默认 combined 格式没有 $request_time,需要在 log_format 中显式配置,如 log_format main '$remote_addr $request_time $upstream_response_time';,然后 awk '{print $2}' access.log | sort -n | tail -20 看最慢的请求(注意取的是配置里的耗时字段列)
        • 检查反向代理超时配置(proxy_read_timeout 等)、upstream 是否有慢节点
      • 应用层

        • 看应用日志的请求处理时间,定位是哪个接口慢
        • 检查应用是否有死锁、线程池打满、GC 频繁(Java)、GIL 阻塞(Python
      • 数据库层

        • 开慢查询日志,看是否有全表扫描、缺索引的 SQL
        • SHOW PROCESSLIST 看是否有长时间运行的查询
        • 检查数据库连接池是否打满(连接等待导致 TTFB 升高)
      • 缓存层

        • Redis/缓存是否生效(缓存命中率低会导致每次都打数据库)
        • 缓存穿透/击穿/雪崩
      • 资源层

        • top/freeCPU、内存是否打满
        • iostat 看磁盘 IO 是否瓶颈
        • 连接堆积用 ss -s(汇总统计)或 ss -ant state established | wc -l 看连接数(注意 ss -lntp 只显示监听中的 socket,看不到 ESTABLISHED 堆积;-lntpSend-Q 列可看 backlog 溢出)
    • 第四步:前端/浏览器侧(如果服务器很快但用户觉得慢)

      • Chrome DevToolsNetwork 面板:看每个资源的加载时间,Waterfall(瀑布图)能看出哪些资源是瓶颈
      • Core Web Vitals2025 年核心指标)LCP(最大内容绘制)、INP(交互延迟,2024 年取代 FID)、CLS(布局偏移)——用 LighthouseRUMCrUX 字段数据)审计
      • 常见前端问题:页面引用了太多大资源、图片未优化、未用 CDN、缓存策略未配置
      • 注意HTTP/2 时代"JS/CSS 合并文件"已不必要(多路复用下合并反而有害),现代实践是 bundling + code splitting + tree-shaking + 按需加载
      • 补充103 Early Hints 可提前 TTFBServer-Timing 响应头可暴露服务端耗时
  • 协助记忆

    • 分层定位口诀:先 curl 计时做差分层,再按层深挖 ——— DNS 慢查解析,TCP 慢查网络,TTFB 慢查服务器,Total 慢查传输
    • curl 变量是累计值,算阶段要"做差"TCP = connectnamelookupTLS = appconnectconnect,服务器 = starttransferappconnect
    • 排查顺序:网络层 → 服务器层 → 数据库层 → 缓存层 → 前端层,别跳过
  • 进阶思考

    • TTFB 高但服务器 CPU/内存都正常,可能是什么原因?

      • TTFB 包含网络 RTT + 服务器处理。如果 CPU/内存正常,可能的隐藏原因:一是数据库慢查询——请求卡在等数据库返回,但数据库 CPU 不高(如缺索引全表扫描、锁等待);二是外部依赖慢——应用调第三方 API,等外部响应;三是连接池/线程池打满——请求排队等待可用连接;四是磁盘 IO——日志或缓存写盘慢。排查:看应用日志确认请求在等什么,必要时用 APM(链路追踪)定位耗时分布
    • 用户分布广(全国/全球),如何区分是"网站慢"还是"用户网络慢"?

      • 用多点拨测——在不同地域的机器上执行同样的 curl 计时(云厂商都有多地拨测工具)。如果所有地域 TTFB 都高 → 服务器端问题;如果只有某些地域高 → 网络/CDN 节点问题(该地域到服务器链路差,或 CDN 在该地域节点少)。这是"网站慢"与"网络慢"的经典区分方法

🤔 QPS、TPS、PV、UV 是什么?怎么统计?

  • QPS/TPS 是实时性能指标(衡量系统处理能力),PV/UV 是业务流量指标(衡量用户访问量)。两者维度不同,但常放在一起讨论。

  • QPSQueries Per Second,每秒查询数)

    • 含义:系统每秒处理的请求/查询数量,衡量系统吞吐能力

    • 注意QPS 在不同语境含义不同 ——— Web 场景指每秒 HTTP 请求数(严格说这是 RPSRequests Per Second),数据库场景指每秒 SQL 查询数。中文语境常混用,面试和讨论中要明确语境

    • 统计方法

      • 监控系统Prometheus + nginx-prometheus-exporter(从 nginx stub_status 取数,nginx_http_requests_total 速率为 QPS)或应用埋点
      • Nginx access log:按时间窗口统计日志条数
      • 压测工具abwrkJMeter 直接报 QPS
    • 相关概念:峰值 QPS(扩容依据,行业更常用最大 5 分钟窗口均值或 TP99,而非秒级瞬时毛刺值)vs 平均 QPS(容量规划参考)

  • TPSTransactions Per Second,每秒事务数)

    • 含义:系统每秒处理的事务数量。事务是业务层面的完整操作,一个事务可能包含多个请求/查询
    • 典型:一次下单 = 一个事务,但可能包含"查库存 + 扣款 + 生成订单 + 通知"等多个请求
    • 通常 TPSQPS(一个事务由多个请求组成时),但取决于事务定义与接口粒度——批量/批处理接口(一个 HTTP 请求处理 N 笔转账)会出现 TPS > QPS
    • 统计方法:应用埋点(在事务完成点打点)、APM 工具
    • 适用:电商下单、支付、银行转账等有明确"事务边界"的业务
  • PVPage View,页面浏览量)

    • 含义:页面被浏览的次数。每次刷新/打开页面都算一次 PV,同一用户重复浏览累加

    • 统计方法

      • Nginx access log:统计 HTML 页面请求数(需过滤静态资源、排除非 2xx、过滤爬虫)
      • 前端埋点 / RUM(真实用户监测)
    • 爬虫污染2025AI 爬虫(GPTBotClaudeBot 等)激增,严重污染 PV/UV 统计,行业标准做法是 UA 白名单过滤

    • 注意 PVQPS 不能直接换算:1PV(页面加载)通常产生 1HTML + 数个静态资源/接口请求(1 PV5~20 个请求);容量规划估算:峰值 QPS ≈(日均 PV × 页面平均请求数 × 峰值系数)/ 86400

  • UVUnique Visitor,独立访客数)

    • 含义:去重后的独立访客数,同一用户只算一次

    • 统计方法(去重口径,不同口径结果不同)

      • 基于 Cookie / 第一方标识:给访客分配唯一 ID 去重。2025 年隐私环境下的主流已演变为"第一方 Cookie + 登录 ID + 设备指纹"的混合识别(GA4 等基于 first-party 标识去重)——— 因为第三方 CookieSafari/Firefox 默认拦截、GDPR/个保法限制下受限(Chrome 2024 年放弃强制淘汰第三方 Cookie2025 年终止 Privacy Sandbox 计划)
      • 基于 IP:按 IP 去重(不准确 —— NAT 后多人同 IP1 个;同一人换 IP 算多个)
      • 基于用户登录 ID:最准确,但只能统计登录用户
    • 注意:UV 是"人"的维度,PV 是"次"的维度。PV/UV 比值 = 人均浏览页数 ——— 不能简单解读为"内容吸引",比值高也可能因导航差反复点击、长文分页;需结合跳出率、停留时长解读

  • 四个指标的维度对比

    • QPS:系统处理能力(实时、按请求数)
    • TPS:业务事务处理能力(实时、按事务数)
    • PV:页面访问量(累计、按次数)
    • UV:独立访客数(累计、按人去重,与 QPS 无换算关系)
  • 协助记忆

    • QPS 是"每秒能扛多少请求",TPS 是"每秒能完成多少业务",PV 是"被看了多少次",UV 是"有多少人来看"
    • QPS/TPS 看系统强不强,PV/UV 看业务火不火
    • PV/UV 比值:人均看几页,需结合跳出率解读
  • 进阶思考

    • 如何从 Nginx access log 统计 QPSPV

      • combined 格式时间戳如 10/Feb/2025:14:23:45$4 是完整时间戳。按分钟统计:awk '{print $4}' access.log | cut -d: -f2-3 | sort | uniq -c(必须 sortuniq,多 worker 写日志时同分钟行不连续,不 sort 会重复计数);按秒看峰值:cut -d: -f2-4 | sort | uniq -c | sort -rn | head。统计 PV:过滤静态资源 + 非 2xx + 爬虫 ——— grep -E '\.(html|htm)'URLquery string 或动态路由站点会失效,更可靠的是按 URL 类型/路径前缀区分或用 GoAccessELK 等分析工具。QPS 更推荐用监控系统(nginx-prometheus-exporter)而非日志
    • UV 统计中"基于 Cookie“和"基于 IP“哪个更准确?为什么行业多用 Cookie

      • 基于 Cookie 更接近真实人数,是行业主流——因为 IPNAT 场景下多人共享一个 IP(会被算成 1UV),而同一用户在不同网络下 IP 会变(会被算成多个 UV),IP 口径误差大。Cookie 的问题是用户清浏览器缓存会重新计数(略微高估)、禁 Cookie 则无法统计。2025 年隐私环境下的主流是"第一方 Cookie + 登录 ID + 设备指纹"混合识别(GA4 基于 first-party 标识去重),第三方 CookieSafari/Firefox 拦截和法规限制已不可依赖
  • 扩展信息

    • ·

      • Apache HTTP Server 自带的基准测试工具,单进程模型(-cfork 子进程,非线程),无 HTTP/2
      • 官方自认"未完整实现 HTTP/1.x"、解析脆弱——定位是快速冒烟测试(“给你当前 Apache 安装表现的一个印象”),不适合严谨压测
      • 适用:随手测一下吞吐量。2025 年已属过时,正式压测选下面这些
    • wrk / wrk2

      • wrk:多线程 + epoll/kqueue 事件驱动,单颗多核 CPU 即可产生高负载,LuaJIT 脚本定制请求
      • 维护状态:长期未实质更新(wrk 停留在 2014 年前后);wrk2 是事实上的标准改进 fork ——— 恒定吞吐(-R 参数)+ HdrHistogram 精确延迟记录,修复"协调遗漏(Coordinated Omission)",可报 99.9999% 分位延迟
      • 适用:命令行快速吞吐/延迟测试;要正确的高分位延迟用 wrk2
    • JMeter

      • Apache 开源、纯 Java 的全功能负载测试工具,从 Web 扩展到 JDBC/JMS/FTP/LDAP/TCP 等十余种协议
      • 图形化 Test IDE + CLI 无头模式 + 动态 HTML 报告,Groovy/JSR223 脚本化,高度可扩展
      • 注意:官方明确”JMeter is not a browser” ——— 协议层工作,不执行 JS
      • 适用:功能/负载测试一体化、多协议、团队 GUI 协作(重量级)
    • 现代压测工具(2025 年主流)

      • k6(最活跃)Go 内核 + JS 脚本"tests as code",HTTP/WebSocket/gRPC/Browser,阈值/SLOCI 集成,2025 年事实上的新一代主流
      • Locust(活跃,Microsoft 赞助):纯 Python 写场景,gevent 协程 + Web UI + 分布式,适合高并发用户模拟
      • VegetaGo,恒定速率 + UNIX 组合式 CLI + Go 库,内置 Prometheus exporter
      • heyGo 单文件,自称 “ApacheBench (ab) replacement",HTTP/2、限速、CSV 输出,小而够用
      • oha(活跃)Rust + tokio,实时 TUIHTTP/2/3(实验)、burst--latency-correction(同样修复协调遗漏)
      • 高分位延迟的正确性wrk2 / Vegeta / oha 都处理协调遗漏,abwrk 不处理
    • APMApplication Performance Monitoring,应用性能监控)

      • 核心能力四件套:链路追踪(跨服务请求流、瓶颈、根因、依赖分析)、性能剖析(方法级 CPU/内存 profiling)、错误监控(异常捕获、聚合、告警)、指标 + 仪表盘 + 告警
      • JaegerCNCF 毕业项目,纯分布式追踪平台,已发 v2、原生拥抱 OpenTelemetryOTLPClickHouse 存储后端) ——— 轻量自托管选它
      • SkyWalking / PinpointJava agent 无侵入字节码注入,覆盖 trace + 指标 + 日志 + profiling 的全栈 APM ——— 全栈自托管选它们
      • Datadog APM / New Relic:商业 SaaS,自动埋点 + 分布式追踪 + 错误监控 + 持续剖析 + SLO/告警的托管全栈——省事省运维选它们

    一句话选型:快速冒烟测试用 ab;命令行脚本化压测用 wrk/wrk2heyCI 常态化压测首选 k6Python 团队用 Locust;多协议/团队协作用 JMeter;自托管链路追踪用 Jaeger;全栈 APM 自托管用 SkyWalking

🤔 简述 HTTP 和 HTTPS 区别?

  • HTTPHTTPS 的核心区别:HTTPS 是在 HTTPTCP 之间插入了一层 TLS(旧称 SSL)加密层,保证传输安全。HTTP 是明文传输,HTTPS 是加密传输。

    • HTTP(HyperText Transfer Protocol)

      • 明文传输:请求和响应内容(URL、请求头、Cookie、表单数据、响应体)在网络中以明文传输,可被中间人抓包直接读取
      • 默认端口 80
      • 无身份验证:无法确认你连的服务器就是目标服务器(可能被 DNS 劫持/中间人冒充)
      • 无认证性完整性保护:数据可能被中间人篡改而不被发现(TCP 校验和只能发现传输错误,防不了恶意篡改)
      • 适用:非敏感场景。如今内网也推荐 HTTPS(零信任趋势)
    • HTTPS(HTTP over TLS)

      • 加密传输:在 HTTPTCP 之间加了一层 TLSTransport Layer Security,旧称 SSL) ,数据加密后传输

      • 默认端口 443

      • 提供三方面安全能力

        • 机密性:内容加密,中间人抓包只能看到密文(但 SNI 域名与流量元数据仍可见,这正是 ECH 要解决的——见下文)
        • 完整性AEAD 认证加密(TLS 1.2 及以前用 MAC)保证数据未被篡改
        • 身份认证:通过服务器证书验证服务器身份,防止中间人冒充
      • 证书机制:服务器需要部署 CA(证书颁发机构)签发的证书,包含公钥和服务器身份信息,客户端验证证书的信任链

    • HTTPS 的建立流程(简版)

      • TCP 三次握手 → TLS 握手(协商加密套件、交换密钥、验证证书)→ 加密的 HTTP 通信
      • TLS 1.3 首次完整握手 1-RTTPSK 会话恢复通常仍为 1-RTT;开启 early data0-RTT)可零往返发送幂等请求,但有重放风险、无前向保密,规范要求默认不启用(部分 CDNQUIC 0-RTT 会开启)
    • 性能差异

      • HTTPSHTTP 多一次 TLS 握手开销(首次连接多 1~2RTTTLS 1.31-RTTTLS 1.22-RTT
      • 现代优化(TLS 1.3、会话恢复、HTTP/3 + QUIC 0-RTT)已让差异很小
    • 应用现状(截至 2026 年)

      • HTTPS 已是绝对主流:主流浏览器对 HTTP 站点显示"不安全"警告,搜索引擎降权 HTTP 站点;TLS 1.32018 发布以来已广泛部署,TLS 1.2 是主要回退版本
      • 免费证书普及:Let's Encrypt 提供免费自动化证书(certbot),HTTPS 部署成本几乎为零
      • HSTS 强制浏览器只走 HTTPS ——— 注意其生效前提是首次请求已走 HTTPS(或加入 preload list),否则第一个请求仍可能被 SSL-strip 降级
      • ECHEncrypted Client Hello20263 月标准化为 RFC 9849) :加密整个 ClientHello(含 SNI 域名),配合 DoH 防域名泄露——解决"抓包只见密文但域名仍可见"的最后一块短板。Chrome/Firefox 已默认启用,OpenSSL 4.0nginx 已支持
      • HTTP/3 基于 QUIC,本身就要求 TLS 1.3 加密 ——— 现代 Web 已无"明文 HTTP/3“这回事
  • 协助记忆

    • 一句话HTTPS = HTTP + TLS 加密层,明文变密文
    • 三个安全能力:机密性(加密)、完整性(防篡改)、身份认证(防冒充)
    • 端口记忆80 明文,443 加密
    • 类比HTTP 是明信片(谁都能看内容),HTTPS 是密封信(只有收发双方能看)
  • 进阶思考

    • HTTPS 能防止所有攻击吗?

      • 不能。HTTPS 保护的是传输过程,不保护端点本身 ——— Web 应用漏洞(SQL 注入、XSS)发生在应用层,HTTPS 管不了;钓鱼网站本身就用 HTTPS(有合法证书),HTTPS 只证明"你是连到了证书对应的服务器”,不证明"这个服务器是可信的”。HTTPS 解决的只是"传输中不被偷看、篡改、冒充"
    • 为什么 HTTP/3 没有明文版本?

      • HTTP/3 基于 QUICQUIC 在设计上强制内置 TLS 1.3(加密是协议的一部分,不是可选项)。这和 HTTP/2 不同 ——— HTTP/2 虽然规范支持 h2c(明文),但浏览器从未实现明文 HTTP/2。所以到了 HTTP/3 时代,明文 HTTP 事实上只剩 HTTP/1.1 还在用

🤔 Session 共享是什么?有哪些实现方式?

  • Session 是服务器端保存的用户会话状态(登录状态、购物车、临时数据)。单机部署时 Session 存在本机内存即可;多实例部署时,用户的请求可能落到不同的服务器——如果 Session 只存在某台服务器上,落到其他服务器的请求就"不认识"这个用户了。Session 共享就是把 Session 从单台服务器内存中拿出来,让集群中所有服务器都能访问同一份会话状态。

    • 为什么需要 Session 共享

      • 单机时代Session 存在本机内存,一个进程处理所有请求,天然可用
      • 集群时代:多台服务器 + 负载均衡,请求会分散到不同机器,Session 存在 A 机器,请求落到 B 机器就丢失登录状态
      • 水平扩展:缩容掉持有 Session 的那台机器,用户就被登出
    • 实现方式一Session 复制(已过时,不推荐)

      • 各服务器之间互相复制 SessionTomcat 集群两种实现:DeltaManagerall-to-all,每台机器保存全量 Session)和 BackupManager(只复制到一台备份节点,主备模式)
      • 细节:成员发现/心跳走 multicast(默认 228.0.0.4:45564),会话数据复制走 TCP ——— 大集群下 all-to-all TCP 复制 + multicast 心跳的网络开销剧增
      • 已基本被淘汰,适合小集群
    • 实现方式二Session Sticky(粘性会话,治标不治本)

      • 负载均衡器把同一个用户的请求始终转发到同一台服务器(基于 IP hashCookieURL 参数)
      • 优点:实现简单,Session 仍可存在单台机器内存
      • 缺点:只是"绕开"了问题而不是解决——某台服务器宕机,粘在上面的用户全部掉线;扩容/缩容会破坏 hash 映射(用一致性哈希可大幅减少重映射,如 Nginx hash ... consistent);无法做到真正的负载均衡(热点用户集中在一台机器)
      • 定位:不推荐作为唯一会话方案(云原生场景如 K8s ingress/ALBsticky 仍是常规实践,但通常与集中共享叠加使用)
    • 实现方式三:集中式 Session 存储(主流方案)

      • Session 从各服务器内存中抽出来,存到一个集中存储(Redis / Memcached
      • 所有服务器从同一个地方读写 Session,天然共享
      • Redis 方案(最常用):支持 TTL 过期,正好匹配 Session 的过期机制;读写快、支持集群
      • 框架支持:JavaSpring Session(支持 Redis/JDBC,切换不改应用代码)、Hazelcast/Infinispan(社区扩展)、云托管 Redis
      • 优点:服务器无状态、支持水平扩展、单台服务器宕机不影响其他机器
      • 注意点:Redis 是新的单点——本身需要高可用(主从、哨兵、集群);Session 是热数据,Redis 内存开销需要考虑
    • 实现方式四:客户端存储 / 无状态 Token(趋势方案)

      • 不把会话状态存在服务器,而是放到客户端

        • JWT(JSON Web Token) :签名后的 token 存在客户端(localStorage/Cookie),服务器验证签名即可,无需存储 Session。注意"无法主动失效"是简化说法——严格可用黑名单/jti/版本号实现服务端撤销,但代价是重新引入状态
        • 签名/加密 Cookie 直接存会话数据(如 Rails cookie_storeFlaskDjango signed_cookies):注意这是"消除共享需求"而非"共享"——数据在 Cookie 里服务端已无状态,不应再叫 Session;受 Cookie4KB 大小限制
      • 优点:服务器完全无状态、天然支持分布式、不需要额外 Session 存储

      • 缺点:JWT 主动失效难、token 泄露后有攻击窗口、体积比 Session ID

      • 适用:API/前后端分离场景主流

    • 2026 年演进补充

      • OIDC/SSO(企业认证标准,基于 JWT)成为多应用统一登录的主流方案
      • Passkeys/WebAuthn(无密码认证)兴起,减少对传统 Session/Cookie 的依赖
      • 第三方 Cookie 逐步淘汰对依赖 CookieSession/Sticky 方案有冲击;SameSite 默认 Lax 影响跨站 Cookie 会话
    • 方案对比速览

      • Session 复制:已淘汰(同步开销大)
      • Sticky:临时过渡(宕机掉线、不均衡)
      • Redis 集中存储:主流(服务器无状态、支持扩展)
      • JWT 无状态:趋势(完全无状态、但难失效)
  • 协助记忆

    • Session 共享的本质:把"存在单台机器内存里的会话"搬到"所有机器都能访问的地方"
    • 一条主线Session 存储位置从"服务器内存"→“集中存储(Redis)"→“客户端(JWT)",越来越无状态
    • 选型:传统 Web 应用用 Redis 集中存储(Spring Session);前后端分离/APIJWT
  • 进阶思考

    • RedisSessionJWT 怎么选?

      • 看业务需求。需要主动失效(登出、踢人、封禁)、需要服务端可控(管理在线用户)、传统服务端渲染应用 → RedisSession(服务端可随时删 Session);需要跨域/多端无缝(小程序、AppWeb 共享登录)、追求服务端零存储、API 场景 → JWT。混合方案也常见:JWT 做认证 + Redis 做登出黑名单
    • Session StickySession 共享是二选一吗?

      • 不是,Sticky 是"让请求总去同一台机器"来规避共享问题,Session 共享是"让所有机器共享同一份状态”。两者可以叠加:生产常见做法是 Sticky 保性能 + 集中共享存储保故障转移——正常时请求粘在本地减少跨节点访问,节点宕机时共享存储兜底。但只依赖 Sticky 的方案(宕机全掉线)不可接受

🤔 Tomcat 8005、8009、8080 端口分别作用是什么?

  • Tomcat 的三个经典端口各有分工:8005Shutdown(关闭)端口、8009AJP 端口(与 Apache httpd 集成)、8080HTTP 端口(对外服务)。都在 conf/server.xml 中配置。

    • 8005Shutdown(关闭)端口

      • 作用:用于关闭 Tomcat 的端口。向该端口发送特定的 SHUTDOWN 命令字符串,Tomcat 会优雅关闭。它只接受一个固定的 SHUTDOWN 字符串,没有其他管理能力(真正的管理机制是 JMX,默认随机端口)
      • 配置<Server port="8005" shutdown="SHUTDOWN">,关闭命令字符串默认为 SHUTDOWN
      • 现状8005Tomcat 9/10/11 的默认 server.xml 中始终启用,且默认只监听 localhost(127.0.0.1)。“禁用"是社区加固建议,不是版本默认行为
      • 安全注意:如果配置不当绑定到 0.0.0.0 或防火墙未限制,任何人连接 8005SHUTDOWN 就能关掉 TomcatDoS
      • 加固方式(注意别把 Tomcat 停不掉)
        • 确保监听 127.0.0.1、修改 shutdown 字符串
        • port="-1" 完全禁用该端口 ——— 但注意 catalina.sh stop 默认正是通过 8005SHUTDOWN,禁用后必须:设置 ·(此时 catalina.shkill 路径)、或用 jsvc / Apache Commons Daemon 停止,否则 Tomcat 无法优雅停止
    • 8009AJP 端口(与 Apache httpd 集成)

      • 作用AJPApache JServ Protocol)连接器端口,用于 Tomcat 与前端 Apache httpd 之间的通信(通过 mod_jkmod_proxy_ajp)。注意 Nginx 不支持 AJP ——— NginxTomcat 集成应走 HTTP(proxy_pass)
      • 场景Apache httpd 作为前端静态服务器 + Tomcat 处理动态请求,两者通过 AJP 通信
      • 配置<Connector port="8009" protocol="AJP/1.3" /> ——— 8.5+ 默认 server.xml8009 已注释(需手动启用,默认示例 address="::1"
      • Ghostcat 漏洞(CVE-2020-1938AJP 端口未限制时可读取 webapps 下任意文件甚至执行代码。修复版(9.0.31/8.5.51+)起默认要求 secretsecretRequired 默认 true)且默认只监听 loopback
      • 现状AJP 未被官方废弃(Tomcat 10/11 仍支持),但主要存在于历史遗留架构(Apache httpd + Tomcat 集成);与 HTTP 相比对 HTTP/2 等现代特性支持不足
    • 8080HTTP 连接器端口(对外服务)

      • 作用Tomcat 对外提供 HTTP 服务的默认端口
      • 配置<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
      • redirectPort="8443":当应用配置了 SSL 要求(web.xmlsecurity-constrainttransport-guarantee=CONFIDENTIAL)时,HTTP 请求自动重定向到 8443HTTPS 端口)
      • 默认 8080 而非 80Unix1024 以下端口需 root 权限而 Tomcat 默认非 root 运行(Windows 无此限制),兼为避免与既有 Web 服务冲突
    • Tomcat 10/11 的变化(2020 年后)

      • 最大变化javax.servletjakarta.servlet 包名迁移(Tomcat 10 起),老应用需改包名才能运行
      • 三个端口的机制与默认配置不变8005/8080 默认启用、8009 默认注释
  • 协助记忆

    • 三个端口一句话:8005Tomcat(管理)、8009ApacheAJP 集成)、8080 给用户(HTTP 服务)
    • 80808443 重定向:HTTP 强制跳 HTTPS 时用(redirectPort
    • 安全三查:8005 别绑外网(禁用前先配 CATALINA_PID)、8009 别裸奔(Ghostcat)、8080 按需开放
  • 进阶思考

    • 8005 端口关闭命令的安全性如何保障?

      • 8005SHUTDOWN 默认字符串是固定的 SHUTDOWN,一旦端口可达任何人都能关掉 Tomcat。保障手段:确保监听 127.0.0.1(默认);防火墙限制本机访问;修改 shutdown 字符串;最彻底是 port="-1" 禁用 ——— 但禁用后必须设置 CATALINA_PID 或改用 jsvc,否则 catalina.sh stop 无法优雅停止(它默认走 8005SHUTDOWN
    • 为什么现在很多架构不用 8009 AJP 了?

      • 一是 Ghostcat 漏洞(CVE-2020-1938)暴露了安全风险;二是现代前端架构变了 ——— Nginx 已成为主流反向代理,直接用 proxy_passHTTP(8080)就能完成转发,而且 Nginx 根本不支持 AJP;三是 AJPHTTP/2 等现代特性支持不足。AJP 的优势(减少解析开销)在现代硬件上可忽略。所以 AJP 主要存在于 Apache httpd + Tomcat 的历史架构中

🤔 Tomcat 如何性能优化?

  • Tomcat 性能优化要分层进行:JVM 参数 → 连接器(Connector)→ 应用层 → 操作系统层。核心原则是"先找准瓶颈再优化”,不要盲目调大参数。

    • 第一层JVM 参数优化

      • 堆内存:设置 -Xms(初始堆)和 -Xmx(最大堆)为相同值,避免运行时动态扩缩堆造成性能抖动。参考值:-Xms2g -Xmx2g(按实际内存调整;容器场景下 JDK 10+ 默认启用 UseContainerSupport-Xmx 受容器配额约束)
      • 元空间-XX:MaxMetaspaceSize 设置上限,防止元空间无限增长
      • GC 选择JDK 9+ 默认 G1,适合大堆(4GB+);超大堆(几十 GB)追求低延迟用 ZGCJDK 11 实验、15 生产可用)
      • GC 日志-Xlog:gc* 启用 GC 日志,用于排查 GC 停顿
      • 常见误区:盲目调大 -Xmx 不一定提升性能,堆过大反而增加 GC 停顿
    • 第二层:连接器(Connector)优化

      • 连接器模式Tomcat 8.5/9 默认 NIO(装了 tomcat-native 时自动用 APR);Tomcat 11 起默认纯 Java NIOBIO8.5 已移除

      • 线程池参数(Executor

        • maxThreads:最大工作线程数,默认 200。不是越大越好——线程过多导致上下文切换开销增大;建议结合压测确定,一般 200~500
        • minSpareThreads:保底存活线程数(Connector 属性默认 10Executor 上默认 25);注意是"保底水位”,线程按需增长到该水位,并非启动即全部创建
        • acceptCount:等待队列长度,默认 100。高并发时调大(如 500~1000
        • maxConnections:最大连接数,NIO 默认 8192
      • 连接超时connectionTimeout 文档默认 60000ms,但随 Tomcat 发行的默认 server.xml 显式配置为 20000ms ——— 如果自定义 server.xml 未写该属性,实际生效的是 60000mskeepAliveTimeout 控制长连接存活时间

      • 压缩compression="on" 开启 gzip 压缩,减少传输量(对文本类资源效果明显)

      • 静态资源:配置资源缓存或交给前端 Nginx 处理(推荐)

    • 第三层:应用层优化

      • 数据库连接池:配置合理的连接池参数(初始/最大连接数),避免频繁创建销毁连接
      • 缓存:热点数据用 Redis/本地缓存,减少数据库压力
      • 异步处理:长耗时操作用 Servlet 3.1 异步处理,释放线程
      • 避免阻塞IO 操作异步化,减少线程占用
    • 第四层:操作系统层

      • 文件描述符:调大 ulimit -n(默认 1024 太小,Tomcat 高并发会报 too many open files
      • 内核参数net.core.somaxconn(配合 acceptCount)、net.ipv4.tcp_* 相关优化
  • 协助记忆

    • 优化四层JVM(堆 + GC)→ 连接器(线程池 + 超时)→ 应用(连接池 + 缓存)→ 系统(fd + 内核)
    • 核心原则:先压测找瓶颈,再对症下药;盲目调大参数反而更糟
    • 三个默认值maxThreads 200acceptCount 100maxConnections 8192(NIO)
  • 进阶思考

    • Tomcat 线程数(maxThreads)是不是越大越好?

      • 不是。线程是"资源"而非"能力"——每个线程占用栈内存,线程过多导致内存占用大、CPU 上下文切换开销大(频繁切换反而降低吞吐)。正确做法:用压测工具(JMeter/k6)逐步加压,观察吞吐量拐点,在吞吐不再增长的点设置 maxThreads。通常 200~500 是常见范围,但具体要压测确定。还要配合 maxConnectionsacceptCount 一起看——三者共同决定了并发处理能力
    • Tomcat 10/11 有哪些值得关注的性能相关变化?

      • Tomcat 10 最大变化是 jakarta 命名空间迁移(javax→jakarta);Tomcat 11 对应 Jakarta EE 11。真正值得关注的是虚拟线程(Virtual Threads) ——— Tomcat 10.111 都支持(通过 StandardVirtualThreadExecutor,需 JDK 21+,且默认都不启用、需在 server.xml 显式配置)。注意概念澄清:Tomcat NIO6.0 起就不是"1 线程 1 连接" ——— acceptor + poller 线程负责连接,工作线程池处理的是请求而非连接;虚拟线程改变的是"处理请求的工作线程"的实现(平台线程→虚拟线程),让每个请求跑在 KB 级栈的虚拟线程上,突破 maxThreads=200 的平台线程上限。仅对 IO 密集型(阻塞占比高)应用收益明显;CPU 密集型无增益;注意 JDK 21synchronized 会固定(pin)虚拟线程(JDK 24JEP 491 才解决)、ThreadLocal 规模放大问题

🤔 简述 LVS 的三种模式及其工作原理?

  • LVSLinux Virtual Server)是 Linux 内核内置的负载均衡方案,工作在内核空间(第四层,基于 IP + 端口),性能高。LVS 有三种工作模式:NATDRDirect Routing)、TUNIP Tunneling),核心区别在于数据报文如何流转、响应流量是否经过调度器。

    • 模式一NAT 模式(VS/NAT

      • 原理:调度器同时改写请求和响应的 IP 地址——请求进来做 DNAT(目标地址改为 RS(Real Server; 真实服务器)),响应方向做逆 NAT(源地址从 RS 改回 VIP,基于连接跟踪的双向改写)

      • 报文流转:请求 → 调度器 → RS;响应 → 调度器 → 客户端。请求和响应都经过调度器

      • 特点

        • 优点RS 可以使用任意操作系统和私网 IP,配置简单;是唯一支持端口映射的模式(VIP 端口可与 RS 端口不同)
        • 缺点:调度器是瓶颈——所有响应都经过它,吞吐受限于网卡带宽 + 连接表/CPU(每个 NAT 连接在哈希表占两个节点)
        • RS 的网关必须指向调度器
      • 适用RS 数量少、流量不是特别大的场景

    • 模式二DR 模式(VS/DR,直接路由)

      • 原理:调度器只改写数据帧的目标 MAC 地址(源 MAC 也会改写)把请求转发给 RSRS 处理完直接把响应绕过调度器返回客户端
      • 报文流转:请求 → 调度器 → RS;响应 → RS → 客户端(不经过调度器)
      • 关键配置VIP 同时配置在调度器和所有 RS 上 ——— RSVIP 配置在 lo 接口上,并抑制 ARP 响应(arp_ignore=1arp_announce=2
      • 特点
        • 优点:响应不经过调度器,调度器只处理请求流量,性能高,生产环境最常用
        • 缺点RS 和调度器必须在同一二层网络(同网段);RS 端口必须与 VIP 端口相同;RS 需额外配置 VIPARP 抑制
        • 适用:大规模、高流量场景(Web 集群主流)
    • 模式三TUN 模式(VS/TUNIP 隧道)

      • 原理:调度器把请求封装在 IP 隧道(IP-in-IP,也支持 GRE/SIT/GUE)中转发给 RSRS 解封装后处理,响应直接返回客户端
      • 报文流转:请求 → 调度器(封装)→ RS(解封装)→ 处理 → 响应 → 客户端(不经过调度器)
      • 关键配置(和 DR 一样)VIP 配置在 RS 的非 ARP 设备(tunl0/dummy/lo)上,同样要抑制 ARP 响应 ——— 否则 RS 会抢答 ARP
      • MTU 坑(TUN 实战第一坑)IPIP 每包 +20 字节头,MTU 1500 网络中 DF(不分片)大包会被拒(PMTU 问题);内核可配置 pmtu_disc 关闭让 TUN 方法分片
      • 特点
      • 优点RS 可以跨地域(不在同一网络),响应不经过调度器
      • 缺点:需 RS 支持隧道协议(modprobe ipiptunl0 up);封装带来开销和 MTU 问题;配置复杂度高
      • 适用:异地多活、RS 分布在多个机房的场景
    • 三种模式对比速览

      • NAT:请求和响应都过调度器(调度器瓶颈),唯一支持端口映射
      • DR:请求过调度器,响应直接回(同二层网络,最常用),RS 端口必须等于 VIP 端口
      • TUN:请求隧道封装,响应直接回(可跨地域),RS 端口必须等于 VIP 端口
    • 2026 年生态现状

      • ipvs 至今在内核 6.x 中活跃维护;kube-proxyIPVS 模式是 K8s 大规模集群的常用方案
      • 演进方向:DPVSDPDKipvs)、Katran/CiliumXDP/eBPF 负载均衡)、ECMP+BGP 替代 Keepalived/VRRP
  • 协助记忆

    • 一句话区分NAT 是"快递员两头跑"(进出发都经调度器),DR 是"只送件不取件"(请求经调度器、响应直达),TUN 是"打包寄送"(隧道封装跨地域)
    • DR 两个关键VIPlo 接口 + 抑制 ARPTUN 同样要)
    • 选型口诀:同网段高流量用 DR,跨地域用 TUN,简单场景用 NAT
  • 进阶思考

    • DR 模式为什么要抑制 RSARP 响应?不抑制会怎样?

      • VIP 同时配置在调度器和所有 RS 上。如果 RS 不抑制 ARP,局域网设备对 VIP 发起 ARP 请求时所有 RS 都会响应(ARP 是广播的),导致 MAC 地址混乱——有的请求被转发到 RS,有的被 RS 直接抢答。抑制 ARParp_ignore=1arp_announce=2)让只有调度器响应 VIPARPRSVIP 只用于接收转发请求,不对外宣告
    • LVSNginx 负载均衡怎么选?

      • LVS 工作在四层(IP + 端口),内核态,性能高(并发连接数可达百万级,注意是并发连接数而非 QPS);但只做转发,本身不带健康检查和故障摘除,需 Keepalived 等外部组件配合。Nginx 工作在七层(HTTP),能做 URL 路由、重写、限流、缓存,但含 TLS 终止/HTTP 解析,开销天然更大(可比对象是 Nginx stream 四层模块)。生产架构常见组合:LVS(四层入口)→ Nginx(七层反向代理)→ 应用服务器,高可用由 Keepalived 实现 ——— VRRPVIP 漂移 + 对 RS 健康检查并动态增删 ipvs 规则

🤔 LVS 支持哪些调度算法?

  • LVSipvs)支持的调度算法分为静态和动态两大类:静态算法不考虑后端实时负载,动态算法根据后端当前负载/连接数做决策。截至 2026 年,ipvs 共有 14 个调度算法(RR/WRR/DH/SH/MH + LC/WLC/SED/NQ/LBLC/LBLCR/FO/OVF/TWOS)。

  • 静态调度算法(不考虑后端实时状态)

    • RRRound Robin,轮询) :请求依次分发到每个 RS,轮流来
    • WRRWeighted Round Robin,加权轮询) :按权重比例分发,权重高的 RS 分到更多请求
    • DHDestination Hashing,目标地址哈希) :按请求的目标 IP 哈希,相同目标 IP 的请求始终分发到同一台 RS(用于缓存场景)
    • SHSource Hashing,源地址哈希) :按客户端源 IP 哈希,相同来源的请求到同一台 RS(天然实现会话保持)。注意"始终"是简化说法——RS 增删/权重变化会重建哈希表,且 SHsh-portIP+端口哈希)和 sh-fallback(故障回退)两个 flag
    • MHMaglev HashingMaglev 哈希,Linux 4.18 合入) :基于源 IP 的一致性哈希(Google Maglev 论文,NSDI'16),表容量按权重分配,支持 mh-port/mh-fallback flag。天然适合会话保持,RS 变化时受影响连接少
  • 动态调度算法(根据后端实时负载决策)

    • LCLeast Connections,最少连接) :把请求分给当前连接数最少的 RS。严格语义是"活动连接数加权"(内核公式 (activeconns<<8) + inactconns
    • WLCWeighted Least Connections,加权最少连接)LC + 权重,按"连接数/权重"最小的原则分配。是 ipvsadm 的缺省算法(内核层面无默认)
    • SEDShortest Expected Delay,最短期望延迟) :考虑"活动连接数 + 1"与权重的比值((active+1)/weight),预测哪个 RS 延迟最短
    • NQNever Queue,永不排队)SED 的改进——如果某台 RS 活动连接数为 0,直接分配给第一个空闲者,避免请求排队;否则用 SED
    • LBLCLocality-Based Least Connections,基于局部性的最少连接) :目标 IP 哈希 + 最少连接结合,适合 Cache 集群(相同目标 IP 优先到同一台 RS
    • LBLCR(带复制的局部性最少连接)LBLC 的改进——每个目标 IP 对应一个服务器集合(set),集合内按最少连接选、目标 IP 热度高时集合扩容(注意不是"复制流量",是集合内多台 RS 可选)
    • FOWeighted Failover,加权故障转移) :把连接发给当前可用且权重最高的 RS ——— 类似主备故障转移(注意:不是"失效次数/权重",那是网上的以讹传讹,内核源码就是"选权重最高的 dest 全给流量")
    • OVFOverflow-Connection,溢出连接) :优先把连接给权重最高的 RS,当活动连接数超过其 weight 时"溢出"到权重次高者;全部过载则调度失败(无 WLC 回退);只统计活动连接,不适合 UDP
    • TWOSPower of Two Choices,两随机选择,Linux 6.4 合入) :按权重随机抽两台候选 RS,比较活动连接数归一化开销,选更空闲的一台
  • 选型建议

    • 通用 Web 集群、无特殊需求:WLCipvsadm 默认)
    • 后端性能差异大:WRR(静态权重明确)
    • 需要会话保持:SH / MH(源地址哈希,RS 变化影响小)或配合持久性(persistence
    • Cache/缓存集群:DHLBLC(目标地址哈希保证缓存命中)
    • 防止单台过载:OVF
    • 高可用故障转移倾向:FO
  • 协助记忆

    • 静态五兄弟:RRWRRDHSHMH(“轮询、加权轮询、目标哈希、源哈希、Maglev 哈希”)
    • 动态九兄弟:LCWLCSEDNQLBLCLBLCRFOOVFTWOS
    • 默认是 WLCipvsadm 缺省) ,大多数场景够用;有特殊需求(会话保持、缓存命中)再换
  • 进阶思考

    • SH(源地址哈希)和持久性(persistence)都能做会话保持,有什么区别?

      • SH 是基于 IP 哈希的确定性分配 ——— 同一源 IP 按哈希到同一台 RS,不依赖连接状态;但 NAT 后面的多个用户共享一个 IP 会被分到同一台(负载不均);且 RS 宕机时哈希到它的用户受影响(可通过 sh-fallback 缓解)。持久性(persistence)是基于连接跟踪的超时绑定——在一定时间窗口(默认 300 秒)内把同一来源的请求绑定到同一台 RS,超时重新分配。持久性更灵活(支持故障转移、负载更均衡),是更推荐的会话保持方式
    • 加权算法(WRR/WLC)的权重怎么确定?

      • 权重反映 RS 的处理能力差异——通常按 CPU 核数、内存大小或压测结果定。例如两台服务器,一台 8 核一台 4 核,权重可设为 2:1。注意:权重是相对值不是绝对值;权重相同(如 1:1)就退化为普通轮询/最少连接。权重要根据实际压测调整,不能拍脑袋
  • CookieSession 都是 Web 应用中记录用户状态的机制,核心区别:Cookie 存在客户端(浏览器),Session 存在服务端。两者常配合使用 ——— Session 通过 Cookie 传递 Session ID 来识别用户。

    • Cookie(客户端状态)

      • 定义:由服务器通过 Set-Cookie 响应头下发的小段文本数据,浏览器保存在本地,后续请求自动通过 Cookie 请求头携带

      • 特点

        • 存储位置:浏览器(客户端)
        • 容量:约 4KB 上限(单个 Cookie4096 字节,浏览器实现惯例;注意 RFC 6265 规范并未强制规定这个数值)
        • 生命周期:可通过 Expires/Max-Age 设置过期时间——持久 Cookie 或会话 Cookie(无 Expires/Max-Age 的"会话 Cookie“与服务器 Session 是两个概念,仅名字相似)
        • 作用域:同域(Domain + Path 限定),默认同站发送
        • 可被篡改:客户端可修改 Cookie 内容(需签名/加密防篡改)
      • 常见属性Secure(仅 HTTPS)、HttpOnly(禁止 JS 读取)、SameSite(缓解 CSRF)、Path/Domain(作用域)

    • Session(服务端状态)

      • 定义:服务器为每个会话创建的状态数据,存储在服务端(内存、文件、数据库、Redis)
      • 特点
        • 存储位置:服务端
        • 容量:无 Cookie 那样的硬限制(受服务端内存/存储限制)
        • 生命周期:由服务端超时控制(如 30 分钟无活动过期),也可主动销毁
        • 标识:通过 Session ID(一串随机字符串)识别,Session ID 对应服务端存储的会话数据
        • 安全性:数据在服务端,客户端无法直接篡改
    • 联系SessionCookie 传递 Session ID

      • 典型流程:用户登录 → 服务器创建 Session 并生成 Session ID → 通过 Set-Cookie 下发 Session ID → 浏览器存储 → 后续请求自动携带 → 服务器根据 Session ID 找到对应 Session 数据

      • Session ID 的传递方式

        • Cookie 方式(主流)Session ID 存在 Cookie 中,自动携带
        • URL 重写方式(备用)Session ID 拼在 URL 参数中(如 ?jsessionid=xxx)——适用于禁用了 Cookie 的场景,但有泄露风险(URL 可能被记录在日志/历史中)
      • 也就是说Session 本身不一定依赖 Cookie,但实践中几乎都靠 Cookie 传递 Session ID

    • 核心区别对比

      • 存储位置:客户端(Cookie)vs 服务端(Session
      • 容量:约 4KBCookie)vs 无硬限制(Session
      • 安全性:可篡改(Cookie)vs 服务端可控(Session
      • 生命周期控制:客户端可控制 vs 服务端控制
      • 性能:每次请求都传输(Cookie)vs 服务端查询(Session
      • 跨域Cookie 同域限制 vs Session 数据本身无域概念(但 Session IDCookie 传递时仍受 Cookie 域限制)
    • 2026 年演进

      • SameSite 默认 Lax:自 Chrome 80(2020)/Firefox 86/Safari 13.1 起默认。精确语义:跨站子资源、fetch/XHRiframe 内请求默认不发送,但顶级导航 GET 请求仍携带(用户从别的站点击链接进入本站时会带 Cookie);且默认值在 Chromium 系稳定为 Lax,其他浏览器略有差异
      • 第三方 Cookie 逐步淘汰SafariITP2020 起)默认全面阻止;Firefox 默认启用 ETP + Total Cookie Protection(第三方 Cookie 按站点分区存储,标准模式仅拦截已知追踪器,并非拦截所有);Chrome 至今不默认拦截,仅无痕模式或用户设置时拦截,2024 年放弃强制淘汰后逐步推出用户选择模式
      • 无状态趋势JWT 等无状态 token 兴起 ——— 不依赖服务端 Session 存储,天然适合分布式;但主动失效难。2026 年业界出现回调反思——纯 JWT 存在吊销难、密钥轮换等痛点,部分场景回归"分布式服务端 Session(Redis)“或混合方案
  • 协助记忆

    • 一句话:Cookie 是"存在浏览器里的便签”,Session 是"存在服务器上的档案柜”,Session ID 是"打开档案柜的钥匙"(钥匙放便签里)
    • 钥匙在客户端,档案在服务端:客户端只有 Session ID(钥匙),真正的数据(档案)在服务端
    • 安全对比:档案(Session 数据)比便签(Cookie)安全,因为档案在服务器上,便签在用户手里随时可能被改
  • 进阶思考

    • Session 数据都放服务端,为什么还需要 Cookie?不能不用 Cookie 吗?

      • HTTP 是无状态协议,服务器不记得"你是谁"。Session 数据虽然存在服务端,但服务器要知道"这个请求对应哪份 Session 数据" ——— 这个对应关系(·)必须由客户端每次带来。· 是最自然的携带方式(自动发送)。如果不用 Cookie,只能靠 URL 重写传 Session ID,但 URL 易泄露(日志、历史记录、分享链接),所以实践中几乎都用 Cookie
    • CookieSession 哪个更安全?

      • 单从"存储"角度 Session 更安全 ——— 数据在服务端,客户端碰不到。Cookie 的主要风险其实是被窃取(XSS 窃取、明文传输窃听、CSRF)而非篡改 ——— 内容篡改在服务端签名校验后危害有限。Session 的风险在 Session ID 失窃(XSS 窃取 Cookie、中间人窃听)导致会话劫持;注意会话固定(Session Fixation)与窃取机制不同——它是攻击者预先固定一个 ID 给受害者使用(RFC 6265 §8.4 专述)。完整方案需组合:Session IDHttpOnly + Secure Cookie 保护、传输用 HTTPS、防 XSS(CSP)SameSite 缓解 CSRF

🤔 网站跨域报错 Access-Control-Allow-Origin 如何解决?

  • 跨域报错是浏览器同源策略(Same-Origin Policy)的保护机制:浏览器默认阻止网页脚本跨域读取响应。CORSCross-Origin Resource Sharing)是让服务器声明"允许哪些来源访问"的机制,报错 Access-Control-Allow-Origin 说明服务器没有正确声明允许的来源。

    • 先理解跨域和同源

      • 同源:协议 + 域名 + 端口都相同才算同源。http://a.comhttps://a.com 不同源(协议不同)、和 http://a.com:8080 不同源(端口不同)
      • 跨域请求:前端页面(http://a.com)向后端(http://api.b.com)发请求,就是跨域
      • 同源策略:浏览器只允许脚本读取同源响应,跨域响应默认被浏览器拦截(注意:请求可能已发出、服务器可能已处理,只是浏览器拦截了响应)
    • 两种请求类型(决定处理方式)

      • 简单请求:满足特定条件(GET/HEAD/POST + Content-Type 限定值 + 仅 safelisted 请求头) ——— 浏览器直接发送,服务器只需返回 Access-Control-Allow-Origin。注意 Content-Type 只有三个值算简单请求:application/x-www-form-urlencodedmultipart/form-datatext/plainapplication/json 会触发预检)
      • 预检请求(Preflight) :非简单请求(如带 Authorization 头、Content-Type: application/jsonPUT/DELETE 方法)——— 浏览器先发 OPTIONS 请求探测,服务器必须正确响应 OPTIONS(且必须返回 2xx)并返回允许的方法/头,才继续发真实请求
      • 2024-2026 新机制 PNAPrivate Network AccessChrome2024 年底(localhost 场景 Chrome 130、内网 RFC1918 场景 Chrome 137)起,对"公网页面 → 内网/本地"的请求无条件强制预检——无论方法、无论 mode(甚至 no-cors 和同源请求),新增 Access-Control-Request-Private-Network: true / Access-Control-Allow-Private-Network: true 头。2025-2026 年"莫名 OPTIONS_预检/请求被拦"很大比例是 PNA 导致
    • 解决方案:后端加 CORS 响应头(根本解法)

      • 在服务器响应中加

        • Access-Control-Allow-Origin: http://a.com(允许的来源)
        • Access-Control-Allow-Methods: GET, POST, PUT, DELETE(允许的方法)
        • Access-Control-Allow-Headers: Content-Type, Authorization(允许的请求头)
        • Access-Control-Allow-Credentials: true(允许携带凭证,值为字面量 true;配了它就不能用 *
        • Access-Control-Max-Age: 3600(预检结果缓存时间,减少 OPTIONS 请求)
        • Access-Control-Expose-Headers(可选):默认前端只能读 6 个简单响应头,自定义响应头需在此列出
      • 配置位置

        • Nginx:add_header Access-Control-Allow-Origin ...
        • Spring Boot@CrossOrigin 注解或全局 CORS 配置
        • Node.js:cors 中间件
      • 注意通配符的坑Access-Control-Allow-Origin: * 允许所有来源,但不能和 credentials(携带 Cookie)一起用——用了 withCredentials 时不允许用 *,必须写具体来源

    • 解决方案Nginx 反向代理(同源化)

      • 前端和后端域名不同导致跨域时,用 Nginx 反代把 /api 转发到后端,前端只访问同源路径 ——— 从根上消除跨域
      • 配置示例:前端访问 http://a.com/apiNginx/api 代理到 http://api.b.com
      • 优点:不需要改后端代码、避免暴露多个 CORS 配置
      • 适用范围:前后端域名固定对应时是常见推荐方案;但 API 需被多个未知域名、第三方或移动端调用时(SaaS、开放平台),CORS 头方案才是唯一可行且是行业标配
    • 解决方案JSONP(历史遗留方案)

      • 利用 script 标签不受同源策略限制的特点,通过回调函数拿数据
      • 缺点:只支持 GET、安全性差(需要服务端配合)、已过时
      • 仅用于兼容老系统的特殊场景
  • 协助记忆

    • 一句话:跨域报错 = 服务器没声明允许这个来源访问
    • 两条路:后端加 CORS 头(改后端)或 Nginx 反代同源化(改架构)
    • 通配符的坑:*credentials 不能同时用
    • 记住预检:带 Authorization / JSON body 的请求会先发 OPTIONS 预检,服务器要正确处理(OPTIONS 必须返回 2xx
  • 进阶思考

    • 为什么有时候 OPTIONS 请求返回 403/404

      • 预检请求(OPTIONS)可能没被正确处理。常见原因:一是网关/防火墙拦截了 OPTIONS 方法(只放行 GET/POST);二是后端没有对 OPTIONS 返回正确的 CORS 响应头(Access-Control-Allow-Methods/Headers);三是 Nginxadd_header 默认只对部分 2xx/3xx 状态码添加(200/201/204/206/301/302/303/304/307/308),需加 always 参数才对所有响应码添加——且预检必须返回 2xxOPTIONS 返回 403 时即使加了头也必然失败。排查:用 curl 手动发 OPTIONS 请求模拟预检,看响应头是否包含 Allow-Methods/Headers 且状态码为 2xx
    • Access-Control-Allow-Origin: *withCredentials 为什么冲突?

      • 安全设计。如果服务器返回 * 允许所有来源,同时又允许携带凭证,任意站点就能代表用户跨域发带凭证请求并读取响应——比只写不读的 CSRF 更严重。所以浏览器规定:凭证请求下 ACAO 必须为具体来源(* 判失败),且要配合 Access-Control-Allow-Credentials: true。补充:现代浏览器 Cookie 默认 SameSite=Lax,跨站 fetch/XHR(非顶级导航)默认不携带 Lax Cookie,只有 SameSite=None; SecureCookie 会带上——实际攻击面比"任何恶意网站都能带上 Cookie“更小,但"带凭证 + 可读响应"的底线依然不能破
  • 扩展信息
    安全响应头是 Nginx 层可以统一配置的 Web 安全防护。核心是 CSPContent-Security-Policy,内容安全策略)——— 它告诉浏览器"页面允许加载哪些来源的资源”,CSP 是浏览器侧缓解 XSS 最重要、最有效的防御机制之一,但不能替代输入校验(Sanitization)与输出编码(Encoding)等后端/开发层面的安全措施。

    • CSP 是什么
      • CSP 通过响应头声明"允许加载什么",浏览器强制执行:不符合策略的资源(脚本、图片、样式、iframe)被阻止加载
      • 缓解 XSS 原理:即使攻击者注入 <script>CSP 如果没允许内联脚本/不可信来源,浏览器会拒绝执行
      • CSP 的威胁模型:缓解内容注入(XSS)与页面被恶意嵌入(clickjacking——注意这是 UI redress 而非"内容注入")
    • CSP 常用指令
      • default-src:大多数 fetch 类指令的兜底策略。但需注意:frame-ancestorsbase-uriform-actionsandbox 等指令不会继承 default-src(未指定即默认为无限制)。
      • script-src:脚本来源(最关键的指令)
      • style-src:样式来源
      • img-src:图片来源
      • connect-srcXHR/fetch/WebSocket 连接来源(注意它和 CORS 是两层不同机制——CSP 是浏览器端限制,CORS 是服务端授权)
      • frame-ancestors:允许哪些来源嵌入本页(防点击劫持,取代 X-Frame-Options
      • object-src<object>/<embed> 来源(建议 ’none’)
      • base-uri<base> 标签来源(限制可被篡改的基准 URL);form-action:表单提交目标
      • upgrade-insecure-requests:页面内 HTTP 请求自动升级为 HTTPS
      • report-to:违规上报(report-uri 已废弃,用 Reporting-Endpoints + report-to 替代)
      • 源关键字'self''none''unsafe-inline'(不推荐)、'unsafe-eval'(不推荐)、'strict-dynamic'(注意:strict-dynamic 应与 noncehash 一起使用。在支持该特性的浏览器中,会忽略传统脚本白名单(如 'self'、主机白名单),改由受信任脚本继续加载其他脚本。)、'nonce-xxx'(每次响应随机生成)
    • CSP 配置案例
      • 基础案例(静态站)Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
      • 进阶案例(带 CDNAPIContent-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; img-src 'self' data: https://cdn.example.com; connect-src 'self' https://api.example.com; style-src 'self' 'unsafe-inline'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
      • 上线前先开报告模式(只报告不拦截)Content-Security-Policy-Report-Only: default-src 'self'; object-src 'none'; base-uri 'self' Reporting-Endpoints: csp-endpoint="https://example.com/csp-violations" Content-Security-Policy-Report-Only: ...; report-to csp-endpoint; 注意两个坑:Report-Only 模式下 frame-ancestors 不生效(既不拦截也不产生报告);若未配置 report-to/report-uri(或 Reporting-Endpoints),Report-Only 依然在浏览器端生效:它会在开发者工具控制台输出违规警告,并可被前端 securitypolicyviolation 事件捕获,只是不会向服务器发送 HTTP 违规上报包。
      • Nginx 配置 CSP: add_header Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'" always;
        • always 必须加add_header 默认只对 200/201/204/206/301/302/303/304/307/308 生效,加 always 才对所有响应码生效(错误页也带 CSP
        • add_header 继承坑:子 location 写了 add_header 会覆盖父级全部(nginx 1.29.3+ 可用 add_header_inherit merge; 改为追加)
      • Nginx 其他安全头(一起配,注意与 CSP 语义一致)
        1
        2
        3
        4
        5
        
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-Frame-Options "DENY" always;             # 与 frame-ancestors 'none' 配套
        add_header Referrer-Policy "strict-origin-when-cross-origin" always;
        add_header Permissions-Policy "geolocation=(), camera=(), microphone=()" always;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;  # 仅 HTTPS 站点
      • 策略一致性CSPframe-ancestors 'none' 应配 X-Frame-Options "DENY"(或 'self' + SAMEORIGIN),两者语义要一致——不要出现"CSP 禁止嵌入、XFO 允许同源嵌入"的自相矛盾
      • HSTS 的坑includeSubDomains 要求子域全部 HTTPS,否则误伤子域;preload 需去 hstspreload.org 提交后才生效
      • X-Frame-Options 有效值只有两档(DENY/SAMEORIGIN)——— ALLOW-FROM 已废弃且会导致整个头被浏览器忽略
    • 进阶思考
      • 为什么 'unsafe-inline' 不推荐?nonce 和它什么关系?
        • 'unsafe-inline' 允许所有内联脚本执行——XSS 注入的正是内联脚本,等于开大后门。完全禁止内联脚本后,页面自带的 <script> 也会被拦截,需要移到外部 .js 或用 nonce/hash 白名单。在必须用内联脚本时,nonce 远比 'unsafe-inline' 安全、且比完全禁止更灵活 ——— nonce 每次响应随机生成,攻击者无法预知。实操坑:nonce 每次响应都变,页面被浏览器/CDN 缓存后 nonce 过期、脚本被误杀——这是高频事故,缓存页面慎用 nonce
      • CSPX-Frame-Options 都能防点击劫持,用哪个?
        • frame-ancestors(CSP)是现代推荐、X-Frame-Options 是旧方案。frame-ancestors 更灵活(可精确指定多个来源),X-Frame-Options 只有 DENY/SAMEORIGIN 两档。两者同时存在时,CSP 优先(仅在 enforce 模式成立;X-Frame-Options 在响应含 frame-ancestors 时被忽略)。为兼容老浏览器可两者都配,但语义必须一致

🤔 简述 CDN 工作原理?

  • CDNContent Delivery Network,内容分发网络)的核心思想:把内容缓存到离用户更近的节点,让用户从"附近的服务器"而不是"远方的源站"获取内容。本质是"空间换时间"——用分布在全国/全球的缓存节点,换取更短的访问延迟。

    • CDN 的核心组件

      • 边缘节点(Edge Node / POPPoints of Presence :分布在各地区/运营商的缓存服务器,真正响应最终用户请求
      • 中心节点 / 源站(Origin :内容的原始来源(你的服务器)
      • GSLBGlobal Server Load Balancing,全局负载均衡) :负责把用户引导到"最合适"的边缘节点——通常以智能 DNS 方式实现,根据用户地理位置、所属运营商、节点负载,返回最优边缘节点 IP
    • CDN 工作原理流程(一次访问)

      1. 用户访问 http://www.example.com,发起 DNS 解析
      2. 智能 DNS / GSLB 调度:DNS 服务器根据用户所属网络的递归解析器出口 IP 判断地理位置和运营商,返回就近的边缘节点 IP(北京用户解析到北京节点,电信用户到电信节点。严格说 DNS 默认看到的是递归解析器出口 IP,启用 EDNS Client Subnet(RFC 7871)才能获知用户真实 IP 前缀)
      3. 用户请求打到边缘节点
      4. 边缘节点判断缓存:
      • 命中:边缘节点有缓存且未过期,直接返回
      • 未命中:边缘节点回源——向源站请求内容,缓存一份后返回(实际大型 CDN 是多级缓存 L1 边缘/L2 区域/L3 中心,边缘未命中常先查上层节点而非直接回源)
      1. 后续同地区用户请求同一内容,直接命中边缘节点缓存
    • CDN 缓存与回源的关键点

      • ``TTL(缓存有效期) :由源站响应头控制 ——— Cache-Control: s-maxage(共享缓存专用,优先于 max-age)、max-ageHTTP/1.0Expires;也可在 CDN 平台配置"强制缓存"忽略源站头
      • revalidation(304 校验) :缓存未命中时,边缘节点先发 If-Modified-Since/ETag 条件请求回源,源站返回 304 则复用缓存、不传 body——这是缓存回源的重要环节
      • 缓存刷新:源站内容更新后,需主动刷新(purgeCDN 缓存或等 TTL 过期
      • 回源率 / 缓存命中率(Cache Hit Ratio) :衡量 CDN 效率的关键指标——命中率越高,源站压力越小
    • CDN 的作用

      • 加速访问:用户从就近节点拿内容,延迟大幅降低(尤其跨地域、跨境场景)
      • 减轻源站压力:大部分请求被边缘节点缓存吸收,源站只处理未命中请求
      • DDoS:用海量带宽池(Anycast)吸收流量型攻击、用 WAF 与限速过滤应用层(CC)攻击,同时隐藏源站 IP 使其无法被直接打击
      • 隐藏源站 IP:用户只和边缘节点通信,源站 IP 降低暴露面(需配合回源 IP 白名单)
    • 现状与前沿(2026 年)

      • 已是标配(成熟多年)HTTP/3QUIC 2021 标准化、HTTP/3 2022 标准化,主流 CDN 2019 年已商用,如今是标配);CDN 证书托管/自动续期(用户侧边缘证书 + 源站回源证书是两个独立维度,可选 mTLS);基础边缘计算(Cloudflare Workers 2017Lambda@Edge 2017
      • 当前热点(2023-2026) :边缘 AI 推理(Workers AIGPU 边缘节点、AI Gateway)、边缘无服务器渲染/SSRVercel/Netlify edge runtime)、边缘 KV/数据库(Durable Objects 等)、SASE/零信任与 CDN 融合(Cloudflare Zero Trust 等)
  • 协助记忆

    • 一句话:CDN = 把内容放到离用户近的地方,就近取货
    • 三个角色:边缘节点(附近的分店)、源站(总仓库)、GSLB(导购员,告诉你哪家分店近)
    • 类比快递:CDN 是"提前把货放到你楼下的便利店",用户不用每次去总部仓库取
  • 进阶思考

    • CDN 一定能提升访问速度吗?什么场景反而更慢?

      • 不一定。CDN 加速依赖"就近取货"——纯动态内容(用户专属页面、实时数据)不适合缓存(核心原因是缓存收益低/需个性化,不完全是"缓存了必然旧数据",一致性可由 TTL 控制);小体量站点用 CDN 可能增加 DNS 解析和节点跳转额外开销;跨运营商调度不当反而更慢。适合 CDN 的是:静态资源(图片、CSS、JS、视频)、大文件下载、API 只读数据。补充:现代 CDN 有动态加速(DSA) ——— 不缓存,但通过优化 TCP/TLS、智能路由选路来加速动态请求
    • CDN 隐藏源站 IP 就一定安全吗?

      • 不是绝对的。CDN 隐藏源站 IP 是"降低暴露面",不是"绝对隐藏"——攻击者仍可能通过:源站直接对外解析的历史 DNS 记录、邮件头/证书透明度日志、源站自身的外发请求、子域爆破等找到真实 IP。真正加固需要:源站只允许 CDN 回源 IP 访问(回源 IP 白名单)、关闭源站不必要的对外端口。CDN 隐藏 IP 只是多层防护中的一层

🤔 四层与七层负载均衡有什么区别?

  • 四层(L4)和七层(L7)负载均衡工作在网络模型的不同层级,核心区别:L4 在传输层(TCP/UDP)基于 IP+端口转发,L7 在应用层(HTTP)基于内容路由。

    • 四层负载均衡(L4

      • 工作层级:传输层(OSI4 层),基于 IP + 端口转发,不解析应用层内容(需解析 TCP/UDP 头)

      • 代表产品LVSHAProxytcp 模式)、云厂商 NLBKatranMeta 开源,XDP/eBPF 转发面) ;F5 BIG-IP LTML4L7 一体化 · 设备(不能仅归 L4);Nginxstream 模块也能做 L4

      • 转发方式NATDRDSR,直接服务器返回——返回流量不经过 LB)、隧道(LVS 三模式)

      • 特点

        • 性能高:内核态或硬件转发,权威性能指标是 pps(每秒包数)而非并发连接数
        • 透明:看不到 HTTP 内容
        • 无法做URL 路由、内容改写、Cookie 会话保持(传统上基于源 IP/五元组哈希——注意标准术语是五元组:源/目的 IP+端口+协议,Katran 即用 5-tuple 一致性哈希)
      • TLS:传统软件 L4LVSnginx stream 透传、HAProxy tcp passthrough)只能透传,不能终止;但现代云 L4AWS/阿里云 NLB 等,2019 年起)支持 TLS 监听器/终止(多在网卡/硬件卸载,ACM 管理证书);另有灰色地带——L4 可只读 TLS ClientHelloSNI 做路由而不解密(nginx stream ssl_preread

      • 健康检查:传统 LVSTCP 端口探测;现代 L4NLB 等)同样支持 HTTP/HTTPS 健康检查与响应码匹配

      • 适用:高吞吐场景、TCP/UDP 通用协议、作为七层的入口

    • 七层负载均衡(L7

      • 工作层级:应用层(OSI7 层),解析 HTTP 内容

      • 代表产品NginxHAProxyhttp 模式)、Envoy/Traefik(云原生/服务网格默认 L7)、云厂商 ALB

      • 特点

        • 功能丰富:URL 路径路由、Header 改写、Cookie 会话保持、限流、缓存、TLS 终止、gRPC/HTTP3 支持
        • 性能低于 L4(需解析报文)
        • 能感知应用状态(基于应用层健康检查)
      • 会话保持:基于 Cookie

      • 健康检查HTTP 探测(检查具体 URL 的响应码,能感知应用是否真的可用)

      • 适用HTTP/HTTPS 业务、需要路由/改写的场景

    • 关键区别对比

      • 工作层级:传输层 vs 应用层
      • 性能L4 高(pps 指标)vs L7 低(需解析)
      • 功能L4 简单转发 vs L7 内容路由/改写
      • TLS 终止:传统 L4 只能透传,现代云 L4 支持 vs L7 原生支持
      • 会话保持L4 传统基于五元组 vs L7 基于 Cookie
      • 健康检查L4 传统 TCP 探测 vs L7 HTTP 探测(现代 L4 也支持 HTTP
      • 典型代表LVS/Katran vs Nginx/Envoy
    • 常见架构组合

      • 大型架构L4(入口,扛高并发)→ L7(应用路由)→ 后端服务器
      • 经典组合LVS / Katran(四层)→ Nginx / Envoy(七层)→ 应用
  • 协助记忆

    • 一句话:L4 是"快递分拣员"(只看地址不分内容),L7 是"前台接待员"(听你需求再安排)
    • L4 管"到不到"(IP+端口转发),L7 管"给谁"(URL/Host 路由)——仅为简化助记,严格说 L4 也做健康检查、L7 路由同样基于 IP+端口
    • 选型:只要转发选 L4,要路由/改写/TLS 终止选 L7,大流量先用 L4 挡一层
  • 进阶思考

    • L4 能做 TLS 终止吗?

      • 分情况。传统软件 L4LVSnginx stream 透传、HAProxy tcp passthrough)不能 ——— TLS 终止需要解密报文,L4 只转发加密 TCP 流,只能透传到后端解密。现代云 L4AWS/阿里云 NLB 等,2019 年起)支持 TLS 监听器,多在网卡/硬件上卸载加解密。所以"HTTPS 业务 + TLS 终止"传统选 L7Nginx/ALB),但现代架构也可以用支持 TLS 的云 L4 做入口
    • 四层负载均衡的性能优势有多大?

      • L4 权威指标是 pps(每秒包数)——— KatranXDP/eBPF 方案在 DPDK/网卡卸载下可达千万级 ppsL7Nginx)通常几万到几十万 QPS(受 HTTP 解析和 TLS 开销限制),数字随硬件/配置浮动。差距来自:L4 不解析应用层内容、L7 要解析 HTTP 报文且常做 TLS 终止。注意量纲:L4 的"百万级"通常是并发连接数/ppsL7 的"几万"是 QPS ——— 两者不是同一个量纲,对比要说清楚

🤔 网站报错 502 Bad Gateway 怎么解决?

🤔 网站 QPS 突降,如何快速定位问题?

🤔 简述 HTTPS 工作原理?

🤔 如何设计高可用的 Web 服务架构?

🤔 秒杀系统,怎么优化?

🤔 在高并发情况下,如何避免数据库的性能瓶颈?

🤔 如何设计高并发的 Web 服务架构?

🤔 网站会监控哪些指标?

🤔 请介绍下你之前维护的网站整体架构?

🤔 HTTP 长连接和短连接有什么区别及适用场景?

🤔 HTTPS 中 CA 证书在客户端还是在服务端?作用是什么?

🤔 打开 APP 后页面空白,怎么排查问题?

目录