天天看點

Apache ShenYu 網關正式支援 Dubbo3 服務代理

Apache ShenYu 網關正式支援 Dubbo3 服務代理

Apache Dubbo 在去年釋出了下一代的雲原生微服務版本 Dubbo3,目前最新版本 Dubbo3 已在阿裡經濟體完成對 HSF2 架構的全面替換與更新,Dubbo3 目前已成為社群企業實踐推薦版本。Apache Shenyu 網關在這個背景下釋出了對 Dubbo3 服務代理的支援。

本文介紹了如何通過 Apache ShenYu 網關通路 Dubbo 服務,主要内容包括從簡單示例到核心調用流程分析,并對設計原理進行了總結。

Apache ShenYu 網關正式支援 Dubbo3 服務代理

01

介紹

Aliware

01

Apache ShenYu

Apache ShenYu 網關正式支援 Dubbo3 服務代理

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 插件設定為開啟,并設定你的注冊位址,請確定注冊中心已經開啟。

Apache ShenYu 網關正式支援 Dubbo3 服務代理

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 網關正式支援 Dubbo3 服務代理

注冊成功的選擇器資訊:

Apache ShenYu 網關正式支援 Dubbo3 服務代理

注冊成功的規則資訊:

Apache ShenYu 網關正式支援 Dubbo3 服務代理

選擇器和規則是 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 在其中起資料與操作解耦的作用,利于擴充。

  • 服務端注冊

Apache ShenYu 網關正式支援 Dubbo3 服務代理

在 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 模式取決于使用哪種同步方式。

Apache ShenYu 網關正式支援 Dubbo3 服務代理

在最初的版本中,配置服務依賴 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 中。繼承關系如下:

Apache ShenYu 網關正式支援 Dubbo3 服務代理
  • ShenyuClientRegisterService:用戶端注冊服務,頂層接口;
  • FallbackShenyuClientRegisterService:注冊失敗,提供重試操作;
  • AbstractShenyuClientRegisterServiceImpl:抽象類,實作部分公共注冊邏輯;
  • ShenyuClientRegisterDubboServiceImpl:實作 Dubbo 插件的注冊;

注冊資訊包括選擇器,規則和中繼資料。

整體的 dubbo 服務注冊流程如下:

Apache ShenYu 網關正式支援 Dubbo3 服務代理
  • 資料同步流程

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 中。在後續使用的時候,也是從這裡拿資料。

上述邏輯用流程圖表示如下:

Apache ShenYu 網關正式支援 Dubbo3 服務代理
  • 服務調用流程

在 Dubbo 插件體系中,類繼承關系如下:

Apache ShenYu 網關正式支援 Dubbo3 服務代理

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 決定,類繼承關系如下:

Apache ShenYu 網關正式支援 Dubbo3 服務代理

MessageWriter:接口,定義消息處理方法;

NettyClientMessageWriter:處理 Netty 調用結果;

RPCMessageWriter:處理 RPC 調用結果;

WebClientMessageWriter:處理 WebClient 調用結果;

Dubbo 服務調用,處理結果是 RPCMessageWriter。

  • org.apache.shenyu.plugin.response.strategy.RPCMessageWriter#writeWith()

在 writeWith()方法中處理響應結果,擷取結果或處理異常。

分析至此,關于 Dubbo 插件的源碼分析就完成了,分析流程圖如下:

Apache ShenYu 網關正式支援 Dubbo3 服務代理

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 正式開源,多家廠商共建微服務治理規範和實作