Dubbo

简介

分布式: ​ 每个模块可能在不同的服务器上单独运行,但是不得不交互,比如A调用B,不同的服务器交互叫RPC(远程过程调用)

传统架构和微服务架构: ​ 传统架构是单一的架构模式,就是将应用整体打包部署。 ​ 微服务则是将单个的整体应用分割成更小的项目关联的独立的服务;一个服务通常实现一组独立的特性或功能,包含自己的业务逻辑和适配器。服务之间通过暴漏的API来关联。

SOA架构和微服务架构的区别: ​ SOA中所有的组件都是独立自主的,并且能为其他组件提供服务;微服务架构在某种程度上是面向服务的架构SOA继续发展的下一步。SO通过ESB来连接各个服务的节点,微服务架构下通过API网关来连接各个服务节点; ​ SOA更适用于需要与其他应用集成的大复杂的企业型程序环境,小型的程序不适合SOA架构,因为它们不需要消息中间件; ​ 而微服务架构更适用较小和良性的分割,基于Web系统

架构运行的原理

​ Provider: 运行服务的服务提供方 暴露服务的服务提供方 服务提供者 ​ Consumer: 调用远程服务的服务消费方 服务消费者 ​ Registry: 服务注册与发现的注册中心 注册中心 ​ Mo i tor: 统计服务的调用次数和调用时间的监控中心 监控中心 ​ Con tai ner: 服务运行容器 Dubbo框架容器

架构运行流程

0.服务容器负责启动,加载,运行服务提供者 1.服务提供者在启动时,向注册中心注册自己提供的服务 2.服务消费者在启动时,向注册中心订阅自己所需的服务 3.注册中心返回服务提供者地址给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者 4.服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,在选取另一台调用 5.服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

0(Container)容器启动, 1(Provider)服务提供者会将自己所提供的信息注册到注册中心里(registry),这样注册中心就知道那些服务上线了 2(Consumer)当服务消费者启动,会从注册中心来订阅(subscribe)他所需要的服务 ​ 0 1 2 初始化完成 3 如果说某一个服务提供者有变更(notify),注册中心会将变更推送给消费者,实时知道有些不能调用了 ​ 3 5 是在异步过程 4 当消费者拿到所有它能调的服务(invoke),调用的可以同步调用提供者提供的服务,比如调用一个查询业务,提供者可能会有好几个机器同时在运行查询,消费者可以根据负载均衡算法选择一个进行调用 ​ 4 服务消费者调用服务提供者是同步的调用 5 它们的调用信息和时间会定时的每隔一分钟发送到监控中心(monitor)

Registry , Provider , Consumer 注册中心,服务提供者,服务消费者。 架构图解析: ​ 生产者和消费者的模式,只是加上了注册中心和监控中心,用于管理提供方提供的URL,以及管理整个过程

编写过程

  1. 服务提供者(Provider)将服务提供者提供的服务注册到注册中心

  2. 服务消费者(Consumer)消费者从注册中心订阅提供者所提供的服务

  3. 测试

注册中心(zookeeper)

支持的注册中心: ​ Multicast ​ Zookeeper ​ Redis ​ Simple Zookeeper的适用 ​

  1. 更改配置文件 ​

  2. 启动zkServer.cmd ​

  3. 启动zkCli.cmd 作用:保存服务提供的信息,我们也可以使用Dubbo直连 命令:

 get  /  #查看根节点
 ls /    
 create -e /节点名 值

管理控制台 (admin)

可以不装 可视化界面 ​ 下载https://github.com/apache/dubbo-admin/tree/master ​ 改端口,退回到src运行 mvn clean package打包 ​ 然后Java -jar 运行 端口7071 ​ 监控中心:http://localhost:7001/ ​ 前提必须启动zookeeper

HelloWord

  1. 创建User ServiceProvider (服务提供)

  2. 创建UserOrderServiceConsumer (消费者)

  3. 创建公共接口放入Bean 和 interface (供使用)

  4. 在服务和消费设置公共 的pom

 <!--引入公共项目-->
     <dependencies>
         <dependency>
             <groupId>org.ph</groupId>
             <artifactId>DubboGmall-Interface</artifactId>
             <version>1.0-SNAPSHOT</version>
         </dependency>
     </dependencies>

