【Spring Cloud Alibaba】Spring Cloud Alibaba 分布式服务调用实践

1. 简介

《Spring Cloud Alibaba 服务注册与发现》篇中曾提到,Spring Cloud Alibaba Nacos Discovery 能无缝整合 Spring Cloud OpenFeign。换言之,Spring Cloud Alibaba 延续了 Spring Cloud 分布式服务调用的特性。除此之外,Spring Cloud Alibaba 引入了 Dubbo Spring Cloud,扩展了分布式服务调用能力,不仅能使 Apache Dubbo 和 OpenFeign 共存,还允许 Spring Cloud 标准调用底层通过 Dubbo 支持的通讯协议传输。无论开发人员是 Dubbo 用户还是 Spring Cloud 用户,都能轻松地驾驭,并以接近“零”成本的代价使应用向上迁移。Dubbo Spring Cloud 致力于简化 Cloud Native 开发成本,提高研发效能以及提升应用性能等目的。

2. 学习目标

  • 使用 Dubbo Spring Cloud 实现 Spring Cloud 分布式服务调用
  • 使用 Dubbo Spring Cloud 替换 Spring Cloud 分布式服务调用底层协议
  • 理解 Dubbo Spring Cloud 高级特性:服务订阅、元数据、Actuator

3. 详细内容

  • 快速上手:使用 Apache Dubbo
  • 适配整合:使用注解 @DubboTransported 适配 Spring Cloud OpenFeign 和 @LoadBalanced RestTemplate
  • 运维特性:演示服务订阅、元信息(服务、REST)以及 Actuator Endpoints

4. 功能特性介绍

由于 Dubbo Spring Cloud 构建在原生的 Spring Cloud 之上,其服务治理方面的能力可认为是 Spring Cloud Plus,不仅完全覆盖 Spring Cloud 原生特性,而且提供更为稳定和成熟的实现,特性比对如下表所示:

功能组件Spring CloudDubbo Spring Cloud
分布式配置(Distributed configuration)Git、Zookeeper、Consul、JDBCSpring Cloud 分布式配置 + Dubbo 配置中心
服务注册与发现(Service registration and discovery)Eureka、Zookeeper、ConsulSpring Cloud 原生注册中心+ Dubbo 原生注册中心
负载均衡(Load balancing)Ribbon(随机、轮询等算法)Dubbo 内建实现(随机、轮询等算法 + 权重等特性)
服务熔断(Circuit Breakers)Spring Cloud HystrixSpring Cloud Hystrix + Alibaba Sentinel17 等
服务调用(Service-to-service calls)Open Feign、RestTemplateSpring Cloud 服务调用 + Dubbo@Reference
链路跟踪(Tracing)Spring Cloud Sleuth+ ZipkinZipkin、opentracing 等

4.1 高亮特性

4.1.1 Dubbo 使用 Spring Cloud 服务注册与发现

Dubbo Spring Cloud 基于 Spring Cloud Commons 抽象实现 Dubbo 服务注册与发现,无需添加任何外部化配置,就能轻松地桥接到所有原生 Spring Cloud 注册中心,包括:

  • Nacos
  • Eureka
  • Zookeeper
  • Consul

注:Dubbo Spring Cloud 将在下个版本支持 Spring Cloud 注册中心与 Dubbo 注册中心并存,提供双注册机制,实现无缝迁移。

4.1.2 Dubbo 作为 Spring Cloud 服务调用

默认情况,Spring Cloud Open Feign 以及@LoadBalanced``RestTemplate作为 Spring Cloud 的两种服务调用方式。Dubbo Spring Cloud 为其提供了第三种选择,即 Dubbo 服务将作为 Spring Cloud 服务调用的同等公民出现,应用可通过 Apache Dubbo 注解@Service@Reference暴露和引用 Dubbo 服务,实现服务间多种协议的通讯。同时,也可以利用 Dubbo 泛化接口轻松实现服务网关。

4.1.3 Dubbo 服务自省

