Dubbo学习笔记

Dubbo

Dubbo学习内容

​ Dubbo发展背景

​ Dubbo概述

​ RPC

​ Zookeeper、Dubbo控制台的安装

​ Dubbo入门例子

​ Dubbo详细讲解

​ Dubbo整合spring mvc

​ Dubbo整合springboot


Dubbo发音:|ˈdʌbəʊ|

Dubbo官方网站:http://dubbo.apache.org/

Dubbo是阿里巴巴开发的,已经贡献给Apache,并且已经成Apache的顶级开源项目

1. Dubbo的发展背景

​ 文档:http://dubbo.apache.org/zh-cn/docs/user/preface/background.html

​ 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。

在这里插入图片描述

1.1 单一应用架构

​ 当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。

​ 此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。

​ 使用一个web容器(如tomcat),然后使用Servlet/JSP技术,最后选择一个合适数据库管理系统来存储数据(MySQL、Oracle)。

1.2 垂直应用架构

​ 当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,提升效率的方法之一是将应用拆成互不相干的几个应用,以提升效率。

​ 此时,用于加速前端页面开发的Web框架(MVC)是关键。

​ 用户系统、权限系统、商品系统、订单系统、物流系统…

特点:系统独立部署,每一个系统都有完整的前后端;

问题:各个系统无法做到完全独立,公共模块无法复用,系统之间通信比较麻烦;

1.3 分布式服务架构

​ 当垂直应用越来越多,应用之间交互不可避免,这时将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。

​ 此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。

分布式架构的难点

  1. 各个系统如何进行远程调用
  2. 如何进行业务拆分

1.4 流动计算架构

​ 当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。

2. RPC

​ RPC(Remote Procedure Call)- 远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层的网络技术协议。RPC假定某种传输协议的存在(如TCP),为通信程序携带数据;

​ 通俗的说,RPC可以让我们像调用本地方法一样调用远程计算机提供的服务;

2.1 RPC的简单原理

在这里插入图片描述

1. 客户端以本地调用的方式调用远程服务
2. client stub接收到调用后,将方法、参数等组装成能够进行网络传输的消息;
3. client stub查找服务地址,找到之后,将消息发送到服务端;
4. server stub收到消息之后,对收到的消息进行解码;
5. server stub根据解码结果,使用反射的方式调用本地服务;
6. 服务端执行完成之后将结果返回给Server stub;
7. server stub将返回结果打包成消息并发送给客户端;
8. client stub收到消息后,对结果进行解码;

总结: 实现RPC的三个技术点

  • 服务寻址
  • 网络连接
  • 数据的序列化

3. Dubbo

3.1 Dubbo是什么

​ Apache Dubbo™ 是一款高性能Java RPC框架

​ Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用智能容错和负载均衡,以及服务自动注册和发现

3.2 Dubbo作者

在这里插入图片描述

​ 从左至右:刘超,梁飞,闾刚,陈雷,刘昊旻,李鼎

3.3 Dubbo的发展历程

​ 2008年阿里内部开始使用;
​ 2009年初,发布1.0版本;
​ 2010年初,发布2.0版本;
​ 2011年10月27日,阿里将Dubbo开源,版本号为2.0.7;
​ 2012年3月,发布2.1.0版本;
​ 2014年10月,发布2.3.11版本,之后版本停滞;
​ 2017年9月,阿里重启维护,重点升级了依赖的JDK版本,发布2.5.4/2.5.5版本;
​ 2017年10月,发布2.5.6版本;
​ 2017年11月,发布2.5.7版本,后期集成了SpringBoot;
​ 2014年10月的时候,当当网Fork了Dubbo源代码,在此基础上增加了HTTP REST协议,发布版本号2.8.0,名字叫DubboX;
​ 网易考拉在Dubbo基础上开发了DubboK;

3.4 Dubbo架构

  1. 架构中的角色

    Provider:服务提供者
    Consumer:服务消费者
    Registry:服务注册和发现的中心
    Monitor:监控中心,用于统计服务调用情况
    Container:Dubbo容器

在这里插入图片描述

  1. 调用关系

    0、容器负责启动、加载、运行服务提供者、消费者;

    1、服务提供者在启动时,向注册中心注册自己提供的服务;

    2、服务消费者在启动时,向注册中心订阅自己需要的服务;

    3、注册中心返回服务提供者的地址列表给消费者;

    ​ 如果有服务变更(服务的上线或下线),注册中心会基于长连接的方式推送变更给消费者;

    4、服务消费者从地址列表中,基于软件负载均衡算法,选择一个服务提供者进行调用,如果调用失败,可以重试其它提供者;

    5、服务消费者和提供者,在内存中累计调用时间和调用次数,每分钟向监控中心发送一次统计数据;