5.为了让消费者Consumer远程调用提供者的impl ​ 一.将服务提供者注册到注册中心(暴露服务)provider引入

 a.导入Dubbo依赖 
 <!--引入Dubbo-->
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>dubbo</artifactId>
             <version>2.6.2</version>
         </dependency>
         <!--注册中心 2.6.2以前是zkclient-->
         <dependency>
             <groupId>org.apache.curator</groupId>
             <artifactId>curator-framework</artifactId>
             <version>2.12.0</version>
         </dependency>
 b.创建提供者的配置文件
 <?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://code.alibabatech.com/schema/dubbo"
        xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
 ​
     <!--当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签-->
     <dubbo:application name="provider" owner="lph">
         <dubbo:parameter key="qos.enable" value="true"/>
         <dubbo:parameter key="qos.accept.foreign.ip" value="false"/>
         <dubbo:parameter key="qos.port" value="55555"/>
     </dubbo:application>
 ​
     <dubbo:monitor protocol="registry"/>
 ​
     <!--dubbo这个服务所要暴露的服务地址所对应的注册中心-->
     <!--<dubbo:registry address="N/A"/>-->
     <dubbo:registry address="zookeeper://localhost:2181" check="false"/>
 ​
     <!--当前服务发布所依赖的协议;webserovice、Thrift、Hessain、http
         使用dubbo协议在20880端口进行通信
     -->
     <dubbo:protocol name="dubbo" port="20880"/>
 ​
     <!--服务发布的配置,需要暴露的服务接口 暴露完别人就能调用了
        此处是公共的接口
        ref:是真正的是实现对象 此处加入bean容器
         -->
     <dubbo:service
             interface="service.UserService"
             ref="providerService"/>
     <!--Bean bean定义 服务的实现-->
     <bean id="providerService" class="service.impl.UserServiceImpl"/>
 ​
 </beans>
 运行后可在监控中心看的一个提供方        

二.让服务消费者去注册中心订阅服务提供者的服务地址 Consumer

 a.和提供者一样引入依赖
 <!--引入Dubbo-->
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>dubbo</artifactId>
             <version>2.6.2</version>
         </dependency>
         <!--注册中心 2.6.2以前是zkclient-->
         <dependency>
             <groupId>org.apache.curator</groupId>
             <artifactId>curator-framework</artifactId>
             <version>2.12.0</version>
         </dependency>
 b.配置文件 只需要配置消费者的名字,设置注册中心的地址,消费哪个服务
 <?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://code.alibabatech.com/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.xsd
           http://code.alibabatech.com/schema/dubbo
            http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
 ​
     <!--扫描组件-->
     <context:component-scan base-package="service"></context:component-scan>
 ​
     <!--当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签-->
     <dubbo:application name="consumer" owner="lph"/>
     <!--dubbo这个服务所要暴露的服务地址所对应的注册中心-->
     <!--点对点的方式-->
     <!--<dubbo:registry address="N/A"/>-->
     <dubbo:registry address="zookeeper://localhost:2181"/>
 ​
 ​
     <!--声明需要调用的远程服务的接口  生成一个远程服务的调用代理   就是提供者暴露的接口-->
     <!--点对点方式-->
     <dubbo:reference id="userService"
                      interface="service.UserService"
     />
     <!--url="dubbo://192.168.127.1:20880/service.ProviderService"-->
 ​
     <!--<dubbo:reference id="providerService"
                      interface="com.sihai.dubbo.provider.service.ProviderService"/>-->
 </beans>
 主程序类
   ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("consumer.xml");
         OrderService bean = classPathXmlApplicationContext.getBean(OrderService.class);
 ​
         bean.initOrder("1");
         System.out.println("调用结束..........");
         System.in.read();

监控中心(dubbo-monitor-simple)

启动start.bat ​ 配置

     <!--连接监控中心-->
     <dubbo:monitor protocol="registry"/>
 生产和消费都需要

与Spring boot整合

创建提供者:

1.pom依赖

  <!--依赖接口-->
         <dependency>
             <groupId>org.ph</groupId>
             <artifactId>DubboGmallInterface</artifactId>
             <version>0.0.1-SNAPSHOT</version>
         </dependency>
         <!--Dubbo整合Spring boot
             如果 spring boot是2.0.x使用 0.2.0版本
                         1.5.x使用0.1.1
            -->
         <dependency>
             <groupId>com.alibaba.boot</groupId>
             <artifactId>dubbo-spring-boot-starter</artifactId>
             <version>0.2.0</version>
         </dependency>

