Go語言微服務框架重磅升級:dubbo-go v3.2.0 -alpha 版本預覽

隨着 Dubbo3 在雲原生微服務方向的快速發展,Dubbo 的 go 語言實現迎來了 Dubbo3 版本以來最全面、最大幅度的一次升級,這次升級是全方位的,涉及 API、協議、流量管控、可觀測能力等。總的來說,新版本的 dubbo-go:

  • 全面升級 Triple 協議,兼容 gRPC、標準 HTTP 客戶端,提供簡單明瞭的 API 用於編寫 RPC server 與 client,解決組件間的基本通信問題。
  • 針對微服務場景,提供了完善的服務治理能力,這包括配置管理、可觀測性、流量管控規則、生態集成與適配等的全面升級。

全新升級的 Triple 協議

基於 dubbo-go 實現的 Triple 協議,你可以輕鬆編寫瀏覽器、gRPC 兼容的 RPC 服務,並讓這些服務同時運行在 HTTP/1 和 HTTP/2 上。

如上圖所示,你可以使用 "http+json" 的標準形式訪問 dubbo-go 發佈的後端 triple 服務,基於這一特性, 我們可以在 dubbo 客戶端在瀏覽器頁面、移動設備上訪問後端服務,使用標準 cURL 工具訪問服務,也可以讓比如 Spring 體系的應用輕鬆的調通 Dubbo 服務。

由於 Triple 協議完全兼容 gRPC 協議,Dubbo 後端服務有可以直接調通標準的 gRPC 服務,它們之間可以無縫的互通,不論是 unary 還是 streaming 通信模式。

發佈一個 triple rpc 服務

爲了體驗升級後的 triple 協議,我們接下來會嘗試啓動一個 dubbo-go server,併發佈一個基於 triple 協議的服務。

創建一個新的 server 並啓動 server,它將在指定的端口監聽 triple 協議請求。

func main() {
  srv, err := server.NewServer(
    server.WithServerProtocol(
      protocol.WithTriple(),
      protocol.WithPort(50051),
    ),
  )
  if err != nil {
    panic(err)
  }
  if err := greettriple.RegisterGreetServiceHandler(srv, &api.GreetTripleServer{}); err != nil {
    panic(err)
  }
  if err := srv.Serve(); err != nil {
    panic(err)
  }
}

cURL 訪問服務

Triple 服務啓動完成之後,最簡單方式是使用 HTTP/1.1 POST 訪問服務,參數則作以標準 JSON 格式作爲 HTTP 負載傳遞。如下是使用 cURL 命令的訪問示例:

curl \
    --header "Content-Type: application/json" \
    --data '{"name": "Dubbo"}' \
    http://localhost:50051/greet.GreetService/Greet

Triple 協議的一項重大升級是支持標準 http 工具直接訪問,通過 cURL 可以極大的降低 dubbo-go 服務的測試驗證、前端接入成本。

簡單明瞭的 API

Dubbo Go SDK 支持使用 IDL 或編程語言特有的方式定義服務,並提供一套輕量的 API 來發布或調用這些服務。在上一節的示例中,我們已經看到了部分 dubbo-go API 的使用方式,接下來,讓我們更仔細全面的看一下新版本的 API 設計。

RPC Server 與 Client

對於一些 RPC 通信的場景,開發者只需要使用 dubbo-go 編寫一個最簡單的 RPC server 或者 RPC client,這在新版本 dubbo-go 中只需要幾行代碼即可完成。

通常,我們會使用 Protocol Buffer (IDL) 來定義一個 Dubbo 服務。

syntax = "proto3";
package greet;

message GreetRequest {
  string name = 1;
}

message GreetResponse {
  string greeting = 1;
}

service GreetService {
  rpc Greet(GreetRequest) returns (GreetResponse) {}
}

使用 Protocol Buffers Compiler 從 IDL 生成 stub 代碼(篇幅關係,我們不在此展示,具體請參見官網 dubbo-go 快速開始)。接下來,我們實現 greettriple.GreeterClient 接口並提供自定義服務實現。

type GreeterServer struct {
}

