SpringCloud+Dubbo+Nacos整合实现RPC调用

Dubbo很多人都不陌生,这毕竟是一款从2012年就开始开源的Java RPC框架,中间由于各种各样的原因停止更新4年半的时间,中间只发过一个小版本修了一个小bug,甚至大家都以为这个项目已经死掉了,竟然又在2017年9月份恢复了更新。
网络上很多人都拿Dubbo和Spring Cloud做对比,可能在大家的心目中,这两个框架是可以画上等号的吧。后来在网络上有一个非常流行的表格,比较详细的对比了 Spring Cloud 和 Dubbo,表格如下:
  Dubbo SpringCloud
服务注册中心 Zookeeper Spring Cloud Netfix Eureka
服务调用方式 RPC REST API
服务监控 Dubbo-monitor Spring Boot Admin
熔断器 不完善 Spring Cloud Netflix Hystrix
服务网关 Spring Cloud Netflix Zuul
分布式配置 Spring Cloud Config
服务跟踪 Spring Cloud Sleuth
数据流 Spring Cloud Stream
批量任务 Spring Cloud Task
信息总线 Spring Cloud Bus
以上列举了一些核心部件,当然这里需要申明一点,Dubbo对于上表中总结为“无”的组件不代表不能实现,而只是Dubbo框架自身不提供,需要另外整合以实现对应的功能,这样看起来确实Dubbo更像是Spring Cloud的一个子集。
Dubbo在国内拥有着巨大的用户群,大家希望在使用Dubbo的同时享受Spring Cloud的生态,出现各种各样的整合方案,但是因为服务中心的不同,各种整合方案并不是那么自然,直到Spring Cloud Alibaba这个项目出现,由官方提供了Nacos服务注册中心后,才将这个问题完美的解决。并且提供了Dubbo和Spring Cloud整合的方案,命名为:Dubbo Spring Cloud。
 
Dubbo Spring Cloud概述
Dubbo Spring Cloud构建在原生的Spring Cloud之上,其服务治理方面的能力可认为是Spring Cloud Plus,不仅完全覆盖Spring Cloud 原生特性,而且提供更为稳定和成熟的实现,特性比对如下表所示:
功能组件Spring CloudDubbo Spring Cloud
分布式配置(Distributed configuration) Git、Zookeeper、Consul、JDBC Spring Cloud 分布式配置 + Dubbo 配置中心
服务注册与发现(Service registration and discovery) Eureka、Zookeeper、Consul Spring Cloud 原生注册中心 + Dubbo 原生注册中心
负载均衡(Load balancing) Ribbon(随机、轮询等算法) Dubbo 内建实现(随机、轮询等算法 + 权重等特性)
服务熔断(Circuit Breakers) Spring Cloud Hystrix Spring Cloud Hystrix + Alibaba Sentinel 等
服务调用(Service-to-service calls) Open Feign、RestTemplate Spring Cloud 服务调用 + Dubbo @Reference
链路跟踪(Tracing) Spring Cloud Sleuth + Zipkin Zipkin、opentracing 等
以上对比表格摘自Dubbo Spring Cloud官方文档。
而且Dubbo Spring Cloud基于Dubbo Spring Boot 2.7.1 和 Spring Cloud 2.x开发,无论开发人员是Dubbo用户还是Spring Cloud用户, 都能轻松地驾驭,并以接近“零”成本的代价使应用向上迁移。Dubbo Spring Cloud致力于简化云原生开发成本,以达成提高研发效能以及提升应用性能等目的。
 
