![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiYWan5iY1MjMmlTYlVTOwQWO2YzY3QGOiN2N0EGNiRWMlZWOm9CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.gif)
Apache Dubbo 在去年釋出了下一代的雲原生微服務版本 Dubbo3,目前最新版本 Dubbo3 已在阿裡經濟體完成對 HSF2 架構的全面替換與更新,Dubbo3 目前已成為社群企業實踐推薦版本。Apache Shenyu 網關在這個背景下釋出了對 Dubbo3 服務代理的支援。
本文介紹了如何通過 Apache ShenYu 網關通路 Dubbo 服務,主要内容包括從簡單示例到核心調用流程分析,并對設計原理進行了總結。
01
介紹
Aliware
01
Apache ShenYu
Apache ShenYu(Incubating)是一個異步的,高性能的,跨語言的,響應式的 API 網關。相容各種主流架構體系,支援熱插拔,使用者可以定制化開發,滿足使用者各種場景的現狀和未來需求,經曆過大規模場景的錘煉。
2021 年 5 月,ShenYu 捐獻給 Apache 軟體基金會,Apache 基金會全票通過,順利進入孵化器。
02
Apache Dubbo
Dubbo3 是下一代的雲原生微服務架構,全面更新了包括下一代 RPC 協定、應用級服務發現、Dubbo Mesh、統一服務治理等核心能力,多語言 Java、Golang 同步釋出 3.0 特性。目前最新版本 Dubbo3 已在阿裡經濟體完成對 HSF2 架構的全面替換與更新,包括阿裡核心電商、阿裡雲、活餓了麼、釘釘、考拉等都已經全面更新 Dubbo3,2022 雙 11 大促核心系統将跑在 Dubbo3 之上,社群使用者包括工商銀行、小米、平安健康等也已成功更新 Dubbo3 核心功能。
02
Dubbo 快速開始
Aliware
本小節介紹如何将 Dubbo 服務接入到 ShenYu 網關,您可以直接在工程下找到本小節的示例代碼 。
01
啟動 shenyu-admin
shenyu-admin 是 Apache ShenYu 背景管理系統, 啟動的方式有多種,本文通過本地部署的方式啟動。啟動成功後,需要在基礎配置->插件管理中,把 dubbo 插件設定為開啟,并設定你的注冊位址,請確定注冊中心已經開啟。
02
啟動 shenyu 網關
在這裡通過源碼的方式啟動,直接運作 shenyu-bootstrap 中的 ShenyuBootstrapApplication。
在啟動前,請確定網關已經引入相關依賴。如果用戶端是 apache dubbo,注冊中心使用 zookeeper,請參考如下配置:
<!-- apache shenyu apache dubbo plugin start-->
<dependency>
<groupId>org.apache.shenyu</groupId>
<artifactId>shenyu-spring-boot-starter-plugin-apache-dubbo</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.0.8</version>
</dependency>
<!-- Dubbo zookeeper registry dependency start -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>4.0.1</version>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.1</version>
</dependency>
<!-- Dubbo zookeeper registry dependency end -->
<!-- apache dubbo plugin end-->
03
啟動 shenyu-examples-dubbo
以官網提供的例子為例 shenyu-examples-dubbo 。假如 dubbo 服務定義如下:
<beans /* ...... * />
<dubbo:application name="test-dubbo-service"/>
<dubbo:registry address="${dubbo.registry.address}"/>
<dubbo:protocol name="dubbo" port="20888"/>
<dubbo:service timeout="10000" inter ref="dubboTestService"/>
</beans>
聲明應用服務名稱,注冊中心位址,使用 dubbo 協定,聲明服務接口,對應接口實作類:
/**
* DubboTestServiceImpl.
*/
@Service("dubboTestService")
public class DubboTestServiceImpl implements DubboTestService {
@Override
@ShenyuDubboClient(path = "/findById", desc = "Query by Id")
public DubboTest findById(final String id) {
return new DubboTest(id, "hello world shenyu Apache, findById");
}
//......
}
在接口實作類中,使用注解@ShenyuDubboClient 向 shenyu-admin 注冊服務。
在配置檔案application.yml中的配置資訊:
server:
port: 8011
address: 0.0.0.0
servlet:
context-path: /
spring:
main:
allow-bean-definition-overriding: true
dubbo:
registry:
address: zookeeper://localhost:2181 # dubbo使用的注冊中心
shenyu:
register:
registerType: http #注冊方式
serverLists: http://localhost:9095 #注冊位址
props:
username: admin
password: 123456
client:
dubbo:
props:
contextPath: /dubbo
appName: dubbo
在配置檔案中,聲明 dubbo 使用的注冊中心位址,dubbo 服務向 shenyu-admin 注冊,使用的方式是 http,注冊位址是 http://localhost:9095。
關于注冊方式的使用,請參考應用用戶端接入。
04
調用 dubbo 服務
shenyu-examples-dubbo 項目成功啟動之後會自動把加 @ShenyuDubboClient 注解的接口方法注冊到網關。
打開 插件清單 -> Proxy -> dubbo 可以看到插件規則配置清單:
注冊成功的選擇器資訊:
注冊成功的規則資訊:
選擇器和規則是 Apache ShenYu 網關中最靈魂的東西。掌握好它,你可以對任何流量進行管理。對應為選擇器與規則裡面的比對條件(conditions),根據不同的流量篩選規則,我們可以處理各種複雜的場景。流量篩選可以從 Header, URI, Query, Cookie 等等 Http 請求擷取資料。
然後可以采用 Match,=,Regex,Groovy,Exclude 等比對方式,比對出你所預想的資料。多組比對添加可以使用 And/Or 的比對政策。
具體的介紹與使用請看: 選擇器與規則管理 。
發起 GET 請求,通過 ShenYu 網關調用 dubbo 服務:
GET http://localhost:9195/dubbo/findById?id=100
Accept: application/json
成功響應之後,結果如下:
{
"name": "hello world shenyu Apache, findById",
"id": "100"
}
至此,就成功的通過 http 請求通路 dubbo 服務了,ShenYu 網關通過 shenyu-plugin-dubbo 子產品将 http 協定轉成了 dubbo 協定。
03
深入了解 Dubbo 插件
Aliware
在運作上述 demo 的過程中,是否存在一些疑問:
- dubbo 服務是如何注冊到 shenyu-admin?
- shenyu-admin 是如何将資料同步到 ShenYu 網關?
- DubboPlugin 是如何将 http 協定轉換到到 dubbo 協定?
帶着這些疑問,來深入了解 dubbo 插件。
01
應用用戶端接入
應用用戶端接入是指将微服務接入到 Apache ShenYu 網關,目前支援 Http、 Dubbo、 Spring Cloud、 gRPC、 Motan、 Sofa、 Tars 等協定的接入。
将應用用戶端接入到 Apache ShenYu 網關是通過注冊中心來實作的,涉及到用戶端注冊和服務端同步資料。注冊中心支援 Http、Zookeeper、Etcd、Consul 和 Nacos。預設是通過 Http 方式注冊。
用戶端接入的相關配置請參考用戶端接入配置。
-
用戶端注冊
Apache ShenYu 網關正式支援 Dubbo3 服務代理
在你的微服務配置中聲明注冊中心用戶端類型,如 Http 或 Zookeeper。應用程式啟動時使用 SPI 方式加載并初始化對應注冊中心用戶端,通過實作 Spring Bean 相關的後置處理器接口,在其中擷取需要進行注冊的服務接口資訊,将擷取的資訊放入 Disruptor 中。
注冊中心用戶端從 Disruptor 中讀取資料,并将接口資訊注冊到 shenyu-admin,Disruptor 在其中起資料與操作解耦的作用,利于擴充。
-
服務端注冊
在 shenyu-admin 配置中聲明注冊中心服務端類型,如 Http 或 Zookeeper。當 shenyu-admin 啟動時,讀取配置類型,加載并初始化對應的注冊中心服務端,注冊中心服務端收到 shenyu-client 注冊的接口資訊後,将其放入 Disruptor 中,然後會觸發注冊處理邏輯,将服務接口資訊更新并釋出同步事件。
Disruptor 在其中起到資料與操作解耦,利于擴充。如果注冊請求過多,導緻注冊異常,也有資料緩沖作用。
02
資料同步原理
資料同步是指在 shenyu-admin 背景操作資料以後,使用何種政策将資料同步到 Apache ShenYu 網關。Apache ShenYu 網關目前支援ZooKeeper、WebSocket、Http長輪詢、Nacos 、Etcd 和 Consul 進行資料同步。預設是通過WebSocket進行資料同步。
資料同步的相關配置請參考資料同步配置。
-
資料同步的意義
網關是流量請求的入口,在微服務架構中承擔了非常重要的角色,網關高可用的重要性不言而喻。在使用網關的過程中,為了滿足業務訴求,經常需要變更配置,比如流控規則、路由規則等等。是以,網關動态配置是保障網關高可用的重要因素。
目前資料同步特性如下:
1、所有的配置都緩存在 Apache ShenYu 網關記憶體中,每次請求都使用本地緩存,速度非常快。
2、使用者可以在 shenyu-admin 背景任意修改資料,并馬上同步到網關記憶體。
3、支援 Apache ShenYu 的插件、選擇器、規則資料、中繼資料、簽名資料等資料同步。
4、所有插件的選擇器,規則都是動态配置,立即生效,不需要重新開機服務。
5、資料同步方式支援 Zookeeper、Http 長輪詢、Websocket、Nacos、Etcd 和 Consul。
-
資料同步原理分析
下圖展示了 Apache ShenYu 資料同步的流程,Apache ShenYu 網關在啟動時,會從配置服務同步配置資料,并且支援推拉模式擷取配置變更資訊,然後更新本地緩存。管理者可以在管理背景(shenyu-admin),變更使用者權限、規則、插件、流量配置,通過推拉模式将變更資訊同步給 Apache ShenYu 網關,具體是 push 模式,還是 pull 模式取決于使用哪種同步方式。
在最初的版本中,配置服務依賴 Zookeeper 實作,管理背景将變更資訊 push 給網關。而現在可以支援 WebSocket、Http長輪詢、Zookeeper、Nacos、Etcd 和 Consul,通過在配置檔案中設定 shenyu.sync.${strategy} 指定對應的同步政策,預設使用 webosocket 同步政策,可以做到秒級資料同步。但是,有一點需要注意的是,Apache ShenYu網關 和 shenyu-admin 必須使用相同的同步政策。
如上圖所示,shenyu-admin 在使用者發生配置變更之後,會通過 EventPublisher 發出配置變更通知,由 EventDispatcher 處理該變更通知,然後根據配置的同步政策(http、weboscket、zookeeper、naocs、etcd、consul),将配置發送給對應的事件處理器。
1、如果是 websocket 同步政策,則将變更後的資料主動推送給 shenyu-web,并且在網關層,會有對應的 WebsocketDataHandler 處理器來處理 shenyu-admin 的資料推送。
2、如果是 zookeeper 同步政策,将變更資料更新到 zookeeper,而 ZookeeperSyncCache 會監聽到 zookeeper 的資料變更,并予以處理。
3、如果是 http 同步政策,由網關主動發起長輪詢請求,預設有 90s 逾時時間,如果 shenyu-admin 沒有資料變更,則會阻塞 http 請求,如果有資料發生變更則響應變更的資料資訊,如果超過 60s 仍然沒有資料變更則響應空資料,網關層接到響應後,繼續發起 http 請求,反複同樣的請求。
03
流程分析
流程分析是從源碼的角度,展示服務注冊流程,資料同步流程和服務調用流程。
-
服務注冊流程
1、讀取 dubbo 服務
使用注解@ShenyuDubboClient 标記需要注冊到網關的 dubbo 服務。
注解掃描通過 ApacheDubboServiceBeanListener 完成,它實作了 ApplicationListener<ContextRefreshedEvent>接口,在 Spring 容器啟動過程中,發生上下文重新整理事件時,開始執行事件處理方法 onApplicationEvent()。在重寫的方法邏輯中,讀取 Dubbo 服務 ServiceBean,建構中繼資料對象和 URI 對象,并向 shenyu-admin 注冊。
具體的注冊邏輯由注冊中心實作,請參考用戶端接入原理。
2、處理注冊資訊
用戶端通過注冊中心注冊的中繼資料和 URI 資料,在 shenyu-admin 端進行處理,負責存儲到資料庫和同步給 shenyu 網關。Dubbo 插件的用戶端注冊處理邏輯在 ShenyuClientRegisterDubboServiceImpl 中。繼承關系如下:
- ShenyuClientRegisterService:用戶端注冊服務,頂層接口;
- FallbackShenyuClientRegisterService:注冊失敗,提供重試操作;
- AbstractShenyuClientRegisterServiceImpl:抽象類,實作部分公共注冊邏輯;
- ShenyuClientRegisterDubboServiceImpl:實作 Dubbo 插件的注冊;
注冊資訊包括選擇器,規則和中繼資料。
整體的 dubbo 服務注冊流程如下:
-
資料同步流程
1、admin 更新資料
假設在在背景管理系統中,新增一條選擇器資料,請求會進入 SelectorController 類中的 createSelector()方法,它負責資料的校驗,添加或更新資料,傳回結果資訊。
在 SelectorServiceImpl 類中通過 createOrUpdate()方法完成資料的轉換,儲存到資料庫,釋出事件,更新 upstream。
在 Service 類完成資料的持久化操作,即儲存資料到資料庫。釋出變更資料通過 eventPublisher.publishEvent()完成,這個 eventPublisher 對象是一個ApplicationEventPublisher 類,這個類的全限定名是 org.springframework.context.ApplicationEventPublisher,釋出資料的功能正是是通過 Spring 相關的功能來完成的。
當事件釋出完成後,會自動進入到 DataChangedEventDispatcher 類中的 onApplicationEvent()方法,根據不同資料類型和資料同步方式進行事件處理。
2、網關資料同步
網關在啟動時,根據指定的資料同步方式加載不同的配置類,初始化資料同步相關類。
在接收到資料後,進行反序列化操作,讀取資料類型和操作類型。不同的資料類型,有不同的資料處理方式,是以有不同的實作類。但是它們之間也有相同的處理邏輯,是以可以通過模闆方法設計模式來實作。相同的邏輯放在抽象類 AbstractDataHandler 中的 handle()方法中,不同邏輯就交給各自的實作類。
新增一條選擇器資料,是新增操作,會進入到 SelectorDataHandler.doUpdate()具體的資料處理邏輯中。
在通用插件資料訂閱者 CommonPluginDataSubscriber,負責處理所有插件、選擇器和規則資訊。
将資料儲存到網關的記憶體中,BaseDataCache 是最終緩存資料的類,通過單例模式實作。選擇器資料就存到了 SELECTOR_MAP 這個 Map 中。在後續使用的時候,也是從這裡拿資料。
上述邏輯用流程圖表示如下:
-
服務調用流程
在 Dubbo 插件體系中,類繼承關系如下:
ShenyuPlugin:頂層接口,定義接口方法;
AbstractShenyuPlugin:抽象類,實作插件共有邏輯;
AbstractDubboPlugin:dubbo插件抽象類,實作dubbo共有邏輯(ShenYu網關支援ApacheDubbo和AlibabaDubbo);
ApacheDubboPlugin:ApacheDubbo插件。
- org.apache.shenyu.web.handler.ShenyuWebHandler.DefaultShenyuPluginChain#execute()
通過 ShenYu 網關代理後,請求入口是 ShenyuWebHandler,它實作了 org.springframework.web.server.WebHandler 接口,通過責任鍊設計模式将所有插件連接配接起來。
- org.apache.shenyu.plugin.base.AbstractShenyuPlugin#execute()
當請求到網關時,判斷某個插件是否執行,是通過指定的比對邏輯來完成。在 execute()方法中執行選擇器和規則的比對邏輯。
- org.apache.shenyu.plugin.global.GlobalPlugin#execute()
最先被執行的是 GlobalPlugin ,它是一個全局插件,在 execute()方法中建構上下文資訊。
- org.apache.shenyu.plugin.base.RpcParamTransformPlugin#execute()
接着被執行的是 RpcParamTransformPlugin , 它負責從 http 請求中讀取參數,儲存到 exchange 中,傳遞給 rpc 服務。在 execute()方法中,執行該插件的核心邏輯:從 exchange 中擷取請求資訊,根據請求傳入的内容形式處理參數。
- org.apache.shenyu.plugin.dubbo.common.AbstractDubboPlugin
然後被執行的是DubboPlugin 。在 doExecute()方法中,主要是檢查中繼資料和參數。在 doDubboInvoker()方法中設定特殊的上下文資訊,然後開始dubbo的泛化調用。
在 genericInvoker()方法中:
1、擷取 ReferenceConfig 對象;
2、擷取泛化服務 GenericService 對象;
3、構造請求參數 pair 對象;
4、發起異步的泛化調用。
通過泛化調用就可以實作在網關調用 dubbo 服務了。
ReferenceConfig 對象是支援泛化調用的關鍵對象 ,它的初始化操作是在資料同步的時候完成的。
- org.apache.shenyu.plugin.response.ResponsePlugin#execute()
最後被執行的是 ResponsePlugin ,它統一處理網關的響應結果資訊。處理類型由 MessageWriter 決定,類繼承關系如下:
MessageWriter:接口,定義消息處理方法;
NettyClientMessageWriter:處理 Netty 調用結果;
RPCMessageWriter:處理 RPC 調用結果;
WebClientMessageWriter:處理 WebClient 調用結果;
Dubbo 服務調用,處理結果是 RPCMessageWriter。
- org.apache.shenyu.plugin.response.strategy.RPCMessageWriter#writeWith()
在 writeWith()方法中處理響應結果,擷取結果或處理異常。
分析至此,關于 Dubbo 插件的源碼分析就完成了,分析流程圖如下:
04
小結
Aliware
本文從實際案例出發,由淺入深分析了 ShenYu 網關對 Dubbo 服務的代理過程。涉及到的主要知識點如下:
- 通過責任鍊設計模式執行插件;
- 使用模闆方法設計模式實作 AbstractShenyuPlugin,處理通用的操作類型;
- 使用單例設計模式實作緩存資料類 BaseDataCache;
- 通過 springboot starter 即可引入不同的注冊中心和數同步方式,擴充性很好;
- 通過 admin 支援規則熱更新,友善流量管控;
- Disruptor 隊列是為了資料與操作解耦,以及資料緩沖。
有任何疑問,歡迎通過以下管道聯系社群:
- Apache Shenyu 社群:
https://github.com/apache/incubator-shenyu
- Dubbo3 社群:
https://github.com/apache/dubbo https://github.com/apache/dubbo
企業使用者可搜尋釘釘群 34129986
作者簡介
劉良:Apache ShenYu PPMC
往期回顧
Dubbo3 落地實踐及 Mesh 解決方案
Nacos 2.1.0 版本釋出,支援鑒權及加解密插件
OpenSergo 正式開源,多家廠商共建微服務治理規範和實作