func (s *GreeterServer) SayHello(ctx context.Context, in *greet.HelloRequest) (*greet.User, error) {
  return &greet.User{Name: "Hello " + in.Name, Id: "12345", Age: 21}, nil
}

以下是一個簡單的 RPC server 示例,執行協議信息,並註冊服務到 server 中:

func main() {
  srv, err := server.NewServer(
    server.WithServer_Protocol(
      protocol.WithTriple(),
      protocol.WithPort(50052),
    ),
  )
  if err != nil {
    panic(err)
  }
  if err := greettriple.RegisterGreetServiceHandler(srv, &api.GreetTripleServer{}); err != nil {
    panic(err)
  }
  if err := srv.Serve(); err != nil {
    panic(err)
  }
}

如前面 Triple 協議一節所述,你可以使用 cURL 直接測試以上 server 服務運行正常。與此同時,對應的 RPC client 示例如下:

func main() {
  // for the most brief RPC case
  cli, err := client.NewClient(
    client.WithURL("tri://127.0.0.1:50052"),
  )
  if err != nil {
    panic(err)
  }
  svc, err := greettriple.NewGreetService(cli)
  if err != nil {
    panic(err)
  }

  common.TestClient(svc)
}

微服務開發

如果你正在開發微服務應用,那麼除了 RPC 通信之外,你通常還需要爲應用配置一些服務治理能力,比如 retistry 註冊中心、配置中心、可觀測能力等。

以下展示瞭如何使用 dubbo-go 開發一個微服務應用。

首先,創建一個代表微服務的應用 Server,將服務註冊給它,添加註冊中心等服務治理配置。

func main() {
  // configure global configurations and common modules
  ins, err := dubbo.NewInstance(
    dubbo.WithName("dubbo_test"),
    dubbo.WithRegistry(
      registry.WithZookeeper(),
      registry.WithAddress("127.0.0.1:2181"),
    ),
    dubbo.WithProtocol(
      protocol.WithTriple(),
      protocol.WithPort(50052),
    ),
  )
    // create a server with registry and protocol set above
  srv, err := ins.NewServer()
  if err != nil {
    panic(err)
  }
    // register a service to server
  if err := greettriple.RegisterGreetServiceHandler(srv, &api.GreetTripleServer{}); err != nil {
    panic(err)
  }
    // start the server
  if err := srv.Serve(); err != nil {
    panic(err)
  }
}

其中,Instance 是我們在新版本中引入的全局配置,你可以將所有微服務全局配置在這裏進行初始化。這裏,我們設置了微服務通信協議 protocol 和註冊中心 registry,如以下代碼片段所示:

ins, err := dubbo.NewInstance(
    dubbo.WithName("dubbo_test"),
    dubbo.WithRegistry(
        registry.WithZookeeper(),
        registry.WithAddress("127.0.0.1:2181"),
    ),
    dubbo.WithProtocol(
        protocol.WithTriple(),
        protocol.WithPort(50052),
    ),
)

接下來的操作就非常簡單明瞭了,我們創建一個 server,將服務註冊給它並啓動,如下所示。如果有更多的服務,則可以依次註冊到 server 後再啓動。

// create a server with registry and protocol set above
srv, err := ins.NewServer()
// register a service to server
if err := greettriple.RegisterGreetServiceHandler(srv, &api.GreetTripleServer{}); err != nil {
    panic(err)
}
// start the server
if err := srv.Serve(); err != nil {
    panic(err)
}

以上就是一個微服務應用的基本開發過程,如果你的微服務應用要調用一些遠程 Dubbo 服務,那麼你只需要參照以下方式創建一個 client 就行了。

下面的代碼示例創建了一個 client,緊接着生成了一個 GreetService 遠程服務代理,之後,就可以像調用本地方法一樣調用遠端 Dubbo 服務了。client 將基於註冊中心實現 server 實例的自動發現並自動爲流量應用負載均衡策略。

