1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-25 02:27:10 +08:00
2019-03-25 17:19:36 +08:00

283 lines
16 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

本文是作者根据官方文档以及自己平时的使用情况 Dubbo 所做的一个总结如果不懂 Dubbo 的使用的话可以参考我的这篇文章[超详细新手都能看懂 使用SpringBoot+Dubbo 搭建一个简单的分布式服务](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484706&idx=1&sn=d413fc17023482f67ca17cb6756b9ff8&chksm=fd985343caefda555969568fdf4734536e0a1745f9de337d434a7dbd04e893bd2d75f3641aab&token=1902169190&lang=zh_CN#rd)
Dubbo 官网http://dubbo.apache.org/zh-cn/index.html
Dubbo 中文文档 http://dubbo.apache.org/zh-cn/index.html
<!-- MarkdownTOC -->
- [ 重要的概念](#-重要的概念)
- [1.1 什么是 Dubbo?](#11-什么是-dubbo)
- [1.2 什么是 RPC?RPC原理是什么?](#12-什么是-rpcrpc原理是什么)
- [1.3 为什么要用 Dubbo?](#13-为什么要用-dubbo)
- [1.4 什么是分布式?](#14-什么是分布式)
- [1.5 为什么要分布式?](#15-为什么要分布式)
- [ Dubbo 的架构](#-dubbo-的架构)
- [2.1 Dubbo 的架构图解](#21-dubbo-的架构图解)
- [2.2 Dubbo 工作原理](#22-dubbo-工作原理)
- [ Dubbo 的负载均衡策略](#-dubbo-的负载均衡策略)
- [3.1 先来解释一下什么是负载均衡](#31-先来解释一下什么是负载均衡)
- [3.2 再来看看 Dubbo 提供的负载均衡策略](#32-再来看看-dubbo-提供的负载均衡策略)
- [3.2.1 Random LoadBalance\(默认基于权重的随机负载均衡机制\)](#321-random-loadbalance默认基于权重的随机负载均衡机制)
- [3.2.2 RoundRobin LoadBalance\(不推荐基于权重的轮询负载均衡机制\)](#322-roundrobin-loadbalance不推荐基于权重的轮询负载均衡机制)
- [3.2.3 LeastActive LoadBalance](#323-leastactive-loadbalance)
- [3.2.4 ConsistentHash LoadBalance](#324-consistenthash-loadbalance)
- [3.3 配置方式](#33-配置方式)
- [ zookeeper宕机与dubbo直连的情况](#-zookeeper宕机与dubbo直连的情况)
<!-- /MarkdownTOC -->
## 重要的概念
### 1.1 什么是 Dubbo?
Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能轻量级的开源Java RPC 框架它提供了三大核心能力面向接口的远程方法调用智能容错和负载均衡以及服务自动注册和发现简单来说 Dubbo 是一个分布式服务框架致力于提供高性能和透明化的RPC远程服务调用方案以及SOA服务治理方案
Dubbo 目前已经有接近 23k Star Dubbo的Github 地址[https://github.com/apache/incubator-dubbo](https://github.com/apache/incubator-dubbo) 。 另外在开源中国举行的2018年度最受欢迎中国开源软件这个活动的评选中Dubbo 更是凭借其超高人气仅次于 vue.js 和 ECharts 获得第三名的好成绩。
Dubbo 是由阿里开源后来加入了 Apache 正式由于 Dubbo 的出现才使得越来越多的公司开始使用以及接受分布式架构
**我们上面说了 Dubbo 实际上是 RPC 框架那么什么是 RPC呢**
### 1.2 什么是 RPC?RPC原理是什么?
**什么是 RPC**
RPCRemote Procedure Call远程过程调用它是一种通过网络从远程计算机程序上请求服务而不需要了解底层网络技术的协议比如两个不同的服务A,B部署在两台不同的机器上那么服务 A 如果想要调用服务 B 中的某个方法该怎么办呢使用 HTTP请求 当然可以但是可能会比较慢而且一些优化做的并不好 RPC 的出现就是为了解决这个问题
**RPC原理是什么**
我这里这是简单的提一下详细内容可以查看下面这篇文章
[http://www.importnew.com/22003.html](http://www.importnew.com/22003.html)
![RPC原理图](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-12-6/37345851.jpg)
1. 服务消费方client调用以本地调用方式调用服务
2. client stub接收到调用后负责将方法参数等组装成能够进行网络传输的消息体
3. client stub找到服务地址并将消息发送到服务端
4. server stub收到消息后进行解码
5. server stub根据解码结果调用本地的服务
6. 本地服务执行并将结果返回给server stub
7. server stub将返回结果打包成消息并发送至消费方
8. client stub接收到消息并进行解码
9. 服务消费方得到最终结果
下面再贴一个网上的时序图
![RPC原理时序图](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-12-6/32527396.jpg)
**说了这么多我们为什么要用 Dubbo **
### 1.3 为什么要用 Dubbo?
Dubbo 的诞生和 SOA 分布式架构的流行有着莫大的关系SOA 面向服务的架构Service Oriented Architecture也就是把工程按照业务逻辑拆分成服务层表现层两个工程服务层中包含业务逻辑只需要对外提供服务即可表现层只需要处理和页面的交互业务逻辑都是调用服务层的服务来实现SOA架构中有两个主要角色服务提供者Provider和服务使用者Consumer
![为什么要用 Dubbo](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-26/43050183.jpg)
**如果你要开发分布式程序你也可以直接基于 HTTP 接口进行通信但是为什么要用 Dubbo呢**
我觉得主要可以从 Dubbo 提供的下面四点特性来说为什么要用 Dubbo
1. **负载均衡**同一个服务部署在不同的机器时该调用那一台机器上的服务
2. **服务调用链路生成**随着系统的发展服务越来越多服务间依赖关系变得错踪复杂甚至分不清哪个应用要在哪个应用之前启动架构师都不能完整的描述应用的架构关系Dubbo 可以为我们解决服务之间互相是如何调用的
3. **服务访问压力以及时长统计资源调度和治理**基于访问压力实时管理集群容量提高集群利用率
4. **服务降级**某个服务挂掉之后调用备用服务
另外Dubbo 除了能够应用在分布式系统中也可以应用在现在比较火的微服务系统中不过由于 Spring Cloud 在微服务中应用更加广泛所以我觉得一般我们提 Dubbo 的话大部分是分布式系统的情况
**我们刚刚提到了分布式这个概念下面再给大家介绍一下什么是分布式为什么要分布式**
### 1.4 什么是分布式?
分布式或者说 SOA 分布式重要的就是面向服务说简单的分布式就是我们把整个系统拆分成不同的服务然后将这些服务放在不同的服务器上减轻单体服务的压力提高并发量和性能比如电商系统可以简单地拆分成订单系统商品系统登录系统等等拆分之后的每个服务可以部署在不同的机器上如果某一个服务的访问量比较大的话也可以将这个服务同时部署在多台机器上
### 1.5 为什么要分布式?
从开发角度来讲单体应用的代码都集中在一起而分布式系统的代码根据业务被拆分所以每个团队可以负责一个服务的开发这样提升了开发效率另外代码根据业务拆分之后更加便于维护和扩展
另外我觉得将系统拆分成分布式之后不光便于系统扩展和维护更能提高整个系统的性能你想一想嘛?把整个系统拆分成不同的服务/系统然后每个服务/系统 单独部署在一台服务器上是不是很大程度上提高了系统性能呢
## Dubbo 的架构
### 2.1 Dubbo 的架构图解
![Dubbo 架构](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-26/46816446.jpg)
**上述节点简单说明**
- **Provider** 暴露服务的服务提供方
- **Consumer** 调用远程服务的服务消费方
- **Registry** 服务注册与发现的注册中心
- **Monitor** 统计服务的调用次数和调用时间的监控中心
- **Container** 服务运行容器
**调用关系说明**
1. 服务容器负责启动加载运行服务提供者
2. 服务提供者在启动时向注册中心注册自己提供的服务
3. 服务消费者在启动时向注册中心订阅自己所需的服务
4. 注册中心返回服务提供者地址列表给消费者如果有变更注册中心将基于长连接推送变更数据给消费者
5. 服务消费者从提供者地址列表中基于软负载均衡算法选一台提供者进行调用如果调用失败再选另一台调用
6. 服务消费者和提供者在内存中累计调用次数和调用时间定时每分钟发送一次统计数据到监控中心
**重要知识点总结**
- **注册中心负责服务地址的注册与查找相当于目录服务服务提供者和消费者只在启动时与注册中心交互注册中心不转发请求压力较小**
- **监控中心负责统计各服务调用次数调用时间等统计先在内存汇总后每分钟一次发送到监控中心服务器并以报表展示**
- **注册中心服务提供者服务消费者三者之间均为长连接监控中心除外**
- **注册中心通过长连接感知服务提供者的存在服务提供者宕机注册中心将立即推送事件通知消费者**
- **注册中心和监控中心全部宕机不影响已运行的提供者和消费者消费者在本地缓存了提供者列表**
- **注册中心和监控中心都是可选的服务消费者可以直连服务提供者**
- **服务提供者无状态任意一台宕掉后不影响使用**
- **服务提供者全部宕掉后服务消费者应用将无法使用并无限次重连等待服务提供者恢复**
### 2.2 Dubbo 工作原理
![Dubbo 工作原理](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-26/64702923.jpg)
图中从下至上分为十层各层均为单向依赖右边的黑色箭头代表层之间的依赖关系每一层都可以剥离上层被复用其中Service Config 层为 API其它各层均为 SPI
**各层说明**
- 第一层**service层**接口层给服务提供者和消费者来实现的
- 第二层**config层**配置层主要是对dubbo进行各种配置的
- 第三层**proxy层**服务接口透明代理生成服务的客户端 Stub 和服务器端 Skeleton
- 第四层**registry层**服务注册层负责服务的注册与发现
- 第五层**cluster层**集群层封装多个服务提供者的路由以及负载均衡将多个实例组合成一个服务
- 第六层**monitor层**监控层对rpc接口的调用次数和调用时间进行监控
- 第七层**protocol层**远程调用层封装rpc调用
- 第八层**exchange层**信息交换层封装请求响应模式同步转异步
- 第九层**transport层**网络传输层抽象mina和netty为统一接口
- 第十层**serialize层**数据序列化层网络传输需要
## Dubbo 的负载均衡策略
### 3.1 先来解释一下什么是负载均衡
**先来个官方的解释**
> 维基百科对负载均衡的定义负载均衡改善了跨多个计算资源例如计算机计算机集群网络链接中央处理单元或磁盘驱动的的工作负载分布负载平衡旨在优化资源使用最大化吞吐量最小化响应时间并避免任何单个资源的过载使用具有负载平衡而不是单个组件的多个组件可以通过冗余提高可靠性和可用性负载平衡通常涉及专用软件或硬件
**上面讲的大家可能不太好理解再用通俗的话给大家说一下**
比如我们的系统中的某个服务的访问量特别大我们将这个服务部署在了多台服务器上当客户端发起请求的时候多台服务器都可以处理这个请求那么如何正确选择处理该请求的服务器就很关键假如你就要一台服务器来处理该服务的请求那该服务部署在多台服务器的意义就不复存在了负载均衡就是为了避免单个服务器响应同一请求容易造成服务器宕机崩溃等问题我们从负载均衡的这四个字就能明显感受到它的意义
### 3.2 再来看看 Dubbo 提供的负载均衡策略
在集群负载均衡时Dubbo 提供了多种均衡策略默认为 `random` 随机调用可以自行扩展负载均衡策略参见[负载均衡扩展](https://dubbo.gitbooks.io/dubbo-dev-book/content/impls/load-balance.html)。
备注:下面的图片来自于尚硅谷2018Dubbo 视频
#### 3.2.1 Random LoadBalance(默认基于权重的随机负载均衡机制)
- **随机按权重设置随机概率**
- 在一个截面上碰撞的概率高但调用量越大分布越均匀而且按概率使用权重后也比较均匀有利于动态调整提供者权重
![基于权重的随机负载均衡机制](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-12-7/77722327.jpg)
#### 3.2.2 RoundRobin LoadBalance(不推荐基于权重的轮询负载均衡机制)
- 轮循按公约后的权重设置轮循比率
- 存在慢的提供者累积请求的问题比如第二台机器很慢但没挂当请求调到第二台时就卡在那久而久之所有请求都卡在调到第二台上
![基于权重的轮询负载均衡机制](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-12-7/97933247.jpg)
#### 3.2.3 LeastActive LoadBalance
- 最少活跃调用数相同活跃数的随机活跃数指调用前后计数差
- 使慢的提供者收到更少请求因为越慢的提供者的调用前后计数差会越大
#### 3.2.4 ConsistentHash LoadBalance
- **一致性 Hash相同参数的请求总是发到同一提供者(如果你需要的不是随机负载均衡是要一类请求都到一个节点那就走这个一致性hash策略)**
- 当某一台提供者挂时原本发往该提供者的请求基于虚拟节点平摊到其它提供者不会引起剧烈变动
- 算法参见http://en.wikipedia.org/wiki/Consistent_hashing
- 缺省只对第一个参数 Hash如果要修改请配置 `<dubbo:parameter key="hash.arguments" value="0,1" />`
- 缺省用 160 份虚拟节点如果要修改请配置 `<dubbo:parameter key="hash.nodes" value="320" />`
### 3.3 配置方式
**xml 配置方式**
服务端服务级别
```java
<dubbo:service interface="..." loadbalance="roundrobin" />
```
客户端服务级别
```java
<dubbo:reference interface="..." loadbalance="roundrobin" />
```
服务端方法级别
```java
<dubbo:service interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>
```
客户端方法级别
```java
<dubbo:reference interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>
```
**注解配置方式**
消费方基于基于注解的服务级别配置方式
```java
@Reference(loadbalance = "roundrobin")
HelloService helloService;
```
## zookeeper宕机与dubbo直连的情况
zookeeper宕机与dubbo直连的情况在面试中可能会被经常问到所以要引起重视
在实际生产中假如zookeeper注册中心宕掉一段时间内服务消费方还是能够调用提供方的服务的实际上它使用的本地缓存进行通讯这只是dubbo健壮性的一种提现
**dubbo的健壮性表现**
1. 监控中心宕掉不影响使用只是丢失部分采样数据
2. 数据库宕掉后注册中心仍能通过缓存提供服务列表查询但不能注册新服务
3. 注册中心对等集群任意一台宕掉后将自动切换到另一台
4. 注册中心全部宕掉后服务提供者和服务消费者仍能通过本地缓存通讯
5. 服务提供者无状态任意一台宕掉后不影响使用
5. 服务提供者全部宕掉后服务消费者应用将无法使用并无限次重连等待服务提供者恢复
我们前面提到过注册中心负责服务地址的注册与查找相当于目录服务服务提供者和消费者只在启动时与注册中心交互注册中心不转发请求压力较小所以我们可以完全可以绕过注册中心采用 **dubbo 直连** 即在服务消费方配置服务提供方的位置信息
**xml配置方式**
```xml
<dubbo:reference id="userService" interface="com.zang.gmall.service.UserService" url="dubbo://localhost:20880" />
```
**注解方式**
```java
@Reference(url = "127.0.0.1:20880")
HelloService helloService;
```