Dubbo 跨語言調用神獸:dubbo-go-pixiu

簡介: Pixiu 是基於 Dubbogo 的雲原生、高性能、可擴展的微服務 API 網關。做爲一款網關產品,Pixiu 幫助用戶輕鬆建立、發佈、維護、監控和保護任意規模的 API ,接受和處理成千上萬個併發 API 調用,包括流量管理、 CORS 支持、受權和訪問控制、限制、監控,以及 API 版本管理。git

Pixiu 是什麼


在回答 Pixiu 是什麼以前,咱們簡單解釋一下 Dubbo 是什麼。Dubbo 是一個開源的高性能 RPC 框架,有着豐富的服務治理能力以及優秀的擴展能力。Dubbo 更擴展出 Dubbo-go​,爲用戶提供了 Golang 的 Dubbo 解決方案,打通了兩種語言之間的隔閡,使 Dubbo 更加貼近雲原生。github

image.png
Dubbo-go 做爲 Golang 服務,實現與 Dubbo 服務之間的相互調用。然而,在平常使用場景中,用戶每每有把 Dubbo 服務以 RESTful 風格向外暴露的需求同時也要兼顧內部 Dubbo 調用。爲了解決這種場景,做爲 Dubbo API 網關的 Pixiu​ (中文: 貔貅, 曾用名 dubbo-go-proxy) 便應運而生。之因此採用 Pixiu 這個名稱,是由於 Java 同類產品 Zuul 的意象是一個西方怪獸,Pixiu 做爲一個國產產品,就用了咱們中國的一個相似的神獸貔貅做爲項目名稱。也同時表達了 Dubbo 社區但願擴展出一整套雲原生生態鏈的決心。
golang

目前 Dubbo 多語言生態,發展最好的天然是 Java,其次是 Golang,其餘語言都差強人意。dubbo-go-pixiu 項目是一個基於 dubbo-go 發展起來的項目,目前接口協議層支持的是七層的 HTTP 請求調用,計劃在將來的 0.5 版本中支持 gRPC 請求調用,其另一個使命是做爲一種新的 dubbo 多語言解決方案。segmentfault

爲何使用 Pixiu


Pixiu 是基於 Dubbogo 的雲原生、高性能、可擴展的微服務 API 網關。做爲一款網關產品,Pixiu 幫助用戶輕鬆建立、發佈、維護、監控和保護任意規模的 API ,接受和處理成千上萬個併發 API 調用,包括流量管理、 CORS 支持、受權和訪問控制、限制、監控,以及 API 版本管理。除此之外,做爲 Dubbo 的衍生產品,Pixiu能夠幫助 Dubbo 用戶進行協議轉換,實現跨系統、跨協議的服務能力互通。
後端

Pixiu 的總體設計遵照如下原則:
服務器

High performance: 高吞吐量以及毫秒級的延時。
可擴展: 經過 go-plugin,用戶能夠根據本身的需求延展 Pixiu 的功能。
簡單可用: 用戶經過少許配置,便可上線。架構

Pixiu 的特性及核心功能


爲 RESTful API 和 Dubbo API 提供支持
併發

非 RESTful 風格的 API 和 Dubbo 協議的服務每每須要修改才能夠以 RESTful API 風格對外開放。Pixiu 提供協議轉換功能,經過 Pixiu,開發者能夠將本身的 HTTP API 或 Dubbo API 經過配置,以 RESTful API 風格對外開放。v0.2.1 版本已支持基於泛化調用的 HTTP 至 Dubbo 的協議轉換以及 HTTP 協議的轉發。在後續的版本,社區將會增長對 gRPC 和 http2 協議的支持。
app

面向用戶的配置方式
框架

通常的網關的配置每每繁瑣且複雜。Pixiu,目標做爲一款易用的網關產品,在設計上擁有三層配置層級,Gateway 層全局配置, API resource 層配置以及 HTTP verbs 方法層配置。經過三個不一樣層級的配置,既能夠實現深度的定製,亦支持統一的默認配置;同時,支持本地的配置文件,亦可以使用統一配置服務器。另外,還提供控制檯模塊,經過控制檯模塊,支持配置的熱更新。Pixiu 配套配套的控制檯界面也在同步開發中。

通用功能的集成

重試、熔斷、流量控制、訪問控制等通用功能再也不須要在每一個後端服務上重複實現。使用 Pixiu,經過配置 filter ,開發者能夠進行全局的控制,亦能夠根據 API 配置各自的規則。所以開發者能夠專一於業務邏輯和服務,而不是將時間用在維護基礎設施上。

可擴展

不一樣的使用場景有着各自獨特的需求。爲知足不一樣用戶的定製化需求,Pixiu 使用了插件模式。開發者能夠經過編寫 go plugin,將自身特有的業務邏輯以 filter 形式內嵌至 Pixiu 網關中,實現諸如企業登陸鑑權等功能。