func main() {
  // configure global configurations and common modules
  ins, err := dubbo.NewInstance(
    dubbo.WithName("dubbo_test"),
    dubbo.WithRegistry(
      registry.WithZookeeper(),
      registry.WithAddress("127.0.0.1:2181"),
    ),
  )
  
  // configure the params that only client layer cares
  cli, err := ins.NewClient()
  if err != nil {
    panic(err)
  }

  svc, err := greettriple.NewGreetService(cli)
  if err != nil {
    panic(err)
  }

  resp, err := svc.Greet(context.Background(), &greet.GreetRequest{Name: "triple"})
  if err != nil {
    return err
  }
  logger.Infof("TRIPLE unary call resp: %s", resp.Greeting)
}

企業級服務治理能力

動態配置

除了 API 模式之外,Dubbo-go 支持基於配置文件驅動的編碼方式,這對於一些更大規模的微服務開發場景非常適用。在這種模式下,我們將 registry、protocol 等組件配置,甚至包括服務聲明等都放在 dubbogo.yml 文件中,框架會在啓動過程中完成配置文件加載。

以下是一個基於 dubbogo.yml 的微服務應用的開發示例:

其中,server.go 定義如下:

func main() {
  greettriple.SetProviderService(&GreeterServiceImpl{})
  if err := dubbo.Load(); err != nil {
    panic(err)
  }
}

dubbogo.yml 示例內容如下:

dubbo:
  application: # 應用信息,服務啓動後會將相關信息註冊到註冊中心,可被客戶端從 url 中識別
    name: myApp
  registries:
    nacos:
      protocol: nacos # 註冊中心選擇 nacos 
      address: 127.0.0.1:8848 # nacos ip
      group: DEFAULT_GROUP # nacos group, 默認 DEFAULT_GROUP
      namespace: 9fb00abb-278d-42fc-96bf-e0151601e4a1 # nacos namespaceID, should be created before. 默認public
      username: abc
      password: abc
  protocols:
    dubbo:
      name: tri
      port: 20000
  provider:
    services:
      UserProviderWithCustomGroupAndVersion: # 接口三元組:接口名、版本號、分組。client 和 server 需要保持一致。
        interface: org.apache.dubbo.UserProvider.Test # 接口名必填
        version: myInterfaceVersion # 默認爲空
        group: myInterfaceGroup # 默認爲空

可以看到相比於之前的 API 編碼方式,這裏的 server.go 只有兩行代碼,dubbo.Load() 會完成所有配置的自動組裝並啓動相關組件,我們只需要在啓動應用時指定 export DUBBO_GO_CONFIG_PATH=$ABSOLUTE_PATH/conf/dubbogo.yml 即可。

可觀測性

自 3.2.0 版本開始,dubbo-go 重點升級了內置 metrics 指標採集能力,提供 RPC 調用(RT、QPS、調用量、請求成功數、請求失敗數、併發請求數等)、註冊中心、元數據中心、配置中心交互統計等豐富的內置採集埋點,支持多維度的指標聚合。

dubbo-go 內置 metrics 指標導出到 Prometheus + Grafana 體系的能力,以下是 dubbo-go v3.2.0 示例在 Grafana 的監控效果圖,具體示例我們將與隨後發佈在 dubbo-go-samples/metrics。

流量管控

Dubbo 提供了豐富的流量管控策略:

  • 地址發現與負載均衡,地址發現支持服務實例動態上下線,負載均衡確保流量均勻的分佈到每個實例上。
  • 基於路由規則的流量管控,路由規則對每次請求進行條件匹配,並將符合條件的請求路由到特定的地址子集。

服務發現保證調用方看到最新的提供方實例地址,服務發現機制依賴註冊中心 (Zookeeper、Nacos、Istio 等) 實現。在消費端,Dubbo 提供了多種負載均衡策略,如隨機負載均衡策略、一致性哈希負載、基於權重的輪詢、最小活躍度優先、P2C 等。

Dubbo 的流量管控規則可以基於應用、服務、方法、參數等粒度精準的控制流量走向,根據請求的目標服務、方法以及請求體中的其他附加參數進行匹配,符合匹配條件的流量會進一步的按照特定規則轉發到一個地址子集。以下是 dubbo-go 流量管控規則可以實現的一些具體管控場景示例:

  • 基於權重的比例流量分發
  • 灰度驗證
  • 金絲雀發佈
  • 按請求參數的路由
  • 同區域優先
  • 超時時間調整
  • 重試
  • 限流降級

