跳转至

03. RPC、消息队列、DNS、CDN(深挖版)

这一章很容易在面试里被问成“系统设计混合题”:

  • 服务之间为什么不用直接 HTTP?
  • MQ 到底解决了什么,不会把系统搞更复杂吗?
  • DNS 查一次域名为什么会有这么多层?
  • CDN 真的是“缓存到离用户更近”这么简单吗?

如果只会背“解耦、削峰、递归查询、边缘节点”,大概率只能停留在一面。更强的回答,应该能说清:

  1. 它解决了什么问题
  2. 它为什么这样设计
  3. 它的代价和边界在哪里
  4. 工程里什么时候该用,什么时候不该用

本章建议按“先理解知识主线,再练问答表达,最后吃透边界条件”的顺序阅读:

  • 先把RPC vs HTTP、消息队列作用、DNS 查询流程
  • 再展开RPC 调用链路、消息队列问题(重复/丢失/堆积)、CDN 原理
  • 最后把幂等性、消息事务、DNS 劫持/污染、CDN 动态加速

先把这一章的知识骨架搭起来

这章讲的是网络能力进入真实系统之后的工程化形态:服务之间怎样调用、消息怎样解耦传递、名字怎样解析成地址、内容怎样更靠近用户。RPC、MQ、DNS、CDN 听起来不像同一类题,但它们都属于“把基础网络能力包装成可扩展的系统组件”。

RPC 解决的是服务间方法调用的抽象与治理,MQ 解决的是削峰、解耦、异步和可靠投递,DNS 解决的是名字到地址的映射和分层解析,CDN 解决的是静态内容的就近分发与回源控制。你只要把它们分别放回“调用链、消息链、解析链、分发链”去理解,面试就不会乱。

面试里高分点,是能说明这些组件不仅带来好处,也会引入一致性、时延、排障和运维复杂度。


第一部分:先把概念和主线讲清楚

进入问答前,先把最小前置知识补齐

这一章讲的是基础网络能力进入工程系统后的几种典型形态。RPC 处理“服务之间怎么像调本地函数一样调用”,消息队列处理“请求怎样解耦、削峰、异步传递”,DNS 处理“名字怎样解析成地址”,CDN 处理“内容怎样更靠近用户”。

它们看起来跨领域,但本质上都在服务大规模系统的四条链:调用链、消息链、解析链、分发链。只要把这四条链记住,很多问题就不再只是名词解释,而会回到系统职责本身。


1. RPC 和 HTTP API 有什么区别?

标准回答

  • RPC:更强调“像调用本地函数一样调用远程服务”,通常有更强的接口定义、序列化协议、超时重试和服务治理能力
  • HTTP API:更强调通用性、开放性、可读性和跨语言/跨平台互通,适合对外接口和弱耦合集成

更深入的理解

RPC 和 HTTP API 不是简单的“二选一对立面”,而是两个不同侧重点:

  • HTTP API 更像“资源/动作暴露协议”
  • RPC 更像“服务间调用框架”

很多 RPC 框架底层照样跑在 HTTP/2、TCP 甚至 QUIC 上,但面试里说 RPC 时,重点不在“它用哪层传输”,而在于:

  • 接口定义是否强约束
  • 序列化是否高效
  • 调用链治理是否完善
  • 超时、重试、负载均衡、熔断、追踪是否内建

面试里更强的说法

HTTP API 更适合开放边界、可调试性强、跨团队/跨语言的场景;RPC 更适合内部服务调用,因为它更强调接口契约、性能和治理能力。


2. 为什么微服务内部常用 RPC,而不是全都用 REST?

原因一:内部调用更看重效率和契约

服务内部往往调用频繁、链路长、QPS 高,更关注:

  • 序列化效率
  • 网络开销
  • 代码自动生成
  • 类型安全
  • 统一治理

原因二:内部系统更容易统一协议和 SDK

对外接口要考虑:

  • 第三方能不能看懂
  • 能不能直接 curl 调试
  • 接入门槛是否低

而内部服务通常可以统一:

  • IDL(如 protobuf/thrift)
  • SDK
  • 服务注册发现
  • 调用规范

原因三:治理能力很关键

真实微服务不是“发个请求回来就完了”,还要处理:

  • 超时
  • 重试
  • 限流
  • 熔断
  • 负载均衡
  • 链路追踪
  • 灰度发布
  • 服务发现

RPC 框架常把这些能力做成基础设施。


3. RPC 调用一次大概经历什么?

简化流程

  1. 调用方发起本地函数调用
  2. 客户端 stub / proxy 把调用参数序列化
  3. 根据服务发现拿到目标实例地址
  4. 通过网络发送请求
  5. 服务端收到后反序列化
  6. 服务端真正执行目标函数
  7. 把结果序列化返回
  8. 客户端反序列化结果,交给调用方

面试高频追问点

这道题真正会被追问的不是流程图,而是这些问题:

  • 服务地址从哪里来?
  • 如果某个实例挂了怎么办?
  • 超时和重试是谁控制?
  • 重试会不会导致副作用重复?
  • 序列化协议为什么选 protobuf?
  • 长连接如何复用?
  • 负载均衡在客户端还是服务端做?

一句总结

RPC 的本质不是“远程函数调用真的像本地函数那么简单”,而是框架在尽量帮你把远程调用包装得接近本地调用,同时接住远程调用的复杂性。


4. RPC 最大的问题是什么?

标准回答

RPC 最大的问题是:它容易让开发者误以为远程调用和本地调用一样便宜、一样可靠。

为什么这是核心问题?

本地函数调用通常:

  • 延迟很低
  • 很少失败
  • 不涉及网络抖动
  • 不涉及序列化/反序列化

远程调用则可能遇到:

  • 网络超时
  • 部分失败
  • 重试导致重复执行
  • 下游雪崩
  • 链路放大
  • 版本兼容问题

高分表达

RPC 最大的风险不是“性能不够快”,而是它把分布式系统的复杂性包装得太像本地调用,导致系统设计者低估失败成本。


第二部分:围绕高频追问继续展开

5. 消息队列的作用是什么?

标准回答

消息队列常见作用:

  • 解耦
  • 削峰填谷
  • 异步处理
  • 广播/订阅

这几个词分别是什么意思?

5.1 解耦

原本 A 系统要直接调用 B、C、D:

  • 依赖多
  • 出错面大
  • 扩展麻烦

引入 MQ 后:

  • A 只负责把消息发出去
  • 谁来消费可以后续扩展
  • 生产方与消费方时序解耦、职责解耦

5.2 削峰填谷

当短时间请求暴增时:

  • 前端流量可能瞬间打爆下游
  • MQ 可以把高峰请求先堆起来
  • 消费端按稳定速率处理

但注意:

MQ 不是“消灭峰值”,而是“把峰值转成排队等待”。

5.3 异步处理

如果一个操作不要求用户实时拿到全部结果,就可以:

  • 先快速返回
  • 再由后台异步处理

典型场景:

  • 发短信
  • 发邮件
  • 刷推荐
  • 生成报表
  • 日志处理

5.4 广播/订阅

一条事件可以被多个系统消费:

  • 订单创建 → 库存系统消费
  • 订单创建 → 营销系统消费
  • 订单创建 → 风控系统消费
  • 订单创建 → 数据埋点系统消费

6. 引入消息队列会带来什么问题?

标准回答

消息队列会引入:

  • 消息重复
  • 消息丢失
  • 顺序性问题
  • 消费积压
  • 一致性复杂化
  • 链路调试困难

这题一定要会反着答

面试官经常问“MQ 有什么好处”,但真正拉开差距的是你能不能补一句:

MQ 的本质不是免费收益,而是用“系统复杂性增加”换“耦合下降和吞吐弹性”。

典型问题拆解

6.1 消息重复

因为生产重试、投递重试、消费重试都可能造成重复消息。

所以消费者常要做:

  • 幂等设计
  • 去重表
  • 业务唯一键校验

6.2 消息丢失

可能发生在:

  • 生产者没成功写入 broker
  • broker 未持久化就宕机
  • 消费成功了但 ack 异常

所以要结合:

  • 生产确认
  • 持久化
  • 副本机制
  • 消费确认

6.3 顺序性

一旦有多分区、多消费者并发处理,顺序就不一定天然成立。

所以要先问清:

  • 是全局顺序?
  • 分区内顺序?
  • 单 key 顺序?

