Skip to content

Dubbo服务框架面试题库 ​

生成时间:2026-05-24 21:12 | 题目数:10


【面试题】1. Dubbo的URL总线设计是什么意思?为什么说URL是Dubbo的配置总线? ​

【标准答案】Dubbo把所有配置参数和运行时元数据都塞进一个URL对象里,格式是protocol://host:port/path?key=value&key=value。比如dubbo://192.168.1.10:20880/com.xxx.UserService?timeout=3000&retries=2&loadbalance=random。整个框架里所有组件——注册中心、协议、负载均衡、集群容错——全都从URL上读参数来决定自己的行为。这样做的好处是:第一,配置传递变得统一,不管是XML配置、注解配置还是动态覆盖,最终都转成URL参数,一套机制搞定;第二,扩展点自适应(@Adaptive)就是根据URL里的参数动态选择实现类,URL就是它的决策依据;第三,注册中心存的就是URL,服务暴露时把URL写进去,消费端拿到的也是URL,天然统一。面试时可以一句话总结:URL是Dubbo的配置总线,所有组件的行为都由URL参数驱动,它是整个框架运转的核心数据结构。

【面试题】2. Dubbo SPI和Java SPI的核心区别是什么?为什么Dubbo要自己搞一套? ​

【标准答案】三个核心区别:第一,按需加载。Java SPI会一次性实例化所有实现类,不管你用不用;Dubbo SPI通过@SPI指定默认实现,只有真正用到时才加载,按key取,比如ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("dubbo")只加载dubbo协议。第二,自动装配和包装。Dubbo SPI支持依赖注入(扩展点里引用其他扩展点会自动注入)和Wrapper机制(实现了相同接口的Wrapper类会自动包装真实实现,比如Protocol的ProtocolFilterWrapper和ProtocolListenerWrapper)。第三,自适应扩展。@Adaptive注解让扩展点可以根据URL参数动态选择实现类,运行时才决定用哪个,这是Java SPI完全做不到的。还有一点,Dubbo SPI配置文件放在META-INF/dubbo/目录下,格式是key=全限定类名,而Java SPI放在META-INF/services/,格式只有全限定类名。总结:Dubbo SPI是Java SPI的增强版,解决了按需加载、自动装配、动态选择三个痛点,是Dubbo微内核+插件架构的基石。

【面试题】3. Dubbo服务暴露的完整流程是怎样的?本地暴露和远程暴露有什么区别? ​

【标准答案】服务暴露分两步走:本地暴露和远程暴露。先说整体流程:Spring容器启动→解析<dubbo:service>→调用ServiceConfig.doExport()→依次执行本地暴露和远程暴露。本地暴露:走injvm协议,把服务暴露在同一个JVM内部,scope=local,不走网络,本JVM内的其他服务引用直接方法调用,性能最高。远程暴露:走配置的协议(默认dubbo),核心流程是:ProxyFactory(默认Javassist)创建Invoker→Protocol(DubboProtocol)把Invoker转成Exporter→启动Netty Server监听端口→把服务URL注册到注册中心。关键源码链路:ServiceConfig.doExportUrls()→exportLocal(url)本地暴露→protocol.export(invoker)远程暴露,其中protocol是被Wrapper包装过的(ProtocolFilterWrapper→ProtocolListenerWrapper→DubboProtocol)。面试重点说清楚:本地暴露走injvm不经过网络,远程暴露要启动Server、注册到注册中心,两者是并列执行的,不是二选一。

【面试题】4. Dubbo的Filter链是怎么工作的?Consumer端和Provider端的Filter分别在哪执行?怎么自定义一个Filter? ​

