- 学习视频:黑马程序员Dubbo快速入门,Java分布式框架必会的dubbo教程
- 学习资料:黑马程序员公众号提供的文档资料(提取码:dor4)(转载自黑马程序员公众号)
- 本文最后更新于 2022-04-25,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系博主删除。
- 大体上是照搬了公众号提供的资料的。
- 写博客的原因:写写笔记,做做记录,巩固知识,方便自己在线阅读。
目录
1.分布式系统中的相关概念
1.1.大型互联网项目架构目标
-
互联网项目的特点
用户多;流量大,并发高;海量数据;易受攻击;功能繁琐;高性能(提供快速的访问体验)。 -
衡量网站的性能指标
- 响应时间:指执行一个请求从开始到最后收到响应数据所花费的总体时间。
- 并发数:指系统同时能处理的请求数量。
- 并发连接数:指的是客户端向服务器发起请求,并建立了TCP连接。每秒钟服务器连接的总TCP数量
- 请求数:也称为 QPS(Query Per Second) 指每秒多少请求.
- 并发用户数:单位时间内有多少用户
- 吞吐量:指单位时间内系统能处理的请求数量。
- QPS:Query Per Second 每秒查询数。
- TPS:Transactions Per Second 每秒事务数。
- 一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。
客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数。 - 一个页面的一次访问,只会形成一个TPS;但一次页面请求,可能产生多次对服务器的请求,就会有多个QPS
- 高性能:提供快速的访问体验。
- 高可用:网站服务一直可以正常访问。
- 可伸缩:通过硬件增加/减少,提高/降低处理能力。
- 高可扩展:系统间耦合低,方便的通过新增/移除方式,增加/减少新的功能/模块。
- 安全性:提供网站安全访问和数据加密,安全存储等策略。
- 敏捷性:随需应变,快速响应。
1.2.集群和分布式
- 集群:一个业务模块,部署在多台服务器上。
(很多“人”一起 ,干一样的事) - 分布式:一个大的业务系统,拆分为小的业务模块,分别部署在不同的机器上。
(很多“人”一起,干不一样的事。这些不一样的事,合起来是一件大事)
集群分布式的优点:高性能+高可用+可伸缩+高可扩展
1.3.架构演进
1.单体架构
- 优点:简单:开发部署都很方便,小型项目首选。
- 缺点:项目启动慢;可靠性差;可伸缩性差;扩展性和可维护性差;性能低。
2.垂直架构
- 垂直架构是指将单体架构中的多个模块拆分为多个独立的项目。形成多个独立的单体架构。
- 单体架构存在的问题:项目启动慢;可靠性差;可伸缩性差;扩展性和可维护性差;性能低。
- 垂直架构存在的问题:重复功能太多。
3.分布式架构
- 分布式架构是指在垂直架构的基础上,将公共业务模块抽取出来,作为独立的服务,供其他调用者消费,以实现服务的共享和重用。
- RPC: Remote Procedure Call 远程过程调用。有非常多的协议和技术来都实现了RPC的过程。
比如:HTTP REST风格,Java RMI规范、WebService SOAP协议、Hession等等。 - 垂直架构存在的问题:重复功能太多
- 分布式架构存在的问题:服务提供方一旦产生变更,所有消费方都需要变更。
4.SOA架构
- SOA(Service-Oriented Architecture/面向服务的架构)
是一个组件模型,它将应用程序的不同功能单元(称为服务)进行拆分,并通过这些服务之间定义良好的接口和契约联系起来。 - ESB(Enterparise Servce Bus)企业服务总线,服务中介:主要是提供了一个服务于服务之间的交互。
ESB包含的功能如:负载均衡,流量控制,加密处理,服务的监控,异常处理,监控告急等等。 - 分布式架构存在的问题:服务提供方一旦产生变更,所有消费方都需要变更。
5.微服务架构
- 微服务架构是在SOA做的升华,微服务架构强调的一个重点是“业务需要彻底的组件化和服务化”,原有的单个业务系统会拆分为多个可以独立开发、设计、运行的小应用。这些小应用之间通过服务完成交互和集成。
- 微服务架构 = 80%的SOA服务架构思想 + 100%的组件化架构思想 + 80%的领域建模思想。
- 特点
- 服务实现组件化:开发者可以自由选择开发技术。也不需要协调其他团队。
- 服务之间交互一般使用REST API。
- 去中心化:每个微服务有自己私有的数据库持久化业务数据
- 自动化部署:把应用拆分成为一个一个独立的单个服务,方便自动化部署、测试、运维
- 缺点
- 粒度太细导致服务太多,维护成本高。
- 分布式系统开发的技术成本高,对团队的挑战大。
Dubbo 是 SOA 时代的产物,SpringCloud 是微服务时代的产物
2.Dubbo概述
2.1.Dubbo简介
- Apache Dubbo是一款高性能的Java RPC框架。
其前身是阿里巴巴公司开源的一个高性能、轻量级的开源Java RPC框架,可以和Spring框架无缝集成。
- 什么是RPC?
RPC全称为remote procedure call,即远程过程调用。比如两台服务器A和B,A服务器上部署一个应用,B服务器上部署一个应用,A服务器上的应用想调用B服务器上的应用提供的方法,由于两个应用不在一个内存空间,不能直接调用,所以需要通过网络来表达调用的语义和传达调用的数据。
需要注意的是RPC并不是一个具体的技术,而是指整个网络远程调用过程。
RPC是一个泛化的概念,严格来说一切远程过程调用手段都属于RPC范畴。各种开发语言都有自己的RPC框架。
Java中的RPC框架比较多,广泛使用的有RMI、Hessian、Dubbo等。
-
Dubbo官网地址:https://dubbo.apache.org/zh/index.html
-
Dubbo提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
2.2.Dubbo架构
节点角色说明
节点 | 角色名称 |
---|---|
Provider | 暴露服务的服务提供方 |
Consumer | 调用远程服务的服务消费方 |
Registry | 服务注册与发现的注册中心 |
Monitor | 统计服务的调用次数和调用时间的监控中心 |
Container | 服务运行容器 |
虚线都是异步访问,实线都是同步访问
蓝色虚线:在启动时完成的功能
红色虚线(实线)都是程序运行过程中执行的功能
调用关系说明
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
3.服务注册中心zookeeper
3.1.zookeeper介绍
通过前面的Dubbo架构图可以看到,Registry(服务注册中心)在其中起着至关重要的作用。
Dubbo官方推荐使用Zookeeper作为服务注册中心。
Zookeeper 是 Apache Hadoop 的子项目,是一个树型的目录服务。
其支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用 。
流程说明
- 服务提供者(Provider)启动时: 向
/dubbo/com.foo.BarService/providers
目录下写入自己的 URL 地址。 - 服务消费者(Consumer)启动时: 订阅
/dubbo/com.foo.BarService/providers
目录下的提供者 URL 地址。
并向/dubbo/com.foo.BarService/consumers
目录下写入自己的 URL 地址。 - 监控中心(Monitor)启动时: 订阅
/dubbo/com.foo.BarService
目录下的所有提供者和消费者 URL 地址。
3.2.zookeeper下载安装
下载地址:https://downloads.apache.org/zookeeper/
从官网或使用公众号提供的资料(zookeeper-3.4.6.tar.gz)
- 环境准备:ZooKeeper服务器是用Java创建的,它运行在JVM之上。需要安装JDK 7或更高版本。
事实上,就zookeeper-3.4.6而言,是需要在虚拟机内下载1.8版本的JDK的。
我这里使用的虚拟机是CentOS7系统,详细下载JDK1.8的情况请参考我之前写的这篇博客:《CentOS7卸载openJDK,安装jdk1.8》
- 上传:使用工具(如putty、SecureCRT等)将压缩包传入虚拟机内
这里不要直接拖拽到虚拟机,直接拖拽到虚拟机可能会对文件造成一定损失,导致安装启动失败。
- 解压:将上传的的ZooKeeper放到 /opt/ZooKeeper 目录下
# 创建zooKeeper目录
mkdir /opt/zooKeeper
# 将zookeeper安装包移动到 /opt/zooKeeper
mv apache-zookeeper-3.5.6-bin.tar.gz /opt/zookeeper/
# 解压
tar -zxvf apache-ZooKeeper-3.5.6-bin.tar.gz
- 配置 zoo.cfg
进入到conf目录拷贝一个zoo_sample.cfg并完成配置
# 进入到conf目录
cd /opt/zooKeeper/apache-zooKeeper-3.5.6-bin/conf/
# 拷贝
cp zoo_sample.cfg zoo.cfg
# 打开目录
cd /opt/zooKeeper/
#创建存储目录
mkdir zkdata
mkdir zkdatalog
#修改zoo.cfg
vim /opt/zooKeeper/apache-zooKeeper-3.5.6-bin/conf/zoo.cfg
添加两行
dataDir=/opt/zooKeeper/zkdata
dataLogDir=/opt/zooKeeper/zkdatalog
3.3 启动、停止zookeeper
进入zookeeper的bin目录,启动服务命令
./zkServer.sh start
停止服务命令
./zkServer.sh stop
查看服务状态:
./zkServer.sh status
4.Dubbo管理控制台的下载安装启动
dubbo-admin 是一个前后端分离的项目。前端使用vue,后端使用springboot,安装 dubbo-admin 其实就是部署该项目。
我们将dubbo-admin安装到开发环境上。要保证开发环境有jdk,maven,nodejs。
1.下载 nodejs
-
因为前端工程是用vue开发的,所以需要安装node.js,node.js中自带了npm,后面我们会通过npm启动
2.下载 安装 Dubbo-Admin
- 下载
进入github,搜索dubbo-admin:https://github.com/apache/dubbo-admin
- 解压
下载zip后,我们可以指定文件夹对其进行解压。
- 修改配置文件
进入…\dubbo-admin-develop\dubbo-admin-server\src\main\resources
目录,找到 application.properties 配置文件 进行配置修改
# centers in dubbo2.7
admin.registry.address=zookeeper://192.168.2.212:2181
admin.config-center=zookeeper://192.168.2.212:2181
admin.metadata-report.address=zookeeper://192.168.2.212:2181
admin.registry.address注册中心
admin.config-center 配置中心
admin.metadata-report.address元数据中心
- 打包项目
在 dubbo-admin-develop 目录执行打包命令
mvn clean package
- 启动后端
切换到目录dubbo-Admin-develop\dubbo-admin-distribution\target
下
java -jar .\dubbo-admin-0.1.jar
- 启动前端
在 dubbo-admin-ui 目录下执行命令
npm run dev
- 访问(用户名是 root,密码是 root)
http://localhost:8081/
5. Dubbo相关配置说明
<!-- 协议 -->
<dubbo:protocol port="20880" />
<!--dubbo的配置-->
<!--1.配置项目的名称,唯一-->
<dubbo:application name="dubbo-service">
<!--<dubbo:parameter key="qos.port" value="44444"/>-->
</dubbo:application>
<!--2.配置注册中心的地址-->
<dubbo:registry address="zookeeper://192.168.2.212:2181"/>
<!--3.配置dubbo包扫描-->
<dubbo:annotation package="com.itheima.service.impl"/>
<!-- 元数据配置 -->
<dubbo:metadata-report address="zookeeper://192.168.2.212:2181"/>
5.1.包扫描
<dubbo:annotation package="com.itheima.service" />
服务提供者和服务消费者都需要配置,表示包扫描,作用是扫描指定包(包括子包)下的类。
如果不使用包扫描,也可以通过如下配置的方式来发布服务:
<bean id="helloService" class="com.itheima.service.impl.HelloServiceImpl" />
<dubbo:service interface="com.itheima.api.HelloService" ref="helloService" />
作为服务消费者,可以通过如下配置来引用服务:
<!-- 生成远程服务代理,可以和本地 bean 一样使用 helloService -->
<dubbo:reference id="helloService" interface="com.itheima.api.HelloService" />
上面这种方式发布和引用服务,一个配置项(<dubbo:service>
、<dubbo:reference>
)只能发布或者引用一个服务;
如果有多个服务,这种方式就比较繁琐了。故推荐使用包扫描方式。
5.2.协议
<dubbo:protocol name="dubbo" port="20880"/>
一般在服务提供者一方配置,可以指定使用的协议名称和端口号。
其中Dubbo支持的协议有:dubbo、rmi、hessian、http、webservice、rest、redis等。
推荐使用的是dubbo协议。
dubbo 协议采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。
也可以在同一个工程中配置多个协议,不同服务可以使用不同的协议,例如:
<!-- 多协议配置 -->
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name="rmi" port="1099" />
<!-- 使用 dubbo 协议暴露服务 -->
<dubbo:service interface="com.itheima.api.HelloService" ref="helloService" protocol="dubbo" />
<!-- 使用 rmi 协议暴露服务 -->
<dubbo:service interface="com.itheima.api.DemoService" ref="demoService" protocol="rmi" />
5.3.启动时检查
<dubbo:consumer check="false"/>
上面这个配置需要配置在服务消费者一方,如果不配置默认check值为true。Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题。可以通过将check值改为false来关闭检查。
建议在开发阶段将check值设置为false,在生产环境下改为true。
6.Dubbo的特性
6.1.序列化
- 问:两个机器传输数据,如何传输 Java 对象?
dubbo 内部已经将 序列化 和 反序列化 的过程内部封装了。
我们只需要在定义pojo类时实现Serializable接口即可。
一般会定义一个公共的pojo模块,让生产者和消费者都依赖该模块。
6.2.地址缓存
- 问:服务中心挂了,地址是否可以正常访问?
可以。因为dubbo服务消费者在第一次调用时,会将服务提供方地址缓存到本地,以后在调用则不会访问注册中心。
当服务提供者地址发生变化时,注册中心会通知服务消费者。
6.3.超时与重试
服务消费者在调用服务提供者的时候发生了阻塞、等待的情形,这个时候,服务消费者会一直等待下去。
在某个峰值时刻,大量的请求都在同时请求服务消费者,会造成线程的大量堆积,势必会造成雪崩。
dubbo 利用超时机制来解决这个问题,设置一个超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。
使用timeout属性配置超时时间,默认值1000,单位毫秒。
设置了超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。
如果出现网络抖动,则这一次请求就会失败。
Dubbo提供重试机制来避免类似问题的发生。
通过retries属性来设置重试次数。默认为 2 次。
可以在服务提供者一方配置(service)。
@Service(timeout = 3000, retries = 2)//当前服务超过3000秒;重试2次,一共是3次
也可以在服务消费者一方配置(contorller)。
@Reference(timeout = 1000)//远程注入
6.4.多版本发布
灰度发布:当出现新功能时,会让一部分用户先使用新功能,用户反馈没问题时,再将所有用户迁移到新功能。
dubbo中使用version属性来设置和调用同一个接口的不同版本。
比如这是serviceImpl_1
@Service(version = "v1.0")
比如这是serviceImpl_2
@Service(version = "v2.0")
比如这是controller
@Reference(version = "v1.0")
6.5.负载均衡
负载均衡(Load Balance):其实就是将请求分摊到多个操作单元上进行执行,从而共同完成工作任务。
在集群负载均衡时,Dubbo 提供了多种均衡策略(包括随机、轮询、最少活跃调用数、一致性Hash),缺省为random随机调用。
配置负载均衡策略,既可以在服务提供者一方配置,也可以在服务消费者一方配置。
如下:
@Controller
@RequestMapping("/demo")
public class HelloController {
//在服务消费者一方配置负载均衡策略
@Reference(check = false,loadbalance = "random")
private HelloService helloService;
@RequestMapping("/hello")
@ResponseBody
public String getName(String name){
//远程调用
String result = helloService.sayHello(name);
System.out.println(result);
return result;
}
}
//在服务提供者一方配置负载均衡
@Service(loadbalance = "random")
public class HelloServiceImpl implements HelloService {
public String sayHello(String name) {
return "hello " + name;
}
}
可以通过启动多个服务提供者来观察Dubbo负载均衡效果。
我们也可以设置权重
@Service(weight = 100)
注意:因为我们是在一台机器上启动多个服务提供者,所以需要修改tomcat的端口号和Dubbo服务的端口号来防止端口冲突。
在实际生产环境中,多个服务提供者是分别部署在不同的机器上,所以不存在端口冲突问题。
- 负载均衡策略(4种):
- Random:按权重随机,默认值。按权重设置随机概率。
- RoundRobin:按权重轮询。
- LeastActive:最少活跃调用数,相同活跃数的随机。
- ConsistentHash:一致性Hash,相同参数的请求总是发到同一提供者。
6.6.集群容错
- 集群容错模式
- Failover Cluster:失败重试。默认值。当出现失败,重试其它服务器 ,默认重试2次,使用 retries 配置。一般用于读操作
- Failfast Cluster :快速失败,只发起一次调用,失败立即报错。通常用于写操作。
- Failsafe Cluster :失败安全,出现异常时,直接忽略。返回一个空结果。
- Failback Cluster :失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
- Forking Cluster :并行调用多个服务器,只要一个成功即返回。
- Broadcast Cluster :广播调用所有提供者,逐个调用,任意一台报错则报错。
例如
@Reference(cluster = "failover")
6.7.服务降级
服务降级方式
mock = force:return null
:- 表示消费方对该服务的方法调用都直接返回null值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
mock = fail:return null
:- 表示消费方对该服务的方法调用在失败后,在返回null值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。
例:
@Reference(mock = "force:return null")//相当于不再调用 UserService 的服务
对于Dubbo的一些特性的讲述,这里推荐个人觉着一篇不错的博客:《dubbo分布式服务框架(高级特性篇)》
更多细节还请参考官方文档:https://dubbo.apache.org/zh/docs/