计算机基础面试题手册

梳理高频技术问题,帮助你按主题复习和查漏补缺。

计算机基础阅读 05月28日 03:47

XML 文档格式良好和有效有什么区别?

格式良好是 XML 的语法底线——标签必须闭合、正确嵌套、单一根元素、属性值加引号、特殊字符转义。解析器碰到不格式良好的文档直接报错,根本不会继续处理。有效是在格式良好的基础上,再对照 DTD 或 XML Schema 检查语义约束——元素顺序对不对、必填字段有没有缺、数据类型匹不匹配。一个文档可以格式良好但无效(语法没问题但违反了 Schema 约束),但有效的一定格式良好。核心区别:格式良好只管"能不能解析",有效还要管"符不符合业务规则"。前者是 XML 规范的硬性要求,后者取决于你定义的 Schema。追问DTD 和 XML Schema 有什么区别?| 维度 | DTD | XML Schema ||------|-----|------------|| 数据类型 | 只有文本,没有类型 | 支持 string、integer、date 等丰富类型 || 命名空间 | 不支持 | 原生支持 || 语法 | 自有一套非 XML 语法 | 本身就是 XML 文档 || 扩展性 | 弱 | 支持复杂类型继承、约束facet || 现状 | 遗留系统在用,新项目不推荐 | 主流方案 |实际项目里怎么选验证方式?配置文件(Spring、Maven)通常自带 Schema 声明,解析时自动验证。数据交换场景建议用 XSD 做强校验,防止对方传过来的结构不符合约定。开发阶段开验证、生产环境看性能需求可以关掉——Schema 验证有开销。格式良好但无效的文档能被解析吗?能。解析器分两类:非验证型解析器只检查格式良好性,不会因为违反 Schema 就拒绝解析。只有开启验证模式的解析器才会同时检查有效性。所以一个缺了必填字段的 XML,照样能被 DOM/SAX 解析成树结构,只是语义上不合规。什么时候 XML 不格式良好也不会报错?用了容错解析器(比如浏览器的 HTML 解析器),或者解析时开了 recover 模式。但标准 XML 解析器遇到格式错误必须报告 fatal error,这是 XML 规范的硬要求——和 HTML 的"宽容解析"不同,XML 的设计哲学就是宁可报错也不要猜。写段代码// 开启 Schema 验证SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);Schema schema = sf.newSchema(new File("book.xsd"));DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();dbf.setSchema(schema); // 设置 Schema 后解析时自动验证
计算机基础阅读 05月28日 03:47

XML 解析中 DOM 和 SAX 有什么区别?

DOM 把整个 XML 一次性加载到内存建树,SAX 逐行读、遇到标签就触发回调。所以 DOM 能随机访问、能改,但吃内存;SAX 省内存、速度快,但只能顺序读、不能改。面试里一般答到"一个树一个事件驱动"就算到位,但追问肯定会问更细。追问DOM 和 SAX 的内存差距到底有多大?解析一个 100MB 的 XML,DOM 可能吃掉 300-500MB 内存(树节点的对象开销远大于原始文本),SAX 基本只占几 KB 的缓冲区。大文件用 DOM 直接 OOM 是真实生产事故,不是理论风险。StAX 和 SAX 有什么区别?为什么有了 SAX 还要 StAX?SAX 是推模型——解析器主动推事件给你,你没法控制解析节奏。StAX 是拉模型——你调用 next() 主动拉下一个事件,想停就停,想跳就跳。实际开发中 StAX 更灵活,代码也更好写(不用写一堆回调)。JDK 6 开始 StAX 就是 JAXP 的一部分了。实际项目里怎么选?| 场景 | 选择 | 原因 ||------|------|------|| 配置文件(几十 KB) | DOM / Dom4j | 小文件内存不是问题,随机访问方便 || 大日志文件(几百 MB+) | SAX / StAX | 流式处理不爆内存 || 需要修改 XML 再写回 | DOM | SAX 只读,改不了 || 只提取少数字段 | SAX / StAX | 不用为几个字段加载整棵树 |JAXB 还在用吗?Java 9 标记废弃,Java 11 正式移除(从 JDK 里删了)。现在要用得手动加 jakarta.xml.bind 依赖。新项目如果要做 XML-对象映射,Jackson 的 XML 模块比 JAXB 好用。DOM 解析有什么常见坑?编码问题:XML 声明的 encoding 和文件实际编码不一致,直接乱码或抛异常空白节点:格式化缩进会产生大量 #text 空白节点,遍历时要 getNodeType() 过滤,否则逻辑全乱命名空间:带命名空间的 XML 必须用 getElementsByTagNameNS(),用错方法查不到元素实体注入:外部实体引用(XXE)是安全漏洞,解析时必须禁用:factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)写段代码StAX 拉式解析,对比上面 SAX 的回调写法,感受下代码简洁度的差距:XMLStreamReader reader = XMLInputFactory.newInstance() .createXMLStreamReader(new FileInputStream("data.xml"));while (reader.hasNext()) { if (reader.next() == START_ELEMENT && reader.getLocalName().equals("title")) { System.out.println(reader.getElementText()); }}
计算机基础阅读 05月28日 03:46

