zoukankan      html  css  js  c++  java
  • SpringCloud Alibaba (四):Dubbo RPC框架

    Dubbo简介

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

    节点角色说明
    Provider 暴露服务的服务提供方
    Consumer 调用远程服务的服务消费方
    Registry 服务注册与发现的注册中心
    Monitor 统计服务的调用次数和调用时间的监控中心
    Container 服务运行容器

    功能特点:

    • 面向接口代理的高性能RPC调用

      提供高性能的基于代理的远程调用能力,服务以接口为粒度,为开发者屏蔽远程调用底层细节。

    • 智能负载均衡

      内置多种负载均衡策略,智能感知下游节点健康状况,显著减少调用延迟,提高系统吞吐量。

    • 服务自动注册与发现

      支持多种注册中心服务,服务实例上下线实时感知。

    • 高度可扩展能力

      遵循微内核+插件的设计原则,所有核心能力如Protocol、Transport、Serialization被设计为扩展点,平等对待内置实现和第三方实现。

    • 运行期流量调度

      内置条件、脚本等路由策略,通过配置不同的路由规则,轻松实现灰度发布,同机房优先等功能。

    • 可视化的服务治理与运维

      提供丰富服务治理、运维工具:随时查询服务元数据、服务健康状态及调用统计,实时下发路由策略、调整配置参数。

    Spring Cloud 为什么需要RPC

    在Spring Cloud构建的微服务系统中,大多数的开发者使用都是官方提供的Feign组件来进行内部服务通信,这种声明式的HTTP客户端使用起来非常的简洁、方便、优雅,但是有一点,在使用Feign消费服务的时候,相比较Dubbo这种RPC框架而言,性能堪忧。

    虽说在微服务架构中,会讲按照业务划分的微服务独立部署,并且运行在各自的进程中。微服务之间的通信更加倾向于使用HTTP这种简答的通信机制,大多数情况都会使用REST API。这种通信方式非常的简洁高效,并且和开发平台、语言无关,但是通常情况下,HTTP并不会开启KeepAlive功能,即当前连接为短连接,短连接的缺点是每次请求都需要建立TCP连接,这使得其效率变的相当低下。

    对外部提供REST API服务是一件非常好的事情,但是如果内部调用也是使用HTTP调用方式,就会显得显得性能低下,Spring Cloud默认使用的Feign组件进行内部服务调用就是使用的HTTP协议进行调用,这时,我们如果内部服务使用RPC调用,对外使用REST API,将会是一个非常不错的选择,恰巧,Dubbo Spring Cloud给了我们这种选择的实现方式。

     

    SpringCloud Alibaba 整合 Dubbo

    创建ApacheDubbo总工程, 在pom.xml添加统一依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion><groupId>com.gofy</groupId>
        <artifactId>ApacheDubbo</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>pom</packaging><parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.8.RELEASE</version>
        </parent><modules>
            <module>dubbo-provider</module>
            <module>dubbo-consumer</module>
        </modules><properties>
            <!-- Environment Settings -->
            <java.version>1.8</java.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
            <spring-cloud-alibaba.version>0.2.1.RELEASE</spring-cloud-alibaba.version>
            <dubbo.version>2.7.6</dubbo.version>
            <dubbo-spring.version>2.7.6</dubbo-spring.version>
            <dubbo-actuator.version>2.7.6</dubbo-actuator.version>
            <dubbo-kryo.version>2.7.6</dubbo-kryo.version>
            <dubbo-nacos.version>2.7.6</dubbo-nacos.version>
            <dubbo-nacos-config.version>2.1.0.RELEASE</dubbo-nacos-config.version>
            <spring-context-support.version>1.0.6</spring-context-support.version>
        </properties><dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                    <version>${spring-cloud-alibaba.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency><!-- Apache Dubbo  -->
                <dependency>
                    <groupId>org.apache.dubbo</groupId>
                    <artifactId>dubbo</artifactId>
                    <version>${dubbo.version}</version>
                    <exclusions>
                        <exclusion>
                            <groupId>org.springframework</groupId>
                            <artifactId>spring</artifactId>
                        </exclusion>
                        <exclusion>
                            <groupId>javax.servlet</groupId>
                            <artifactId>servlet-api</artifactId>
                        </exclusion>
                        <exclusion>
                            <groupId>log4j</groupId>
                            <artifactId>log4j</artifactId>
                        </exclusion>
                    </exclusions>
                </dependency>
                <dependency>
                    <groupId>org.apache.dubbo</groupId>
                    <artifactId>dubbo-spring-boot-actuator</artifactId>
                    <version>${dubbo-actuator.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.apache.dubbo</groupId>
                    <artifactId>dubbo-spring-boot-starter</artifactId>
                    <version>${dubbo-spring.version}</version>
                </dependency>
                <!-- 使用kryo序列化/反序列化工具, 提高项目性能 -->
                <dependency>
                    <groupId>org.apache.dubbo</groupId>
                    <artifactId>dubbo-serialization-kryo</artifactId>
                    <version>${dubbo-kryo.version}</version>
                </dependency><!-- Spring Cloud Alibaba -->
                <dependency>
                    <groupId>com.alibaba</groupId>
                    <artifactId>dubbo-registry-nacos</artifactId>
                    <version>${dubbo-nacos.version}</version>
                </dependency>
                <dependency>
                    <groupId>com.alibaba.nacos</groupId>
                    <artifactId>nacos-client</artifactId>
                    <version>1.2.1</version>
                </dependency>
                <dependency>
                    <groupId>com.alibaba.cloud</groupId>
                    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
                    <version>${dubbo-nacos-config.version}</version>
                </dependency>
                <dependency>
                    <groupId>com.alibaba.spring</groupId>
                    <artifactId>spring-context-support</artifactId>
                    <version>${spring-context-support.version}</version>
                </dependency>
            </dependencies>
        </dependencyManagement><build>
            <plugins>
                <!-- Compiler 插件, 设定 JDK 版本 -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <showWarnings>true</showWarnings>
                    </configuration>
                </plugin>
            </plugins><!-- 资源文件配置 -->
            <resources>
                <resource>
                    <directory>src/main/java</directory>
                    <excludes>
                        <exclude>**/*.java</exclude>
                    </excludes>
                </resource>
                <resource>
                    <directory>src/main/resources</directory>
                </resource>
            </resources>
        </build>
    </project>

    服务提供者

    在Dubbo RPC框架中, 服务提供者的接口类和实现类应该分开为俩个模块, 所以我们应该在服务提供者下创建两个子模块, 分别为 接口模块dubbo-provider-api实现模块dubbo-provider-service

    在总工程 ApacheDubbo下创建dubbo-provider模块, 添加服务提供者的统一依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <parent>
            <artifactId>ApacheDubbo</artifactId>
            <groupId>com.gofy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
    
        <groupId>com.gofy</groupId>
        <artifactId>dubbo-provider</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>pom</packaging>
    
        <modules>
            <module>dubbo-provider-api</module>
            <module>dubbo-provider-service</module>
        </modules>
    </project>
    • dubbo-provider下创建dubbo-provider-api子模块, 并添加依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <artifactId>dubbo-provider</artifactId>
            <groupId>com.gofy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent><groupId>com.gofy</groupId>
        <artifactId>dubbo-provider-api</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging></project>

    创建接口类 EchoService

    package com.gofy.dubbo.api;
    ​
    public interface EchoService {
        String echo(String s);
    }
    • dubbo-provider下创建dubbo-provider-service子模块, 并添加依赖

    导入接口模块失败原因: 一般是总工程的统一依赖出了问题, 可以查看本地maven仓库的中总工程导入的依赖的包有没有缺失文件. 我之前失败原因就是 spring-cloud-dependencies 包出了问题, Greenwich.SR5版本下载一直缺失文件, 改为Greenwich.SR3就好了.

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <artifactId>dubbo-provider</artifactId>
            <groupId>com.gofy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
    
        <groupId>com.gofy</groupId>
        <artifactId>dubbo-provider-service</artifactId>
        <packaging>jar</packaging>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-serialization-kryo</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>dubbo-registry-nacos</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba.nacos</groupId>
                <artifactId>nacos-client</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba.spring</groupId>
                <artifactId>spring-context-support</artifactId>
            </dependency>
    
            <!-- 导入接口模块 -->
            <dependency>
                <groupId>com.gofy</groupId>
                <artifactId>dubbo-provider-api</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <mainClass>com.gofy.dubbo.ProviderApplication</mainClass>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>

    dubbo-provider-service的application.yml里添加配置

    注:如果要在 SpringClou Alibaba+Dubbo 中使用nacos动态配置,操作与之前naocs动态配置的操作一样

    spring:
      application:
        name: dubbo-provider
      main:
        allow-bean-definition-overriding: true # 解决bean重复定义,设置为true时,后定义的bean会覆盖之前定义的相同名称的bean
    
    dubbo:
      scan:
        base-packages: com.gofy.dubbo.service # 实现类所在的包
      protocol:
        name: dubbo
        port: -1 # 端口为-1时,即是让dubbo自动分配端口
        serialization: kryo # 使用kryo序列化/反序列化工具
      registry:
        address: nacos://192.168.11.132:8848 #注册中心地址,格式为 注册中心组件名://注册中心访问地址

    创建实现类 EchoServiceImpl

    package com.gofy.dubbo.service;
    ​
    import com.gofy.dubbo.api.EchoService;
    import org.apache.dubbo.config.annotation.Service;
    import org.springframework.beans.factory.annotation.Value;
    ​
    @Service(version = "1.0.0") //服务版本号
    public class EchoServiceImpl implements EchoService {
    ​
        @Override
        public String echo(String s) {
            return "Hello Dubbo "+s;
        }
    }

    创建启动类 ProviderApplication

    @SpringBootApplication
    public class ProviderApplication {
        public static void main(String[] args) {
            SpringApplication.run(ProviderApplication.class, args);
        }
    }

    服务消费者

    在总工程 ApacheDubbo下创建服务消费者 dubbo-consumer, 并添加依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <artifactId>ApacheDubbo</artifactId>
            <groupId>com.gofy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
    
        <groupId>com.gofy</groupId>
        <artifactId>dubbo-consumer</artifactId>
        <packaging>jar</packaging>
    
        <dependencies>
            <!-- SpringBoot -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
    
            <!-- Dubbo -->
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-spring-boot-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-serialization-kryo</artifactId>
            </dependency>
            
            <!-- Spring Cloud Alibaba -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>dubbo-registry-nacos</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba.nacos</groupId>
                <artifactId>nacos-client</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba.spring</groupId>
                <artifactId>spring-context-support</artifactId>
            </dependency>
    
            <!-- 导入接口模块 -->
            <dependency>
                <groupId>com.gofy</groupId>
                <artifactId>dubbo-provider-api</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <mainClass>com.gofy.dubbo.ConsumerApplication</mainClass>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>

    dubbo-consumer的application.yml里添加配置

    server:
      port: 8080
    ​
    spring:
      application:
        name: dubbo-consumer
      main:
        allow-bean-definition-overriding: true
    ​
    dubbo:
      scan:
        base-packages: com.gofy.dubbo.controller #controller类所在包
      protocol:
        name: dubbo
        port: -1
        serialization: kryo
      registry:
        address: nacos://192.168.11.132:8848
    ​
    endpoints:
      dubbo:
        enabled: true #允许暴露dubbo分配的端点
    ​
    management:
      health: #健康检查
        dubbo:
          status:
            defaults: memory
            extras: threadpool
      endpoints: #暴露所有web端点
        web:
          exposure:
            include: "*"

    创建controller类 EchoController

    package com.gofy.dubbo.controller;
    ​
    import com.gofy.dubbo.api.EchoService;
    import org.apache.dubbo.config.annotation.Reference;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    ​
    @RestController
    public class EchoController {
    ​
        @Reference(version = "1.0.0") //通过服务的版本号注入
        EchoService echoService;
        
        @GetMapping("/echo/{s}")
        public String echo(@PathVariable("s")String s){
            return echoService.echo(s);
        }
    }

    创建启动类 ConsumerApplication

    @SpringBootApplication
    public class ConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
    }

    访问测试

    访问nacos注册中心,查看已注册服务

    访问 localhost:8080/echo/hi , 成功获取到服务提供者返回的信息

     

    Dubbo负载均衡

    当我们对内使用Dubbo的RPC通信,不再使用RestTemplate或feign的 HTTP通信时,我们要怎么使用负载均衡呢?

    在 Dubbo 中,也有负载均衡的概念和相应的实现。Dubbo 需要对服务消费者的调用请求进行分配,避免少数服务提供者负载过大。服务提供者负载过大,会导致部分请求超时。因此将负载均衡到每个服务提供者上,是非常必要的。Dubbo 提供了4种负载均衡实现,分别是基于权重随机算法的 RandomLoadBalance、基于最少活跃调用数算法的 LeastActiveLoadBalance、基于 hash 一致性的 ConsistentHashLoadBalance,以及基于加权轮询算法的 RoundRobinLoadBalance。

    源码分析

    Dubbo负载均衡的源码在 org.apache.dubbo:dubbo下的org.apache.dubbo.rpc.cluster.loadbalance

    通过源码可以发现4个负载均衡策略的实现类都继承了AbstractLoadBalance抽象类,而AbstractLoadBalance实现了LoadBalance接口。

    再来看看LoadBalance接口,可以知道duboo是通过 loadbalance属性来适配负载均衡接口的实现类,且默认值为 random权重随机。

    @SPI("random")
    public interface LoadBalance {
        @Adaptive({"loadbalance"})
        <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
    }

    所以,我们只要在@Reference注解里添加 loadbalance属性,就可以选择dubbo的负载均衡策略了

    loadbalance属性值为负载均衡实现类的 NAME属性,分别是:

    random 、roundrobin 、leastactive 、consistenthash

    @Reference(version = "1.0.0", loadbalance = "roundrobin")
    EchoService echoService;

    负载均衡策略实现类的详细源码分析,dubbo官方文档里讲解得非常好,就不多转述了



    我的个人博客站

    翻译 朗读 复制 正在查询,请稍候…… 重试 朗读 复制 复制 朗读 复制 via 谷歌翻译(国内)

    翻译 朗读 复制 正在查询,请稍候…… 重试 朗读 复制 复制 朗读 复制 via 谷歌翻译(国内)

  • 相关阅读:
    HTML5表单元素的学习
    微博账号注册
    微博三方登陆流程
    Vue发送短信逻辑
    celery异步发送短信
    celery
    celery
    jwt安装配置与原理
    图片验证
    Vue组件
  • 原文地址:https://www.cnblogs.com/gaofei200/p/13237342.html
Copyright © 2011-2022 走看看