Dubbo Spring Cloud 主要特性
(1)面向接口代理的高性能RPC调用:提供高性能的基于代理的远程调用能力,服务以接口为粒度,屏蔽了远程调用底层细节。
(2)智能负载均衡:内置多种负载均衡策略,智能感知下游节点健康状况,显著减少调用延迟,提高系统吞吐量。
(3)服务自动注册与发现:支持多种注册中心服务,服务实例上下线实时感知。
(4)高度可扩展能力:遵循微内核+插件的设计原则,所有核心能力如Protocol、Transport、Serialization被设计为扩展点,平等对待内置实现和第三方实现。
(5)运行期流量调度:内置条件、脚本等路由策略,通过配置不同的路由规则,轻松实现灰度发布,同机房优先等功能。
(6)可视化的服务治理与运维:提供丰富服务治理、运维工具:随时查询服务元数据、服务健康状态及调用统计,实时下发路由策略、调整配置参数。
 
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+Nacos+Dubbo整合实战
下面将会以一个简单的入门案例,介绍一下在使用Nacos作为服务中心,使用Dubbo来实现服务提供方和服务消费方的案例。
(1)服务端接口契约定义
创建普通Maven项目dubbo-sample-api,定义服务端与消费端的接口契约。该项目仅是用于定义Dubbo服务端与消费端的接口契约。这里创建仅为更好的代码重用以及接口、模型规格控制管理。然后打包成jar包,安装到私有仓库,供客户端与Dubbo服务端接口实现的项目来依赖使用。

pom.xml不用引用任何包。

定义服务端接口类IHelloService:
package com.zxy.dubbo_sample_api;
 
public interface IHelloService {
    String sayHello(String name);
}

然后执行mvn install,将dubbo-sample-api添加到本地仓库,供其他项目依赖。

(2)服务端服务实现
创建一个SpringBoot项目dubbo-sample-provider。该项目实现上面定义好的接口,并该项目作为服务注册到服务注册中心,这里采用nacos,也可以采用ZooKeeper,而且dubbo还可以支持多注册中心。
工程依赖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.zxy</groupId>
    <artifactId>dubbo-sample-provider</artifactId>
    <version>1.0</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.7.RELEASE</version>
        <relativePath/>
    </parent>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR10</spring-cloud.version>
        <spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <!-- spring-cloud -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- spring-cloud-alibaba -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
 
    <dependencies>
        <!-- spring boot -->
        <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.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- Nacos Discovery -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- Dubbo -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>
        <!-- 健康监控,必须包含spring-boot-starter-actuator包,不然启动会报错 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- 需要实现的服务接口包 -->
        <dependency>
            <groupId>com.zxy</groupId>
            <artifactId>dubbo-sample-api</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>
</project>

注意:必须包含spring-boot-starter-actuator包,不然启动会报错。pom中引入定义服务契约接口的API模块的包。

实现Dubbo接口IHelloService,新建HelloServiceImpl类,代码如下:
package com.zxy.dubbo_sample_provider.service;
import com.zxy.dubbo_sample_api.IHelloService;
import org.apache.dubbo.config.annotation.DubboService;
 
@DubboService
public class HelloServiceImpl implements IHelloService {
    public String sayHello(String name){
        return "Hello World:"+ name;
    }
}

注意:这里的@DubboService注解是Dubbo的org.apache.dubbo.config.annotation.DubboService,千万不要引用错误。@DubboService注解仅声明该Java服务(本地)实现为Dubbo服务。旧版本的dubbo使用该包下的@Service直接,后来为了防止与spring混淆改为了@DubboService。

配置文件application.properties,将Java服务(本地)配置为Dubbo服务(远程)如下:
#Spring应用名称,用于SpringCloud服务注册和发现。该值在Dubbo Spring Cloud加持下被视作dubbo.application.name,因此,无需再显示地配置dubbo.application.name。
spring.application.name=dubbo-sample-provider
server.port=3001
 
#Dubbo服务实现类的扫描基准包路径
dubbo.scan.base-packages=com.zxy.dubbo_sample_provider.service
#Dubbo服务暴露的协议配置,其中子属性name为协议名称,port为协议端口(-1 表示自增端口,从 20880 开始)
#因为项目中存在多个服务提供端比如商品服务、会员服务等,这里为了方便设置为了-1
dubbo.protocol.name=dubbo
dubbo.protocol.port=-1
#Dubbo服务注册中心的配置地址,它的值spring-cloud://localhost表示挂载到Spring Cloud注册中心,不配置的话会提示没有配置注册中心的错误。
dubbo.registry.address=spring-cloud://localhost
 
