Go语言微服务框架重磅升级:dubbo-go v3.2.0 -alpha 版本预览

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 随着 Dubbo3 在云原生微服务方向的快速发展,Dubbo 的 go 语言实现迎来了 Dubbo3 版本以来最全面、最大幅度的一次升级,这次升级是全方位的,涉及 API、协议、流量管控、可观测能力等。

作者:王宇轩, Apache Dubbo Committer

随着 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 功能与生态,社区内置提供了大量的内置扩展实现,同时,开发者可以非常容易的根据需求增加扩展实现。以下是一些典型的插件定义:

  • Protocoldubbo-go 基于 protocol 插件内置提供了 triple、dubbo2、rest 等协议支持,通过扩展 protocol 可以为 dubbo-go 扩展更多协议。
  • Service Discovery支持 Nacos、Zookeeper、Polaris 等主流注册中心集成。
  • Traffic Managementdubbo-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


社区期待 Go 语言相关开发者的加入,可搜索关注 “apachedubbo” 微信公众号并回复 “dubbogo” 接受邀请,加入官方社群组织。


电子书免费下载本书为 CoC Asia 2023(原ApacheCon) RPC & Service Mesh 专题分享实录,通过摘取 Community Over Code Asia 2023(原 ApacheCon Asia)的 RPC & Service Mesh专题的精彩内容,我们以 Apache Dubbo 为中心展开,给大家带来开源微服务技术方向发展、云原生微服务选型、企业实践分享的精彩内容!


相关链接:

[1] 流量管控规则详情

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

[2] 流量管控商场示例解读

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

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
3天前
|
Go 开发者
Go语言中的错误处理与异常机制:实践与最佳策略
【2月更文挑战第7天】Go语言以其独特的错误处理机制而闻名,它鼓励显式错误检查而不是依赖于异常。本文将探讨错误处理与异常机制在Go语言中的实际应用,并分享一些最佳实践,帮助开发者编写更加健壮和易于维护的Go代码。
|
4天前
|
Java 编译器 Go
Go语言面试题1
【2月更文挑战第5天】Go语言面试题15个问题
35 2
|
2天前
|
Java 测试技术 Go
Go语言标准库进阶应用与最佳实践:提升代码质量与性能
【2月更文挑战第8天】在掌握了Go语言标准库的基础应用后,如何进一步发掘其潜力,提升代码质量和性能,是每位Go语言开发者所关心的问题。本文将探讨Go语言标准库的进阶应用与最佳实践,包括标准库与其他库的协同使用、性能优化与内存管理、错误处理与异常捕获、标准库在实际项目中的应用案例,以及推荐的最佳实践与编程规范。通过深入了解这些内容,开发者能够更好地利用Go语言标准库,提升代码质量与性能,构建出更加高效、可靠的软件应用。
|
2天前
|
算法 安全 Go
Go语言标准库核心模块详解:构建高效应用的基石
【2月更文挑战第8天】Go语言标准库中的核心模块为开发者提供了构建高效应用所需的基础功能和工具。本文将深入探讨Go语言标准库中的几个核心模块,包括容器与集合、并发与并行、输入输出、时间与日期、字符串处理以及加密与安全,帮助读者更好地理解和应用这些核心模块,为构建高效应用打下坚实基础。
|
2天前
|
Go API 数据安全/隐私保护
Go语言标准库概览:构建高效、可靠的软件开发基石
【2月更文挑战第8天】Go语言标准库是Go语言生态系统的重要组成部分,它为开发者提供了一系列高效、可靠的工具和函数,帮助开发者构建高质量的软件应用。本文将对Go语言标准库进行概览,介绍其组成特点、设计哲学以及使用场景与优势,帮助读者更好地理解和应用Go语言标准库。
|
3天前
|
Go
Go语言中的异常处理:理解panic与recover
【2月更文挑战第7天】Go语言虽然以简洁和直接错误处理机制而著称,但它也提供了`panic`和`recover`这两个内置函数来处理程序中的异常情况。本文将深入探讨Go语言中的异常处理机制,包括`panic`和`recover`的使用场景、原理以及最佳实践,帮助读者更好地理解如何在Go中处理异常情况。
|
3天前
|
Go 开发者
Go语言错误处理机制:原理与实践
【2月更文挑战第7天】在Go语言中,错误处理是一项核心特性。Go语言鼓励显式的错误检查,而不是依赖于异常机制。本文将深入探讨Go语言的错误处理机制,包括错误的表示、传播和处理方式,以及如何在日常编程中有效地应用这一机制,确保代码的健壮性和可读性。
24 10
|
4天前
|
存储 缓存 网络协议
Go语言并发编程实战:构建高性能Web服务器
【2月更文挑战第6天】本文将通过构建一个高性能的Web服务器实战案例,深入探讨如何在Go语言中运用并发编程技术。我们将利用goroutine和channel实现高效的请求处理、资源管理和并发控制,以提升Web服务器的性能和稳定性。通过这一实战,你将更好地理解和掌握Go语言在并发编程方面的优势和应用。
|
4天前
|
消息中间件 Go
Go语言高级并发编程技术:深入探索同步原语与复杂并发模式
【2月更文挑战第6天】在Go语言中,除了基础的goroutine和channel之外,还提供了丰富的同步原语和高级并发模式。本文将深入探讨Go语言中的sync包、atomic包以及更复杂的并发模式,如管道、消息队列和生产者消费者模型。通过理解这些高级并发编程技术,我们可以更好地构建高性能、可扩展的并发系统。
|
4天前
|
Go 调度 开发者
Go语言并发基础:轻量级线程与通道通信
【2月更文挑战第6天】本文介绍了Go语言在并发编程方面的基础知识和核心概念。我们将深入探讨goroutine(轻量级线程)的创建与调度,以及如何利用channel进行goroutine间的通信与同步。此外,还将简要提及select语句的使用,并解释其在处理多个channel操作时的优势。

相关产品

  • 微服务引擎
  • 服务网格