以下是一個基於 dubbo-go 實現的全鏈路灰度示例:

以下是一個基於 dubbo-go 實現的按比例流量轉發示例:

關於 dubbo-go 流量管控,我們以一個商城系統提供了一個完整的 demo 示例,感興趣的讀者可以參考詳細信息:

  • 流量管控規則詳情[1]
  • 流量管控商場示例解讀[2]

生態

dubbo-go 總體上遵循框架內核+插件的的設計理念,左側的框架內核定義了 dubbo-go 作爲微服務框架的一些核心概念,右側的插件部分則提供了核心概念擴展實現。

框架內核 可分爲 4 個層次,從上到下依次爲:

  • API 層

dubbo-go 同時支持基於 IDL、interface/struct 的服務契約定義,兼顧跨語言與易用性訴求;支持基於純 yaml 文件的微服務配置模式;提供了同步、異步、單次(unary)、流式(streaming) 等 RPC 通信與編碼模型。

  • 服務治理層

dubbo-go 內置了多維度的服務治理能力抽象,確保滿足微服務開發與集羣治理的核心訴求,這包括地址發現(Service Discovery)、負載均衡(Load Balancing)、可觀測指標(Metrics)、流量管控(Traffic Management)、全鏈路追蹤(Tracing)等。

  • RPC 協議層

dubbo-go 實現的最核心的 RPC 協議是 - triple 協議,triple 可同時工作在 http1/2 之上 (支持 CURL 直接訪問),兼容 gRPC;從設計上,dubbo-go 還提供了多協議發佈服務的支持,你可以在一個進程內同時發佈 triple、dubbo2、rest、jsonRPC 等多種不同通信協議的服務。

  • 傳輸層

支持 HTTP1/2、TCP 傳輸層,兼顧性能與通用性,同時支持多種序列化方式。

插件體系極大的豐富了 dubbo-go 功能與生態,社區內置提供了大量的內置擴展實現,同時,開發者可以非常容易的根據需求增加擴展實現。以下是一些典型的插件定義:

  • Protocol

dubbo-go 基於 protocol 插件內置提供了 triple、dubbo2、rest 等協議支持,通過擴展 protocol 可以爲 dubbo-go 擴展更多協議。

  • Service Discovery

支持 Nacos、Zookeeper、Polaris 等主流注冊中心集成。

  • Traffic Management

dubbo-go 支持 Dubbo 體系定義的流量規則,可以實現在運行期動態的調整服務行爲如超時時間、重試次數、限流參數等,通過控制流量分佈可以實現 A/B 測試、金絲雀發佈、多版本按比例流量分配、條件匹配路由、黑白名單等。

  • Metrics

提供 RPC 調用(RT、QPS、調用量、請求成功數、請求失敗數、併發請求數等)、註冊中心、元數據中心、配置中心交互統計等豐富的內置採集埋點,支持多維度的指標聚合。

  • Logging

提供通用的日誌採集接口定義,內置 Zap、Logrus 支持

  • Tracing

提供分佈式鏈路追蹤能力,通過此插件擴展可接入 Zipkin、Jaeger、Skywalking 等鏈路追蹤系統。

總結

dubbo-go 3.2.0 的首個 alpha 版本將於 11 月底發佈,本文是發版前的搶先預覽,感興趣的讀者也可以訪問源碼嚐鮮:https://github.com/apache/dubbo-go/tree/feature-triple/protocol/triple/internal

接下來,我們將持續推進 3.2.0 版本迭代並計劃與 2 月份發佈正式穩定版本,詳細 Roadmap 請關注項目倉庫:https://github.com/apache/dubbo-go

相關鏈接:

[1] 流量管控規則詳情

https://cn.dubbo.apache.org/zh-cn/overview/core-features/traffic/

[2] 流量管控商場示例解讀

https://cn.dubbo.apache.org/zh-cn/overview/tasks/traffic-management/

作者:王宇軒, Apache Dubbo Committer

原文鏈接

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章