4. 安装单机Zookeeper

4.1 windows版本

  1. 解压zookeeper-3.4.12.tar.gz到当前目录

  2. 在zookeeper-3.4.12目录下创建data目录

在这里插入图片描述

  1. zookeeper-3.4.12/conf目录下的zoo_sample.cfg文件重命名为zoo.cfg

在这里插入图片描述

  1. 修改zoo.cfg文件中的dataDir选项

在这里插入图片描述

  1. 启动zookeeper服务端

    双击zookeeper-3.4.12/bin/zkServer.cmd

  2. 启动zookeeper的客户端

    双击zookeeper-3.4.12/bin/zkCli.cmd

4.2 Linux安装

  1. 将zookeeper-3.4.12.tar.gz上传到centos的/opt目录下

  2. 解压zookeeper-3.4.12.tar.gz到当前文件夹下(即/opt)

    tar -zxf zookeeper-3.4.12.tar.gz -C /opt
    
  3. 进入zookeeper-3.4.12,创建一个data目录

    cd zookeeper-3.4.12
    mkdir data
    
  4. 进入zookeeper-3.4.12/conf目录,将zoo_sample.cfg修改zoo.cfg

    cd conf
    mv zoo_sample.cfg zoo.cfg
    
  5. 编辑zoo.cfg文件

    # 将dataDir修改为../data
    dataDir=../data
    
  6. 启动ZK server

    cd bin
    ./zkServer.sh start
    
  7. 启动ZK客户端

    ./zkCli.sh
    

5. Dubbo控制台安装

  1. Dubbo主要用于服务治理

  2. 可以通过控制台查看所有服务(提供者、消费者)

  3. 可以设置负载均衡、权重调节、服务降级策略等

​ Dubbo控制台默认访问地址:http://localhost:7001

​ Dubbo默认的用户名/密码:root/root

​ 在dubbo-admin.jar所在目录执行 java -jar dubbo-admin.jar即可(命令行执行)

在这里插入图片描述

6. Dubbo入门工程 - Hello World

  1. maven依赖

     <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>dubbo</artifactId>
         <version>2.6.5</version>
     </dependency>
     <dependency>
         <groupId>org.apache.curator</groupId>
         <artifactId>curator-framework</artifactId>
         <version>2.13.0</version>
     </dependency>
    
  2. 工程搭建 - maven聚合工程

    dubbo-hello
    dubbo-hello-interface
    dubbo-hello-provider
    dubbo-hello-consumer
    
  3. 步骤

    1. 在interface工程创建服务接口
    2. 在provider工程实现接口
    3. 在provider工程发布服务
    4. 在consumer工程中引用
    5. 在consumer工程中调用远程服务

Demo

  1. 首先创建一个聚合工程
    其中consumer与provider都需要依赖interface
    在这里插入图片描述

  2. 在interface工程创建服务接口 HelloService

    public interface HelloService {
    	String hello (String name);
    }
    
  3. 在provider工程实现接口 HelloServiceImpl

    public class HelloServiceImpl implements HelloService {
          @Override
          public String hello(String name) {
              System.out.println("hello invoke!");
              return "hello" + name;
          }
      }
    
  4. 在provider工程发布服务
    provider.xml

      <?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">
      
          <!--1.应用名称-->
          <dubbo:application name="hello-service"/>
          <!--2.注册中心:把dubbo服务注册到注册中心-->
          <dubbo:registry address="zookeeper://127.0.0.1:2181" />
          <!--3.使用dubbo协议在20880端口号发布服务-->
          <dubbo:protocol name="dubbo" port="20880" />
          <!--4.暴露服务-->
          <dubbo:service ref="helloService"  interface="com.service.HelloService">
          </dubbo:service>
          <!--5.配置服务实现-->
          <bean id="helloService" class="com.service.impl.HelloServiceImpl" />
      </beans>
    

ProviderTest

public class ProviderTest {
    public static void main(String[] args) throws IOException {
        new ClassPathXmlApplicationContext("provider.xml");
        System.in.read();
    }
}
  1. 在consumer工程中引用
    consumer.xml
<?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">

 <!--1.应用名称-->
 <dubbo:application name="hello-consumer"/>
 <!--2.配置注册中心-->
 <dubbo:registry address="zookeeper://127.0.0.1:2181"  />
 <!--3.引用服务-->
 <!--创建了HelloService的代理对象 并注册成BEAN-->
 <dubbo:reference id="helloService" interface="com.etoak.service.HelloService">
 </dubbo:reference>

