Spring Cloud Alibaba 架构实战
视频:https://blog.csdn.net/weixin_44062339/article/details/103394897
完整讲义:http://www.pbteach.com/post/java_distribut/nacos-discovery/
http://www.pbteach.com/post/java_distribut/nacos-config/
代码:
链接:https://pan.baidu.com/s/1jweoGABWxrtF9WUOAtxQaQ
提取码:sgxx
Spring Cloud是一个较为全面的微服务框架集,集成了如服务注册发现、配置中心、消息总线、负载均衡、断路器、API网关等功能实现。而在网上经常会发现Spring Cloud与阿里巴巴的Dubbo进行选择对比,这样做其实不是很妥当,前者是一套较为完整的架构方案,而Dubbo只是服务治理与RPC实现方案。
Dubbo在国内有着非常大的用户群体,但是其周边设施与组件相对来说并不那么完善。很多开发者用户又很希望享受Spring Cloud的生态,因此也会有一些Spring Cloud与Dubbo一起使用的案例与方法出现,但是一直以来大部分Spring Cloud整合Dubbo的使用方案都不完善。直到Spring Cloud Alibaba的出现,才得以解决这样的问题。
在此之前,我们已经学了如何使用Spring Cloud Alibaba来集成Nacos与Spring Cloud应用,并且在此之下可以如传统的Spring Cloud应用一样地使用Ribbon或Feign来微服务之间的协作。由于Feign是基于Http Restful的调用,在高并发下的性能不够理想,RPC方案能否切换为Dubbo?Spring Cloud与阿里系的若干组件能否完美集成呢?本章内容将指引大家集成一个微服务的基础架构,并讨论其合理性。
1 总体结构
系统架构图如下:
组件说明:
API网关 :系统统一入口,屏蔽架构内部结构,统一安全拦截,采用Zuul实现。
application-1 :应用1,模拟应用,提供http接口服务。
service-1 :微服务1,模拟微服务,提供dubbo接口服务。
service-2 :微服务2,模拟微服务,提供dubbo接口服务。
调用流程:
所有访问系统的请求都要经过网关,网关转发Http请求至application-1,application-1使用dubbo调用service1完成自身业务,而后sevice1调用service2完成自身业务。至此,完成所有组件贯穿。
架构中application与sevice的区别是什么?
- service提供了基础服务功能;application组装基础服务功能,提供给用户直接可用的业务。
- service服务粒度小、功能基础,不易发生改变;application提供上游业务功能,紧贴业务需求,容易发生改变。
- 形成service支撑application的整体架构,增加多变的application甚至不需要变动service。
2 工程结构说明
采用maven工程,结构如下:
nacos-micro-service 整体父工程
├─api-gateway API网关,端口:56010
├─application-1 应用1,端口:56020
├─service-1 服务1父工程
│ ├─service-1-api 服务1API
│ └─service-1-server 服务1实现,端口:56030
└─service-2 服务2父工程
├─service-2-api 服务2API
└─service-2-server 服务2实现,端口:56040
3 创建父工程
创建 artifactId
名为 nacos-micro-service
的 Maven 工程,此父工程继承nacos-discovery父工程,间接指定了Spring boot、spring cloud 以及spring-cloud-alibaba的依赖版本。
<parent>
<artifactId>nacos-discovery</artifactId>
<groupId>com.pbteach.nacos</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nacos-micro-service</artifactId>
<packaging>pom</packaging>
nacos-discovery的pom.xml如下:
<groupId>com.pbteach.nacos</groupId>
<artifactId>nacos-discovery</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
4 实现application1
application1属于应用层,提供http接口服务。
(1)初始化 application-1
Maven 工程
<artifactId>application-1</artifactId>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
(2)实现 application-1
功能
package com.pbteach.microservice.application1.controller;
@RestController
public class Application1Controller {
@GetMapping("/service")
public String service(){
return "test" ;
}
}
(3) application1 配置
纯粹的dubbo服务消费者,配置看起来更简单。
定义bootstrap.yml
server:
port: 56020 #启动端口 命令行注入
servlet:
context-path: /application1
spring:
application:
name: application1
main:
allow-bean-definition-overriding: true # Spring Boot 2.1 需要设定
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: c67e4a97-a698-4d6d-9bb1-cfac5f5b51c4
cluster-name: DEFAULT
config:
server-addr: 127.0.0.1:8848 # 配置中心地址
file-extension: yaml
namespace: c67e4a97-a698-4d6d-9bb1-cfac5f5b51c4 # 开发环境
group: NACOS_MICROSERVICE_GROUP # xx业务组
(4) application1 启动
@SpringBootApplication
@EnableDiscoveryClient
public class Application1Bootstrap {
public static void main(String[] args) {
SpringApplication.run(Application1Bootstrap.class,args);
}
}
当 Service1Bootstrap
启动后,应用 application1
将出现在 Nacos 控制台界面。
5 实现 Service1
5.1 定义父工程
定义service1父工程,pom.xml如下:
<parent>
<artifactId>nacos-micro-service</artifactId>
<groupId>com.pbteach.nacos</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Service1</artifactId>
5.2 定义service-1-api
为了方便其它服务调用dubbo服务,专门定义api工程,此工程将作为jar被其它工程依赖。
定义service-1-api工程,pom.xml如下:
<parent>
<artifactId>Service1</artifactId>
<groupId>com.pbteach.nacos</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-1-api</artifactId>
定义服务接口:
package com.pbteach.microservice.service1.api;
public interface ConsumerService {
public String service();
}
5.3 实现service-1-server
(1)初始化 service-1-server
Maven 工程
与服务提供方 Maven工程类似,需添加相关 Maven 依赖:
<parent>
<artifactId>Service1</artifactId>
<groupId>com.pbteach.nacos</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-1-server</artifactId>
<dependencies>
<dependency>
<groupId>com.pbteach.nacos</groupId>
<artifactId>service-1-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<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>
</dependencies>
(2)实现 Dubbo 服务
package com.pbteach.microservice.service1.service;
@org.apache.dubbo.config.annotation.Service
public class ConsumerServiceImpl implements ConsumerService {
@Override
public String service() {
return "Consumer invoke " ;
}
}
注意:使用@org.apache.dubbo.config.annotation.Service标记dubbo服务
(3)配置 Dubbo 服务
Service2 作为Dubbo服务消费方配置与服务提供方类似,注意,service1不仅是消费方,同时还是服务提供方:
server:
port: ${port:56030} #启动端口 命令行注入
spring:
application:
name: service1
main:
allow-bean-definition-overriding: true # Spring Boot 2.1 需要设定
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: c67e4a97-a698-4d6d-9bb1-cfac5f5b51c4
cluster-name: DEFAULT
config:
server-addr: 127.0.0.1:8848 # 配置中心地址
file-extension: yaml
namespace: c67e4a97-a698-4d6d-9bb1-cfac5f5b51c4 # 开发环境
group: NACOS_MICROSERVICE_GROUP # xx业务组
dubbo:
scan:
# dubbo 服务扫描基准包
base-packages: com.pbteach.microservice
protocol:
# dubbo 协议
name: dubbo
# dubbo 协议端口
port: ${dubbo_port:20881}
registry:
address: nacos://127.0.0.1:8848
application:
qos-enable: false #dubbo运维服务是否开启
consumer:
check: false #启动时就否检查依赖的服务
以上 YAML 内容,dubbo开头的为dubbo服务 的配置:
-
dubbo.scan.base-packages
: 指定 Dubbo 服务实现类的扫描基准包,将@org.apache.dubbo.config.annotation.Service注解标注的service暴露为dubbo服务。 -
dubbo.protocol
: Dubbo 服务暴露的协议配置,其中子属性name
为协议名称,port
为dubbo协议端口可以指定多协议,如:dubbo.protocol.rmi.port=1099
-
dubbo.registry
: Dubbo 服务注册中心配置,其中子属性address
的值 “nacos://127.0.0.1:8848”,说明dubbo服务注册到nacos相当于原生dubbo的xml配置中的
<dubbo:registry address="10.20.153.10:9090" />
上半部分为SpringCloud的相关配置:
spring.application.name
: Spring 应用名称,用于 Spring Cloud 服务注册和发现。
该值在 Dubbo Spring Cloud 加持下被视作
dubbo.application.name
,因此,无需再显示地配置dubbo.application.name
-
spring.cloud.nacos.discovery
: Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口 -
spring.cloud.nacos.config
: Nacos 配置中心配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口。
(4)启动服务消费方应用
@SpringBootApplication
@EnableDiscoveryClient
public class Service1Bootstrap {
public static void main(String[] args) {
SpringApplication.run(Service1Bootstrap.class, args);
}
}
当 Service1Bootstrap
启动后,应用 service1
将出现在 Nacos 控制台界面。
启动成功,观察nacos服务列表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RK8sIFvq-1575467002609)(1572439366107.png)]
6 实现 application1调用Service1
现在service1已暴露dubbo服务并注册到nacos中,下边实现application1调用service1
6.1 引用service1
下边在application1中引用service1
在pom.xml中引入service-1-api的依赖
<dependency>
<groupId>com.pbteach.nacos</groupId>
<artifactId>service-1-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
引入 spring-cloud-starter-dubbo依赖,它会根据接口生成代理对象
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
6.2 实现远程调用
@RestController
public class Application1Controller {
@org.apache.dubbo.config.annotation.Reference
private ConsumerService consumerService;
@GetMapping("/service")
public String service(){
return "test" + consumerService.service();
}
}
Note:注意:这里的@Reference
注解是org.apache.dubbo.config.annotation.Reference
测试:
请求:http://localhost:56020/application1/service
consumerService正常生成代理对象,service1被调用。
7 实现 Service2
如上面设计所示,Service2需要暴露dubbo接口以供service1消费,若想在Spring cloud Alibaba中集成并使用dubbo。
7.1 定义父工程
定义service2父工程,pom.xml如下:
<parent>
<artifactId>nacos-micro-service</artifactId>
<groupId>com.pbteach.nacos</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Service2</artifactId>
7.2 定义service-2-api
定义service-2-api工程,pom.xml如下:
<parent>
<artifactId>Service2</artifactId>
<groupId>com.pbteach.nacos</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-2-api</artifactId>
并定义服务接口,Dubbo 服务接口是服务提供方与消费方的远程通讯契约,通常由普通的 Java 接口(interface)来声明,如 ProviderService
接口:
package com.pbteach.microservice.service2.api;
public interface ProviderService {
String service();
}
7.3 实现service-2-server
(1)初始化 service-2-server
Maven 工程
首先,创建 artifactId
名为 service-2-server
的 Maven 工程,并在其 pom.xml
文件中增添 Dubbo Spring Cloud 必要的依赖:
<parent>
<artifactId>Service2</artifactId>
<groupId>com.pbteach.nacos</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-2-server</artifactId>
<dependencies>
<dependency>
<groupId>com.pbteach.nacos</groupId>
<artifactId>service-2-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<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>
</dependencies>
以上依赖 artifact 说明如下:
service-2-api
: 提供ProviderService
接口的 artifactspring-boot-starter-web
: Spring Boot starterartifact
,间接引入spring-boot
artifactspring-cloud-starter-dubbo
: Dubbo Spring Cloud Starterartifact
,间接引入dubbo-spring-boot-starter
等 artifactspring-cloud-starter-alibaba-nacos-discovery
: Nacos Spring Cloud 服务注册与发现artifact
(2)实现 Dubbo 服务
ProviderService
作为暴露的 Dubbo 服务接口,服务提供方 service-2-server
需要将其实现:
package com.pbteach.microservice.service2.service;
@org.apache.dubbo.config.annotation.Service
public class ProviderServiceImpl implements ProviderService {
@Override
public String service() {
return "Provider invoke";
}
}
其中,@org.apache.dubbo.config.annotation.Service
是 Dubbo 服务注解,仅声明该 Java 服务(本地)实现为 Dubbo 服务。 因此,下一步需要将其配置 Dubbo 服务(远程)。
(3)配置 Dubbo 服务
在暴露 Dubbo 服务方面,推荐开发人员外部化配置的方式,即指定 Java 服务实现类的扫描基准包。
Dubbo Spring Cloud 继承了 Dubbo Spring Boot 的外部化配置特性,也可以通过标注
@DubboComponentScan
来实现基准包扫描。
同时,Dubbo 远程服务需要暴露网络端口,并设定通讯协议,完整的 YAML 配置如下所示:
server:
port: ${port:56040} #启动端口 命令行注入
spring:
application:
name: service2
main:
allow-bean-definition-overriding: true # Spring Boot 2.1 需要设定
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: c67e4a97-a698-4d6d-9bb1-cfac5f5b51c4
cluster-name: DEFAULT
config:
server-addr: 127.0.0.1:8848 # 配置中心地址
file-extension: yaml
namespace: c67e4a97-a698-4d6d-9bb1-cfac5f5b51c4 # 开发环境
group: NACOS_MICROSERVICE_GROUP # xx业务组
dubbo:
scan:
# dubbo 服务扫描基准包
base-packages: com.pbteach.microservice
protocol:
# dubbo 协议
name: dubbo
# dubbo 协议端口( -1 表示自增端口,从 20880 开始)
port: ${dubbo_port:20891}
registry:
address: nacos://127.0.0.1:8848
application:
qos-enable: false
consumer:
check: false
(4)启动服务提供方应用
Dubbo Spring Cloud 引导类与普通 Spring Cloud 应用并无差别,如下所示:
@SpringBootApplication
@EnableDiscoveryClient
public class Service2Bootstrap {
public static void main(String[] args) {
SpringApplication.run(Service2Bootstrap.class, args);
}
}
在引导 Service2Bootstrap
之前,请提前启动 Nacos 服务器。 当 Service2Bootstrap
启动后,应用 service2
将出现在 Nacos 控制台界面。
8 实现service1调用service2
8.1 引用service2
在service2中添加service1的依赖:
<dependency>
<groupId>com.pbteach.nacos</groupId>
<artifactId>service-2-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
8.2 实现远程调用
@org.apache.dubbo.config.annotation.Service
public class ConsumerServiceImpl implements ConsumerService {
@Reference
ProviderService providerService;
public String service() {
return "Consumer invoke | "+providerService.service();
}
}
测试:
请求:http://localhost:56020/application1/service
application1调用service1,service1调用service2
9 实现api-gateway
9.1 Zuul介绍
什么是网关?
原来的单体架构,所有的服务都是本地的,UI可以直接调用,现在按功能拆分成独立的服务,跑在独立的一般都在独立的虚拟机上的 Java进程了。客户端UI如何访问?他的后台有N个服务,前台就需要记住管理N个服务,一个服务下线/更新/升级,前台就要重新部署,这明显不服务我们拆分的理念,特别当前台是移动应用的时候,通常业务变化的节奏更快。另外,N个小服务的调用也是一个不小的网络开销。
有了网关作为服务统一入口,就可以避免上述问题,不仅如此,服务网关是在微服务前边设置一道屏障,请求先到服务网关,网关会对请求进行过虑、校验、路由等处理。有了服务网关可以提高微服务的安全性,网关校验请求的合法性,请求不合法将被拦截,拒绝访问。
- 提供统一服务入口,让微服务对前台透明
- 聚合后台的服务,节省流量,提升性能
- 提供安全,过滤,流控等API管理功能
什么是Zuul?
Spring Cloud Zuul是整合Netflix公司的Zuul开源项目实现的微服务网关,它实现了请求路由、负载均衡、校验过虑等 功能。
官方:https://github.com/Netflix/zuul
Zuul与Nginx怎么配合使用?
Zuul与Nginx在实际项目中需要配合使用,如下图,Nginx的作用是反向代理、负载均衡,Zuul的作用是保障微服务的安全访问,拦截微服务请求,校验合法性及负载均衡。
9.2 搭建网关工程
初始化 api-gateway
Maven 工程
<parent>
<artifactId>nacos-micro-service</artifactId>
<groupId>com.pbteach.nacos</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>api-gateway</artifactId>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
9.3 api-gateway配置
server:
port: 56010 #启动端口 命令行注入
spring:
application:
name: api-gateway
main:
allow-bean-definition-overriding: true # Spring Boot 2.1 需要设定
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: c67e4a97-a698-4d6d-9bb1-cfac5f5b51c4
cluster-name: DEFAULT
config:
server-addr: 127.0.0.1:8848 # 配置中心地址
file-extension: yaml
namespace: c67e4a97-a698-4d6d-9bb1-cfac5f5b51c4 # 开发环境
group: NACOS_MICROSERVICE_GROUP # xx业务组
网关的路由配置采用nacos远程配置,在nacos控制台开发环境中新增api-gateway.yaml配置集,配置组为TEST_GROUP,配置内容如下:
zuul:
routes:
application1:
stripPrefix: false
path: /application1/**
将请求为/application1/
开头的请求路由至application1
服务,保留请求url中的/application1/
。
(4) api-gateway启动
注意在启动类上使用@EnableZuulProxy注解标识此工程为Zuul网关,启动类代码如下:
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class ApiGatewayBootstrap {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayBootstrap.class, args);
}
}
当 Service1Bootstrap
启动后,应用 api-gateway
将出现在 Nacos 服务列表中。
测试:
通过网关(api-gateway)请求Application1应用,Application1的业务实现又贯穿service1、service2,访问http://127.0.0.1:56010/application1/service ,将得到如下结果: