Dubbo
一、分布式系统
1.1 分布式
什么是分布式?来自维基百科–分布式系统(distributed system)是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件。看了这个解释我是一头雾水。到底什么是分布式,分布式用来做什么,我们先来看些与分布式有关的东西。
1.2 分布式拆分
-
水平拆分
就是不断地增加服务器部署同一个应用,但这样治标不治本。所以产生了垂直拆分
-
垂直拆分
就是不断地拆分服务将不同的微服务交付给不同的服务器上单独运行。弊端是由于应用不可能完全脱离互相的其他服务,所以我们将项目的前后端分离,并将不同的业务代码的处理放到不同的服务器。
这样的话,由于我们将不同的业务逻辑分开,就会导致web服务器和逻辑处理的服务器分开难以管理。这时,就需要我们的RPC来解决找个问题。那什么是RPC呢?
这里先简单介绍一下,***RPC***又称远程过程调用,是一种分布式服务框架,专门管理web端和service服务端的通信的。
当业务越来越多的时候,不同业务之间的访问量参差不齐,有的“门客满盈”,有成千上百次的访问,而有的却寥寥几次。所以为了解决这个问题,我们还需要引进***流动计算架构***来调度,进行服务器集群的管理,提高服务器的利用率。
1.3 dubbo简介
dubbo使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。
1.3.1 特性
是一款高性能、轻量级的开源Java RPC框架,它主要提供了三大核心能力:
-
面向接口的远程方法调用,
-
智能容错和负载均衡,
-
服务自动注册和发现。
那么这些都是什么呢?我们可以在apache官网里找到dubbo的一些特性:
-
面向接口代理的高性能RPC调用
也就是当服务器A要调用服务器B中的服务的时候,我们只需要在A中调用某一个接口就可以使用到B中功能,而不用考虑其中是如何调用的。就类似可以理解为mybatis中可以用调用dao层接口而不用考虑具体实现一样。
-
智能负载均衡
当我们对同一个业务有多个服务器被垂直拆分了之后,可以对这几台服务器实现负载均衡。可以类比成nginx中的负载均衡实现。
-
服务自动注册发现
当服务A需要服务B的时候,可以自动帮我们找到该服务所在的服务器
这个的具体是由注册中心实现的,注册中心维护一个功能–服务器对应的清单,负载均衡也是在这里实现,所以这个就相当于是Nginx服务器中的那个被最先访问的服务器。
-
运行期流量调度
这个主要是手动配置路由规则,然后实现灰度发布(就是当我们服务需要升级时,可以让流量先访问升级后的服务器,再把旧版本升级后再投入使用)
-
可视化的服务治理与运维
有可视化的管理界面
-
1.3.2 高性能RPC框架
上面说了那么多,可以得出一个结论,Dubbo最根本还是逃不了RPC框架。那么先来了解一下RPC的大致组成框架:消费者–注册中心–服务提供者----监控者
我们先简单了解一下,Dubbo具体是怎么调用的。首先,注册中心注册服务提供者;并且让消费者订阅;在监控者中注入消费者和服务者的信息。这些是在初始化的时候我们需要做完的。然后在运行时,只需要做唯一一件事,就是消费者向注册中心发送信息请求,并且服务提供者提供相应的服务给注册中心转交给消费者。
二、RPC框架的具体实现
到这儿,我们已经知道了RPC框架的是由 消费者–注册中心–服务提供者----监控者 来实现的。所以我们分别来具体实现这四部分。
2.1 注册中心
实际上,Dubbo支持多种注册中心的,但是在参考手册的介绍中明确标明,真的很明确,因为就只有一行字——“推荐使用 Zookeeper 注册中心”。所以,我们还是听从它的官方文档来做。具体的在Zookeeper官方手册可以查看。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Us6NJQt2-1587655483035)(D:\App\Typora\resources\md-image\dubbo\image-20200409232212399.png)]
2.2 监控中心
便于管理各个服务器,需要一个管理控制台来管理监控器,这也相应了它的可视化界面。
-
安装
在GitHub网站上去查找相应的源码下载
-
启动
打成jar包,启动
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wrW0zOge-1587655483038)(D:\App\Typora\resources\md-image\dubbo\image-20200423205047047.png)]
-
访问管理控制台
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AZNcLfYe-1587655483040)(D:\App\Typora\resources\md-image\dubbo\image-20200423205130745.png)]
密码和用户名都默认为root
2.3 具体实现(Spring为例)
-
注册服务到服务中心
-
在服务端引入dubbo的依赖
<!-- https://mvnrepository.com/artifact/com.alibaba/dubbo --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.6</version> </dependency>
-
引入注册中心操作客户端
<dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>2.12.0</version> </dependency>
-
配置服务基本端口
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <!-- 提供方应用信息(主要是名字),用于计算依赖关系 --> <dubbo:application name="hello-world-app" /> <!-- 使用zookeeper广播注册中心暴露服务地址 --> <!--<dubbo:registry address="zookeeper://127.0.0.1:2181" />--> <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"/> <!-- 指定通信协议,用dubbo协议在20880端口暴露服务 --> <dubbo:protocol name="dubbo" port="20880" /> <!-- 声明需要暴露的服务接口,ref填写服务的真正实现--> <dubbo:service interface="com.zxc.test.service.UserService" ref="demoService" /> <!-- 将服务的真正实现类加入到bean管理中 --> <bean id="demoService" class="com.zxc.service.UserServiceImpl" /> </beans>
-
启动类
public class MainApplication { public static void main(String[] args) throws IOException { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"provider.xml"}); context.start(); System.in.read(); // DemoService demoService = (DemoService)context.getBean("demoService"); // 获取远程服务代理 // String hello = demoService.sayHello("world"); // 执行远程方法 // System.out.println( hello ); // 显示调用结果 } }
-
-
消费者端
-
引入Dubbo和zookeeper依赖(同上)
-
配置文件,声明自己需要的接口
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 --> <dubbo:application name="consumer-of-helloworld-app" /> <!-- 使用multicast广播注册中心暴露发现服务地址 --> <dubbo:registry address="zookeeper://127.0.0.1:2181" /> <!-- 生成远程服务代理,可以和本地bean一样使用demoService --> <dubbo:reference id="UserService" interface="com.zxc.test.service.UserService" /> <context:component-scan base-package="com.zxc.test.service.impl"/> </beans>
-
-
监控中心
- 在上面的github中下载,并打包运行(在conf目录下填写正确的zookeeper地址),
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F0FlhlJ8-1587655483043)(D:\App\Typora\resources\md-image\dubbo\image-20200412160622733.png)]
-
将消费者和提供者两端注册到相应的监控中心
这里只以消费者为例:
<!-- <dubbo:monitor protocol="registry"/>-->//这是在注册中心自动发现 <dubbo:monitor address="127.0.0.1:7070"/>//这是指定了注册中心
其实到这步,最基本的RPC框架就已经搭建好了,消费者一端也可以成功的调用到提供者一端的接口。但这以上都是使用的Spring框架,那么我们该如何整合Dubbo和SpringBoot框架呢?接下去就列出使用中的几项不同点-:
-
在消费者和使用者中导入Dubbo依赖不同(在git中就有明确指出)
-
然后配置(主要是注册到注册中心,和声明,)可以用yml,properties
方法1.
-
service使用dubbo的**@service**来暴露
-
然后在主类上加**@EnableDubbo**开启Dubbo 的注解支持
-
当我们需要调用远程接口的时候,需要注入的时候,需要加上**@Reference**注解
方法2.(这个方法可以使注解到方法级别的)
-
保留dubbo.xml配置文件
-
只需要@ImportResource(location=“XXX.XXX.XXX.calss”)导入配置文件
方法3.(使用API注解的方式,将每一个组件手动地注册到Bean中,然后远程调用的时候只需要像本地方法一样使用)
-
可以设置一个配置类,然后将不同的类注册进IOC容器(就是相当于是)
// 当前应用配置 ApplicationConfig application = new ApplicationConfig(); application.setName("yyy"); // 连接注册中心配置 RegistryConfig registry = new RegistryConfig(); registry.setAddress("10.20.130.230:9090"); registry.setUsername("aaa"); registry.setPassword("bbb"); // 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接 // 引用远程服务 ReferenceConfig<XxxService> reference = new ReferenceConfig<XxxService>(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏 reference.setApplication(application); reference.setRegistry(registry); // 多个注册中心可以用setRegistries() reference.setInterface(XxxService.class); reference.setVersion("1.0.0"); // 和本地bean一样使用xxxService XxxService xxxService = reference.get(); // 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用
-
tips:
-
配置文件优先级:
方法级优先;接口次之;全局配置再次之;
(这能使我们方便修改其中一个服务端的配置而不影响其他的端口
消费方优先;服务端次之;
-
-
本地存根:
我们在消费者本地创建一个本地的代码实现,方便先在本地实现一些逻辑
具体实现:
1> 在本地继承需要调用的服务端接口
2> 实现一个有参构造器,传入一个远程的代理对象
3> 在配置文件中,远程调用的对象中的stub属性来确定需要的存根类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9SuRYOf9-1587655483046)(D:\App\Typora\resources\md-image\dubbo\image-20200423223242375.png)]
三、高可用
什么是高可用?总的来说,高可用就是通过一些设计,减少不能提供服务的时间。
3.1 健壮性:
-
Zookeeper宕机
- 注册中心有主备从机
- 如果注册中心的机器全部宕机则我们仍可以在一段时间内继续消费服务,因为有本地缓存,所以消费者就不需要去访问注册中心寻找所需要的服务提供者
- 即使我们缓存到期或者没有缓存,我们也可以通过dubbo直连(具体实现是通过在**@Reference(服务端的主机号:端口号)**)来直接绕过注册中心连接服务端
3.2 负载均衡(默认采用随机)
-
负载均衡机制(ˉ▽ ̄~) ~~
-
权重
即为每一个服务器分配一个权重,按照所占比例大小来将其进行分配使用
-
基于权重的轮询
在依次调用的基础上考虑权重的机制
-
fair机制
挑一个最快的服务器来响应,谁能力大,就责任多
-
hash
根据hash值去到相应的服务器
-
-
设置机制o( ̄︶ ̄)o
- 通过**@Reference注解设置LoadBalance**属性
- 设置权重的话,可以在**@Service**(weight="")中设置
3.3 服务降级
什么是服务降级?当服务器压力过大的情况下,让一些情况不严重的服务,让资源给被频繁访问的服务。这部分是针对消费者一端的。
- 降级机制方法
- 禁用:对该服务的调用返回都为空值
- 容错:在对服务调用失败后,不抛出异常,返回为空
3.4 集群容错
集群调用失败的机制
-
Failover Cluster
失败自动切换,出现失败,重试其他服务器,通常用于读操作
-
Failfast Cluster
快速失败,只发起一次调用,失败立即报错
-
Failsafe Cluster
失败安全,出现异常时,直接忽略
-
Failback Cluster
失败自动恢复,后台记录失败记录
-
Forking Cluster
并行调用多个服务器,只要一个成功即返回,forks=“2”,用于实时性要求较高的读操作
-
Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错即报错,用于通知
集群模式配置
<dubbo:server cluster="failsafe"/>或<dubbo:reference cluster="failsafe"/>
3.5 整合hystrix
hystrix是什么?在分布式环境中,许多服务依赖项中的一些必然会失败。Hystrix是一个库,通过添加延迟容忍和容错逻辑,帮助你控制这些分布式服务之间的交互。
-
具体实现
-
导入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
-
开启服务容错功能
@EnableHystrix
-
在可能出现异常的地方,加上**@HystrixCommand**
-
四、dubbo原理
些必然会失败。Hystrix是一个库,通过添加延迟容忍和容错逻辑,帮助你控制这些分布式服务之间的交互。
-
具体实现
-
导入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
-
开启服务容错功能
@EnableHystrix
-
在可能出现异常的地方,加上**@HystrixCommand**
-