Dubbo 面试题
本页只放面试标准回答、追问点、项目话术和原理页跳转。详细原理请跳到对应知识点页学习。
核心问题
| 问题 | 标准回答 | 原理页 |
|---|---|---|
| Dubbo 是什么 | Dubbo 是 Java 生态常用的 RPC 和服务治理框架,让 Consumer 通过接口代理调用远程 Provider,同时提供注册发现、负载均衡、容错、超时、重试、版本分组、路由、Filter 和 SPI 扩展能力。 | Dubbo 总览 |
| RPC 是什么 | RPC 是远程过程调用。它把网络通信、序列化、协议、连接、超时等细节封装起来,让调用方像调用本地接口一样调用远程服务。但底层仍是不可靠网络,必须考虑超时、失败、重复和幂等。 | Dubbo 总览 |
| Dubbo 一次调用怎么走 | Consumer接口代理把方法转成Invocation并进入Cluster Invoker;Directory列出本地Invoker快照,Router过滤,LoadBalance为一次尝试选实例,Consumer Filter后由Protocol Invoker经ExchangeClient发送。Provider解码和线程派发后按serviceKey找Exporter,经过Provider Filter和Proxy Invoker调用真实实现;响应按requestId完成Consumer对应Future。 | Consumer调用链、Provider接收链、响应链 |
| 注册中心做什么 | 注册中心属于控制面,只保存和推送接口地址或应用实例、元数据引用和治理信息,不转发RPC。Consumer把通知对账成本地Invoker快照,调用时再直连Provider。 | 控制面与数据面、注册中心职责 |
| Dubbo 2和Dubbo 3服务发现有什么区别 | Dubbo 2.x常见每个接口注册完整Provider URL;Dubbo 3主线按应用实例发现,并通过接口到应用映射和元数据还原RPC服务能力,减少实例与接口笛卡尔积产生的注册数据。迁移期可双模型过渡。 | 接口级发现、应用级发现、迁移模型 |
| ZooKeeper 在 Dubbo 里做什么 | ZooKeeper可保存传统接口节点并通过Session临时节点和Watch支持变化感知。短暂断连不会立即删除节点;Session过期后客户端必须重新注册、订阅。Watch是变化提示,Consumer仍要重读当前完整状态。 | 临时节点、Watcher语义、失效窗口 |
| Dubbo 和 OpenFeign 区别 | Dubbo 是 RPC 框架,传统上更适合 Java 内部服务强契约、高性能二进制协议调用;OpenFeign 是声明式 HTTP 客户端,更贴近 Spring Cloud HTTP 主线,跨语言和开放 API 更友好。 | Dubbo 总览、Feign |
调用链追问
| 追问 | 标准回答 | 原理页 |
|---|---|---|
| Provider启动时怎样暴露服务 | ServiceConfig校验接口、实现、协议和注册中心;ProxyFactory把实现对象包装为Provider Invoker,Filter等扩展包装后由Protocol.export生成Exporter并放入本地服务映射,打开/复用Server端口,再向注册中心发布地址和元数据。 | Provider服务暴露全过程 |
| Consumer 注入的是什么对象 | 注入的是接口代理,不是Provider实现或固定地址客户端。ReferenceConfig建立动态Directory,把地址转换为远程Invoker,Cluster将多个Invoker包装成统一Invoker,ProxyFactory再生成接口代理;每次调用读取当前目录快照。 | Consumer引用全过程、Directory刷新 |
| Invoker 是什么 | Invoker是Dubbo统一可调用抽象:Provider实现可包装成本地Invoker,单个远程地址是Protocol Invoker,多个地址经Cluster包装后仍是Invoker。代理和Filter只依赖invoke接口,使协议、集群和扩展可以组合。 | 核心对象 |
| Directory、Router、LoadBalance、Cluster区别 | Directory回答当前有哪些Invoker;Router按标签、条件、机房等过滤本次候选;LoadBalance从候选中为一次尝试选一个;Cluster决定失败后重试、并行还是快速失败,并把多Invoker包装成一个调用入口。 | 四层区别、Cluster容错 |
| Provider怎样找到真实服务 | Provider完成帧解码和线程派发后,从Invocation中的interface、group、version和端口等形成serviceKey,在Exporter映射中找到Provider Invoker,再经过Provider Filter和Proxy Invoker调用真实Bean。端口可达不代表serviceKey一定匹配。 | Provider接收与Exporter查找 |
| Filter 能做什么 | Filter是Invoker装饰链,可在Consumer/Provider调用前后做trace、鉴权、租户、限流、指标和异常映射。顺序和激活范围很重要,慢业务不能放Filter,ThreadLocal必须在finally清理。 | Filter调用链、SPI扩展点 |
注册发现追问
| 追问 | 标准回答 | 原理页 |
|---|---|---|
| 注册中心挂了还能调用吗 | 运行中的Consumer若已有内存快照且Provider数据面可达,可能继续调用;新Consumer、Provider注册、地址变化、元数据和治理规则会受影响。必须区分启动期/运行期和接口级/应用级发现。 | 故障矩阵、本地缓存 |
| RegistryDirectory怎样刷新地址 | 收到新快照后先校验和合并配置,以规范化URL构建新Map,复用未变化Invoker,为新增/实质变化地址创建Invoker,完整构建后原子发布不可变快照,再销毁移除的旧Invoker。 | Directory对账、地址Diff、并发快照 |
| No provider available 怎么排查 | 先确认Provider完成export和register,再核对interface/group/version/protocol与发现模型,查看元数据映射、Consumer原始通知和Directory候选数,最后逐层检查Router过滤;候选为零时LoadBalance尚未执行。 | No Provider排查 |
| Provider 下线 Consumer 如何感知 | 正常下线先取消注册并等待通知传播,异常宕机要等Session或健康机制判定;Consumer收到变化后发布新Directory快照。传播期间已选中的Invoker和断连Consumer仍可能发送请求。 | 优雅下线、Session窗口 |
| 注册中心恢复为什么调用还没恢复 | Server进程恢复后还要等待Provider重新注册、元数据可读、Consumer重新订阅、Directory发布新快照、路由获得候选,并确认Consumer到Provider数据面网络可达。 | 恢复排查 |
协议与性能追问
| 追问 | 标准回答 | 原理页 |
|---|---|---|
| Dubbo 协议解决什么 | 经典Dubbo协议用固定Header表达Magic、请求类型、响应状态、requestId、序列化方式和body长度,请求体描述接口、版本、方法、参数和附件,从而在TCP字节流上建立RPC消息边界与请求响应关联。Triple使用HTTP/2流模型,不能套用经典Header。 | 经典Header、请求体布局、经典协议与Triple |
| Dubbo 如何解决粘包拆包 | 经典Dubbo解码器先累计至少16字节头,校验Magic并读取body length;Body未到齐就保留读取位置等待,完整后切出一帧,缓冲区有多帧则继续循环。长度还必须校验上限,避免恶意超大分配。 | TCP字节流、帧解码 |
| 为什么需要请求 ID | 同一长连接可并发多个请求且响应乱序。Consumer发送前按requestId注册Future,响应回来后按ID取出并完成对应Future;正常、超时、发送失败和断连都必须清理pending映射。 | RequestId与Future |
| Consumer超时后Provider会停止吗 | 通常不会。Consumer只是在超时时移除/完成本地Future,Provider请求可能仍在队列、正在执行或已提交;迟到响应无法交给原等待者。写接口需要幂等键和事实查询,future.cancel()也不能默认回滚远程事务。 | 超时与迟到响应、调用链超时语义 |
| 序列化失败怎么排查 | 记录接口、方法、requestId和两端serialization,比较API包、DTO包名、字段类型、枚举、方法签名和依赖;再检查类型白名单/安全校验。不能为了兼容在生产直接关闭反序列化安全机制。 | 序列化排查、DTO兼容、反序列化安全 |
| Provider 线程池满怎么办 | 先按方法看active、queue、reject和P99,再用线程栈区分DB连接等待、慢SQL、下游HTTP、锁和CPU;检查Consumer重试放大。通过限流、隔离、优化慢点和匹配下游容量止损,不能只盲目加线程或队列。 | 线程池原理、线程池排查、服务治理 |
治理追问
| 追问 | 标准回答 | 原理页 |
|---|---|---|
| Directory、Router、LoadBalance、Cluster执行顺序 | Cluster组织一次逻辑调用;它从Directory拿Invoker快照,经Router过滤,再让LoadBalance为每次物理尝试选一个Provider。失败后是否产生下一次尝试由Cluster决定。 | 五层对象、逻辑调用与尝试 |
| Dubbo 有哪些负载均衡策略 | 常见有加权随机、加权轮询、LeastActive、ShortestResponse和ConsistentHash。Random按有效权重做概率区间;LeastActive用Consumer局部未完成调用近似压力;一致性哈希提供Key亲和但不保证数据一致。 | 算法总览、加权随机、LeastActive、一致性哈希 |
| Dubbo 有哪些容错策略 | 常见有Failover、Failfast、Failsafe、Failback、Forking、Broadcast,部分版本还有Available、Mergeable等。它们分别组织重试、立即失败、吞错、后台补偿、并行调用和全实例广播,必须按业务副作用选择。 | Cluster策略、版本化策略 |
retries=2总共调用几次 | Failover中通常表示首次失败后最多再重试2次,因此理论总尝试是3次。网关、业务、RPC和HTTP多层重试还会形成乘法放大,必须监控逻辑调用数与物理尝试数。 | 逻辑调用与尝试、重试放大 |
| 为什么写接口不建议重试 | Consumer超时只表示没在等待窗口收到响应,Provider可能已提交。盲目重试会重复扣减;应Failfast、retries=0、使用稳定幂等键和唯一裁决,并按请求号查询事实状态。 | UNKNOWN状态、写接口幂等 |
| Dubbo超时怎样配置 | 从入口SLO建立端到端Deadline,扣除本地、网络和数据库时间后再给下游分配预算;重试必须消耗同一总预算并退避,不能每层都配置完整入口超时。 | 端到端超时预算、退避和重试配额 |
| Dubbo 怎么灰度 | 先给少量Provider打Tag,再由Router根据请求附件或Consumer条件过滤;必须明确无灰度实例时是强制失败还是回退稳定集群,并监控规则版本和路由前后候选数。 | Router链、Tag灰度 |
| Provider线程池满为什么不能只加线程 | 下游数据库连接、锁和CPU容量不变时,加线程只会增加等待、上下文切换和内存;加队列会把拒绝变成长尾和超时重试。应先定位慢点,再做限流、隔离、有界队列和容量匹配。 | Provider保护、生产排查 |
threads、queues、executes、actives区别 | threads/queues主要限制Provider业务线程池和等待队列;executes常用于Provider侧限制某服务或方法的并发执行;actives常用于Consumer侧限制某Consumer对某方法的在途调用;connections/accepts限制连接维度。它们位置不同,不能互相替代。 | 方法级治理、方法隔离Demo |
| 一个慢方法拖垮整个Provider怎么办 | 先按方法看QPS、P99、active、queue和线程栈,确认是否慢导出、外部接口或慢SQL占满共享线程池。止血可限制该方法并发、降低Consumer actives、快速拒绝或摘流;长期应拆服务、异步化、独立线程池/资源池,并用幂等和状态机兜底写操作。 | 方法级隔离、线程池满证据链 |
| 怎么做降级 | 非核心接口可用Mock、缓存或默认值;核心写链不能返回假成功。Cluster容错、熔断、降级和限流作用阶段不同,要分别设计。 | 熔断与降级边界 |
SPI 追问
| 追问 | 标准回答 | 原理页 |
|---|---|---|
| Dubbo SPI 是什么 | Dubbo SPI 是 Dubbo 自己实现的扩展机制,通过配置文件按名称加载实现类,并支持依赖注入、自适应扩展和 Wrapper 包装。 | SPI 扩展点 |
| 为什么不用 JDK SPI | JDK SPI 一次加载所有实现,不支持按名加载、自适应选择、依赖注入和 Wrapper,不适合 Dubbo 大量扩展点场景。Dubbo SPI 可以按名称从 URL 参数选择扩展,并把 Filter、Protocol、Listener 等能力通过 Wrapper 组合进调用链。 | ExtensionLoader内部流程 |
| 自定义 Filter 怎么做 | 实现 org.apache.dubbo.rpc.Filter,通过 META-INF/dubbo/org.apache.dubbo.rpc.Filter 配置扩展名和实现类,再用 @Activate(group="consumer/provider") 或显式配置启用。必须说明执行侧、顺序、失败语义和 ThreadLocal 清理,不能在 Filter 中做慢业务。 | Filter Demo、@Activate顺序 |
| 自适应扩展是什么 | 自适应扩展像一个运行时生成的路由器,根据 URL 或 Invocation 上下文里的参数选择具体扩展实现,例如根据 loadbalance=random 选择随机负载均衡。它避免框架核心到处写 if/else,也让协议、序列化、负载均衡等能力可插拔。 | 自适应扩展Demo |
| Wrapper 有什么用 | Wrapper 是 SPI 层面的装饰器,构造函数接收同类型扩展对象并在外层增强。Dubbo 的 Filter、Listener、Protocol 增强等能力很多不是原始扩展类直接完成,而是通过 Wrapper 织入;排查时要看最终扩展外面包了哪些 Wrapper。 | Wrapper顺序 |
| 自定义扩展不生效怎么排查 | 先查最终 jar 是否包含 META-INF/dubbo/扩展接口全限定名,再查扩展名、实现类、无参构造、Dubbo版本接口签名、@Activate group、URL最终参数和启动日志。不要只看代码存在,要验证 ExtensionLoader 实际加载到了哪个扩展。 | 扩展排查Runbook |
项目话术
我们项目里内部 Java 服务之间使用 Dubbo 做 RPC 调用,公共接口放在 api 模块,Provider 用 @DubboService 暴露服务,Consumer 用 @DubboReference 引用服务,注册中心使用 ZooKeeper。核心写接口统一配置 retries=0,请求携带幂等号,Provider 端用唯一约束或状态机防重复。查询接口按场景允许少量重试。我们还通过 Filter 透传 traceId、租户 ID 和用户信息,接入调用耗时和错误率监控。上线灰度时会用 version、group 或 tag 路由隔离新旧服务。
常见错误回答纠正
| 错误回答 | 为什么错 | 正确说法 |
|---|---|---|
| Dubbo 调用就是本地调用 | 忽略网络失败 | 编程体验像本地,底层是远程调用 |
| 注册中心转发请求 | 注册中心不转发流量 | Consumer 拿地址后直连 Provider |
| 超时就是失败 | Provider 可能已经执行成功 | 超时状态不确定,要查状态或做幂等 |
| 重试能保证可靠 | 重试可能放大故障和重复写 | 查询可重试,写接口先幂等 |
| 线程池越大越好 | 可能压垮 DB 和下游 | 线程池要结合下游容量设计 |
本章小结
Dubbo 面试不要只背功能点,要按调用链回答:代理如何生成调用,注册中心如何发现地址,负载均衡如何选择实例,协议和序列化如何传输,Provider 如何执行,失败后容错策略如何处理。再结合项目说明超时、重试、幂等、灰度、Filter 和监控,答案就会有深度。