【标准答案】Filter链的核心原理是责任链模式。服务暴露时,ProtocolFilterWrapper会用buildInvokerChain()把所有激活的Filter串成一条链,每个Filter持有下一个Invoker的引用,依次调用。Consumer端在服务引用时构建Filter链,Provider端在服务暴露时构建Filter链,两端各自独立。判断Filter在哪端执行靠@Activate注解的group属性:group = Constants.CONSUMER只在消费端生效,group = Constants.PROVIDER只在提供端生效,不指定则两端都生效。内置Filter举例:Consumer端有ConsumerContextFilter(设RpcContext)、FutureFilter(处理异步回调);Provider端有ContextFilter(接收上下文)、AccessLogFilter(记录访问日志)、ActiveLimitFilter(并发控制)、ExecuteLimitFilter(线程池控制)。自定义Filter三步走:第一步实现Filter接口写invoke()方法;第二步在META-INF/dubbo/下建org.apache.dubbo.rpc.Filter文件,写myFilter=com.xxx.MyFilter;第三步用@Activate(group = {Constants.PROVIDER})标注生效端,或者配置<dubbo:provider filter="myFilter"/>。面试强调:Filter是Dubbo最核心的扩展点,限流、日志、监控、熔断全靠它,掌握Filter链就掌握了Dubbo的治理骨架。

【面试题】5. Dubbo3的应用级服务发现和之前的接口级服务发现有什么区别?为什么要改? ​

【标准答案】接口级服务发现是Dubbo2的做法:每个接口每个版本每个分组注册一条URL到注册中心,比如有100个接口就注册100条。问题很明显:规模一大,注册中心数据量爆炸。一个应用100个接口、3个实例就是300条,1000个应用就是30万条,Zookeeper的Node和Watch机制扛不住。应用级服务发现是Dubbo3的做法:每个应用实例只注册一条数据,包含实例IP、端口、支持的接口列表等元数据,100个接口3个实例只注册3条。消费端先从注册中心拿到实例列表,再通过元数据服务(MetadataService)获取具体接口信息。两者对比:数据量从O(接口数×实例数)降到O(实例数),注册中心压力直接降一个数量级;同时和K8s Service、Spring Cloud的模型对齐,更容易做Service Mesh对接。迁移上Dubbo3默认双注册(接口级+应用级同时注册),保证向下兼容,消费端优先用应用级。面试一句话:应用级发现把注册中心数据量从接口维度降到实例维度,是Dubbo3面向大规模微服务的核心架构升级。

【面试题】6. Dubbo的泛化调用是什么?在什么场景下使用?怎么实现? ​

【标准答案】泛化调用就是消费端不需要依赖服务接口的jar包,也能调用服务端的方法。普通调用必须把服务接口类放到消费端classpath里,泛化调用不需要。核心API是GenericService接口,它只有一个方法$invoke(String methodName, String[] parameterTypes, Object[] args),方法名、参数类型、参数值全靠字符串和Object传递。使用场景主要有三个:第一,API网关:网关要转发所有服务的调用,不可能依赖每个服务的接口jar包,泛化调用是唯一选择;第二,通用测试平台:类似Dubbo Admin那样的运维工具,动态输入方法名和参数就能调服务;第三,跨语言调用:非Java客户端通过HTTP等方式调用Dubbo服务,不需要Java接口。配置方式:消费端<dubbo:reference interface="com.xxx.UserService" generic="true"/>,然后强转成GenericService,调用$invoke("getUser", new String[]{"java.lang.Long"}, new Object[]{1L})。返回值是Map或基本类型。面试强调:泛化调用是Dubbo框架级能力,不是hack,网关场景几乎是必选项。

【面试题】7. Dubbo的超时配置优先级是怎样的?为什么Consumer端优先级高于Provider端? ​

【标准答案】超时优先级从高到低:方法级Consumer配置 > 方法级Provider配置 > 接口级Consumer配置 > 接口级Provider配置 > 全局Consumer配置 > 全局Provider配置。精简记忆:Consumer优先于Provider,方法级优先于接口级优先于全局。为什么Consumer优先?因为消费端更清楚自己能等多久。举例子:一个查询服务,Provider设了5秒超时,但某个Consumer的场景是前端页面展示,用户等不了5秒,需要2秒就返回。如果Provider优先,Consumer就得被5秒卡住;Consumer优先,Consumer自己设2秒就2秒超时返回,用户体验更好。本质上这是控制权在调用方的设计思想——谁发起调用谁决定能容忍多久。源码层面,消费端发起调用时会把自己的超时值放在Attachment里传给Provider端,Provider端的TimeoutFilter检查到有Consumer传来的超时值就用Consumer的。面试关键:不只是超时,retries、loadbalance、cluster等配置都是Consumer优先,这是Dubbo的通用设计原则。