#nacos
#spring.cloud.nacos.discovery定义Nacos服务发现与注册配置,其中子属性server-addr指定Nacos服务器主机和端口。
spring.cloud.nacos.discovery.server-addr=localhost:8848

注意:在暴露Dubbo服务方面,推荐使用外部化配置的方式,即指定Java服务实现类的扫描基准包。

Dubbo Spring Cloud 继承了 Dubbo Spring Boot 的外部化配置特性,也可以通过标注@DubboComponentScan来实现基准包扫描。
创建应用主类,即项目入口DubboSampleProviderApplication.java文件。如果使用SpringBoot自动创建项目该文件是自动创建的不用做任何修改。
package com.zxy.dubbo_sample_provider;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@SpringBootApplication
public class DubboSampleProviderApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(DubboSampleProviderApplication.class, args);
    }
 
}

运行dubbo-sample-provider项目,将会在Nacos中注册服务。(注意:在运行项目前,先安装并启动Nacos服务端)

 

 

 

 (3)消费端(客户端)实现

创建一个SpringBoot项目dubbo-consumer,实现调用以上的服务。
工程依赖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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.zxy</groupId>
    <artifactId>dubbo-consumer</artifactId>
    <version>1.0</version>
 
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.7.RELEASE</version>
        <relativePath/>
    </parent>
 
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR10</spring-cloud.version>
        <spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>
    </properties>
 
    <dependencyManagement>
        <dependencies>
            <!-- spring-cloud -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- spring-cloud-alibaba -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
 
    <dependencies>
        <!-- spring boot -->
        <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.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- web项目 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Nacos Discovery -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- Dubbo -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>
        <!-- 健康监控,必须包含spring-boot-starter-actuator包,不然启动会报错 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
 
        <!-- dubbo服务接口契约包 -->
        <dependency>
            <groupId>com.zxy</groupId>
            <artifactId>dubbo-sample-api</artifactId>
            <version>1.0</version>
        </dependency>
 
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

注意:pom中一定要引入定义服务契约接口的API模块的包dubbo-sample-api。

工程配置application.properties:
#服务名称
spring.application.name=dubbo-consumer
server.port=4001
 
#表示要订阅服务的服务名,可以配置'*'代表订阅所有服务(不推荐使用)。若需订阅多应用,使用","分割。
dubbo.cloud.subscribed-services=dubbo-sample-provider
 
#nacos
spring.cloud.nacos.discovery.server-addr=localhost:8848
#禁止该服务注册到Nacos服务列表中
spring.cloud.nacos.discovery.register-enabled=false

实现服务调用,新建HelloController.java类:

package com.zxy.dubbo_consumer.control;
 
import com.zxy.dubbo_sample_api.IHelloService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
public class HelloController {
 
    @DubboReference
    private IHelloService helloService;
 
    @GetMapping("/say")
    public String sayHello(){
        return helloService.sayHello("Lily");
    }
}

注意:这里的@DubboReference注解是Dubbo的org.apache.dubbo.config.annotation.DubboReference,千万不要引用错误。

手写过RPC框架的同学,应该都知道,客户端通过服务端的接口契约可以调用服务端的接口,其实是采用动态代理的方式,dubbo中默认采用javasist,大家不妨debug一下。@DubboReference作用就是将动态代理注入进来。
创建应用主类,即项目入口DubboConsumerApplication.java文件。如果使用SpringBoot自动创建项目该文件是自动创建的不用做任何修改。
package com.zxy.dubbo_consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DubboConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(DubboConsumerApplication.class, args);
    }
}

(4)测试:

启动Nacoe、启动服务提供项目dubbo-sample-provider、服务消费项目dubbo-consumer、确保接口契约项目已经添加到maven本地仓库中。启动完成后,我们可以访问Nacos控制台的服务列表上已经注册的以上服务。具体参照之前的步骤。
我们打开浏览器访问:http://localhost:4001/say,可以看到页面正常显示Hello World:Lily!表示测试成功。

 

 

 
posted @ 2021-05-18 16:59  悬铃木pp  阅读(7132)  评论(0编辑  收藏  举报