2.properties配置文件

 #当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签
 dubbo.application.name=UserProvider
 #dubbo这个服务所要暴露的服务地址所对应的注册中心
 dubbo.registry.address=localhost:2181
 dubbo.registry.protocol=zookeeper
 ​
 #当前服务发布所依赖的协议;webserovice、Thrift、Hessain、http
 #使用dubbo协议在20880端口进行通信
 dubbo.protocol.name=dubbo
 dubbo.protocol.port=20880
 ​
 #连接监控中心 registry是自己发现
 dubbo.monitor.protocol=registry
 ​
 #省略xml配置的第四步 使用注解完成
 ​
 ##
 ##xml的配置
 #1.指定当前的服务/应用的名字(同样的服务名相同,不要和别的服务名相同)
     #<dubbo:application name="provider" owner="lph">
     #<!--<dubbo:parameter key="qos.enable" value="true"/>
     #   <dubbo:parameter key="qos.accept.foreign.ip" value="false"/>
     #   <dubbo:parameter key="qos.port" value="55555"/>-->
     #</dubbo:application>
 #2.这个服务所要暴露的服务地址所对应的注册中心
     #<!--<dubbo:registry address="N/A"/>-->
     #<dubbo:registry address="zookeeper://localhost:2181"/>
 #3.指定通信规则   通信协议 通信端口
     #当前服务发布所依赖的协议;webserovice、Thrift、Hessain、http
     #使用dubbo协议在20880端口进行通信
     #<dubbo:protocol name="dubbo" port="20880"/>
 #4.暴露服务ref,指向服务真实的实现对象
     #<!--服务发布的配置,需要暴露的服务接口 暴露完别人就能调用了
     #此处是公共的接口
     #ref:是真正的是实现对象 此处加入bean容器
     #-->
     #<dubbo:service interface="service.UserService" ref="userService"/>
     #
     #<!--Bean bean定义 服务的实现-->
     #<bean id="userService" class="service.impl.UserServiceImpl"/>

创建消费者:

1.pom

 <!--依赖接口-->
 <dependency>
     <groupId>org.ph</groupId>
     <artifactId>DubboGmallInterface</artifactId>
     <version>0.0.1-SNAPSHOT</version>
 </dependency>
 <!--Dubbo整合Spring boot
   如果 spring boot是2.0.x使用 0.2.0版本
               1.5.x使用0.1.1
  -->
 <dependency>
     <groupId>com.alibaba.boot</groupId>
     <artifactId>dubbo-spring-boot-starter</artifactId>
     <version>0.2.0</version>
 </dependency>

2.propertis配置文件

 # 应用服务 WEB 访问端口
 server.port=8081
 dubbo.application.name=OrderConsumer
 dubbo.registry.address=zookeeper://127.0.0.1:2181
 dubbo.monitor.protocol=registry
 #省略了 使用注解实现 @Reference
 #声明需要调用的远程服务的接口  生成一个远程服务的调用代理   就是提供者暴露的接口

创建公共:

公共的实体类和接口等

明细:

提供方的impl 使用Dubbo的注解 import com.alibaba.dubbo.config.annotation.Service;

 @Service    //提供者暴露服务 供消费者调用
 @Component
 public class UserServiceImpl implements UserService {
 ​
     @Override
     public List<UserAddress> getUserAddressList(String userId) {
         UserAddress userAddress1 = new UserAddress(1, "北京市xxx", "1", "香油王", "010-343442434", "Y");
         UserAddress userAddress2 = new UserAddress(2, "厦门市xxx", "1", "钓鱼李", "010-423543344", "Y");
         return Arrays.asList(userAddress1, userAddress2);
     }
 }

消费方的impl使用 @Reference 注解来导入远程的Service

 @Service
 public class OrderServiceImpl implements OrderService {
 ​
     @Reference
     UserService userService;
 ​
     @Override
     public List<UserAddress> initOrder(String userId) {
         //1.查询用户的收货地址
         System.out.println("userId = " + userId);
         List<UserAddress> userAddressList = userService.getUserAddressList(userId);
         return userAddressList;
     }
 }
 。。编写Controller测试
 消费和提供方的主配置类不要忘记@EnableDubbo

Dubbo.properties属性加载顺序

  1. -D虚拟机参数

  2. xml文件 dubbo.xml

  3. properties dubbo.properties

启动检查