image.png
圖 1: Pixiu 核心功能列表

Pixiu 的架構設計

image.png
圖 2: Pixiu 架構

貔貅: 即 dubbo-go-pixiu,由四個主要模塊:Listener、Router、Filters 和 Clients 組成;

Dubbo Cluster: Dubbo 服務所在集羣,包含一個或多個 Dubbo Services;

Other Cluster: Dubbo 之外的服務所在集羣,現支持 HTTP 服務,將來將拓展支持 gRPC 等其餘服務;

Registry Center: 註冊中心,維護每一個業務服務的調用地址信息;

Metadata Center: 元數據中心,維護每一個業務服務的配置信息以及存儲 Pixiu 自己的配置信息。

做爲 Dubbo 所衍生的 API 網關,Pixiu 使用 Golang 搭建,主要由於: 1. Golang 的 G-M-P,net poller 等特性使 Golang 很是適合構建IO密集型應用;2. 使用 Golang 能夠直接引入 Dubbo-go 中的一些組建,簡化開發。

整個Pixiu大體能夠拆分爲四個主要模塊:Listener、Router、Filters 和 Client。

一、Listener

在 Pixiu 中,Listener 表明外部能夠訪問Pixiu的方式。經過配置指定協議類型,地址,端口等屬性,暴露 Gateway。現階段暫支持 HTTP 協議,將來將會加入 gRPC。

listeners: 
  - name: "net/http" 
    address: 
      socket_address: 
        protocol_type: "HTTP" 
        address: "0.0.0.0" 
        port: 8888 
    config: 
      idle_timeout: 5s 
      read_timeout: 5s 
      write_timeout: 5s

二、Router

Router 是 Pixiu 的路由組件。根據配置文件,Pixiu 將對外暴露的 URLs 以樹的形勢存儲於內存中,當請求到了 router 組件時,即會根據 URL 及 HTTP 方法查找到對應的後端服務及其 API 配置,並將信息封裝於請求中,爲後續 filter,及 client 的調用提供足夠的內容。

現階段,Router 提供如下功能:

  • 支持請求一對一轉發路由配置或 wildcard 路由配置。
  • 支持 HTTP 請求的轉發到後端 HTTP 服務。
  • 支持 HTTP 請求轉化爲 dubbo 泛化調用請求。

三、Filters

Filter 是 Pixiu 實現額外功能及其擴展性的主要組件。其實現相似於 Dubbo-go 中的 filter,根據配置中 filter 的指定,生成調用鏈,從而在調用後端服務前,將各 filter 中的邏輯運行一遍,實現節流,日誌等功能。

用戶若是須要客製化的 filter,可經過編寫 go-plugin 實現。在配置中,可經過相似以下配置,加載 .so文件,並在 API config 中指定使用的 plugin group,plugin name 實現。

pluginFilePath: "" 
pluginsGroup: 
  - groupName: "group1" 
    plugins: 
      - name: "rate limit" 
        version: "0.0.1" 
        priority: 1000 
        externalLookupName: "ExternalPluginRateLimit" 
      - name: "access" 
        version: "0.0.1" 
        priority: 1000 
        externalLookupName: "ExternalPluginAccess" 
  - groupName: "group2" 
    plugins: 
      - name: "blacklist" 
        version: "0.0.1" 
        priority: 1000 
        externalLookupName: "ExternalPluginBlackList"

四、Client

Client 負責調用具體服務。現階段,Pixiu 支持 HTTP 與 Dubbo 的後端服務。社區將逐漸增長 gRPC 等其餘 Client 以知足不一樣的協議。

HTTP client 的實現相對簡單,根據 Router 中獲取的後端服務信息,經過 Golang 官方包 net/http 生成請求並調用。

Dubbo client 的實現對比 HTTP client 會稍微複雜,其基礎爲 Dubbo 服務的泛化調用。泛化調用技術是 Dubbo 提供的一個很基礎的功能只須要知道調用的方法名、參數類型和返回值類型,便可發起服務調用。客戶端對服務端的泛化調用既能夠經過註冊中心發現服務,也能夠直連服務端,實現對服務的動態調用。

以下面代碼所示,Pixiu 經過動態配置 referenceConfig,而後經過 GetRPCService 生成 Dubbo 的 Generic Client(泛化調用客戶端)進行下一步的調用。