XML 属性和子元素有什么区别?什么时候该用哪个?

XML 属性适合放元数据——ID、类型、状态这类简单的键值对;子元素适合放实际数据和可能变复杂的内容。属性的硬限制是:只能存纯文本、同一元素内不能重复、不能嵌套子结构。所以只要信息有可能扩展、可能多值、可能变复杂,就应该用子元素。一个实用的判断方法:如果你犹豫"这个该放属性还是子元素",大概率该用子元素。属性只在你非常确定它永远是一个简单原子值时才用。W3C 和 Google XML Style Guide 的建议一致:元数据用属性,数据本身用子元素。追问属性和子元素的核心区别是什么?属性是开始标签上的 name="value" 对,值只能是纯文本,同名属性在同一元素内只能出现一次。子元素是嵌套在父元素内的独立元素,可以重复、可以嵌套、可以有混合内容(文本和子元素混排),且保持文档顺序。用代码看最直观:<!-- 属性:简单键值对 --><book id="B001" category="programming" lang="zh"> <title>XML 实战</title></book><!-- 子元素:可以重复、嵌套、保持顺序 --><book> <id>B001</id> <categories> <category>programming</category> <category>reference</category> </categories></book>category 如果可能多值,属性就搞不定——它不能重复,只能用子元素。实际项目里选错会怎样?配置文件把数据库连接参数全写成属性:<db driver="mysql" host="127.0.0.1" port="3306"/>后来要给 host 加 failover 列表、给连接加 SSL 配置,属性扩展不了,只能全部拆成子元素重写。如果一开始就用子元素,加字段只是多写几行的事。再比如 SOAP 协议里,早期版本大量使用属性传业务数据,后来扩展性需求上来后不得不迁移到子元素,导致版本兼容成了大坑。Google 和 W3C 的官方建议是什么?Google XML Style Guide 明确说:属性只用于 ID 引用等元数据,其他一律用子元素。W3C 的 XML 推荐标准虽然没有强制规定,但示例中始终把元数据(id、class)放属性,内容数据放子元素。两条规则的内核一样——属性是"关于数据的数据",子元素是"数据本身"。有没有属性确实更合适的场景?HTML/SVG 是属性发挥优势的典型场景:<div id="main" class="container">、<rect x="10" y="20" width="100"/>——id、class、坐标、尺寸都是纯元数据,不会变复杂,用属性比嵌套子元素简洁得多,解析也更快。另外在 SAX 流式解析中,一个元素的所有属性一次性报出,而子元素逐个触发事件。如果你需要快速读取元数据做路由分发,属性在性能上有微小优势。属性值有长度限制吗?多行文本能放属性吗?XML 规范没有规定属性值长度上限,但实际中有两个问题:很多 SAX 解析器实现在属性值超过一定长度时性能下降甚至截断;更关键的是,属性值中的换行符会被 XML 解析器规范化为空格——多行文本放属性里会丢失格式。所以长文本、多行内容、含换行的代码片段,必须用子元素。写段代码<!-- 推荐:元数据用属性,数据用子元素 --><book id="B001" isbn="978-0-123456-78-9" lang="zh"> <title>XML 实战</title> <authors> <author>张三</author> <author>李四</author> </authors></book>
计算机基础阅读 05月27日 22:51

TCP 和 UDP 的主要区别是什么?

答案速览TCP 面向连接、可靠传输、一对一通信,代价是延迟高、开销大;UDP 无连接、不保证可靠、支持一对多,优势是快。面试中一句话总结:要可靠选 TCP,要速度选 UDP。核心区别| 维度 | TCP | UDP ||------|-----|-----|| 连接 | 三次握手建立,四次挥手断开 | 无连接,直接发 || 可靠性 | 确认应答+重传+校验,保证不丢不重不乱 | 尽力交付,可能丢包乱序 || 传输方式 | 面向字节流 | 面向报文,保留边界 || 流量/拥塞控制 | 滑动窗口+慢启动+拥塞避免 | 无 || 通信模式 | 仅一对一 | 一对一/一对多/多对多 || 首部开销 | 最少 20 字节 | 固定 8 字节 |理解的关键不在背表,而在为什么:TCP 的每一个"可靠"特性(确认、重传、序号、窗口)都是有代价的——更多握手、更大首部、更低效率。UDP 丢掉这些,换来的是简单和快速。适用场景怎么选TCP:HTTP/HTTPS、FTP、SSH、数据库连接——数据不能丢的场景UDP:视频会议、直播、在线游戏、DNS 查询——延迟比完整性更重要的场景面试常见的陷阱题:DNS 既用 UDP 又用 TCP,为什么? 普通查询用 UDP(快),响应超过 512 字节或区域传输时切 TCP(可靠)。这说明选协议不是非此即彼,而是按场景取舍。面试追问三次握手为什么不能两次?——两次无法确认客户端接收能力,可能产生死连接为什么视频通话用 UDP 而不重传丢包?——重传到达时画面已经过了,不如跳过QUIC 为什么基于 UDP 而不是 TCP?——TCP 的握手和拥塞控制内核实现,无法快速迭代;UDP 在用户态可实现同等可靠性和更快的连接建立
计算机基础阅读 05月27日 22:48

TCP SYN Flood 攻击的原理和防御方法是什么?

攻击原理:三次握手的致命缺陷TCP 建立连接需要三次握手:客户端发 SYN,服务器回 SYN+ACK 并分配资源等待 ACK,客户端确认后连接建立。SYN Flood 攻击正是利用第二步——攻击者发送大量伪造源 IP 的 SYN 包,服务器为每个请求分配半连接资源并等待永远不会到来的 ACK,直到半连接队列被填满,正常请求无法处理。核心危害:半连接队列(SYN Queue)被占满 → 新连接被丢弃 → 服务不可用。每个半连接约占 200 字节内存,攻击者用极低成本即可耗尽服务器资源。防御方法(按实战优先级排列)SYN Cookie——最核心的防御服务器收到 SYN 时不分配半连接资源,而是将连接信息编码到 SYN+ACK 的初始序列号(Cookie)中。收到合法 ACK 后,通过验证 Cookie 还原连接状态。sysctl -w net.ipv4.tcp_syncookies=1追问:SYN Cookie 的局限? 会禁用 TCP 窗口缩放和 SACK 等选项,影响高延迟链路性能;Cookie 可被暴力猜解,不适用于超高带宽攻击。调整内核参数——配合 Cookie 的辅助手段# 增大半连接队列sysctl -w net.ipv4.tcp_max_syn_backlog=8192# 减少重试次数,加速释放sysctl -w net.ipv4.tcp_synack_retries=2增大 backlog 只是延缓耗尽,不能根治;缩短超时可能影响高延迟正常连接,需根据业务权衡。网络层限速与过滤iptables -A INPUT -p tcp --syn -m limit --limit 1/s --limit-burst 3 -j ACCEPTiptables -A INPUT -p tcp --syn -j DROP单 IP 限速可防小规模攻击,但分布式攻击下效果有限,且可能误伤 NAT 出口用户。生产环境建议使用专业 DDoS 防护服务(Cloudflare、AWS Shield 等)做流量清洗。如何检测 SYN Flood?netstat -n | grep SYN_RCVD | wc -l 大量 SYN_RCVD 状态连接ss -s 观察 sockets 统计异常监控系统 SYN 收包速率突增检测到攻击后,优先启用 SYN Cookie,再结合限速和外部清洗逐步缓解。与 UDP Flood、HTTP Flood 相比,SYN Flood 靶向传输层,防御手段更成熟,但仍是互联网上最经典的 DDoS 攻击方式之一,1996 年至今未被根治。
计算机基础阅读 05月27日 22:48

