Dubbo想要個閘道器怎麼辦?試試整合Spring Cloud Gateway

zlt2000發表於2020-06-28

mark

一、背景

在微服務架構中 API閘道器 非常重要,閘道器作為全域性流量入口並不單單是一個反向路由,更多的是把各個邊緣服務(Web層)的各種共性需求抽取出來放在一個公共的“服務”(閘道器)中實現,例如安全認證、許可權控制、限流熔斷、監控、跨域處理、聚合API文件等公共功能。

 

在以 Dubbo 框架體系來構建的微服務架構下想要增加API閘道器,如果不想自研開發的情況下在目前的開源社群中幾乎沒有找到支援dubbo協議的主流閘道器,但是 Spring Cloud 體系下卻有兩個非常熱門的開源API閘道器可以選擇;本文主要介紹如何通過 Nacos 整合 Spring Cloud GatewayDubbo 服務

 

二、傳統 dubbo 架構

dubbo屬於rpc呼叫,所以必須提供一個web層的服務作為http入口給客戶端呼叫,並在上面提供安全認證等基礎功能,而web層前面對接Nginx等反向代理用於統一入口和負載均衡。

web層一般是根據業務模組來切分的,用於聚合某個業務模組所依賴的各個service服務

file

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 ,並把 安全認證 等共性功能前移至閘道器處實現
mark

由於web層服務本身提供的就是http介面,所以閘道器層無需作協議轉換,但是由於 安全認證 前移至閘道器了需要通過網路隔離的手段防止被繞過閘道器直接請求後面的web層

 

3.2. 方式二

dubbo服務本身修改或新增 rest 傳輸協議的支援,這樣閘道器就可以通過http傳輸協議與dubbo服務通訊了

rest傳輸協議:基於標準的Java REST API——JAX-RS 2.0(Java API for RESTful Web Services的簡寫)實現的REST呼叫支援

mark

目前版本的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

 
掃碼關注有驚喜!

file

相關文章