Dubbo Spring Cloud 引入了全新的服务治理特性 - 服务自省(Service Introspection),其设计目的在于最大化减轻注册中心负载,去 Dubbo 注册元信息中心化。假设一个 Spring Cloud 应用引入 Dubbo Spring Boot Starter,并暴露 N 个 Dubbo 服务,以Dubbo Nacos 注册中心为例,当前应用将注册 N+1 个 Nacos 应用,除 Spring Cloud 应用本身之前,其余 N 个应用均来自于 Dubbo 服务,当 N 越大时,注册中心负载越重。因此,Dubbo Spring Cloud 应用对注册中心的负载相当于传统 Dubbo 的 N 分之一,在不增加基础设施投入的前提下,理论上,使其集群规模扩大 N 倍。当然,未来的 Dubbo 也将提供服务自省的能力。

4.1.4 Dubbo 迁移 Spring Cloud 服务调用

尽管 Dubbo Spring Cloud 完全地保留了原生 Spring Cloud 服务调用特性,不过 Dubbo 服务治理的能力是 Spring Cloud Open Feign 所不及的,如高性能、高可用以及负载均衡稳定性等方面。因此,建议开发人员将 Spring Cloud Open Feign 或者@LoadBalanced``RestTemplate迁移为 Dubbo 服务。考虑到迁移过程并非一蹴而就,因此,Dubbo Spring Cloud 提供了方案,即@DubboTransported注解。该注解能够帮助服务消费端的 Spring Cloud Open Feign 接口以及@LoadBalanced``RestTemplateBean 底层走 Dubbo 调用(可切换 Dubbo 支持的协议),而服务提供方则只需在原有@RestController类上追加 Dubbo@Servce注解(需要抽取接口)即可,换言之,在不调整 Feign 接口以及RestTemplateURL 的前提下,实现无缝迁移。如果迁移时间充分的话,建议使用 Dubbo 服务重构系统中的原生 Spring Cloud 服务的定义。

5. 准备工作

5.1 初始化 Nacos 服务端

创建prepare.sh 脚本文件

#!/bin/bash

wget -O /home/shell/nacos-server-1.3.2.tar.gz https://handson.oss-cn-shanghai.aliyuncs.com/nacos-server-1.3.2.tar.gz

tar -xzvf /home/shell/nacos-server-1.3.2.tar.gz -C /home/shell/

sh /home/shell/nacos/bin/startup.sh -m standalone

请使用下面的命令初始化nacos服务端

sh ~/prepare.sh

通过如下命令观察nacos启动日志:

cat /home/shell/nacos/logs/start.out

待出现如下输出时,代表启动完成(如果未完成启动,可以重复执行上一条命令):

INFO Tomcat started on port(s): 65000 (http) with context path '/nacos'
……
INFO Nacos started successfully in stand alone mode. use embedded storage

5.2 获取服务端代码

通过下面的命令,或缺的服务端初始化代码

cloudshell-git-open "https://start.aliyun.com/type=maven-project&language=java&architecture=none&bootVersion=2.3.7.RELEASE&baseDir=dubbo-provider-sample&groupId=com.alibaba.cloud&artifactId=dubbo-provider-sample&name=dubbo-provider-sample&description=Demo%20project%20for%20Spring%20Boot&packageName=com.alibaba.cloud.dubbo-provider-sample&packaging=jar&javaVersion=1.8&dependencies=sca-dubbo,sca-nacos-discovery,web/dubbo-provider-sample.git" /home/shell/dubbo-provider-sample

5.3 获取客户端代码

使用下面的命令引入服务消费应用

cloudshell-git-open "https://start.aliyun.com/type=maven-project&language=java&architecture=none&bootVersion=2.3.7.RELEASE&baseDir=dubbo-consumer-sample&groupId=com.alibaba.cloud&artifactId=dubbo-consumer-sample&name=dubbo-consumer-sample&description=Demo%20project%20for%20Spring%20Boot&packageName=com.alibaba.cloud.dubbo-consumer-sample&packaging=jar&javaVersion=1.8&dependencies=sca-dubbo,sca-nacos-discovery,web/dubbo-consumer-sample.git" /home/shell/dubbo-consumer-sample

6. 如何引入 Dubbo Spring Cloud

本节介绍如何在自己的环境汇总引入 Dubbo Spring Cloud 组件依赖

