dubbo-gateway 高效能dubbo閘道器

小小豆子 發表於 2022-01-24
Dubbo

dubbo-gateway

dubbo-gateway 提供了http協議到dubbo協議的轉換,但【並非】使用dubbo的【泛化】呼叫(泛化呼叫效能比普通呼叫有10-20%的損耗,通過普通非同步的呼叫方式與基於webflux系列的響應式閘道器整合提高系統的吞吐量,普通呼叫需要依賴api jar包,需要對介面定義進行改造,除此之外不需要做任何其它改造.另外也支援基於servlet類的應用或閘道器進行整合

泛化缺點

  • 泛化過程資料流會經過了三次轉換, 會產生大量的臨時物件, 有很大的記憶體要求。使用反射方式對於旨在榨乾伺服器效能以獲取高吞吐量的系統來說, 難以達到效能最佳
  • 同時服務端也會對泛化請求多一重 Map <-> POJO 的來回轉換的過程。整體上,與普通的Dubbo呼叫相比有10-20%的損耗
  • 泛化呼叫在閘道器或服務消費者階段無法校驗引數型別的有效性,資料要到服務提供者反序列化時才能校驗出引數型別的有效性

開源地址

開源地址
https://github.com/smallbeanteng/dubbo-gateway

相關注解

@GateWayDubbo

標識這個介面需要自動進行協議轉換

/**
 * 服務id,可以和dubbo普通呼叫的配置屬性關聯.
 */
@AliasFor("id")
String value() default "";

/**
 * 服務id,可以和dubbo普通呼叫的配置屬性關聯.
 * 例如: 
		com.atommiddleware.cloud.config.dubboRefer.<userService>.version=1.1.0
		com.atommiddleware.cloud.config.dubboRefer.<userService>.group=userSystem
		以上相當於會呼叫版本號為1.1.0並且groupw為userSystem的dubbo服務,與@DubboReference的引數對齊,具體支援哪些引數詳見配置類DubboReferenceConfigProperties
 */
@AliasFor("value")
String id() default "";

@PathMapping

標記這個介面方法需要進行協議自動轉換

/**
 * 路徑表示式
 */
@AliasFor("path")
String value() default "";

/**
 * 路徑表示式
 */
@AliasFor("value")
String path() default "";

/**
 * 提交方法,GET或POST
 */
RequestMethod requestMethod() default RequestMethod.POST;

public enum RequestMethod {
	GET, POST

}

@FromBody

表示引數物件來源於訊息體

/**
 * 是否檢查引數
 */
@AliasFor(annotation = ParamAttribute.class)
boolean required() default true;

@FromHeader

表示引數物件來源於訊息頭

/**
 * 訊息頭名稱
 */
@AliasFor(annotation = ParamAttribute.class)
String value() default "";

/**
 * 訊息頭名稱
 */
@AliasFor(annotation = ParamAttribute.class)
String name() default "";

/**
 * 是否檢查引數
 */
@AliasFor(annotation = ParamAttribute.class)
boolean required() default true;

@FromCookie

表示引數物件來源於cookie

/**
 * cookie名稱
 */
@AliasFor(annotation = ParamAttribute.class)
String value() default "";

/**
 * cookie名稱
 */
@AliasFor(annotation = ParamAttribute.class)
String name() default "";

/**
 * 是否檢查引數
 */
@AliasFor(annotation = ParamAttribute.class)
boolean required() default true;

@FromPath

表示引數物件來源於path,支援path表示式

/**
 * path佔位符名稱
 */
@AliasFor(annotation = ParamAttribute.class)
String value() default "";

/**
 * path佔位符名稱
 */
@AliasFor(annotation = ParamAttribute.class)
String name() default "";

/**
 * 是否檢查引數
 */
@AliasFor(annotation = ParamAttribute.class)
boolean required() default true;

@FromQueryParams

表示引數來源於query部分

/**
 * query名稱
 */
@AliasFor(annotation = ParamAttribute.class)
String value() default "";

/**
 * query名稱
 */
@AliasFor(annotation = ParamAttribute.class)
String name() default "";

/**
 * 是否檢查引數
 */
@AliasFor(annotation = ParamAttribute.class)
boolean required() default true;

@FromAttribute

表示引數來源於attribute

/**
 * attribute 名稱
 */
@AliasFor(annotation = ParamAttribute.class)
String value() default "";

/**
 * attribute 名稱
 */
@AliasFor(annotation = ParamAttribute.class)
String name() default "";

/**
 * 是否檢查引數
 */
@AliasFor(annotation = ParamAttribute.class)
boolean required() default true;

配置示例

@GateWayDubbo("userService")
public interface UserService {
/**
 * 資料來源訊息體
 */
@PathMapping("/sample/registerUser")
Result registerUser(@FromBody User user);
/**
 * 物件資料來源來自header
 * @param user 使用者資訊
 * @return 結果
 */
@PathMapping(value="/sample/registerUserFromHeader",requestMethod=RequestMethod.GET)
Result registerUserFromHeader(@FromHeader("user") User user);
/**
 * 物件資料來源來自cookie
 * @param user 使用者資訊
 * @return 結果
 */
@PathMapping(value="/sample/registerUserFromCookie",requestMethod=RequestMethod.GET)
Result registerUserFromCookie(@FromCookie("user") User user);
/**
 * 物件資料來源來自path
 * @param user 使用者資訊
 * @return 結果
 */
@PathMapping(value="/sample/registerUserFromPath/{user}",requestMethod=RequestMethod.GET)
Result registerUserFromPath(@FromPath("user") User user);
/**
 * 資料來源queryParam
 * @param userId 使用者id
 * @return 取消登出結果
 */
@PathMapping(value="/sample/unRegisterUser",requestMethod=RequestMethod.GET)
Result unRegisterUser(@FromQueryParams("userId")Long userId);
/**
 * 資料來源path
 * @param userId
 * @return
 */
@PathMapping(value="/sample/getUserInfo/{userId}/{gender}",requestMethod=RequestMethod.GET)
Result getUserInfo(@FromPath("userId") Long userId,@FromPath("gender") Short gender);
/**
 * 資料來源header 和cookie
 * @param userId 使用者id
 * @param age 年齡
 * @return 返回插敘結果
 */
@PathMapping(value="/sample/getUserInfo/byHeaderAndCookie",requestMethod=RequestMethod.GET)
Result getUserInfo(@FromHeader("userId")Long userId,@FromCookie("age")Integer age);

/**
 * 全場景
 * @param userId 使用者id
 * @param age 年齡
 * @param gender 性別
 * @param user 使用者資訊
 * @return 查詢結果
 */
@PathMapping("/sample/getUserUserInfoAll/{userId}")
Result getUserUserInfoAll(@FromPath("userId") Long userId,@FromCookie("age")Integer age,@FromHeader("gender")Long gender,@FromBody User user);
}

使用步驟

第一步:按照示例改造api介面,介面需要引入dubbo-gateway-api jar包

  	<dependency>
		<groupId>com.atommiddleware</groupId>
		<artifactId>dubbo-gateway-api</artifactId>
		<version>1.0.5</version>
	</dependency>

第二步:閘道器引入改造後的jar包,同時引用以下jar包

`	<dependency>
		<groupId>com.atommiddleware</groupId>
		<artifactId>dubbo-gateway-spring-boot-starter</artifactId>
		<version>1.0.5</version>
	</dependency>`

第三步:沒有了。。就是這麼簡單

專案說明

  • dubbo-gateway-api 是核心的api,相關注解都是在此專案中定義
  • dubbo-gateway-core 核心實現,實現dubbo-gateway的相關邏輯都在此專案中
  • dubbo-gateway-spring-boot-autoconfigure dubbo-gateway的自動裝配
  • dubbo-gateway-spring-boot-starter dubbo-gateway的starter
  • dubbo-gateway-sample-api 示例服務api定義在此專案中
  • dubbo-gateway-sample-provider 基於spring cloud的dubbo 服務提供者示例
  • dubbo-gateway-sample 基於webflux(spring cloud gateway、zuul2)的接入dubbo-gateway示例
  • dubbo-gateway-sample-web-provider 基於sevlet型別的dubbo服務提供者示例
  • dubbo-gateway-sample-web-consumer 基於sevlet型別的專案(包括閘道器比如zuul-1)接入dubbo-gateway示例

配置中心

按照dubbo的正常接入配置進行配置就好了,以下貼出例子使用的配置在nacos配置中心的配置,其中filters使用了Dubbo作為過濾器

服務提供者配置:

dubbo:
  protocol:
    name: dubbo
    port: 20861
server:
  port: 8861
spring:
  cloud:
    nacos:
      discovery:
        namespace: dev
        server-addr: 127.0.0.1:8848

服務消費者配置:

dubbo:
  cloud:
    subscribed-services: dubbo-gateway-sample-provider
server:
  port: 8862
spring:
  cloud:
    nacos:
      discovery:
        namespace: dev
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: myGateway
        uri: http://127.0.0.1:8862
        predicates:
        - Path=/**
        filters:
        - Dubbo

注意:其中filters下面配的"Dubbo"表示使用的是DubboGatewayFilter去處理,如果不配置則不會生效.

其它說明

基於webflux的閘道器與基於servlet類的web應用接入整合方式是一樣的步驟,例子使用的nacos版本2.0.3,如果需要在cookie,header,url,傳遞複雜引數【非java基本型別】,需先將引數轉為json,然後使用UrlEncode進行編碼,js中可以使用encodeURIComponent進行編碼