Apache ShenYu 閘道器正式支援 Dubbo3 服務代理
作者:劉良
Apache Dubbo 在去年釋出了下一代的雲原生微服務版本 Dubbo3,目前最新版本 Dubbo3 已在阿里經濟體完成對 HSF2 框架的全面替換與升級,Dubbo3 目前已成為社群企業實踐推薦版本。Apache Shenyu 閘道器在這個背景下發布了對 Dubbo3 服務代理的支援。
本文介紹瞭如何通過 Apache ShenYu 閘道器訪問 Dubbo 服務,主要內容包括從簡單示例到核心呼叫流程分析,並對設計原理進行了總結。
介紹
Apache ShenYu
Apache ShenYu(Incubating)是一個非同步的,高效能的,跨語言的,響應式的 API 閘道器。相容各種主流框架體系,支援熱插拔,使用者可以定製化開發,滿足使用者各種場景的現狀和未來需求,經歷過大規模場景的錘鍊。
2021 年 5 月,ShenYu 捐獻給 Apache 軟體基金會,Apache 基金會全票通過,順利進入孵化器。
Apache Dubbo
Dubbo3 是下一代的雲原生微服務框架,全面升級了包括下一代 RPC 協議、應用級服務發現、Dubbo Mesh、統一服務治理等核心能力,多語言 Java、Golang 同步釋出 3.0 特性。目前最新版本 Dubbo3 已在阿里經濟體完成對 HSF2 框架的全面替換與升級,包括阿里核心電商、阿里雲、活餓了麼、釘釘、考拉等都已經全面升級 Dubbo3,2022 雙 11 大促核心系統將跑在 Dubbo3 之上,社群使用者包括工商銀行、小米、平安健康等也已成功升級 Dubbo3 核心功能。
Dubbo 快速開始
本小節介紹如何將 Dubbo 服務接入到 ShenYu 閘道器,您可以直接在工程下找到本小節的示例程式碼 。
啟動 shenyu-admin
shenyu-admin 是 Apache ShenYu 後臺管理系統, 啟動的方式有多種,本文通過本地部署的方式啟動。啟動成功後,需要在基礎配置->外掛管理中,把 dubbo 外掛設定為開啟,並設定你的註冊地址,請確保註冊中心已經開啟。
啟動 shenyu 閘道器
在這裡通過原始碼的方式啟動,直接執行 shenyu-bootstrap 中的 ShenyuBootstrapApplication。
在啟動前,請確保閘道器已經引入相關依賴。如果客戶端是 apache dubbo,註冊中心使用 zookeeper,請參考如下配置:
```
<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-->
```
啟動 shenyu-examples-dubbo
以官網提供的例子為例 shenyu-examples-dubbo 。假如 dubbo 服務定義如下:
```
<dubbo:application name="test-dubbo-service"/>
<dubbo:registry address="${dubbo.registry.address}"/>
<dubbo:protocol name="dubbo" port="20888"/>
<dubbo:service timeout="10000" interface="org.apache.shenyu.examples.dubbo.api.service.DubboTestService" ref="dubboTestService"/>
```
宣告應用服務名稱,註冊中心地址,使用 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。關於註冊方式的使用,請參考應用客戶端接入。
呼叫 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 協議。
深入理解 Dubbo 外掛
在執行上述 demo 的過程中,是否存在一些疑問:
- dubbo 服務是如何註冊到 shenyu-admin?
- shenyu-admin 是如何將資料同步到 ShenYu 閘道器?
- DubboPlugin 是如何將 http 協議轉換到到 dubbo 協議?
帶著這些疑問,來深入理解 dubbo 外掛。
應用客戶端接入
應用客戶端接入是指將微服務接入到 Apache ShenYu 閘道器,當前支援 Http、 Dubbo、 Spring Cloud、 gRPC、 Motan、 Sofa、 Tars 等協議的接入。
將應用客戶端接入到 Apache ShenYu 閘道器是通過註冊中心來實現的,涉及到客戶端註冊和服務端同步資料。註冊中心支援 Http、Zookeeper、Etcd、Consul 和 Nacos。預設是通過 Http 方式註冊。
客戶端接入的相關配置請參考客戶端接入配置。
- 客戶端註冊
在你的微服務配置中宣告註冊中心客戶端型別,如 Http 或 Zookeeper。應用程式啟動時使用 SPI 方式載入並初始化對應註冊中心客戶端,通過實現 Spring Bean 相關的後置處理器介面,在其中獲取需要進行註冊的服務介面資訊,將獲取的資訊放入 Disruptor 中。
註冊中心客戶端從 Disruptor 中讀取資料,並將介面資訊註冊到 shenyu-admin,Disruptor 在其中起資料與操作解耦的作用,利於擴充套件。
- 服務端註冊
在 shenyu-admin 配置中宣告註冊中心服務端型別,如 Http 或 Zookeeper。當 shenyu-admin 啟動時,讀取配置型別,載入並初始化對應的註冊中心服務端,註冊中心服務端收到 shenyu-client 註冊的介面資訊後,將其放入 Disruptor 中,然後會觸發註冊處理邏輯,將服務介面資訊更新併發布同步事件。
Disruptor 在其中起到資料與操作解耦,利於擴充套件。如果註冊請求過多,導致註冊異常,也有資料緩衝作用。
資料同步原理
資料同步是指在 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 請求,反覆同樣的請求。
流程分析
流程分析是從原始碼的角度,展示服務註冊流程,資料同步流程和服務呼叫流程。
- 服務註冊流程
1、讀取 dubbo 服務
使用註解@ShenyuDubboClient 標記需要註冊到閘道器的 dubbo 服務。
註解掃描通過 ApacheDubboServiceBeanListener 完成,它實現了 ApplicationListener
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 外掛的原始碼分析就完成了,分析流程圖如下:
小結
本文從實際案例出發,由淺入深分析了 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
- KubeVela 1.4:讓應用交付更安全、上手更簡單、過程更透明
- 函式計算非同步任務能力介紹 - 任務觸發去重
- 雲原生混部最後一道防線:節點水位線設計
- 深度解讀 RocketMQ 儲存機制
- 程式碼註釋的藝術,優秀程式碼真的不需要註釋嗎?
- 「技術人生」第8篇:如何畫業務大圖
- 函式計算非同步任務能力介紹 - 任務觸發去重
- 程式碼註釋的藝術,優秀程式碼真的不需要註釋嗎?
- 上篇:技術架構的設計方法
- 下篇:技術 Leader 的思考方式
- RocketMQ 5.0: 儲存計算分離新思路
- 從原理到操作,讓你在 Apache APISIX 中代理 Dubbo3 服務更便捷
- 成本節省 50%,10 人團隊使用函式計算開發 wolai 線上文件應用
- Apache ShenYu 閘道器正式支援 Dubbo3 服務代理
- 談談技術能力
- Dubbo3 落地實踐及 Mesh 解決方案
- Dubbo3 落地實踐及 Mesh 解決方案
- 使用 Nocalhost 與 KubeVela 端雲聯調,一鍵完成多叢集混合雲環境部署
- 如何在雲原生混部場景下利用資源配額高效分配叢集資源?
- 招商銀行 KubeVela 離線部署實踐