Dubbo Spring Cloud 引入的方式通常有两种,由易到难分别为:Java 工程脚手架 引入和 Maven pom.xml 依赖。官方推荐使用 Java 工程脚手架 方式引入 Dubbo Spring Cloud,以便简化组件之间的依赖关系。

6.1 [简单] 通过 Java 工程脚手架 创建工程并引入 Dubbo Spring Cloud(推荐)

Dubbo Spring Cloud 组件的在整个 Spring Cloud Alibaba 版本和依赖最为复杂,推荐读者使用 Java 工程脚手架 构建应用工程。读者选择偏好的 Web 浏览器访问 Java 工程脚手架,其资源网址为:https://start.aliyun.com/bootstrap.html

下文以 Google Chrome 浏览器为例,当网页加载后,首先,在 "项目基本信息" 部分输入 Group :“com.alibaba.cloud” 以及 Artifact:“dubbo-provider-sample”(见下图绿框部分) 然而,“组件依赖” 输入框搜索:“Dubbo”(见下图红箭头部分),最后,选择 "Spring Cloud Alibaba Dubbo"(见下图红框部分),如下所示: image.png 继续依赖其他组件:

  • Nacos Service Discovery - 服务注册与发现组件
  • Spring Web - Spring Web MVC 组件
  • Spring Boot Actuator - Spring Boot Actator 组件

完整组件汇总如下图所示: image.png

点击 “生成” 高亮按钮,平台将生成一个名为 “dubbo-provider-sample.zip” 的压缩文件,将其保存到本地目录,并解压该文件,工程目录将随之生成。打开目录下的 pom.xml 文件,不难发现 Dubbo Spring Cloud Starter 声明其中(以下 XML 内容均来自于项目根路径中的 pom.xml 文件):

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>

不过该 starter 并未指定版本,具体的版本声明在 com.alibaba.cloud:spring-cloud-alibaba-dependencies 部分:

    <dependencyManagement>
        <dependencies>
            <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>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

其中,${spring-cloud-alibaba.version} 和 ${spring-boot.version} 分别为 Spring Cloud Alibaba 和 Spring Boot 组件依赖的版本,它们的版本定义在 <properties> 元素中,即 2.2.1.RELEASE 和 2.3.0.RELEASE

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.0.RELEASE</spring-boot.version>
        <spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
    </properties>

如果读者非常熟悉 Maven 依赖管理的配置方式,可以考虑 Maven pom.xml 依赖 Dubbo Spring Cloud。

6.2 [高级] 通过 Maven pom.xml 依赖 Dubbo Spring Cloud

如果要在您 Dubbo Spring Cloud 的项目中使用 Nacos 来实现服务注册/发现,可将两者 Stater 同时依赖:

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>

该声明方式同样需要声明 com.alibaba.cloud:spring-cloud-alibaba-dependencies,内容与上小节相同,在此不再赘述。下一节将讨论如何使用 Dubbo Spring Cloud 构建服务提供者。

7 创建服务接口

按照传统的 Dubbo 开发模式,在构建服务提供者之前,第一个步骤是为服务提供者和服务消费者定义 Dubbo 服务接口。

为了确保契约的一致性,推荐的做法是将 Dubbo 服务接口打包在第二方或者第三方的 artifact(jar)中,该 artifact 甚至无需添加任何依赖。

对于服务提供方而言,不仅通过依赖 artifact 的形式引入 Dubbo 服务接口,而且需要将其实现。对应的服务消费端,同样地需要依赖该 artifact,并以接口调用的方式执行远程方法。接下来的步骤则是创建 artifact。

7.1 创建 api 工程 - dubbo-sample-api

选择合适的文件目录,通过 Maven 命令行工具构建 artifact dubbo-sample-api,如下所示:

mvn archetype:generate -DgroupId=com.alibaba.cloud -DartifactId=dubbo-sample-api -Dversion=0.0.1-SNAPSHOT -DinteractiveMode=false -DoutputDirectory=/home/shell

命令执行后,名为“dubbo-sample-api” 的项目目录生成,切换至该目录,内部结构如下:

├── pom.xml
└── src
    ├── main
    │ └── java
    │     └── com
    │         └── alibaba
    │             └── cloud
    │                 └── App.java
    └── test
        └── java
            └── com
                └── alibaba
                    └── cloud
                        └── AppTest.java

11 directories, 3 files

其中,App.java 和 AppTest.java 文件并非需要文件,可将其删除。除此之外,当然最重要的是 pom.xml

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>dubbo-sample-api</artifactId>
  <packaging>jar</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>dubbo-sample-api</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

不难看出,Maven GAV 信息均按照之前的命令来设定,并没有依赖其他组件。接下来,为当前工程定义 Dubbo 服务接口。

7.2 定义 Dubbo 服务接口

Dubbo 服务接口是服务提供方与消费方的远程通讯契约,通常由普通的 Java 接口(interface)来声明,如EchoService接口(点击右上角自动拷贝代码):

package com.alibaba.cloud;

public interface EchoService {
    String echo(String message);
}

该接口非常简单,仅有一个方法,接下来将 dubbo-sample-api 部署到本地 Maven 仓库。

7.3 部署 api 工程 - dubbo-sample-api

利用 Maven 命令, 将 dubbo-sample-api 部署到本地 Maven 仓库:

cd /home/shell/dubbo-sample-api && mvn clean install 

注:如果读者所使用机器的 JDK 版本过高的话,可能会出现错误提示:"不再支持源选项 5。请使用 7 或更高版本"。本例推荐选择 JDK 8 编译。

本地部署成功后,该 artifact 能被 Dubbo 服务提供者应用 dubbo-provider-sample 依赖。

8 服务端开发

前面的准备工作,已经创建了服务端工程,本节主要完成了针对服务接口的实现工作

8.2 添加 api 依赖 - dubbo-sample-api

打开 dubbo-provider-sample 的 pom.xml 文件;

将 artifact dubbo-sample-api 依赖信息添加到应用 dubbo-provider-sample 中的 pom.xml点我自动插入:

        <!-- Dubbo 服务 artifact -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>dubbo-sample-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

依赖增加之后,下一步实现 Dubbo 服务 -EchoService

8.3 实现 Dubbo 服务

在应用 dubbo-provider-sample 中的 com.alibaba.cloud.dubboprovidersample 包下创建实现类(点击右上角自动拷贝代码):

package com.alibaba.cloud.dubboprovidersample;

import com.alibaba.cloud.EchoService;
import org.apache.dubbo.config.annotation.Service;

@Service
public class SimpleEchoService implements EchoService {

    @Override
    public String echo(String s) {
        return "[ECHO] " + s;
    }
}

其中,@org.apache.dubbo.config.annotation.Service是 Dubbo 服务注解,仅声明该 Java 服务(本地)实现为 Dubbo 服务。 因此,下一步需要将其配置 Dubbo 服务(远程)。

8.4 配置 Dubbo 服务提供方

打开 dubbo-provider-sample 的 application.properties 文件;

修改注册中心地址 (点我执行修改):

spring.cloud.nacos.discovery.server-addr=127.0.0.1:65000

修改服务端端口 (点我执行修改):

server.port=61000

在暴露 Dubbo 服务方面,推荐开发人员外部化配置的方式,即指定 Java 服务实现类的扫描基准包。

Dubbo Spring Cloud 继承了 Dubbo Spring Boot 的外部化配置特性,也可以通过标注 @DubboComponentScan 来实现基准包扫描。

application.properties 的配置项说明:

  • dubbo.scan.base-packages: 指定 Dubbo 服务实现类的扫描基准包

  • dubbo.protocol: Dubbo 服务暴露的协议配置,其中子属性name为协议名称,port为协议端口( -1 表示自增端口,从 20880 开始)

  • spring.application.name: Spring 应用名称,用于 Spring Cloud 服务注册和发现。

该值在 Dubbo Spring Cloud 加持下被视作dubbo.application.name,因此,无需再显示地配置dubbo.application.name

  • spring.cloud.nacos.discovery: Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口

完成以上步骤后,还需编写一个 Dubbo Spring Cloud 引导类。

8.5 引导 Dubbo Spring Cloud 服务提供方应用

