go 2025年1月9日

GRPC Microservices in Go

使用Go语言开发gRPC微服务
书籍封面

GRPC Microservices in Go

作者:Hüseyin Babal 出版日期:2023-11-14 出版社:Manning
本书《gRPC Microservices in Go》是一本关于使用Go语言和gRPC框架构建微服务的指南。它涵盖了微服务架构理论、Go语言基础、gRPC原理及实践、以及在Kubernetes上的部署和监控等方面的内容。书中通过一个电子商务应用的例子,逐步讲解了gRPC微服务的生命周期,包括开发、测试、部署和运维等各个阶段,并提供了大量的代码示例和最佳实践,适合有一定Go语言基础的开发者阅读。

第一章:Go gRPC 微服务简介

  • gRPC 的跨平台和多语言兼容性:gRPC 工具和库与多种平台和语言兼容,包括 Go、Java、Python、Ruby、JavaScript 和 C# 等。Protobuf 二进制线格式和代码生成功能使开发者能够构建高性能的跨平台应用程序。
  • gRPC 的优势:gRPC 越来越受欢迎,因为它能够快速生成客户端存根,为不同语言的服务提供 SDK。开发者只需定义业务对象和方法,gRPC 就可以生成特定语言的实现,使得服务器端和客户端可以使用不同的开发语言进行通信。
  • 容错能力:容错是指系统在发生故障时仍能继续运行的能力。幂等操作是实现容错环境的关键,因为它可以确保即使多次调用同一操作,资源的状态也不会发生改变。此外,容错还包括限流、熔断和故障注入等主题,这些将在第六章详细介绍。
  • 多语言开发环境:gRPC 非常适合多语言开发环境,因为可以使用 Python 客户端访问用 Java 编写的 Payment 服务,客户端存根生成非常方便。
  • 微服务验证机制:当服务定义发生更改时,客户端的测试会失败,这是一种用于验证微服务的有效机制。

第二章:gRPC 与微服务

  • 微服务架构的优势:单体架构在产品开发的初期阶段很有帮助,但在评估产品的可扩展性、开发和部署问题后,以及熟悉业务能力和服务上下文后,切换到微服务架构是一种最佳实践。
  • 扩展立方体(Scale Cube):扩展立方体是一个三维可扩展模型,包括 X 轴扩展(运行多个相同应用副本)、Y 轴扩展(根据功能分解服务)和 Z 轴扩展(根据请求属性路由请求)。
  • 异步通信:发布/订阅(Pub/Sub)或命令通道机制是异步通信的示例,而请求/响应风格(如 gRPC)是同步通信的示例。
  • Saga 模式:基于编排(Choreography)和协调器(Orchestrator)的 Saga 模式提供了分布式环境中的数据一致性。
  • gRPC 的应用:gRPC 是一种现代、轻量级的通信协议,也是一个高性能的 RPC 框架,它通过协议缓冲区高效地连接微服务环境中的服务,并内置支持负载均衡、跟踪、健康检查和身份验证。
  • .proto 文件:使用 Protocol Buffers 定义消息和服务函数,并通过协议缓冲区编译器(protoc)生成服务器和客户端存根。
  • gRPC 的工作流程:定义 .proto 文件,生成客户端和服务器存根,实现服务器端和客户端的业务逻辑,最后运行服务和客户端。
  • 流式处理:gRPC 支持客户端和服务器端的流式处理,允许客户端连续发送请求,服务器可以返回一个对象流。

第三章:开始使用 gRPC 和 Golang

  • Protocol Buffers:Protocol Buffers 允许序列化结构化数据以便通过网络传输,并定义服务函数以生成特定语言的源代码。
  • .proto 文件:.proto 文件是配置文件的形式,包含消息和服务函数的定义,也包含协议的版本信息(例如 proto3)。
  • 消息类型定义:消息字段可以是单数(最多一个)、重复(多个值,包括零)或者保留的。字段类型可以是标量类型(如字符串和整数)、枚举或其他嵌入消息类型。
  • 消息编码:协议缓冲区将消息转换为二进制格式进行传输,包括元数据部分和数据部分。
  • 生成存根:protoc 工具可以接受多种参数来生成特定语言的源代码。
  • 维护 .proto 文件:维护 .proto 文件需要考虑版本控制和向后/向前兼容性,通常会将 .proto 文件保存在单独的仓库中。
  • 在 CI/CD 管道中添加存根生成过程:使用 GitHub Actions 可以自动化存根的生成过程。
  • Go 代码生成:使用 protoc 生成 Go 源代码,包括 go_package 选项和源代码相对路径。
  • 消息和服务的定义: 了解如何在 .proto 文件中定义消息(message)类型,包括字段规则、字段类型以及保留字段。同时,也包含了服务(service)的定义,以及如何使用 rpc 调用定义服务函数。

第四章:微服务项目设置

  • 六边形架构:六边形架构通过端口允许外部参与者使用、实现和编排业务逻辑。
  • 项目文件夹:一个典型的 Go 项目包含以下文件夹:application(包含业务逻辑),cmd(包含入口点),config(包含配置),internal/adapters(包含适配器),internal/ports(包含端口),以及 domain (包含核心业务实体)。
  • 应用核心的实现:应用核心是业务逻辑的组合,包括领域模型和 API,外层依赖于内层,这使得先实现应用核心,再实现外层依赖变得更容易。
  • 端口和适配器:端口是定义应用核心与外部世界交互的接口,适配器是端口的具体实现。
  • 依赖注入:通过依赖注入来组合端口和适配器,然后运行应用。
  • 配置管理:使用环境变量来分离生产和非生产环境,并读取数据库连接 URL 和应用端口。
  • 使用 grpcurl 测试 gRPC 端点:使用 grpcurl 工具可以发送请求并测试 gRPC 服务。

