03. RPC、消息队列、DNS、CDN(深挖版)¶
这一章很容易在面试里被问成“系统设计混合题”:
- 服务之间为什么不用直接 HTTP?
- MQ 到底解决了什么,不会把系统搞更复杂吗?
- DNS 查一次域名为什么会有这么多层?
- CDN 真的是“缓存到离用户更近”这么简单吗?
如果只会背“解耦、削峰、递归查询、边缘节点”,大概率只能停留在一面。更强的回答,应该能说清:
- 它解决了什么问题
- 它为什么这样设计
- 它的代价和边界在哪里
- 工程里什么时候该用,什么时候不该用
本章建议按“先理解知识主线,再练问答表达,最后吃透边界条件”的顺序阅读:
- 先把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 调用一次大概经历什么?¶
简化流程¶
- 调用方发起本地函数调用
- 客户端 stub / proxy 把调用参数序列化
- 根据服务发现拿到目标实例地址
- 通过网络发送请求
- 服务端收到后反序列化
- 服务端真正执行目标函数
- 把结果序列化返回
- 客户端反序列化结果,交给调用方
面试高频追问点¶
这道题真正会被追问的不是流程图,而是这些问题:
- 服务地址从哪里来?
- 如果某个实例挂了怎么办?
- 超时和重试是谁控制?
- 重试会不会导致副作用重复?
- 序列化协议为什么选 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 查询过程大概是怎样的?¶
标准回答¶
通常包括:
- 浏览器缓存
- 系统缓存
- 本地域名解析器(递归解析器)
- 根域名服务器
- 顶级域(TLD)服务器
- 权威域名服务器
- 返回目标 IP
更准确地理解¶
很多人背成“客户端一路去问根、问顶级、问权威”,但实际更常见的用户视角是:
- 客户端把问题交给本地递归解析器
- 真正去层层查询根/TLD/权威的,通常是递归解析器
所以要分清两种查询¶
- 递归查询:我把问题交给你,你替我查到底
- 迭代查询:我问你,你告诉我下一步该去问谁
面试高分点¶
终端用户通常感知到的是递归解析服务;根、TLD、权威这套分层体系主要是为了把全球域名空间按层级拆分管理。
第三部分:把难点、边界和代价吃透¶
10. DNS 为什么要设计成分层结构?¶
原因一:全球命名空间太大,不能全放在一个地方¶
如果所有域名都靠一个中心服务器管理:
- 扩展性差
- 容错差
- 管理成本高
- 全球访问延迟大
原因二:按层授权更自然¶
比如:
- 根管顶级域
.com管二级域example.com的权威服务器只管自己名下记录
这样管理边界清晰。
原因三:有利于缓存¶
DNS 大量依赖缓存:
- 本地缓存
- 递归解析器缓存
- TTL 控制刷新时间
缓存能显著减少重复查询。
11. DNS 为什么有时会“改了记录但不立刻生效”?¶
原因¶
因为 DNS 不是每次都从权威服务器重新查,而是大量依赖缓存,而缓存是否失效由:
- TTL
- 中间递归解析器策略
- 本地系统缓存
- 浏览器缓存
共同决定。
这题真正想考什么?¶
想考你是否理解:
DNS 不是强实时配置中心,而是一个大规模、分层、强依赖缓存的名字解析系统。
12. CDN 原理是什么?¶
标准回答¶
CDN 通过把内容缓存到离用户更近的边缘节点,减少跨地域传输延迟,提升访问速度和可用性,并降低源站压力。
不能只停在这句¶
CDN 的本质可以拆成两部分:
- 调度问题:让用户访问到“合适”的边缘节点
- 缓存问题:让边缘节点尽可能命中用户要的数据
常见流程¶
- 用户访问资源域名
- DNS / 调度系统把用户引导到合适的 CDN 节点
- 如果边缘节点已有缓存,直接返回
- 若未命中,再回源站拉取并缓存
高分表达¶
CDN 不只是“把文件复制到很多地方”,而是“通过智能调度 + 分层缓存 + 回源机制,优化用户访问路径和源站负载”。
13. CDN 为什么能加速?¶
原因一:物理距离更近¶
用户访问本地或近区域边缘节点,时延通常更低。
原因二:减少跨网和跨地域链路¶
避免很多长路径传输中的抖动与拥塞。
原因三:缓存命中后不用每次都回源¶
减少源站压力,也减少请求总链路长度。
原因四:边缘节点通常经过专门优化¶
比如:
- 更强带宽
- 更优路由
- 更多接入点
- 更高并发处理能力
14. CDN 会带来什么问题?¶
常见问题¶
- 缓存一致性问题
- 热点内容失效风暴
- 回源压力突增
- 动态资源不易缓存
- 调度不精准导致访问到“并不近”的节点
典型追问一:缓存一致性¶
如果源站内容更新了,但 CDN 边缘节点还在用旧缓存,就可能产生:
- 用户看到旧版本
- 不同地区内容不一致
所以要结合:
- TTL
- 主动刷新
- 版本号/文件指纹
- Cache-Control 策略
典型追问二:缓存穿透 / 回源风暴¶
如果大量请求同时打到未命中的资源:
- 边缘节点可能都去回源
- 源站压力会瞬间暴涨
这和本地缓存系统的“击穿”问题很像。
15. 动态内容也能用 CDN 吗?¶
可以,但方式不同。¶
静态资源最适合 CDN,比如:
- 图片
- 视频
- JS/CSS
- 下载包
动态内容也可以优化,但通常不是简单“全量缓存”,而是:
- 动静分离
- 边缘鉴权
- 边缘计算
- API 网关加速
- 部分页面片段缓存
面试里别说绝对话¶
不要说“CDN 只适合静态资源”。 更准确的说法是:
CDN 对静态内容最天然有效,对动态内容也能参与优化,但策略会复杂得多。
16. 一组很常见的追问链¶
- 为什么内部服务常用 RPC?
- RPC 和 HTTP API 的核心差异是什么?
- RPC 调用一次经历什么?
- 服务发现、超时、重试、负载均衡怎么做?
- MQ 为什么能解耦和削峰?
- 引入 MQ 后会有什么问题?
- 幂等为什么重要?
- DNS 查询为什么是分层的?
- 递归查询和迭代查询有什么区别?
- CDN 为什么能加速?它和普通缓存有什么不同?
- CDN 缓存一致性怎么处理?
这条链非常适合中高级后端岗位继续往系统设计方向深挖。
17. 一份更像面试现场的总结回答¶
RPC、MQ、DNS、CDN 这几个点表面上很散,本质都在解决“分布式系统如何把复杂性组织起来”的问题。RPC 解决的是服务之间如何高效、可治理地调用;MQ 解决的是时序解耦、异步扩展和流量缓冲,但代价是顺序性、重复消费和一致性复杂化;DNS 解决的是全球域名到地址的分层映射问题,核心依赖递归解析和缓存;CDN 解决的是内容分发路径和源站压力问题,本质是调度 + 缓存。真正好的回答,不是背定义,而是能把这些机制的收益、代价和适用边界讲清楚。
18. 复习建议¶
如果你想把这一章答得更像工程面试,不只是背概念,至少做到:
- 能解释内部服务为什么偏爱 RPC
- 能说明 RPC 的治理能力为什么重要
- 能说清 MQ 的收益和复杂性是一起出现的
- 能解释幂等为什么是分布式系统基础能力
- 能讲清 DNS 的递归/迭代和缓存机制
- 能把 CDN 说成“调度 + 缓存 + 回源”,而不是一句“离用户更近”
做到这些,这一章就不再只是“网络边角料”,而会变成后端系统设计题的重要基础。