防止没有提供者消费者就启动,我们可以使用启动时检查:check=”true“ 来检查提供者是否在注册中心 xml配置:消费者

 <!--开启某个服务的启动时检查(没有提供者时报错)-->
 <dubbo:reference id="userService"
                      interface="service.UserService"
                      check="true"   
     />
 ​
 <!--后期服务太多我们可以使用:开启所有服务的启动时检查(没有提供者时报错)-->
     <dubbo:consumer check="true"></dubbo:consumer>
 ​
 <!--关闭注册中心的启动时检查(注册订阅失败时报错)注册中心不存在时就报错 默认为true -->
 <dubbo:registry check="false"></dubbo:registry>

我们还可已使用properties文件配置

超时和覆盖配置

timout:服务消费方调用服务提供方的时候网络超时的话会出现线程堵塞的情况 ​ 使用:在某个方法上使用timeout属性来设置请求时间

 单个服务的设置
 <dubbo:reference id="userService"
                      interface="service.UserService"
                      timeout="3000"
     />
 <dubbo:reference id="userService" interface="service.UserService" timeout="2">
         <dubbo:method name="" timeout="1">配置具体的方法 公共接口的方法</dubbo:method>
 </dubbo:reference>
 ​
 不配置的话默认是一秒
 ​
 全局的设置 所有的接口
     <dubbo:consumer check="true" timeout="3000"></dubbo:consumer>

配置的覆盖优先级

 1.消费
       <dubbo:reference id="userService" interface="service.UserService">
             1  <dubbo:method name=""></dubbo:method>
       </dubbo:reference>
 2.服务提供                                                                      方法级别
      <dubbo:service interface="service.UserService" ref="userService">
        2   <dubbo:method name="" timeout=""></dubbo:method>
       </dubbo:service>
 ​
 3.消费的
    3 <dubbo:reference id="userService" interface="service.UserService" timeout=""/>
 4.提供的                                                                       接口级别
     4 <dubbo:service interface="service.UserService" timeout="" ref="userService"/>
 ​
 ​
 5.全局的消费
     5 <dubbo:consumer check="true" timeout="3000"></dubbo:consumer>
 6.全局的提供                                                                     全局配置
     6     <dubbo:provider timeout=""/>
 总结:
     消费的具体方法 --> 服务的具体方法 --> 消费的具体接口 --> 服务的具体接口 --> 全局的消费 --> 全局的提供
     级别一样的话消费方优先 还是按照由内到外

重试次数

消费:

 <dubbo:reference id="userService" interface="service.UserService" check="true">
     <dubbo:method name="getUserAddressList" timeout="3000" retries="3"></dubbo:method>
 </dubbo:reference>
 当有多台服务器的时候 还会自动的都试一次
 适用场景:
     幂等适用        查询 删除 修改
     非幂等不适用      增加

多版本灰度发布

provider

 <!--服务发布的配置,需要暴露的服务接口 暴露完别人就能调用了
    此处是公共的接口
    ref:是真正的是实现对象 此处加入bean容器
     -->
 <dubbo:service interface="service.UserService" ref="userService1" version="1.0.0"/>
 ​
   <!--Bean bean定义 服务的实现-->
 <bean id="userService1" class="service.impl.UserServiceImpl"/>
 ​
 <dubbo:service interface="service.UserService" ref="userService2" version="2.0.0"/>
 ​
 <!--Bean bean定义 服务的实现-->
 <bean id="userService2" class="service.impl.UserNewServiceImpl"/>
 多版本同时存在

consumer

   <!--声明需要调用的远程服务的接口  生成一个远程服务的调用代理   就是提供者暴露的接口-->
     <!--点对点方式       check:启动时检查-->
     <dubbo:reference id="userService" interface="service.UserService" check="true" version="1.0.0 or *">
         <dubbo:method name="getUserAddressList" timeout="3000" retries="3"></dubbo:method>
     </dubbo:reference>  

本地存根

服务消费者这要调用服务提供者的功能,功能实现都在提供者,消费只有接口 我们在调用之前可能会做一些参数验证,缓存,我们就可以编写一个本地存根 实现: ​ Consumer

 public class UserServiecStub implements UserService {
 ​
     private final UserService userService;
 ​
     /**
      * 调用远程的User Service必须的有参构造
      *
      * @param userService 传入的是UserService的远程代理对象
      */
     public UserServiecStub(UserService userService) {
         super();
         this.userService = userService;
     }
     @Override
     public List<UserAddress> getUserAddressList(String userId) {
         if (!StringUtils.isEmpty(userId)) {
             return userService.getUserAddressList(userId);
         }
         return null;
     }
 }

