dubbo要解决的问题
1、rpc调用需要定制。额外的工作量
2、分布式服务中,服务动辄几十上百,相互之间的调用错综复杂,相互依赖严重
3、对集群性的服务,需要负载策略
4、对集群性的服务,能动态扩展节点
注意:dubbo的扩展性相当好,使用了spi机制,比如,负载策略只有5种,我们可以自定义一种,然后实现dubbo的对应的负载接口即可使用,而整个dubbo的设计理念都是这样的。
dubbo只能支持spring管理的服务。
Dubbo支持的协议
Dubbo支持dubbo、rmi、hessian、http、webservice、thrift、redis等多种协议,但是Dubbo官网是推荐我们使用Dubbo协议的。
dubbo协议:
缺省协议,使用基于mina1.1.7+hessian3.2.1的tbremoting交互。
连接个数:单连接
连接方式:长连接
传输协议:TCP
传输方式:NIO异步传输
序列化:Hessian二进制序列化
适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用dubbo协议传输大文件或超大字符串。
适用场景:常规远程服务方法调用
注意:
1、dubbo默认采用dubbo协议,dubbo协议采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况
2、他不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。
rmi协议:
Java标准的远程调用协议。
连接个数:多连接
连接方式:短连接
传输协议:TCP
传输方式:同步传输
序列化:Java标准二进制序列化
适用范围:传入传出参数数据包大小混合,消费者与提供者个数差不多,可传文件。
适用场景:常规远程服务方法调用,与原生RMI服务互操作
hessian协议:
基于Hessian的远程调用协议。
连接个数:多连接
连接方式:短连接
传输协议:HTTP
传输方式:同步传输
序列化:表单序列化
适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。
适用场景:需同时给应用程序和浏览器JS使用的服务。
1、Hessian协议用于集成Hessian的服务,Hessian底层采用Http通讯,采用Servlet暴露服务,Dubbo缺省内嵌Jetty作为服务器实现。
2、Hessian是Caucho开源的一个RPC框架:http://hessian.caucho.com,其通讯效率高于WebService和Java自带的序列化。
http 协议:
基于http表单的远程调用协议。参见:[HTTP协议使用说明]
连接个数:多连接
连接方式:短连接
传输协议:HTTP
传输方式:同步传输
序列化:表单序列化
适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。
适用场景:需同时给应用程序和浏览器JS使用的服务。
webservice 协议:
基于WebService的远程调用协议
连接个数:多连接
连接方式:短连接
传输协议:HTTP
传输方式:同步传输
序列化:SOAP文本序列化
适用场景:系统集成,跨语言调用
1、基于CXF的 frontend-simple 和 transports-http 实现。
2、CXF是Apache开源的一个RPC框架:http://cxf.apache.org,由Xfire和Celtix合并而来 。
thrift 协议:
当前 dubbo 支持的 thrift 协议是对 thrift 原生协议的扩展,在原生协议的基础上添加了一些额外的头信息,比如service name,magic number等。使用dubbo thrift协议同样需要使用thrift的idl compiler编译生成相应的java代码,后续版本中会在这方面做一些增强。
Thrift不支持null值,不能在协议中传
memcached 协议
redis 协议
读取配置文件
DUBBO在读取配置的时候会先读取XML文件中的配置,如果没找到就会默认去读取resources目录下的dubbo.properties文件。如果你即配置了 XML 又配置了 properties 的内容,那么 DUBBO 读取时将直接读取 XML 中的配置,忽略 properties 里的配置。
配置文件
标签有个继承关系:
1,下层会继承上层属性配置
2,消费方,会继承服务方属性配置:服务只提供者自己知道,配什么属性最合适
Dubbo的执行流程
项目一启动,加载配置文件的时候,就会初始化,并且每设置一个协议就会有一个中转对象,这个中转对象负责将注册的服务暴露出去,并且生成对外暴露的url,向注册中心注册自己提供的服务和对应的url,当消费者在启动时,代理对象就会向注册中心订阅自己所需要的服务,如果服务提供方有数据变更等,注册中心将基于长连接的形式推送变更数据给消费者,并且代理对象会去调用这些服务,这里是动态代理的方式。
Dubbo使用spring:
1,Dubbo通过DubboNamespaceHandler类去继承spring的DubboNamespaceHandler这个抽象类,就可以在初始化的时候向spring容器中注册一些自定义的标签,比如application,service,protocol等。
2,Dubbo的中转对象实现了spring的InitializingBean接口,在中转对象初始化工作完成之后,通过afterPropertiesSet()方法设置一些属性配置。
3,Dubbo的中转对象还实现了spring的DisposableBean接口,然后另开了一个线程调用destroy用于监控bean被销毁后做的一些处理。
Dubbo的安全性如何得到保障
a.在有注册中心的情况下,可以通过dubbbo admin中的路由规则,来指定固定ip的消费方来访问
b.在直连的情况下,通过在服务的提供方中设置密码(令牌)token,消费方需要在消费时也输入这 个密码,才能够正确使用。
Dubbo添加服务ip白名单,防止不法调用
Duubo中如何保证分布式事务
一般情况下,我们尽量将需要事务的方法放在一个service中,从而避开分步式事务。
Dubbo的心跳机制
目的:
维持provider和consumer之间的长连接
实现:
dubbo心跳时间heartbeat默认是1s,超过heartbeat时间没有收到消息,就发送心跳消 息(provider,consumer一样),如果连着3次(heartbeatTimeout为heartbeat*3)没有收到心跳响应,provider会关闭channel,而consumer会进行重连;不论是provider还是consumer的心跳检测都是通过启动定时任务的方式实现;
Dubbo中zookeeper做注册中心,如果注册中心集群都挂掉,发布者和订阅者之间还能通信么
可以通信的,启动dubbo时,消费者会从zk拉取注册的生产者的地址接口等数据,缓存在本地。每次调用时,按照本地存储的地址进行调用;
注册中心对等集群,任意一台宕机后,将会切换到另一台;注册中心全部宕机后,服务的提供者和消费者仍能通过本地缓存通讯。服务提供者无状态,任一台 宕机后,不影响使用;服务提供者全部宕机,服务消费者会无法使用,并无限次重连等待服务者恢复;
dubbo服务负载均衡策略
1,Random:按权重随机,根据weight值(服务方设置)来随机。
2,Roundrobin:轮询访问。
3,Leastactive:谁最轻松,访问谁,慢的机器,收到的请求少。
4,ConsistentHash:一致性Hash,相同参数的请求总是发到同一提供者,当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
dubbo连接注册中心和直连的区别
在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,点对点直联方式,将以服务接口为单位,忽略注册中心的提供者列表,服务注册中心,动态的注册和发现服务,使服务的位置透明,并通过在消费方获取服务提供方地址列表,实现软负载均衡和Failover,注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外,注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者,注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表,注册中心和监控中心都是可选的,服务消费者可以直连服务提供者。
dubbo服务集群配置(集群容错模式)
1、 Failover :当出现失败,重试其它服务器。 retries=“2” 来设置重试次数(不含第一次)。幂等性操作使用,如读操作。
幂等操作:一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。
2、 Failfast :快速失败,只发起一次调用,失败立即报错,非幂等性操作,如写操作
3、 Failsafe :出现异常时,直接忽略,无关紧要的旁支操作,如打日志
4、 Failback :后台记录失败请求,定时重发,后续专业处理
5、 Forking :并行调用多个服务器,只要一个成功即返回,forks=“2” 来设置最大并行数
注意:这里其实是dubbo的spi机制,其实和策略模式相近。
dubbo通信协议dubbo协议为什么要消费者比提供者个数多
因dubbo协议采用单一长连接,假设网络为千兆网卡(1024Mbit=128MByte),根据测试经验数据每条连接最多只能压满7MByte(不同的环境可能不一样,供参考),理论上1个服务提供者需要20个服务消费者才能压满网卡。
dubbo通信协议dubbo协议为什么不能传大包
因dubbo协议采用单一长连接,如果每次请求的数据包大小为500KByte,假设网络为千兆网卡(1024Mbit=128MByte),每条连接最大7MByte(不同的环境可能不一样,供参考),单个服务提供者的TPS(每秒处理事务数)最大为:128MByte/500KByte=262。单个消费者调用单个服务提供者的TPS(每秒处理事务数)最大为:7MByte / 500KByte = 14。如果能接受,可以考虑使用,否则网络将成为瓶颈。
声明式缓存
lru:最少使用原则删除缓存(此参数长期未调,就不缓存了)
threadlocal:对调用者缓存(下次还是你调用,就返回缓存的数据)
dubbo的一些功能
1,异步调用
1,Future方式,先异步执行再总的通过get方法接收结果。
2,回调方式
2,回声测试
检测提供方的接口是否正常,所有服务接口都实现了EchoService,获取成功就表示正常,失败就不正常
3,泛化调用
就是在消费方需要调用服务方的接口,但是再公共代理接口模块中没有这个接口,可以通过generic="true",利用反射通过类路径得到这个接口。
dubbo的spi机制
使用:只要是dubbo里面标注了@SPI注解的接口,均对外扩展,例如扩展负载功能。
1,实现LoadBalance接口,重写负载算法。
2,在resource路径下的META-INF下建dubbo文件夹,然后在这个路径下建接口的全路径名的文件com.alibaba.dubbo.rpc.cluster.LoadBalance,在文件里面以key=value的形式指定自定义的负载器即可。
ExtensionLoader:
是整个SPI的核心,创建对应扩展接口的适配对象。
原理(以protocol为例),也是dubbo的亮点:
1,dubbo启动加载实现类时,以key-value实例方式map缓存各个实现类。
2,通过ExtensionLoader创建一个protocol的类加载器。
3,类加载器再创建一个protocol的适配对象(首先会去缓存中取,没有就创建)。
注意:这个适配对象的创建是通过代码编写类源码,然后编译生成的一个实例,类似于mybatis的逆向工程,适配类生成源码的逻辑中,只生成protocol接口中标注了@Adaptive的方法。
4,通过适配对象去从URL总线中找到key,然后根据key调用对应的实现类。
好处:大大增加了扩展性,对于向其他的loadbalance,cache等之类的功能都用一个ExtensionLoader来管理扩展,省去了很多重复的代码。
dubbo集成zk原理:
1,dubbo消费端启动过程中,第一次在serviceconfig中执行refprotocol.refer,此时对应的url是registryUrl,根据registryUrl中的re gistry这个key得到registryProtocol。
2,根据registryProtocol执行监听器,利用ZookeeperRegistry进行zk注册
3,注册完毕之后,利用监听器进行消息通知,通知所有模块url的变化(即是注册在zk上的url),刷新缓存
4,监听器最后,调用toInvokers方法,将新注册的url转为invokers对象,此处url转为invokers的过程,交由dubboprotocol来完成,即 :protocol.refer的url在此时是dubbo协议(SPI机制)
5,将这个invokers对象交给中转对象,暴露出去