【面试题】8. Dubbo的线程模型有哪些?IO线程和业务线程是怎么分离的?生产环境怎么选? ​

【标准答案】Dubbo通过Dispatcher派发策略控制IO线程和业务线程的分工,有5种:AllDispatcher(默认):所有消息(请求、响应、连接、断开)都派发到业务线程池,IO线程只做网络读写,最安全;DirectDispatcher:所有消息都在IO线程上执行,没有业务线程池,性能最好但不安全,一个慢调用就阻塞IO;MessageOnlyDispatcher:只有请求消息派发到业务线程,响应和连接事件在IO线程处理;ExecutionDispatcher:只把请求消息派发到业务线程,但用了独立的线程池(和All的区别是响应也在IO线程);ConnectionOrderedDispatcher:请求消息走业务线程池,连接/断开事件走独立的连接线程池(防止连接风暴占满业务线程)。生产环境首选AllDispatcher,因为最稳定,慢调用不会影响网络层。如果对延迟极致敏感且接口都很轻量,可以考虑MessageOnlyDispatcher。线程池配置:<dubbo:protocol threads="200" />设置业务线程池大小,默认FixedThreadPool固定200个线程。面试重点:IO线程只管网络读写,业务逻辑必须丢到业务线程池,否则一个慢接口拖垮整个服务,这是Netty+Dubbo的基本功。

【面试题】9. Dubbo的服务预热机制是怎样的?新上线的实例怎么避免瞬间被打满? ​

【标准答案】Dubbo的服务预热(WarmUp)机制核心是:新注册的实例在预热期内,负载均衡分配到的流量会按比例递增,而不是上来就全量分配。原理在Random LoadBalance和LeastActive LoadBalance的实现里:计算权重时会检查当前时间减去服务注册时间的差值,如果小于预热时长(默认10分钟,通过warmup参数配置),实际权重=原始权重×(已运行时间/预热时长)。比如原始权重100、预热10分钟,第1分钟时实际权重只有10,第5分钟时实际权重50,第10分钟满权重100。这样流量是慢慢灌进来的,JVM的JIT编译、连接池初始化、缓存预热都有时间完成。配置方式:Provider端<dubbo:service weight="100" warmup="600000" />,warmup单位毫秒。结合灰度发布,可以先调低新实例权重,预热完成后再恢复。面试话术:预热机制本质是动态权重调节,让新实例流量线性增长而非瞬间打满,避免冷启动导致的超时和线程池溢出,是生产环境必须开启的能力。

【面试题】10. Dubbo和Spring Cloud的核心区别是什么?什么场景选Dubbo,什么场景选Spring Cloud? ​

【标准答案】核心区别三条:通信方式——Dubbo是RPC(默认TCP长连接+Hessian序列化),Spring Cloud是HTTP(RestTemplate/Feign+JSON),RPC性能天然比HTTP高1-3倍;注册中心——Dubbo支持ZK/Nacos/Redis多选,Spring Cloud默认Eureka/Consul/Nacos,模型上Dubbo2是接口级注册粒度更细,Spring Cloud是应用级;治理体系——Dubbo的治理是框架内建的(负载均衡、集群容错、服务路由都在框架层),Spring Cloud的治理靠独立组件(Ribbon做负载均衡、Hystrix做熔断、Gateway做网关,各干各的)。选型逻辑:选Dubbo的场景——内部服务间高频调用、对性能延迟敏感、已有Java技术栈统一、服务量大需要细粒度治理;选Spring Cloud的场景——技术栈多语言混合、团队对Spring全家桶更熟、需要和外部系统HTTP对接、微服务数量中等不需要极致性能。融合方案也有:Dubbo Spring Cloud项目已经让Dubbo服务可以注册到Spring Cloud注册中心,用Dubbo RPC替代Feign HTTP调用,两边服务可以互相发现。面试总结:不是非此即彼,性能敏感走Dubbo,生态开放走Spring Cloud,融合方案也成熟了。