SPI
你是否了解SPI,讲一讲什么是SPI,为什么要使用SPI?
SPI具体约定:当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/
目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/
里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入(从使用层面来说,就是运行时,动态给接口添加实现类)。 基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定(不需要在代码里写死)。
这样做的好处:java设计出SPI目的是为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。这样程序运行的时候,该机制就会为某个接口寻找服务的实现,有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。例如,JDBC驱动,可以加载MySQL、Oracle、或者SQL Server等,目前有不少框架用它来做服务的扩张发现。
回答这个问题可以延伸一下和API的对比,API是将方法封装起来给调用者使用的,SPI是给扩展者使用的。
Dubbo的SPI和JDK的SPI有区别吗?有的话,究竟有什么区别?
Dubbo 的扩展点加载是基于JDK 标准的 SPI 扩展点发现机制增强而来的,Dubbo 改进了 JDK 标准的 SPI 的以下问题:
- JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
- 增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。
Dubbo的IOC是怎么实现的,和Spring有什么差别?
Dubbo IOC 是通过 setter 方法注入依赖。Dubbo 首先会通过反射获取到实例的所有方法,然后再遍历方法列表,检测方法名是否具有 setter 方法特征。若有,则通过 ObjectFactory 获取依赖对象,最后通过反射调用 setter 方法将依赖设置到目标对象中。
dubbo中的IOC实例是通过ExtensionFactory实现的,其实就是检测扩展实现类有没有通过set方法设置的属性,如果有,就通过ExtensionFactory加载而设置。
Dubbo的AOP是怎么实现的,和Spring有什么差别?
多次使用装饰类,实现了dubbo扩展点的AOP功能。。。。
Dubbo原理
有没有考虑过自己实现一个类似dubbo的RPC框架,如果有,请问你会如果着手实现?
可从两个方面去入手,考虑接口扩展性,改造JDK的SPI机制来实现自己的扩展SPI机制。另外就是从动态代理入手,从网络通信、编码解码这些步骤以动态代理的方式植入远程调用方法中,实现透明化的调用。
服务发布过程中做了哪些事?
暴露本地服务、暴露远程服务、启动netty、连接zookeeper、到zookeeper注册、监听zookeeper。
什么是本地暴露和远程暴露,他们的区别?
在dubbo中我们一个服务可能既是Provider,又是Consumer,因此就存在他自己调用自己服务的情况,如果再通过网络去访问,那自然是舍近求远,因此他是有本地暴露服务的这个设计.从这里我们就知道这个两者的区别
- 本地暴露是暴露在JVM中,不需要网络通信.
- 远程暴露是将ip,端口等信息暴露给远程客户端,调用时需要网络通信.
通信协议、序列化协议
dubbo都有哪些通信协议,他们之间有什么特点,缺省值是什么?
------dubbo协议
Dubbo 缺省协议。采用单一长连接和 NIO 异步通讯,Hessian 二进制序列化,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。
反之,Dubbo 缺省协议不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。传送地址:相关协议介绍
为什么要消费者比提供者个数多?
因 dubbo 协议采用单一长连接,假设网络为千兆网卡 [3],根据测试经验数据每条连接最多只能压满 7MByte(不同的环境可能不一样,供参考),理论上 1 个服务提供者需要 20 个服务消费者才能压满网卡。
为什么不能传大包?
因 dubbo 协议采用单一长连接,如果每次请求的数据包大小为 500KByte,假设网络为千兆网卡 [3:1],每条连接最大 7MByte(不同的环境可能不一样,供参考),单个服务提供者的 TPS(每秒处理事务数)最大为:128MByte / 500KByte = 262。单个消费者调用单个服务提供者的 TPS(每秒处理事务数)最大为:7MByte / 500KByte = 14。如果能接受,可以考虑使用,否则网络将成为瓶颈。
为什么采用异步单一长连接?
因为服务的现状大都是服务提供者少,通常只有几台机器,而服务的消费者多,可能整个网站都在访问该服务,比如 Morgan 的提供者只有 6 台提供者,却有上百台消费者,每天有 1.5 亿次调用,如果采用常规的 hessian 服务,服务提供者很容易就被压跨,通过单一连接,保证单一消费者不会压死提供者,长连接,减少连接握手验证等,并使用异步 IO,复用线程池,防止 C10K 问题。
------RMI协议
RMI 协议采用 JDK 标准的 java.rmi.*
实现,采用阻塞式短连接和 JDK 标准序列化方式。
多个短连接,适合消费者和提供者数量差不多的情况,适用于文件的传输,一般较少用。
------hessian协议
Hessian协议用于集成 Hessian 的服务,Hessian 底层采用 Http 通讯,采用 Servlet 暴露服务,Dubbo 缺省内嵌 Jetty 作为服务器实现。
多个短连接,适用于提供者数量比消费者数量还多的情况,适用于文件的传输,一般较少用。
------http协议
基于 HTTP 表单的远程调用协议,走 json 序列化。多个短连接。
------webservice协议
基于 WebService 的远程调用协议,走SOAP 文本序列化。多个短连接。
------thrift、memcached、Reids、Rest协议
很少使用,暂不介绍。
Dubbo的序列化协议
dubbo 支持 hession、Java 二进制序列化、json、SOAP 文本序列化多种序列化协议。但是 hessian 是其默认的序列化协议。
为什么Protocal Buffer效率最高?
可能有一些同学比较习惯于 JSON or XML 数据存储格式,对于 Protocal Buffer 还比较陌生。Protocal Buffer 其实是 Google 出品的一种轻量并且高效的结构化数据存储格式,性能比 JSON、XML 要高很多。
其实 PB 之所以性能如此好,主要得益于两个:
第一,它使用 proto 编译器,自动进行序列化和反序列化,速度非常快,应该比 XML 和 JSON 快上了 20~100 倍;
第二,它的数据压缩效果好,就是说它序列化后的数据量体积小。因为体积小,传输起来带宽和速度上会有优化。
ZK
一般选择什么注册中心,还有别的选择吗?
zk为默认推荐,其余还有Multicast、redis、Simple等注册中心。
dubbo中zookeeper做注册中心,如果注册中心集群都挂掉,那发布者和订阅者还能通信吗?(面试高频题)
zookeeper的信息会缓存到服务器本地作为一个cache缓存文件,并且转换成properties对象方便使用,每次调用时,按照本地存储的地址进行调用,但是无法从注册中心去同步最新的服务列表,短期的注册中心挂掉是不要紧的,但一定要尽快修复。所以挂掉是不要紧的,但前提是你没有增加新的服务,如果你要调用新的服务,则是不能办到的。
项目中有使用过多线程吗?有的话讲讲你在哪里用到了多线程?(面试高频题)
服务提供者能实现失效踢出是什么原理(高频题)
在dubbo中,什么时候更新本地的zookeeper信息缓存文件?订阅zookeeper信息的整体过程是怎么样的?
动态代理
dubbo的服务引用中封装通信细节是用到了动态代理,那请问创建动态代理常用的方式有哪些,他们又有什么区别?dubbo中用的是哪一种?(高频题)
集群容错
dubbo提供了几种集群容错模式?
谈谈dubbo中的负载均衡算法及特点?最小活跃数算法中是如何统计活跃数的?简单谈谈一致性哈希算法
怎么通过dubbo实现服务降级的,降级的方式有哪些,又有什么区别?
当网站处于高峰期时,并发量大,服务能力有限,那么我们只能暂时屏蔽边缘业务,这里面就要采用服务降级策略了。首先dubbo中的服务降级分成两个:屏蔽(mock=force)、容错(mock=fail)。
mock=force:return+null
表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。mock=fail:return+null
表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。
要生效需要在dubbo后台进行配置的修改。
dubbo监控平台能够动态改变接口的一些设置,其原理是怎样的?
改变注册在zookeeper上的节点信息,从而zookeeper通知重新生成invoker(这些具体细节在zookeeper创建节点,zookeeper连接,zookeeper订阅中都详细讲了,这里不再重复)。