在实验室的工程中,已经由脚手架自动添加了 Nacos 服务注册配置,所以 Application 类只需保留SpringBoot的入口即可,参见: NacosDiscoveryConfiguration


如果你在本地操作,可以参考下面的做法

Dubbo Spring Cloud 引导类与普通 Spring Cloud 应用并无差别,如下所示:

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

当 Dubbo 服务提供方启动后,下一步实现一个 Dubbo 服务消费方。

9 客户端开发

9.1 增加 api 依赖 - dubbo-sample-api

与服务提供方 Maven 工程类似,将 artifact dubbo-sample-api 依赖信息添加到应用 dubbo-consumer-sample 中的 pom.xml 点我自动插入::

        <!-- Dubbo 服务 artifact -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>dubbo-sample-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

9.2 修改消费端配置

Dubbo 服务消费方配置与服务提供方类似,当前应用 dubbo-consumer-sample 属于纯服务消费方,只有很少的地方需要修改:

  • 打开 dubbo-consumer-sample 的 application.properties 文件

  • 修改订阅服务

dubbo.cloud.subscribed-services: 用于服务消费方订阅服务提供方的应用名称的列表,若需订阅多应用,请使用 "," 分割。不推荐使用默认值为 "*",它将订阅所有应用。
当应用使用属性 dubbo.cloud.subscribed-services 默认值时,日志中将会输出一行警告:

Current application will subscribe all services(size:x) in registry, a lot of memory and CPU cycles may be used, thus it’s strongly recommend you using the externalized property ‘dubbo.cloud.subscribed-services’ to specify the services

  • 修改访问端口 点我修改
    由于当前应用属于 Web 应用,它会默认地使用 8080 作为 Web 服务端口,如果 dubbo-provider-sample 和 dubbo-consumer-sample 在本地同步部署的话, 两者 Web 端口会出现冲突,需调整 dubbo-consumer-sample application.properties 中的server.portmanagement.server.port
# 应用服务 WEB 访问端口
server.port=60000
  • 修改注册中心 这里改为准备阶段开启的nacos服务端的地址

9.3. 增加web访问控制器

dubbo-consumer-sample 增加一个控制器,以支持处理web请求,并调用服务端的EchoService(点击右上角进行复制):

package com.alibaba.cloud.dubboconsumersample;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.cloud.EchoService;
import org.apache.dubbo.config.annotation.Reference;

@RestController
public class DubboConsumerSampleController {

    @Reference
    private EchoService echoService;

    // http://127.0.0.1:8080/echo?message=somemessage
    @GetMapping("/echo")
    public String echo(@RequestParam(name = "message", defaultValue = "no message") String message) {
        return echoService.echo(message);
    }
}

10 编译、启动和访问

10.1 编译应用

编译服务端应用

cd /home/shell/dubbo-provider-sample && mvn package

编译客户端应用

cd /home/shell/dubbo-consumer-sample && mvn package

10.2 启动两个应用

启动服务端

java -jar /home/shell/dubbo-provider-sample/target/dubbo-provider-sample-0.0.1-SNAPSHOT.jar

在 新窗口 中启动客户端

java -jar /home/shell/dubbo-consumer-sample/target/dubbo-consumer-sample-0.0.1-SNAPSHOT.jar

10.3 访问应用

查看 Nacos控制台 确认服务端、客户端已经完成注册;

在 新窗口 中通过curl命令访问 REST 资源/echo:

curl "http://127.0.0.1:60000/echo?message=Hello,World"

你会看到下面的输出:

[ECHO] Hello,World

不难发现,Dubbo 服务提供方应用 dubbo-provider-sample 的EchoService计算结果返回到 dubbo-consumer-sample 中的 REST 资源/echo。同时,在 dubbo-provider-sample 应用日志出现了以下内容:

[DUBBO] The connection of /x.x.x.x:64051 -> /x.x.x.x:20881 is established., dubbo version: 2.7.6, current host: x.x.x.x

说明 Dubbo 服务消费端应用 dubbo-consumer-sample(端口:64051) 向服务提供方应用 dubbo-provider-sample 建立连接(端口:20881)。

11. 课后资料

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

52it.club

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值