乐趣区

Dubbo想要个网关怎么办试试整合Spring-Cloud-Gateway

一、背景

在微服务架构中 API 网关 非常重要,网关作为全局流量入口并不单单是一个反向路由,更多的是把各个边缘服务(Web 层) 的各种共性需求抽取出来放在一个公共的“服务”(网关)中实现,例如安全认证、权限控制、限流熔断、监控、跨域处理、聚合 API 文档等公共功能。

 

在以 Dubbo 框架体系来构建的微服务架构下想要增加 API 网关,如果不想自研开发的情况下在目前的开源社区中几乎没有找到支持 dubbo 协议的主流网关,但是 Spring Cloud 体系下却有两个非常热门的开源 API 网关可以选择;本文主要介绍如何通过 Nacos 整合 Spring Cloud GatewayDubbo 服务

 

二、传统 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 的话需要解决以下问题:

  1. 打通注册中心:spring cloud gateway 需要通过注册中心发现下游服务,而 dubbo 也需要通过注册中心实现服务的注册与发现,如果两者的注册中心不能打通的话就会变成双注册中心架构就非常复杂了!
  2. 协议转换:gateway 使用 http 传输协议调用下游服务,而 dubbo 服务默认使用的是 tcp 传输协议

上面提到的第一个问题“打通注册中心”其实已经不是问题了,目前 dubbo 支持 ZookeeperNacos 两个注册中心,而 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”} 则该服务同时支持 dubborest 两种传输协议

 

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 工程,通过网关的以下两个接口分别测试两种整合方式

  1. http://127.0.0.1:9900/api-web/test/abc:请求 web-dubbo 工程测试整合方式一
  2. http://127.0.0.1:9900/api-rest/test/abc:请求 rest-dubbo 工程测试整合方式二

 

五、demo 下载

ide 需要安装 lombok 插件

https://github.com/zlt2000/dubboSpringCloud

 
扫码关注有惊喜!

退出移动版