TCP TIME_WAIT 状态的作用和问题是什么?

答案:TIME_WAIT 是主动关闭方在四次挥手最后发送 ACK 后进入的等待状态,持续 2MSL,核心作用是保证连接可靠终止和防止旧报文干扰新连接主动关闭方发送最后一个 ACK 后不能直接关闭,必须等待 2MSL(最大报文生存时间,Linux 默认 60 秒)。这段等待有两个目的:第一,兜底最后的 ACK。 如果这个 ACK 丢了,对端会重传 FIN,TIME_WAIT 状态下还能重发 ACK 响应。没有这个等待,ACK 丢失后对端永远收不到确认,连接无法正常关闭。第二,让网络中的残留报文过期。 同一个四元组(源IP、源端口、目的IP、目的端口)可能很快建立新连接,旧连接的延迟报文如果还没消失,会被新连接误收。等 2MSL 后这些报文必然被丢弃,不会串扰。TIME_WAIT 带来的实际问题高并发短连接场景下,大量连接同时处于 TIMEWAIT,会导致端口耗尽。客户端可用端口约 6 万个,每个 TIMEWAIT 占一个,当并发远超这个数,新连接报 "address already in use"。服务端主动关闭连接时问题更突出。HTTP/1.0 默认 connection: close,服务端每次响应后主动关连接,短时间积累大量 TIME_WAIT。怎么解决实际工程中常用三种手段配合:开启 tcptwreuse: 允许将 TIMEWAIT 状态的连接端口分配给新连接,前提是开启了 TCP 时间戳(tcptimestamps=1),用时间戳区分新旧连接,比单纯缩短等待更安全。用长连接和连接池: 根本思路是减少连接的频繁创建和销毁。HTTP/1.1 默认 keep-alive,数据库连接池复用连接,都是这个逻辑。扩大端口范围: 调整 iplocalport_range 到 "1024 65535",治标不治本但能缓解。# Linux 常用配置sysctl -w net.ipv4.tcp_tw_reuse=1sysctl -w net.ipv4.tcp_timestamps=1sysctl -w net.ipv4.ip_local_port_range="1024 65535"注意 tcp_tw_recycle 在 NAT 环境下会导致连接失败,Linux 4.12 后已移除该参数,不要用。面试追问为什么是 2MSL 而不是 1MSL? ACK 最多存活 1MSL 到达对端,对端重传的 FIN 也最多存活 1MSL 回来,加起来恰好 2MSL,覆盖了两个方向的最坏情况。服务端出现大量 TIME_WAIT 说明什么? 说明服务端在主动关闭连接。检查是否 HTTP 响应头缺了 keep-alive,或者业务逻辑在用完连接后主动 close 而非复用。客户端出现大量 TIME_WAIT 呢? 客户端用短连接高频请求服务端,每次自己主动关连接。排查是否可以用连接池或长连接替代。
计算机基础阅读 05月27日 22:44

TCP 粘包问题是什么?如何解决?