通常工程里只保证“局部顺序”,因为全局顺序代价很高。

6.4 消费积压

削峰是有前提的:

  • 高峰只是暂时的
  • 消费能力最终能追上生产速度

如果长期生产速度 > 消费速度,MQ 只会把问题延后暴露,最后变成:

  • 队列堆满
  • 消息延迟飙升
  • 磁盘/内存压力上升

6.5 一致性复杂化

同步调用时,成功/失败边界相对直观。 引入 MQ 后就会碰到:

  • 本地事务成功但消息没发出去
  • 消息发出去了但本地事务回滚
  • 下游消费成功但状态回写失败

这会把一致性问题从“单系统事务”升级为“分布式事务/最终一致性设计”。


7. 什么是幂等?为什么 MQ 特别爱问它?

标准回答

同一个操作执行一次和执行多次,结果一致,这叫幂等。

为什么 MQ 场景特别重要?

因为消息系统常见语义往往是:

  • 至少一次投递(at least once)

这意味着:

  • 消息可能会重复送达
  • 消费者必须能承受重复处理

典型幂等实现思路

  • 业务唯一 ID
  • 数据库唯一索引
  • 去重表
  • 状态机校验(如只能从 A 状态流转到 B 状态一次)

高分点

幂等不是消息队列专属概念,而是所有“可能重试”的分布式场景的基础生存能力。


8. 消息队列是“同步改异步”,那是不是越多越好?

不是。

这是特别典型的工程追问。

不该滥用 MQ 的场景

如果业务要求:

  • 强一致实时返回
  • 调用结果必须立刻知道
  • 错误必须立刻反馈给用户

那强行上 MQ 可能会让体验和系统都更糟。

比如:

  • 用户转账后必须立刻确认是否成功
  • 登录鉴权必须立即判断通过/拒绝
  • 下单库存校验必须在当前请求闭环完成

这些场景里,异步化只能做旁路能力,不能替代主链路判断。

一句总结

MQ 适合“允许延迟、允许最终一致、允许异步扩散”的场景,不适合所有核心流程都无脑改异步。


9. DNS 查询过程大概是怎样的?

标准回答

通常包括:

  1. 浏览器缓存
  2. 系统缓存
  3. 本地域名解析器(递归解析器)
  4. 根域名服务器
  5. 顶级域(TLD)服务器
  6. 权威域名服务器
  7. 返回目标 IP

更准确地理解

很多人背成“客户端一路去问根、问顶级、问权威”,但实际更常见的用户视角是:

  • 客户端把问题交给本地递归解析器
  • 真正去层层查询根/TLD/权威的,通常是递归解析器

所以要分清两种查询

  • 递归查询:我把问题交给你,你替我查到底
  • 迭代查询:我问你,你告诉我下一步该去问谁

面试高分点

终端用户通常感知到的是递归解析服务;根、TLD、权威这套分层体系主要是为了把全球域名空间按层级拆分管理。


第三部分:把难点、边界和代价吃透

10. DNS 为什么要设计成分层结构?

原因一:全球命名空间太大,不能全放在一个地方

如果所有域名都靠一个中心服务器管理:

  • 扩展性差
  • 容错差
  • 管理成本高
  • 全球访问延迟大

原因二:按层授权更自然

比如:

  • 根管顶级域
  • .com 管二级域
  • example.com 的权威服务器只管自己名下记录

这样管理边界清晰。

原因三:有利于缓存

DNS 大量依赖缓存:

  • 本地缓存
  • 递归解析器缓存
  • TTL 控制刷新时间

缓存能显著减少重复查询。


11. DNS 为什么有时会“改了记录但不立刻生效”?

原因

因为 DNS 不是每次都从权威服务器重新查,而是大量依赖缓存,而缓存是否失效由:

  • TTL
  • 中间递归解析器策略
  • 本地系统缓存
  • 浏览器缓存

共同决定。

这题真正想考什么?

想考你是否理解:

DNS 不是强实时配置中心,而是一个大规模、分层、强依赖缓存的名字解析系统。


12. CDN 原理是什么?

标准回答

CDN 通过把内容缓存到离用户更近的边缘节点,减少跨地域传输延迟,提升访问速度和可用性,并降低源站压力。

不能只停在这句