referenceConfig := dg.NewReferenceConfig(irequest.Interface, context.TODO())
  referenceConfig.InterfaceName = irequest.Interface
  referenceConfig.Cluster = constant.DEFAULT_CLUSTER
  var registers []string
  for k := range dgCfg.Registries {
    registers = append(registers, k)
  }
  referenceConfig.Registry = strings.Join(registers, ",")

  if len(irequest.DubboBackendConfig.Protocol) == 0 {
    referenceConfig.Protocol = dubbo.DUBBO
  } else {
    referenceConfig.Protocol = irequest.DubboBackendConfig.Protocol
  }

  referenceConfig.Version = irequest.DubboBackendConfig.Version
  referenceConfig.Group = irequest.Group
  referenceConfig.Generic = true
  if len(irequest.DubboBackendConfig.Retries) == 0 {
    referenceConfig.Retries = "3"
  } else {
    referenceConfig.Retries = irequest.DubboBackendConfig.Retries
  }
  dc.lock.Lock()
  defer dc.lock.Unlock()
  referenceConfig.GenericLoad(key)
  clientService := referenceConfig.GetRPCService().(*dg.GenericService)

實際上,在泛化調用的客戶端中,實際執行泛化調用的關鍵步驟是 Dubbo-go 中的 generic_filter (以下代碼片斷)。在調用 generic_filter 的 Invoke 時,約定 invocation 參數列表第一個爲方法名,第二個爲參數類型列表,第三個爲參數值列表。generic_filter 將用戶請求的參數值列表轉化爲統一格式的 map(代碼中的 struct2MapAll ),將類( golang 中爲 struct )的正反序列化操做變成 map 的正反序列化操做。這使得無需 POJO 描述經過硬編碼注入 hessain 庫,從而完成 Dubbo 服務的泛化調用。

func (ef *GenericFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
  if invocation.MethodName() == constant.GENERIC && len(invocation.Arguments()) == 3 {
    oldArguments := invocation.Arguments()
    if oldParams, ok := oldArguments[2].([]interface{}); ok {
      newParams := make([]hessian.Object, 0, len(oldParams))
      for i := range oldParams {
        newParams = append(newParams, hessian.Object(struct2MapAll(oldParams[i])))
      }
      newArguments := []interface{}{
        oldArguments[0],
        oldArguments[1],
        newParams,
      }
      newInvocation := invocation2.NewRPCInvocation(invocation.MethodName(), newArguments, invocation.Attachments())
      newInvocation.SetReply(invocation.Reply())
      return invoker.Invoke(ctx, newInvocation)
    }
  }
  return invoker.Invoke(ctx, invocation)
}
​

總結


經過上面的四個模塊以及註冊中心的簡單介紹不難發現,當請求經過 listener 被 Pixiu 接收後,請求被傳入 router 中。router 根據接口的配置,從原請求中找到目標後端服務連同相關API配置下發到 filter 組件。filter 組件根據原請求、 API 配置等信息順序執行,最終請求到達 client, 經過 client 調用後端服務。

Pixiu的將來

image.png
圖 3: Pixiu 迭代里程碑

Pixiu 做爲網關產品外,其衍生項目也會在咱們的將來計劃中,主要目的是提供更好的可用性。例如,因爲 Golang 語言缺少原生的註解, 所以 Dubbo-go 須要經過配置文件方式生成服務的元數據寫入註冊中心。開課啦教育公司相關同窗寫了一個掃描代碼的工具 _https://github.com/jack15083/...,在每一個 RPC 服務方法前加上對應的註釋,從而在服務啓動前經過掃描註釋生成元數據。Pixiu 也計劃在將來的版本上經過提供 package,容許服務經過註釋藉助 _https://github.com/MarcGrol/g... _生成 API 配置並註冊到 Pixiu 上。

Pixiu 目前的定位是一個七層協議網關,其最第一版本是被定義成一個 Dubbo 的服務網關。做爲雲時代的產品,Pixiu 的發展方向必然是面向雲原生的。如今的版本爲0.2.1, 已經實現基本的 Dubbo/Http 服務代理和部分的網關通用功能。目前正在開發中的 0.4 及其後續版本支持 gRPC 和 Spring Cloud 服務調用, 後續還將提供 MQ 服務支持。另外,社區將繼續優化配置方式,下降用戶的使用難度,繼續優化官方的 filter,使 Pixiu 能夠在官方層面實現更多的網關通用功能。

image.png

在將來的一年內,社區計劃支持 xDS API,將 Pixiu 演化爲 Dubbo mesh 的 sidecar。其最終目的就是:在現有的 dubbo mesh 形態中演化出 Proxy Service Mesh 形態。基於這個形態,Js、Python、PHP、Ruby 和 Perl 等腳本語言程序除了收穫 dubbo mesh 原有的技術紅利以外,大機率還能收穫性能上的提高。

Pixiu 在 Dubbo Mesh 中的終極目的是:把東西向和南北向數據面流量逐步統一 Pixiu 中的同時,讓它逐步具有 Application Runtime 的能力,做爲 Dubbo 多語言生態的關鍵解決方案。

馮振宇,Apache Dubbo Committer,目前負責管理香港一家消費品公司的IT部門整個團隊。2020 年夏天 偶然看到了介紹 dubbogo 的文章後加入了 dubbogo 社區,目前在主導 Pixiu 0.4.0 版本的開發。

原文連接

本文爲阿里雲原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索