TCP 粘包问题是什么?如何解决?TCP 粘包是指发送方多次 send 的数据,在接收方被一次性 read 出来,多个消息"粘"在了一起。根本原因是 TCP 是字节流协议,不维护消息边界——它只保证数据可靠、按序到达,但不关心你这条消息从哪开始到哪结束。粘包是怎么产生的?发送端:Nagle 算法。多个小包攒成一个大包再发,减少网络开销。这意味着你连续调用两次 send,数据可能被合并成一个 TCP 段发出。接收端:缓冲区读取时机。应用层 read 的速度慢于数据到达速度,缓冲区里攒了好几条消息,一次 read 全取出来了。注意:粘包不是 TCP 的 bug,而是字节流协议的设计特性。UDP 就不会有这个问题,因为 UDP 保留消息边界,每次 sendto 对应一次 recvfrom。怎么解决?核心思路:在应用层定义消息边界。1. 固定长度:每条消息固定 N 字节,不够补齐。简单但浪费带宽,实际很少用。2. 分隔符:消息之间用特殊字符(如 \n)分隔。HTTP/1.1 就是用 \r\n\r\n 分隔头部和 body。缺点是消息内容本身包含分隔符时要转义,处理麻烦。3. 长度前缀(最常用):消息头加一个字段表示 body 长度,接收方先读长度再读对应字节数。绝大多数二进制协议都用这种方式。import structdef send_msg(sock, data: bytes): # 前4字节表示消息长度,大端序 sock.sendall(struct.pack('!I', len(data)) + data)def recv_msg(sock): # 先读4字节拿到长度 raw = _recv_exact(sock, 4) length = struct.unpack('!I', raw)[0] # 再读对应长度的body return _recv_exact(sock, length)def _recv_exact(sock, n): buf = b'' while len(buf) < n: chunk = sock.recv(n - len(buf)) if not chunk: raise ConnectionError('连接断开') buf += chunk return buf面试追问Q: 关掉 Nagle 算法能解决粘包吗?不能。设置 TCP_NODELAY 只解决发送端的合并问题,接收端缓冲区仍然可能一次读出多条消息。粘包的本质是缺乏消息边界,必须由应用层协议解决。Q: 什么时候不需要处理粘包?如果连续发送的数据本身就是一个整体(比如传文件),那接收端粘在一起反而是正确的,不需要额外处理。只有当每条消息是独立的、需要分别处理时,才必须定义边界。Q: 长度前缀方案,长度字段本身被拆包了怎么办?这正是 _recv_exact 函数存在的意义——用循环确保读满指定字节数。这是处理拆包的标准做法。
计算机基础阅读 05月27日 22:32

CDN 缓存策略有哪些?命中率怎么优化?

直接回答CDN 缓存策略核心就三件事:控制缓存多久(TTL)、区分缓存谁(Cache Key)、决定何时更新(刷新机制)。优化命中率的关键是:减少回源、合理分 TTL、忽略无关参数、预热热门资源。缓存策略拆解TTL 策略——最基础的缓存控制TTL 决定内容在边缘节点的存活时间:静态资源(图片、字体、CSS/JS 带 hash):设长 TTL,甚至 max-age=31536000, immutable半静态内容(商品页、文章页):分钟级 TTL,配合软刷新动态接口(用户数据、实时行情):不缓存或秒级 TTL,走协商缓存(ETag / Last-Modified)Cache-Control: public, max-age=31536000, immutable // 带 hash 的静态资源Cache-Control: public, max-age=300, s-maxage=60 // CDN 缓 60s,浏览器缓 5minCache-Control: no-cache, ETag: "v2-abc" // 协商缓存Cache Key 策略——决定哪些请求共享缓存默认 Cache Key 是完整 URL。问题在于:?utm_source=weibo 和 ?utm_source=zhihu 本是同一资源,却被分成两条缓存,白白回源。优化方式:忽略无关查询参数:过滤 utm_*、timestamp 等不影响内容的参数自定义 Cache Key:加入 Cookie 中的地区码,忽略 PHPSESSIDVary 头:让 CDN 按 Accept-Encoding 区分 gzip/br 版本分层缓存——边缘 → 区域 → 源站请求查找顺序:边缘节点 → 区域节点 → 源站。边缘未命中会回区域,区域未命中才回源。所以优化重点是让请求尽量在边缘命中。命中率优化实战1. 忽略 URL 参数这是命中率低最常见的原因。一条 ?token=xxx 就能让缓存全部失效。阿里云 CDN 实测:忽略无关参数后命中率可从 40% 提升到 90%+。2. 大文件分片回源(Range 回源)用户看视频只看了前 5 分钟,但 CDN 回源拉了整个文件。开启 Range 回源后只拉需要的片段,减少回源流量,也提升字节命中率。3. 缓存预热新版本发布或大促前,主动把热门资源推到各边缘节点。两种方式:API 预热:调用 CDN 控制台接口主动推送模拟请求:用脚本批量请求触发被动缓存4. 版本化发布代替刷新与其发版后全站刷新缓存,不如在文件名里带 hash:app.3f2a1b.js。内容变了 hash 就变,旧缓存自然过期,无需主动刷新。5. 监控命中率指标请求命中率 = 缓存命中请求数 / 总请求数字节命中率 =(边缘响应流量 - 回源流量)/ 边缘响应流量请求命中率 >90% 为健康,70%-90% 需要优化,<70% 必须排查。追问:内容更新后用户还看到旧版本怎么办?三层解法,按优先级:文件名带 hash,一劳永逸(最推荐)URL 刷新,精确清除单条缓存全站刷新,最后手段,会瞬间压高源站追问:缓存命中率突然下降怎么排查?按这个顺序查:看是否有新参数打入了 Cache Key(查访问日志里的 URL 变体)看源站是否返回了 no-store / private 头看 TTL 是否被覆盖缩短看是否有大流量回源(可能是爬虫或攻击绕过缓存)
计算机基础阅读 05月27日 22:21

CDN 如何配置 HTTPS?三种回源模式有什么区别?

直接回答CDN 配置 HTTPS 主要有三种方式:自定义证书上传、CDN 免费证书、SNI 多域名证书。HTTPS 回源模式分三档:Flexible(仅客户端加密)、Full(全链路加密但不验证源站证书)、Full Strict(全链路加密且严格验证源站证书),生产环境应选 Full Strict。HTTPS 配置方式自定义证书上传:购买或申请 SSL 证书后,在 CDN 控制台上传 .crt 证书和 .key 私钥。优点是完全可控,支持通配符和 EV 证书;缺点是需手动续期。CDN 免费证书:主流 CDN 支持 Let's Encrypt 等免费证书,自动签发和续期,适合中小站点。Cloudflare 的 Universal SSL 就属此类。SNI 方式:CDN 在同一 IP 上通过 SNI 区分不同域名的证书,客户端握手时携带域名,服务端返回对应证书。现代浏览器均支持。# Cloudflare 启用 Universal SSL 示例curl -X PATCH "https://api.cloudflare.com/client/v4/zones/{zone_id}/settings/ssl" \ -H "Authorization: Bearer {api_token}" \ -H "Content-Type: application/json" \ -d '{"value":"strict"}'三种 HTTPS 回源模式这是面试核心,务必理解三者区别:Flexible:用户→CDN 走 HTTPS,CDN→源站走 HTTP。源站无需证书,但回源链路明文传输,存在中间人风险。仅适合测试环境或纯静态内容。Full:全链路 HTTPS,但 CDN 不验证源站证书是否合法(自签名证书也接受)。比 Flexible 安全,但无法防御源站侧的证书伪造攻击。Full Strict:全链路 HTTPS + 严格证书验证,要求源站证书由受信 CA 签发且域名匹配。安全性最高,证书异常会直接拒绝连接。金融、政务等场景必选。关键配置实践强制 HTTPS 跳转和 HSTS 是标配:# Nginx 强制跳转server { listen 80; return 301 https://$host$request_uri;}# HSTS 响应头add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;SSL 协议只保留 TLS 1.2 和 1.3,禁用弱加密套件。启用 OCSP Stapling 减少握手延迟,配置会话缓存复用 SSL 连接:ssl_protocols TLSv1.2 TLSv1.3;ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;ssl_session_cache shared:SSL:10m;ssl_stapling on;ssl_stapling_verify on;常见坑无限重定向循环:CDN 开启强制 HTTPS,源站又把 HTTPS 重定向回 HTTP,形成死循环。解决办法是源站只监听 80 端口或正确识别 CDN 传递的 X-Forwarded-Proto 头。混合内容警告:HTTPS 页面加载了 HTTP 资源,浏览器会拦截。用 CSP 头自动升级:Content-Security-Policy: upgrade-insecure-requests。证书链不完整:只上传了域名证书缺少中间证书,导致客户端无法验证。解决:按域名证书→中间证书的顺序拼接后上传。追问方向SNI 在什么场景下会失效?老旧客户端(IE6/Windows XP)不支持 SNI,CDN 如何兼容?如果源站证书过期,Full Strict 模式下会发生什么?如何做到零停机续期?CDN 开启 HSTS 后源站切换回 HTTP 会有什么后果?
计算机基础阅读 05月27日 22:21