Consumer

 <dubbo:reference id="userService" interface="service.UserService" retries="3" check="true" version="*"
                  stub="service.impl.UserServiecStub">
     <!--<dubbo:method name="getUserAddressList" timeout="3000" retries="3"></dubbo:method>-->
 </dubbo:reference>

整体整合SpringBoot

适用注解API的方法 ​ Provider

 package org.ph.userserviceprovider.config;
 ​
 import com.alibaba.dubbo.config.*;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import service.UserService;
 import java.util.ArrayList;
 import java.util.List;
 ​
 /**
  * @author 李鹏辉Code
  * @create 2020 -11 -25 21:11
  */
 @Configuration
 public class ProviderConfig {
 ​
     /**
      * 当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签
      * <dubbo:application name="provider" owner="lph">
      * <dubbo:parameter key="qos.enable" value="true"/>
      * <dubbo:parameter key="qos.accept.foreign.ip" value="false"/>
      * <dubbo:parameter key="qos.port" value="55555"/>
      * </dubbo:application>
      */
     @Bean
     public ApplicationConfig applicationConfig() {
         ApplicationConfig applicationConfig = new ApplicationConfig();
         //
         applicationConfig.setName("provider");
         return applicationConfig;
     }
 ​
     /**
      * dubbo这个服务所要暴露的服务地址所对应的注册中心
      * <!--<dubbo:registry address="N/A"/>-->
      * <dubbo:registry address="zookeeper://localhost:2181"/>
      */
     @Bean
     public RegistryConfig registryConfig() {
         RegistryConfig registryConfig = new RegistryConfig();
         registryConfig.setProtocol("zookeeper");
         registryConfig.setAddress("localhost:2181");
         return registryConfig;
     }
 ​
     /**
      * 当前服务发布所依赖的协议;webserovice、Thrift、Hessain、http
      * 使用dubbo协议在20880端口进行通信
      * <dubbo:protocol name="dubbo" port="20880"/>
      * 指定通信规则
      */
     @Bean
     public ProtocolConfig protocolConfig() {
         ProtocolConfig protocolConfig = new ProtocolConfig();
         protocolConfig.setName("dubbo");
         protocolConfig.setPort(20880);
         return protocolConfig;
     }
 ​
     /**
      * -服务发布的配置,需要暴露的服务接口 暴露完别人就能调用了
      * 此处是公共的接口
      * ref:是真正的是实现对象 此处加入bean容器
      * <dubbo:service interface="service.UserService" ref="userService1" version="1.0.0">
      * <dubbo:method name="公共接口名" timeout=""></dubbo:method>
      * </dubbo:service>
      */
     @Bean
     public ServiceConfig<UserService> serviceConfig(UserService userService) {
         ServiceConfig serviceConfig = new ServiceConfig<>();
         serviceConfig.setInterface(UserService.class);
         serviceConfig.setRef(userService);
         serviceConfig.setVersion("1.0.0");
 ​
         //设置每一个method的配置
         MethodConfig methodConfig = new MethodConfig();
         methodConfig.setName("getUserAddressList");
         methodConfig.setTimeout(3000);
 ​
         //将method的配置关联到service中
         List<MethodConfig> methodConfigs = new ArrayList<>();
         methodConfigs.add(methodConfig);
         return serviceConfig;
     }
 ​
     /**
      * 监控中心
      */
     @Bean
     public MonitorConfig monitorConfig() {
         MonitorConfig monitorConfig = new MonitorConfig();
         monitorConfig.setProtocol("register");
         return monitorConfig;
     }
 }

Consumer

 @Configuration
 public class ConsumerConfig {
 ​
     @Bean
     public ApplicationConfig applicationConfig() {
         ApplicationConfig applicationConfig = new ApplicationConfig();
         applicationConfig.setName("consumer");
         applicationConfig.setOwner("lph");
         return applicationConfig;
     }
 ​
     @Bean
     public RegistryConfig registryConfig() {
         RegistryConfig registryConfig = new RegistryConfig();
         registryConfig.setProtocol("zookeeper");
         registryConfig.setAddress("localhost:2181");
         registryConfig.setCheck(true);
         return registryConfig;
     }
 }

ZooKeeper宕机与Dubbo直连(高可用)

监控中心宕掉之后不影响使用,只是部分采样数据丢失 ​ 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询了,但不能注册新的服务 ​ 注册中心对集群,任意一台宕掉后,将自动切换到另一台 ​ 当我们的Zookeeper挂掉之后,提供和服务仍能通过本地缓存通讯 ​ 服务提供者无状态,任意一台宕机后,不影响使用, ​ 服务提供全部宕掉后,消费者应用将无法使用,并无限次重连等待服务提供者恢复

直连 Impl ​ @Reference(url = "localhost:20880")UserService userService;

Dubbo负载均衡

有四种策略:

  1. Random LoadBalance 随机,按权重设置随机概率。“在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。“

  2. RoundRobin LoadBalance 轮循,按公约后的权重设置轮循比率。“存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。

  3. LeastActive LoadBalancer 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。“使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。“

  4. ConsistentHash LoadBalancer 一致性 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"/>

Random LoadBalance

RoundRobinLoadBalance

LeastActive LoadBalance

ConsistentHashLoadBalance

我们可以使用控制台调节权重,也可以使用消费的impl某个service调节使用某种策略@Reference("")

服务降级

当服务器压力大的时候,对一些服务进行简单的处理,来释放服务器的压力 1.不发起服务直接返回为Null ​ 在控制台直接屏蔽 2.调用失败后返回空 容错 ​ 在控制台点击容错

服务容错 Hystrix 集群容错

集群容错模式 ​ 1.Failover Cluster 默认 ​ 失败自动切换,当出现失败m,重试其他服务器。通常用于读操作,但重试会带来更长延迟。可以通过"retries=2"来设置重试的次数(不含第一次) ​ 例子: ​ <dubbo: service retries="2"/> ​ 或 ​ <dubbo: reference retries="2"/> ​ 或 ​ <dubbo:referencec > ​ <dubbo:method name="xx" retries="2"/> ​ </dubbo:reerence > ​ 2.Failfast Cluster ​ 快速失败,只发起一次调用,失败立即报错,通常用于非幂等操作,比如新增操作 ​ 3.Failsafe Cluster ​ 失败安全,出现异常时,直接忽略,写入审计日志等操作, ​ 4.Failback Cluster ​ 失败自动恢复,后台j记录失败请求,定时重发,通常用于消息通知操作 ​ 5.Forking Cluster ​ 并行调用多个服务器,只要有一个成功立即返回,通常用于实时性要求高的读操作,但是要浪费更多二点服务资源,可通过 forks=”2“l来设置最大并行数 ​ 6.Broadcast Cluster ​ 广播调用所有提供者,整个调用,任意一台报错则报错通常长用于通知所有提供者更新缓存或日志等本地资源信息,适用同步 ​ 集群配置模式 ​ <dubbo:service cluster="failsafe"/> ​ 或 ​ <dubbo:reference cluster="failsafe"/> 使用: ​ 导入依赖: 提供方

 <spring-boot.version>2.3.2.RELEASE</spring-boot.version>
 <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
             <version>2.2.2.RELEASE</version>
    </dependency>

被调用额方法:@HystrixCommand ​ 启动类加上@EnableHystrix

报错怎么办? ​ Consumer

 <spring-boot.version>2.3.2.RELEASE</spring-boot.version>
 <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
             <version>2.2.2.RELEASE</version>
    </dependency>
 @Service
 public class OrderServiceImpl implements OrderService {
 ​
 ​
     @Reference(loadbalance = "random")
     UserService userService;
 ​
     @HystrixCommand(fallbackMethod = "error")
     @Override
     public List<UserAddress> initOrder(String userId) {
         //1.查询用户的收货地址
         System.out.println("userId = " + userId);
         List<UserAddress> userAddressList = userService.getUserAddressList(userId);
         return userAddressList;
     }
     //失败才会调用的方法
     public List<UserAddress> error(String userId) {
         return Arrays.asList(new UserAddress(1, "出错", "出错", "出错", "出错", "出错"));
     }
 }
 ​

Dubbo原理

Dubbo是RPC框架,所以也会遵循RPC框架的原理执行流程 ​

RPC 一次完整的PRC框架的调用过程,(同步调用) client stub相当于客户端的代理 ​ 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框架就是将2-8这些步骤封装起来。对于用户来说是看不见的

Netty通信原理

Dubbo两个服务器通信使用的就是netty ​ BIO(阻塞IO) ​ 一个线程执行一个请求

NIO ​ 是基于通道