一、背景
在微服务架构中 API 网关 非常重要,网关作为全局流量入口并不单单是一个反向路由,更多的是把各个边缘服务(Web 层) 的各种共性需求抽取出来放在一个公共的“服务”(网关)中实现,例如安全认证、权限控制、限流熔断、监控、跨域处理、聚合 API 文档等公共功能。
在以 Dubbo 框架体系来构建的微服务架构下想要增加 API 网关,如果不想自研开发的情况下在目前的开源社区中几乎没有找到支持 dubbo 协议的主流网关,但是 Spring Cloud 体系下却有两个非常热门的开源 API 网关可以选择;本文主要介绍如何通过 Nacos
整合 Spring Cloud Gateway
与 Dubbo 服务
。
二、传统 dubbo 架构
dubbo 属于 rpc 调用,所以必须提供一个 web 层的服务作为 http 入口给客户端调用,并在上面提供安全认证等基础功能,而 web 层前面对接 Nginx 等反向代理用于统一入口和负载均衡。
web 层一般是根据业务模块来切分的,用于聚合某个业务模块所依赖的各个 service 服务
PS:我们能否把上图中的 web 层全部整合在一起成为一个 API 网关呢?(不建议这样做)
因为这样的 web 层并没有实现 泛化调用 必须引入所有 dubbo 服务的 api 依赖,会使得网关变得非常不稳定,任何服务的接口变更都需要修改网关中的 api 依赖!
三、整合 Srping Cloud Gateway 网关
下面就开始聊聊直接拿热门的 Srping Cloud Gateway
来作为 dubbo 架构体系的网关是否可行,首先该 API 网关是属于 Spring Cloud 体系下的组件之一,要整合 dubbo 的话需要解决以下问题:
- 打通注册中心:spring cloud gateway 需要通过注册中心发现下游服务,而 dubbo 也需要通过注册中心实现服务的注册与发现,如果两者的注册中心不能打通的话就会变成双注册中心架构就非常复杂了!
- 协议转换:gateway 使用 http 传输协议调用下游服务,而 dubbo 服务默认使用的是 tcp 传输协议
上面提到的第一个问题“打通注册中心”其实已经不是问题了,目前 dubbo 支持
Zookeeper
与Nacos
两个注册中心,而 Spring Cloud 自从把@EnableEurekaClient
改为@EnableDiscoveryClient
之后已经基本上支持所有主流的注册中心了,本文将使用Nacos
作为注册中心打通两者
3.1. 方式一
把传统 dubbo 架构中的 Nginx
替换为 Spring Cloud Gateway
,并把 安全认证
等共性功能前移至网关处实现
由于 web 层服务本身提供的就是 http 接口,所以网关层无需作协议转换,但是由于
安全认证
前移至网关了需要通过网络隔离的手段防止被绕过网关直接请求后面的 web 层
3.2. 方式二
dubbo 服务本身修改或添加 rest
传输协议的支持,这样网关就可以通过 http 传输协议与 dubbo 服务通信了
rest 传输协议:基于标准的 Java REST API——JAX-RS 2.0(Java API for RESTful Web Services 的简写)实现的 REST 调用支持
目前版本的 dubbo 已经支持 dubbo、rest、rmi、hessian、http、webservice、thrift、redis 等 10 种传输协议了,并且还支持同一个服务同时定义多种协议,例如配置 protocol = {“dubbo”, “rest”} 则该服务同时支持
dubbo
与rest
两种传输协议
3.3. 总结
方式一 对比 方式二 多了一层 web 服务所以多了一次网络调用开销,但是优点是各自的职责明确单一,web 层可以作为聚合层用于聚合多个 service 服务的结果经过融合加工一并返回给前端,所以这种架构下能大大减少服务的 循环依赖
四、代码实践
依赖环境
- lombok
- jdk 1.8
- Nacos 1.3
- Spring Boot 2.2.8.RELEASE
- Spring Cloud Hoxton.SR5
- Spring Cloud Alibaba 2.2.1.RELEASE
在根目录的 pom.xml
中定义全局的依赖版本
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>8</java.version>
<spring-boot-dependencies.version>2.2.8.RELEASE</spring-boot-dependencies.version>
<spring-cloud-dependencies.version>Hoxton.SR5</spring-cloud-dependencies.version>
<spring-cloud-alibaba-dependencies.version>2.2.1.RELEASE</spring-cloud-alibaba-dependencies.version>
<jaxrs.version>3.12.1.Final</jaxrs.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
4.1. 创建 dubbo-api 工程
分别定义两个 api 接口
DubboService 使用 dubbo 协议的服务
public interface DubboService {String test(String param);
}
RestService 使用 rest 协议的服务
public interface RestService {String test(String param);
}
4.2. 创建 web-dubbo 工程
使用 方式一 整合对接网关,这里为了简化在同一个服务下只使用逻辑分层定义 controller 层与 service 层,并没有做服务拆分
4.2.1. 创建配置
定义 spring boot 配置
server:
port: 8081
spring:
application:
name: zlt-web-dubbo
main:
allow-bean-definition-overriding: true
cloud:
nacos:
server-addr: 192.168.28.130:8848
username: nacos
password: nacos
server.port
:配置应用服务器暴露的端口
spring.cloud.nacos
:配置 spring cloud 的注册中心相关参数,nacos 的配置需要改为自己环境所对应
定义 dubbo 配置
dubbo:
scan:
base-packages: org.zlt.service
protocols:
dubbo:
name: dubbo
port: -1
registry:
address: spring-cloud://localhost
consumer:
timeout: 5000
check: false
retries: 0
cloud:
subscribed-services:
dubbo.scan.base-packages
:指定 Dubbo 服务实现类的扫描基准包
dubbo.protocols
:服务暴露的协议配置,其中子属性name
为协议名称,port
为协议端口(-1 表示自增端口,从 20880 开始)
dubbo.registry.address
:Dubbo 服务注册中心配置,其中子属性address
的值 “spring-cloud://localhost”,说明挂载到 Spring Cloud 注册中心
4.2.2. 创建 DubboService 的实现类
通过 protocol = "dubbo"
指定使用 dubbo 协议
定义服务
@Service(protocol = "dubbo")
public class DubboServiceImpl implements DubboService {
@Override
public String test(String param) {return "dubbo service:" + param;}
}
4.2.3. 创建 Controller 类
使用 Spring Boot
的 @RestController
注解定义 web 服务
@RestController
public class WebController {
@Autowired
private DubboService dubboService;
@GetMapping("/test/{p}")
public String test(@PathVariable("p") String param) {return dubboService.test(param);
}
}
4.3. 创建 rest-dubbo 工程
使用 方式二 整合对接网关,由于该服务是通过 dubbo 来创建 rest 服务,所以并不需要使用 Spring Boot 内置应用服务
4.3.1. 创建配置
定义 spring boot 配置
spring:
application:
name: zlt-rest-dubbo
main:
allow-bean-definition-overriding: true
cloud:
nacos:
server-addr: 192.168.28.130:8848
username: nacos
password: nacos
因为不使用 Spring Boot 内置的应用服务所以这里并不需要指定
server.port
定义 dubbo 配置
dubbo:
scan:
base-packages: org.zlt.service
protocols:
dubbo:
name: dubbo
port: -1
rest:
name: rest
port: 8080
server: netty
registry:
address: spring-cloud://localhost
consumer:
timeout: 5000
check: false
retries: 0
cloud:
subscribed-services:
dubbo.protocols
:配置两种协议,其中 rest 协议定义 8080 端口并使用 netty 作为应用服务器
4.3.2. 创建 RestService 的实现类
通过 protocol = "rest"
指定使用 rest 协议
定义服务
@Service(protocol = "rest")
@Path("/")
public class RestServiceImpl implements RestService {
@Override
@Path("test/{p}")
@GET
public String test(@PathParam("p") String param) {return "rest service:" + param;}
}
4.4. 创建 Spring Cloud Gateway 工程
定义 spring boot 配置
server:
port: 9900
spring:
application:
name: sc-gateway
main:
allow-bean-definition-overriding: true
cloud:
nacos:
server-addr: 192.168.28.130:8848
username: nacos
password: nacos
server.port
:定义网关端口为 9090
定义网关配置
spring:
cloud:
gateway:
discovery:
locator:
lowerCaseServiceId: true
enabled: true
routes:
- id: web
uri: lb://zlt-web-dubbo
predicates:
- Path=/api-web/**
filters:
- StripPrefix=1
- id: rest
uri: lb://zlt-rest-dubbo
predicates:
- Path=/api-rest/**
filters:
- StripPrefix=1
分别定义两个路由策略:
- 路径
/api-web/
为请求web-dubbo
工程 - 路径
/api-rest/
为请求rest-dubbo
工程
4.5. 测试
分别启动:Nacos、sc-gateway、web-dubbo、rest-dubbo 工程,通过网关的以下两个接口分别测试两种整合方式
-
http://127.0.0.1:9900/api-web/test/abc:请求
web-dubbo
工程测试整合方式一 -
http://127.0.0.1:9900/api-rest/test/abc:请求
rest-dubbo
工程测试整合方式二
五、demo 下载
ide 需要安装 lombok
插件
https://github.com/zlt2000/dubboSpringCloud
扫码关注有惊喜!