CDN 如何实现视频加速?有哪些关键技术?

CDN 如何实现视频加速?有哪些关键技术?CDN 视频加速的核心思路:把视频切片、多码率编码、缓存在离用户最近的边缘节点,播放时根据网络状况动态选择码率和分片,从而降低首屏时间、减少卡顿。一、自适应码率(ABR)播放器实时检测带宽和缓冲区水位,动态切换码率档位。主流 ABR 算法分三类:基于缓冲区:缓冲区低选低码率,充足选高码率,实现简单但反应慢基于吞吐量:用近期下载速率预估带宽,选不超过带宽的最高码率,反应快但波动大混合算法:同时参考缓冲区和吞吐量,BOLA 和 MPC 是工业界常用方案追问:ABR 切换时为什么会出现画面模糊再清晰?因为切换发生在分片边界,中间需要等当前分片播完才能请求新码率分片,这段时间画面保持旧码率。二、视频编码优化| 编码格式 | 相比 H.264 体积 | 编码速度 | 兼容性 | 典型场景 ||---------|----------------|---------|--------|---------|| H.264 | 基准 | 快 | 最好 | 通用点播 || H.265 | 小 50% | 慢 3-5x | 较差 | 高清/带宽受限 || AV1 | 小 60% | 极慢 | 有限 | 未来/超高清 |生产中通常生成多码率多分辨率版本(码率阶梯),编码参数重点控制:GOP 大小(关键帧间隔)、maxrate/bufsize(码率上限)、帧率(动态场景 60fps,静态 24fps)。三、流媒体协议:HLS vs DASHHLS(Apple 主导):m3u8 播放列表 + .ts 分片,生态成熟,iOS 原生支持。DASH(MPEG 标准):mpd(XML)+ .m4s 分片,跨平台,灵活度更高。两者都能跑在纯 HTTP 上,天然适配 CDN 缓存。CMAF 格式让 HLS 和 DASH 共用同一套 fMP4 分片,只需维护两份 manifest,存储成本减半。追问:直播场景下 HLS 延迟为什么高?如何优化?HLS 延迟 = 分片时长 x 3(编码缓冲 + 播放列表刷新 + 缓冲区预载)。优化方向:缩短分片到 2-4 秒、用 LL-HLS 的部分分片预加载、或改用 WebRTC/FLV 方案。四、CDN 缓存策略分片缓存:每个 .ts/.m4s 独立缓存,命中率高,TTL 可设较长(1-24h)播放列表缓存:.m3u8/.mpd 动态更新,TTL 短(直播 5s,点播 5min)缓存锁:proxy_cache_lock 防止同一分片并发回源击穿缓存智能预加载:播放器预取后续 2-3 个分片和下一码率档位五、传输层优化HTTP/2 多路复用减少连接数、头部压缩降低开销;HTTP/3(QUIC)基于 UDP 减少握手延迟、改善弱网拥塞控制。点播用 HTTP 足够,直播低延迟场景倾向 UDP(WebRTC)。六、播放体验优化首屏慢的典型链路:DNS 解析 → TCP 连接 → TLS 握手 → 请求 m3u8 → 请求分片 → 解码首帧。优化手段:预连接、初始选低码率快速起播、增加关键帧频率(GOP 缩小到 1-2 秒)、预加载首屏分片。拖动进度条时,需要定位到目标时间对应的关键帧所在的分片。关键帧间隔越短,seek 响应越快,但编码效率略降。七、质量监控关键指标:首屏时间、卡顿率、码率切换频率、平均播放码率。播放端通过 waiting/playing 事件采集缓冲数据,定时上报,服务端做聚合告警。追问:卡顿率高但码率切换少,可能是什么原因?ABR 没有及时降码率,可能是吞吐量估算偏高、缓冲区水位阈值设置过高,或者分片缓存未命中导致回源延迟。