</beans>
  1. 在consumer工程中调用远程服务
    ConsumerTest
  public class ConsumerTest {
   public static void main(String[] args) throws IOException {
       ApplicationContext ioc = new ClassPathXmlApplicationContext("consumer.xml");
       //获取远程服务HelloService的代理对象
       HelloService helloService = ioc.getBean(HelloService.class);
       //调用远程服务
       String result = helloService.hello("Dubbo");
       System.out.println(result);

       System.in.read();
   }
}

7. Dubbo详解

7.1 Dubbo的注册中心有哪些

1、Multicast注册中心

​ Multicast注册中心不需要启动任何中心节点,只要广播地址一样,就可以互相发现。

2、Zookeeper注册中心

Zookeeper 是 Apache Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用。

3、Redis注册中心

4、Simple 注册中心

5、Nacos注册中心

推荐使用 zookeeper注册中心

7.2 Dubbo支持的协议

dubbo、rmi、hessian、http、webservice、rest、thrift、memcached、redis、grpc

推荐使用 Dubbo 协议

7.3 Dubbo服务在ZK中的存储结构

在这里插入图片描述

7.4 启动时检查

​ Dubbo默认情况下会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 check="true"

7.4.1 关闭单个服务的启动检查 - 消费方

​ 可以通过<dubbo:reference check="false"> 关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动;

<dubbo:reference id="helloService" check="false"
  interface="com.etoak.service.HelloService">
</dubbo:reference>

7.4.2 关闭所有服务的启动检查 - 消费方

<dubbo:consumer check="false" />

7.4.1 关闭注册中的启动检查 - 消费方和提供方

<dubbo:registry address="zookeeper://127.0.0.1:2181" 
                check="false" />

7.5 配置加载流程

文档地址

​ 此篇文档主要讲在应用启动阶段,Dubbo框架如何将所需要的配置采集起来(包括应用配置、注册中心配置、服务配置等),以完成服务的暴露和引用流程。

7.5.1 配置来源

  • JVM System Properties,-D参数

  • Externalized Configuration,外部化配置

  • ServiceConfig、ReferenceConfig等编程接口采集的配置、spring配置

  • 本地配置文件dubbo.properties(写在src/main/resources)

    配置在classpath根目录

7.5.2 配置流程

配置加载的优先级

jvm参数 > 外部化配置 > 编程接口、spring配置 > dubbo.properties

Idea中配置jvm参数

在这里插入图片描述

7.6 XML配置 - 不同粒度配置的覆盖关系

  • 方法级优先,接口级次之,全局配置再次之。
  • 如果级别一样,则消费方优先,提供方次之。
  1. 配置级别

    方法级:<dubbo:method>

    接口级:<dubbo:service><dubbo:reference>

    全局级:<dubbo:provider><dubbo:consumer>

  2. 配置优先级

在这里插入图片描述

7.7 直连提供者

​ 在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连;点对点直连方式,以服务接口为单位,忽略注册中心的提供者列表,A 接口配置点对点,不影响 B 接口从注册中心获取列表。

<dubbo:reference id="helloService"
                 url="dubbo://127.0.0.1:20880"
                 interface="com.etoak.service.HelloService">
  <dubbo:method name="hello" />
</dubbo:reference>

7.8 本地存根

​ 提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等。

实现步骤

  1. 在服务接口旁边写一个名字为接口名Stub的服务实现类

  2. 在这个实现类中添加一个有参的构造方法,构造方法参数就是这个服务接口的代理(也就是可以直接写这个服务接口)

  3. 配置服务

    <!--这种方式的配置需要命名十分规范 会去找相同文件夹下的serviceNameStub
    	 即:com.etoak.service.HelloServiceStub-->
    <dubbo:service interface="com.service.HelloService"
    stub="true" />
    
    <!-- 直接指定stub方式 -->
    <dubbo:service interface="com.service.HelloService"
    stub="com.etoak.service.HelloServiceStub" />
    
  4. Demo

        /**
      * 这个代码是由提供者边写  消费者执行
      */
     public class HelloServiceStub implements HelloService{
     
         HelloService helloService;
         //构造方法参数:是真正的远程代理对象
         public HelloServiceStub(HelloService helloService){
             this.helloService = helloService;
         }
         @Override
         public String hello(String name) {
             System.out.println("这行代码在客户端(消费方)执行");
             //如果name不为空
             if(name != null && ! "".equals(name)){
                 //发起远程调用
                 return helloService.hello(name);
             }
             //如果为空 则不发起远程调用
             return "参数异常";
         }
     }
    

7.9 服务分组

