Dubbo相关整理

是基于java的高性能RPC(远程调用)分布式服务框架,内部使用了Netty、Zookeeper保证了高性能。使用Dubbo可以将核心业务抽取出来做为独立服务。

Dubbo是什么?能做什么?     

Dubb是阿里巴巴开源的基于Java的高性能RPC分布式服务框架,现已成为Apache基金会孵化项目。致力于提供高性能和送明化的RPC远程服务调用方案,以及SOA服务治理方案。简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候。才有 dubbo这样的分布式服务框架的需求,本质上是个远程服务调用的分布式框架     

其核心部分包含:     

  1. 远程通讯:提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应"模式的信息交换方式,适明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。     
  2. 集群容错:提供基于按口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持,可在内网替代F5等硬件负载均衡器,降低成本,减少单点
  3. 自动发现:基于注册中心目录服务,服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。

 Dubbo的工作流程

  1. Start:启动Spring容器时,自动启动Dubbo的Provider     
  2. Register: Dubbo的ProvIder在启动后会去注册中心注册内容.注册的内容包括:     IP. 端口、接口列表(接口类、方法)、 版本、Provider的协议。     
  3. Subscribe:订阅.当Consumer启动时,自动去Registry获取到所已注册的服务的信息.   
  4. Notify:通知.当Provider的信息发生变化时,自动由Registry向Consumer推送通知.   
  5. Invoke: Consumer调用Provider中方法   
    同步请求,消耗-定性能但是必须是同步请求,因为需要接收调用方法后的结果     
  6. Count:次数,每隔2分钟,Provoider和Consumer自动向Monitor发送访问次数.Monitori进行统计. 

dubbo的SPI机制     

spi: service provider interface 服务发现机制     

通过接口全限定名找到指定目录下对应的文件。获取具体的实现类然后加载即可,做到了灵活的替换其体的实现类。

为什么Dubbo不用jJDK的SPI,而是要自己实现

java spi缺点:     

  1. 需要遍历所有实现并实例化,假设一个实现类初始化过程比较消耗资源且耗时,但是你的代码里面又用不上它,这就产生了资源的浪费。也无法准确引用     
  2. 没有使用缓存每次load都需要重新加载     

Dubbo SPI:   

  1. 给每个实现类配了个名字,通过名字去文件里面找到对应的实现类全限定名然后加载实例化,按需加载,解决资源浪费。     
  2. 增加了缓存存储实例,提高读取性能。   
  3. 提供了对IOC和AOP等高级功能的支持,以实现更多类型的扩展。

dubbo服务暴露过程     

 Dubbo采用URL的方式来作为约定的参数类型(URL指向资源)。   

protoco1://username :passwordehost:port/path?key=va1ue&key=value     
protocol:指的是dubbo中的各种协议,如: dubbo thrift http     
username/password:用户名/密码     
host/port:主机/端口     
path:接口的名称     
parameters:多数键值对 

ServiceBean实现了ApplicationListener,监听ContextRefreshedEvent事件, 在Spring IOC容器刷新完成后调用onApplicationEvent监听方法,服务暴露的启动点。根据配置得到URL,再利用Dubbo SPI机制根据URL的参数选择对应的实现类,实现扩展。     

通过javassist动态封装服务实现类(代理类),统一暴露出Invoker使得调用方便、屏蔽底层实现细节,然后封装成 exporter存储起来,等待消费者的调用,并且会将URL注册到注册中心,使得消费者可以获取服务提供者的信息

一个服务如果有多个协议那么就都需要暴露,比如同时支持dubbo协议和hessian协议,那么需要将这个服务用两种协议分别向多个注册中心(如果有多个的话)暴露注册。

URL-->invoker-->找到exporter-->动态封装的实现类-->实现调用

归纳:

1.检测配置,如果有些配置空的话会默认创建,并且组装成URL。     

2.根据URL进行服务暴露、创建代理类invoker.根据URL得知具体的协议。根据Dubbo SPI选取实现类实现exporter。(这个过程组装了网络过程)     

3.、如果只是本地暴露,将exporter 存入ServiceConfig的缓存 (调用时直接在本地缓存获取)

4、远程暴露,先通过registry协议找到RegistryProtocol进行export(导出),组装URL。将URL中export= d://...先转换成 exporter,然后获取注册中心的相关配置,如果需要注册则向注册中心注册,并且在ProviderConsumerRegTable这个表格中记录服务提供者,其实就是往一个ConcurrentHashMap中塞入invoker, key 就是服务接口全限定名,value是一个 set, set 里面会存包装过的invoker,根据URL上Dubbo协议暴露出exporter,打开Server调用NettyServer来监听服务。有网络调用

dubbo服务引入过程     

服务的引入和服务的暴露一样,也是通过 spring 自定义标签机制解析生成对应的 Bean,Provider Service 对应解析的是 ServiceBean 而 Consumer Reference 对应的是 ReferenceBean 

服务的引用有饿汉式和懒汉式 

饿汉式是通过调用ReferenceBean的afterPropertiesSet方法时引入服务。     

懶汉式是只有当这个服务被注入到其他类中时启动引入流程,也就是说用到了才会开始服务引入。默认使用懒汉式,如果需要使用饿汉式,可通过配置dubbo:reference的init属性开启。

ReferenceBean实现了FactoryBean接口,当对任意服务Interface 进行自动注入或者getBean获取时,就会触发getObject()函数的服务引用过程。     

  • 本地引入走injvm协议不走rpc,到服务暴露的缓存中取exporter个服务端既是 Provider 又是 Consumer 的情况是存在的,有可能自己会调用自己的服务,因此就弄了一个本地引入,这样就避免了远程网络调用的开销。所以服务引入会先去本地缓存找找看有没有本地服务。   
  • 直连远程引入服务,测试的情况下用,不需要启动注册中心,由Consumer直接配置写死Provider的地址,然后直连即可。     
  • 注册中心引入远程服务, Consumer 通过注册中心得知Provider的相关信息,然后进行服务的引入

获取注册中心实例,向注册中心注册自身,并订阅providers 、configurators、 routers 节点,触发    Dubbolnvoker的生成,cluster将多个服务调用者进行封装,返回一个invoker,

通过配置构建一个map,然后利用map来构建URL,再通过URL上的协议利用自适应扩展机制调用对应的protocol.refer 得到相应的invoker。然后再构建代理,封装invoker返回服务引用,之后Comsumer调用这个代理类 

dubbo服务调用过程     

调用某个接口的方法会调用之前生成的代理类,然后会从cluster(集群)中经过路由的过滤、负载均衡机制选择一个invoker 发起远程调用,此时会记录此请求和请求的ID等待服务端的响应。     

服务端接受请求之后会通过参数找到之前暴露存储的map,得到相应的exporter。然后最终调用真正的实现类, 再组装好结果返回,这个响应会带上之前请求的ID。     

消费者收到这个响应之后会通过ID去找之前记录的请求,然后找到请求之后将响应塞到对应的Future中,唤醒等待的线程,最后消费者得到响应。 

dubbo中Zk集群挂掉,发布者和订阅者还能通信么?   

 可以。     因为当启动dubbo容器时,消费者会去zookeeper拉取注册的生产者地址列表,并将其缓存在本地。每次发起调用时,都会按照本地的地址列表,以负载均衡的策略去进行调用。但是zookeeper挂掉则后续新的生产者无法被消费者发现。     

  • 注册中心对等集群,任意- 台宕掉后,会自动切换到另一台     
  • 注册中心全部宕掉,服务提供者和消费者仍可以通过本地缓存通讯     
  • 服务提供者无状态,任一台宕机后,不影响使用     
  • 服务提供者全部宕机,服务消费者会无法使用,并无限次重连等待服务者恢复

Dubbo支持的注册中心有哪些?   

Zookeeper(官方推荐)     

  • 优点:支持分布式     
  • 缺点:受限于Zookeeper的特性     集群可用性

Multicast:组播协议允许将一台主机发送的数据通过网络路由器和交换机复制到多个加入此组播的主机,是一种一对多的通讯方式。每一台服务提供方和服务消费方都可以看作是注册中心的一部分    

  • 优点:去中心化,不需要单独安装软件.     
  • 缺点: Provider和Consumer和Registry不能跨机房(路由)     不需要启动任何中心节点,只要广播地址一样,就可以互相发现,组播受网络结构限制,只适合小规模应用或     开发阶段使用。    

Redis     

  • 优点:支持集群,性能高     
  • 缺点:要求服务器时间同步.否则可能出现集群失败问题     

Simple     

  • 优点:标准RPC服务.没有兼容问题 类似一个demo
  • 缺点:不支持集群

dubbo集群容错策略有哪些

Failover Cluster失败自动切换: dubbo的默认容错方案,当调用失败时自动切换到其他可用的节点,貝休的重试次数和问隔时间可通过引用服务的时候配置,默认重试次数为1也就是只调用一次。     

Failback Cluster失败自动恢复:在调用失败,记录日志和调用信息,然后返回空结果给consumer,并且通过定时任务每隔5秒对失败的调用进行重试   

Failfast Cluster快速失败:只会调用一次,失败后立刻抛出异常     

Failsafe Cluster失败安全:调用出现异常,记录日志不抛出,返回空结果     

Forking Cluster并行调用多个服务提供者:通过线程池创建多个线程,并发调用多个provider,结果保存到阻塞队列,只要有一-个provider成功返回了结果,就会立刻返回结果。适用对实时性要求较高的选择

Broadcast Cluster广播模式:逐个调用每个provider,如果其中一台报错, 在循环调用结束后,抛出异常。 适用缓存一致性,一致性要求高的

dubbo支持的协议有哪些   

 Dubbo协议(官方推荐协议)   

  • 采用NIO复用单一长连接, 并使用线程池并发处理请求,减少握手和加大并发效率,性能较好(推荐使用)   
  • 大文件.上传时,可能出现问题(不使用Dubbo文件上传)     

RMI(Remote Method Invocation)协议   

  • JDK白带的能力。可与原生RMI互操作,基于TCP协议、 短连接   

 Hessian协议     

  • 可与原生Hessian互操作,基于HTTP协议。对于数据包比较大的情况比较友好   
  • 需Hessian.jar支持,Http短连接的开销大,它的参数和返回值都需要实现Serializable接口   

http协议   :比较方便使用广泛  

Webservice:基于CXF的Frontend simple和Transports http实现;基于WebService的远程调用协议。

  • 序列化: SOAP文本序列化     
  • 适用场景:系统集成,跨语言调用。   

Thrif: Thrif是Facebook捐给Apache的一个RPC框架,     

  • 语言中立  
  • 平台中立