CDN 的本质可以拆成两部分:

  1. 调度问题:让用户访问到“合适”的边缘节点
  2. 缓存问题:让边缘节点尽可能命中用户要的数据

常见流程

  1. 用户访问资源域名
  2. DNS / 调度系统把用户引导到合适的 CDN 节点
  3. 如果边缘节点已有缓存,直接返回
  4. 若未命中,再回源站拉取并缓存

高分表达

CDN 不只是“把文件复制到很多地方”,而是“通过智能调度 + 分层缓存 + 回源机制,优化用户访问路径和源站负载”。


13. CDN 为什么能加速?

原因一:物理距离更近

用户访问本地或近区域边缘节点,时延通常更低。

原因二:减少跨网和跨地域链路

避免很多长路径传输中的抖动与拥塞。

原因三:缓存命中后不用每次都回源

减少源站压力,也减少请求总链路长度。

原因四:边缘节点通常经过专门优化

比如:

  • 更强带宽
  • 更优路由
  • 更多接入点
  • 更高并发处理能力

14. CDN 会带来什么问题?

常见问题

  • 缓存一致性问题
  • 热点内容失效风暴
  • 回源压力突增
  • 动态资源不易缓存
  • 调度不精准导致访问到“并不近”的节点

典型追问一:缓存一致性

如果源站内容更新了,但 CDN 边缘节点还在用旧缓存,就可能产生:

  • 用户看到旧版本
  • 不同地区内容不一致

所以要结合:

  • TTL
  • 主动刷新
  • 版本号/文件指纹
  • Cache-Control 策略

典型追问二:缓存穿透 / 回源风暴

如果大量请求同时打到未命中的资源:

  • 边缘节点可能都去回源
  • 源站压力会瞬间暴涨

这和本地缓存系统的“击穿”问题很像。


15. 动态内容也能用 CDN 吗?

可以,但方式不同。

静态资源最适合 CDN,比如:

  • 图片
  • 视频
  • JS/CSS
  • 下载包

动态内容也可以优化,但通常不是简单“全量缓存”,而是:

  • 动静分离
  • 边缘鉴权
  • 边缘计算
  • API 网关加速
  • 部分页面片段缓存

面试里别说绝对话

不要说“CDN 只适合静态资源”。 更准确的说法是:

CDN 对静态内容最天然有效,对动态内容也能参与优化,但策略会复杂得多。


16. 一组很常见的追问链

  1. 为什么内部服务常用 RPC?
  2. RPC 和 HTTP API 的核心差异是什么?
  3. RPC 调用一次经历什么?
  4. 服务发现、超时、重试、负载均衡怎么做?
  5. MQ 为什么能解耦和削峰?
  6. 引入 MQ 后会有什么问题?
  7. 幂等为什么重要?
  8. DNS 查询为什么是分层的?
  9. 递归查询和迭代查询有什么区别?
  10. CDN 为什么能加速?它和普通缓存有什么不同?
  11. CDN 缓存一致性怎么处理?

这条链非常适合中高级后端岗位继续往系统设计方向深挖。


17. 一份更像面试现场的总结回答

RPC、MQ、DNS、CDN 这几个点表面上很散,本质都在解决“分布式系统如何把复杂性组织起来”的问题。RPC 解决的是服务之间如何高效、可治理地调用;MQ 解决的是时序解耦、异步扩展和流量缓冲,但代价是顺序性、重复消费和一致性复杂化;DNS 解决的是全球域名到地址的分层映射问题,核心依赖递归解析和缓存;CDN 解决的是内容分发路径和源站压力问题,本质是调度 + 缓存。真正好的回答,不是背定义,而是能把这些机制的收益、代价和适用边界讲清楚。


18. 复习建议

如果你想把这一章答得更像工程面试,不只是背概念,至少做到:

  • 能解释内部服务为什么偏爱 RPC
  • 能说明 RPC 的治理能力为什么重要
  • 能说清 MQ 的收益和复杂性是一起出现的
  • 能解释幂等为什么是分布式系统基础能力
  • 能讲清 DNS 的递归/迭代和缓存机制
  • 能把 CDN 说成“调度 + 缓存 + 回源”,而不是一句“离用户更近”

做到这些,这一章就不再只是“网络边角料”,而会变成后端系统设计题的重要基础。