dubbo-gateway 高性能dubbo網關
- 2022 年 1 月 24 日
- 筆記
- Dubbo, Gateway, Spring Cloud
dubbo-gateway
dubbo-gateway 提供了http協議到dubbo協議的轉換,但【並非】使用dubbo的【泛化】調用(泛化調用性能比普通調用有10-20%的損耗,通過普通非同步的調用方式與基於webflux系列的響應式網關整合提高系統的吞吐量,普通調用需要依賴api jar包,需要對介面定義進行改造,除此之外不需要做任何其它改造.另外也支援基於servlet類的應用或網關進行整合
泛化缺點
- 泛化過程數據流會經過了三次轉換, 會產生大量的臨時對象, 有很大的記憶體要求。使用反射方式對於旨在榨乾伺服器性能以獲取高吞吐量的系統來說, 難以達到性能最佳
- 同時服務端也會對泛化請求多一重 Map <-> POJO 的來迴轉換的過程。整體上,與普通的Dubbo調用相比有10-20%的損耗
- 泛化調用在網關或服務消費者階段無法校驗參數類型的有效性,數據要到服務提供者反序列化時才能校驗出參數類型的有效性
開源地址
相關註解
@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: //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進行編碼