​ 当一个接口有多种实现时,可以用 group 区分。

  1. 提供方配置

    <dubbo:service ref="helloService"
                   group="service"
                   interface="com.etoak.service.HelloService">
      <dubbo:method name="hello" timeout="4000" />
    </dubbo:service>
    <bean id="helloService"
          class="com.etoak.service.impl.HelloServiceImpl" />
    
    
    <dubbo:service ref="helloService2" 
                   group="service2"
                   interface="com.etoak.service.HelloService">
    </dubbo:service>
    <bean id="helloService2" 
          class="com.etoak.service.impl.HelloService2" />
    
    
  2. 消费方配置

    <dubbo:reference id="helloService"
                group="service2"
    				interface="com.etoak.service.HelloService">
      <dubbo:method name="hello" />
    </dubbo:reference>
    

7.10 服务的多版本

​ 当一个接口实现出现不兼容需要升级时,可以用版本号过渡,版本号不同的服务相互间不引用。

可以按照以下的步骤进行版本迁移:

  1. 在低压力时间段,先升级一半提供者为新版本
  2. 再将所有消费者升级为新版本
  3. 然后将剩下的一半提供者升级为新版本

服务端配置方式

<dubbo:service ref="helloService" stub="true"
               timeout="6000" retries="5"
               version="1.0"
               interface="com.etoak.service.HelloService">
</dubbo:service>

消费端配置

<dubbo:reference id="helloService"
                 timeout="5500"
                 version="2.0"
                 interface="com.etoak.service.HelloService">
</dubbo:reference>

7.11 负载均衡

​ Dubbo 提供了多种均衡策略,缺省为 random 随机调用。

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

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

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

4. ConsistentHash LoadBalance
一致性 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” />

控制台配置

在这里插入图片描述

7.12 服务降级

​ 可以通过服务降级功能临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。

  • mock=force:return+null 表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
  • 还可以改为 mock=fail:return+null 表示消费方对该服务的方法调用失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。

8. Dubbo整合springboot

​ 用户服务 - 根据id查询用户信息

  1. 创建工程

    dubbo-boot
    dubbo-boot-bean        java bean
    dubbo-boot-interface   服务接口
    dubbo-boot-mapper      mapper接口 + sql
    dubbo-boot-provider  服务实现  springboot
    dubbo-boot-consumer      消费者    springboot
    

    在这里插入图片描述

  2. 编写步骤

    1. 在bean工程创建User,要实现序列化接口

    2. 在mapper工程中创建UserMapper接口、sql

    3. 在interface工程定义服务接口UserService

    4. 在provider工程编写服务实现

      整合mybatis、dubbo

    5. 在consumer工程引用UserService服务

      整合dubbo

    6. 启动springboot测试

      先启动注册中心

      再启动服务提供者

      再启动消费者

Demo

在bean创建User实现序列化接口

@Data
public class User implements Serializable {
    private Integer id;
    private String name;
    private Integer age;
    private String email;
}

mapper中创建UserMapper接口&xml

public interface UserMapper {
    User getById(int id);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mapper.UserMapper">
    <select id="getById" parameterType="int" resultType="user">
        Select id,name,age,email from sys_user where id =#{value}
    </select>
</mapper>

在interface工程定义服务接口UserService

public interface UserService {
    User getById(int id);
}

在provider工程编写服务实现&配置&启动类

//com.alibaba 的 service
@Service(timeout = 6000 ,retries = 3)
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper usermapper;

    @Override
    public User getById(int id) {
        User user = usermapper.getById(id);
        return user;
    }
}

配置文件application.yml

server:
  port: 9090
#数据源
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1/et2004?serverTimezone=UTC
    username: root
    password: etoak
#mybatis
mybatis:
  type-aliases-package: com.etoak.bean
  mapper-locations: classpath:mappers/*.xml
#pageHelper
pagehelper:
  reasonable: true
#dubbo
dubbo:
  application:
    name: user-service
  registry:
    address: zookeeper://127.0.0.1:2181
  protocol:
    name: dubbo
    port: 20880

启动类UserApp

@SpringBootApplication
@EnableDubbo
@MapperScan(basePackages = "com.etoak.mapper")
public class UserApp {
    public static void main(String[] args) {
        SpringApplication.run(UserApp.class,args);
    }
}

在consumer工程引用UserService服务整合dubbo

@SpringBootApplication
@EnableDubbo
@RestController
public class ConsumerApp {
    @Reference
    UserService userService;
    @GetMapping("/user/{id}")
    public User getUser(@PathVariable int id){
        User byId = userService.getById(id);
        return byId;
    }
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

application.yml

server:
  port: 8080

dubbo:
  application:
    name: user-consumer
  registry:
    address: zookeeper://127.0.0.1:2181
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页