dubbo面试题,看完也碾压不了面试官

最近在准备dubbo相关内容的面试题,百度了相关的内容,全部是看完这篇碾压面试官、一文搞定面试官,标题浮夸,内容也是不敢恭维,正好借着看完源码的热乎劲,索性自己整理一篇。

基于dubbo 2.5.6版本

1.什么是dubbo?

官网上有很简单的一句话,apache dubbo是一款高性能Java RPC框架。
当然如果你觉得太简练,你也可以自己丰富一下,比如:dubbo支持负载均衡、支持集群容错等等。

2.dubbo SPI机制

Dubbo 并未使用 Java SPI,而是重新实现了一套功能更强的 SPI 机制。Dubbo SPI 的相关逻辑被封装在了 ExtensionLoader 类中,通过 ExtensionLoader,我们可以加载指定的实现类。
加载的数据来源有三个,分别是:
META-INF/service
META-INF/dubbo
META-INF/dubbo/internal
代码里也有体现
com.alibaba.dubbo.common.extension.ExtensionLoader
在这里插入图片描述
dubbo的扩展点适应机制贯穿始终,建议深入了解一下。

3.dubbo支持的协议

在谈dubbo协议之前,先说一下dubbo定义的接口

@SPI("dubbo")
public interface Protocol {
    @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
    @Adaptive
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
    void destroy();
}

可以看出,无论是类还是方法上都标记了注解。先就这个接口,给大家解释下:
被标记为SPI的接口,表示为该类是一个扩展点,里面的值"dubbo"是默认的协议。
方法上标记的Adaptive,表示该方法是一个需要生成自适应方法。
可能说的很笼统,没办法理解,举个例子吧,dubbo支持的协议有dubbo、hessian、rmi、webservice、thrift、http、redis等等,我们不可能都通过if/else判断来实现吧,这样也限制了dubbo的扩展,所以就诞生了扩展点的自适应。dubbo是基于url驱动的,如dubbo://host:port/interfacename/…这样。自适应的功能就是解析出url中的协议内容,做动态扩展,上面的例子自适应后得到的是dubbo,最终找到的处理类是dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol。

上面的机制了解后,就可以很容易的自己找到dubbo支持的协议,下面就是基于DUBBO SPI的配置文件:
在这里插入图片描述
所以可以很简单的得出,dubbo支持的协议有:
dubbo (默认)
hessian
rmi
webservice
http
thrift
redis
rest

4.dubbo内置的容器

一样的配方、一样的套路。
这是dubbo的容器接口

com.alibaba.dubbo.container.Container

怎么查,相信你也清楚了
spring
jetty
log4j
logback

5.注册中心

dubbo 默认
zookeeper 推荐
redis
multicast

6.配置方式

api 和spring 两种,只考虑spring

7.序列化的方式

hessian2 默认、推荐
java
json
fastjson
nativejava
compactedjava

8.通信框架

netty 默认
netty4
mina
grizzly

9.容错机制

  1. failover 默认,附带参数 retries=2 默认 失败自动切换至其他服务器,默认重试两次
  2. failfast 失败即报错
  3. failback 失败自动恢复,会记录失败请求,定时重发
  4. failsafe 失败安全,出现异常时忽略
  5. forking 并行调用,只要一个成功返回即成功,用于对响应速度要求高的场景,缺点是占用服务器资源
  6. broadcast 广播调用,只要一个失败即报错

10. 负载均衡

  1. random 默认随机
  2. roundrobin 轮询
  3. leastactive 最小活跃数
  4. consistenthash 一致性hash

11. 服务上下线感知

以zookeeper做注册中心为例,主要是利用了zookeeper的临时节点特性,当客户端与server失去连接时,临时节点会被自动删除。

12. 服务降级

消费端配置mock,三种方式
假设在com.xx.xx.IHello接口配置mock

方式方式
mock=“return null”服务调用异常,会返回null
mock=“true”会自动调用com.xx.xx.IHelloMock
mock=“com.xx.xx.IHelloMock”也可以自行定义处理类

13.dubbo的服务发布过程

dubbo中有这样一个类

com.alibaba.dubbo.config.spring.ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware

实现了这么多接口,用过spring的人应该了解spring容器初始化的工作中和完成后都会调用相关接口的实现类。我们注意到有这样一个接口,

org.springframework.beans.factory.InitializingBean

他会在bean初始化完成后调用afterPropertiesSet()方法。我们以此方法作为入口

public void afterPropertiesSet() throws Exception {
.......忽略部分内容
   if (!isDelay()) {
        export();
    }
 }

里面调用的export()方法是关键,这就是服务发布的方法。
顺着该方法继续往下找,会看到这样一段代码:

Exporter<?> exporter = protocol.export(invoker);

这就是调用Protocol.export(...)方法进行发布了

public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
 //使用netty进行暴露服务
 final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);
        //注册中心进行服务注册
        final Registry registry = getRegistry(originInvoker);
        final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);
        registry.register(registedProviderUrl);
        final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl);
        final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
        overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
        registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
        .....省略
        }

所以服务发布总结起来只有两步
1.使用netty进行本地服务暴露
2.zookeeper注册服务

14. 本地存根stub

有这样一个场景,服务端进行分布式化后,本地通常只剩下接口,而实现全部在服务端,而有时候客户端想在服务调用前做一部分事情。

<dubbo:service interface="com.foo.BarService" stub="true" />
<dubbo:service interface="com.foo.BarService" stub="com.foo.BarServiceStub" />

本地存根实现

package com.foo;
public class BarServiceStub implements BarService {
    private final BarService barService;
    
    // 构造函数传入真正的远程代理对象
    public BarServiceStub(BarService barService){
        this.barService = barService;
    }
 
    public String sayHello(String name) {
        // 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等
        try {
            return barService.sayHello(name);
        } catch (Exception e) {
            // 你可以容错,可以做任何AOP拦截事项
            return "容错数据";
        }
    }
}

这样的好处就是提前进行部分参数的校验,由stub来决定下一步的动作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值