Dubbo的分层设计 

 

  • Service, 业务层,就是咱们开发的业务逻辑层。     
  • Config, 配置层,主要围绕ServiceConfig和ReferenceConfig, 初始化配置信息。     
  • Proxy, 代理层,服务提供者还是消费者都会生成一 个代理类,使得服务接[透明化,代理层做远程调用和返回结果。     
  • Register, 注册层,封装了服务注册和发现。     
  • Cluster, 路由和集群容错层,负责选取具休调用的节点,处理特殊的调用要求和负责远程调用失败的容错措施。     
  • Monitor, 监控层,负责监控统计调用时间和次数。   
  • Portocol, 远程调用层,主要是封装RPC调用,主要负责管理Invoker,   
  • Exchange, 信息交换层,用来封装请求响应模型,同步转异步。   
  • Transport, 网络传输层,抽象了网络传输的统- 接口,Netty. Mina等。     
  • Serialize, 序列化层,将数据序列化成二进制流,以及反序列化。 

一、Dubbo和SpringCloud的区别

1、dubbo使用RPC通信,SpringCloud是HTTP restFul方式

2、dubbo的服务注册中心是Zookeerper,监控中心为dubbo-monitor,无消息总线服务跟踪批量任务等组件。cloud的服务注册中心为springcloud netflix enruka,监控中心为springboot admin,有消息总线,数据流跟踪及批量任务组建。

  • dubbo由于是二 进制的传输基于TCP长连接, 占用带宽会更少   
  • springCloud是http协议传输短链接, 带宽会比较多,同时使用http协议-般会使用JSON报文,消耗会更大
  • dubbo的开发难度较大,原因是dubbo的jar包依赖问题很多大型工程无法解决   
  • springcloud的接口协议约定比较自由且松散, 需要有强有力的行政措施来限制接口无序升级
  • dubbo只是springcloud的一 个子集,解决的是分布式中的服务调用问题,而springcloud提供 了全套的解决方案

二、Dubbo不需要web容器。dubbo内置了三种服务容器(spring container、jetty、Log4j)dubbo的服务容器只是一个简单的main方法,并加载一个简单的spring容器用于暴露服务。

三、dubbo支持的协议:dubbo(推荐)、http、rest、redis等

四、dubbo里有几种节点角色?

1、provide:暴露服务的服务提供方
2、consumer:调用远程服务的服务消费方
3、registry:服务注册于发现的注册中心
4、monitor:统计服务调用次数和调用时间的监控中心
5、container:服务运行容器

五、dubbo默认使用zookeeper为注册中心,还有redis等

六、dubbo的核心配置

七、provider上可以配置的消费端属性有哪些?

1、timeout:方法调用超时
2、retries:失败重试次数,默认重试 2 次
3、loadbalance:负载均衡算法,默认随机
4、actives 消费者端,最大并发调用限制

 八、负载均衡策略

1、random loadbalance:安权重设置随机概率(默认);
2、roundrobin loadbalance:轮寻,按照公约后权重设置轮训比例;
3、lastactive loadbalance:最少活跃调用数,若相同则随机;
4、consistenthash loadbalance:一致性hash,相同参数的请求总是发送到同一提供者。

九、dubbo的集群容错方案

十、服务提供者能实现失效踢出的原理:基于zookeeper的临时节点原理

十一、dubbo服务之间的调用是阻塞的吗?

默认是同步等待结果阻塞的,支持异步调用。dubbo是基于NIO的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小,异步调用会返回一个Future对象。dubbo暂时不支持分布式事务。

十二、dubbo的控制台能做什么?

管理控制台主要包含:路由规则,动态配置,服务降级,访问控制,权重调整,负载均衡等管理功能。另外,dubbo源码中的dubbo-admin模块打成war包,发布运行即可得到dubbo控制管理界面。

十三、dubbo服务暴露的过程

Dubbo 会在 Spring 实例化完 bean 之后,在刷新容器最后一步发布 ContextRefreshEvent 事件的时候,通知实现了 ApplicationListener 的 ServiceBean 类进行回调 onApplicationEvent 事件法,Dubbo 会在这个方法中调用 ServiceBean 父类 ServiceConfig 的 export 方法,而该方法真正实现了服务的(异步或者非异步)发布。

 十四、当一个服务接口有多种实现时可以用group属性来分组,服务提供方和消费方都指定同一个组即可。

十五、出现调用超时异常怎么办(com.alibaba.dubbo.remoting.TimeoutException)

通常是业务处理太慢,可在服务提供方执行:jstack PID > jstack.log 查看log分析线程都卡在哪个方法调用上,这里就是慢的原因。如果不能调优性能,请将timeout调大。

十六、出现java.util.concurrent.RejectedExecutionException或者Thread pool exhausted怎么办?

1、RejectedExecutionException表示线程池已经达到最大值,并且没有空闲连,拒绝执行了一些任务。 
2、Thread pool exhausted通常是min和max不一样大时,表示当前已创建的连接用完,进行了一次扩充,创建了新线程,但不影响运行。 原因可能是连接池不够用,请调整dubbo.properites:
// 设成一样大,减少线程池收缩开销  
dubbo.service.min.thread.pool.size=200  
dubbo.service.max.thread.pool.size=200

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值