第五章:服务间通信

  • gRPC 存根:gRPC 存根用于在服务之间进行通信,它是由 .proto 文件生成的 Go 源代码。
  • 依赖模块和实现端口和适配器:解释了如何在 Order 服务中依赖 Payment 服务,并实现相应的端口和适配器。
  • gRPC 客户端配置:使用 grpc.WithTransportCredentials(insecure.NewCredentials()) 来禁用 TLS 握手,使用 payment.NewPaymentClient(conn) 来初始化 payment 存根实例。
  • 错误处理:gRPC 使用预定义的状态码来表示不同的错误情况,并提供了一种结构化的方式来处理错误。
  • 错误详情:通过 errdetails.BadRequest_FieldViolationerrdetails.BadRequest 可以传递详细的错误信息,包括字段和描述。
  • 状态码:详细列出了 gRPC 中常用的状态码,例如 OK,CANCELLED, INVALID_ARGUMENT, ALREADY_EXISTS, PERMISSION_DENIED, RESOURCE_EXHAUSTED 等,这些状态码用于在服务间传递错误信息。

第六章:弹性通信

  • 弹性模式:弹性模式是用于处理分布式系统中网络故障的模式,包括超时、重试和熔断器。
  • 超时模式:使用 context.WithTimeoutcontext.WithDeadline 来设置请求超时,防止长时间等待。
  • 重试模式:使用 grpc_retry 中间件来自动重试失败的请求,并使用 WithCodesWithMaxWithBackoff 等配置来控制重试行为。
  • 熔断器模式:熔断器模式可以防止级联故障,并在服务恢复后自动重置。使用 gobreaker 包来实现熔断器,通过 MaxRequestsReadyToTripOnStateChange 等配置来控制熔断器的行为。
  • gRPC 错误模型:gRPC 使用 status 包来处理错误,包括 Code、Status 和 Message 三个主要字段,以及 ErrorDetails 部分来包含详细的错误列表。
  • TLS 配置:使用 TLS 配置来保护服务间的通信,包括证书生成和 gRPC TLS 凭证的使用。

第七章:测试微服务

  • 测试金字塔:测试金字塔将软件测试分为单元测试、集成测试和端到端测试三个类别,单元测试占比最大,端到端测试占比最小。
  • 单元测试:单元测试用于验证软件的特定单元,例如类或函数。测试工作流程包括设置、调用 SUT(被测系统)、验证和拆卸。
  • 系统测试(SUT):SUT 可以是类或整个应用程序,测试套件用于验证 SUT 的行为。
  • Mock:使用 Mock 来模拟依赖项,从而快速验证系统行为。使用 testify/mock 或 mockery 来生成 Mock。
  • 集成测试:使用 Testcontainers 来初始化数据库等外部依赖项,并使用 Go 的测试框架来验证集成。
  • 端到端测试:使用 Docker Compose 来定义和运行应用程序堆栈,并通过测试来验证整个流程。
  • 测试覆盖率: 使用 go test -cover 命令来查看测试覆盖率,并使用 -coverprofile 来生成覆盖率报告。

第八章:部署

  • Kubernetes:Kubernetes 是一个用于自动化部署、扩展和管理容器化应用程序的开源平台。
  • Kubernetes 的核心组件:包括 API 服务器、调度器、控制器管理器、etcd 和 kubelet 等。
  • Kubernetes 部署:通过 Deployment 资源来管理 Pod 的部署和更新。
  • Service:使用 Service 资源来暴露 Pod 作为内部或公共端点。
  • 部署策略:包括 RollingUpdate、Blue-Green 和 Canary 等部署策略。
  • 证书管理:介绍如何在 Kubernetes 环境中进行证书管理,包括 ClusterIssuer 和 Certificate 的使用。
  • 使用 kubectl 进行部署: 详细介绍了如何使用 kubectl 命令来部署 Kubernetes 资源,包括 Deployment 和 Service。
  • GitOps:使用 ArgoCD 和 FluxCD 等工具来自动化部署过程。

第九章:可观测性

  • 可观测性:可观测性是跟踪和分析分布式系统中问题的根本原因的关键,它通过跟踪、指标和日志来帮助我们了解系统状态。
  • 跟踪(Traces):跟踪是记录跨多个服务的请求旅程,包括操作和跨度(spans)。
  • 指标(Metrics):指标是用于量化系统性能的度量,例如延迟、请求数和错误率。
  • 服务级别目标 (SLO):定义了服务应达到的目标,例如正常运行时间或响应延迟。
  • 日志(Logs):日志是应用程序产生的消息,可以帮助我们理解发生了什么 。
  • OpenTelemetry:OpenTelemetry 是一组 API、SDK 和工具,用于收集和发送跟踪、指标和日志数据。
  • Jaeger:Jaeger 是一个用于分布式跟踪的开源系统。
  • Prometheus:Prometheus 是一个用于收集和存储指标的开源系统。
  • Fluent Bit:Fluent Bit 是一个轻量级的日志收集器,用于将日志转发到 Elasticsearch。
  • Elasticsearch:Elasticsearch 是一个用于存储和搜索日志的开源系统 。
  • Kibana:Kibana 是一个用于可视化日志的开源工具 。
  • 整合可观察性工具: 详细介绍了如何将 OpenTelemetry、Jaeger、Prometheus、Fluent Bit、Elasticsearch 和 Kibana 集成在一起,以建立一个完整的可观察性堆栈。