Python 微服务 | 使用 gRPC 实现 Python 微服务

2025年3月17日 | 阅读 12 分钟

在本教程中,我们将学习微服务、微服务的重要性以及如何使用 Python 编程语言来实现它们。我们还将讨论 gRPC 并将其与 Python 一起使用。

在当前场景下,技术更侧重于“微服务架构”,而抛弃了旧的“单体架构”。我们相信“小东西更容易处理”,因此我们有了易于管理的微服务。我们需要与不同的微服务进行交互。

在这里,我们将学习如何使用 gRPC(最流行的框架之一)来启动和运行 Python 微服务。

让我们简要介绍一下微服务以及如何在我们的项目中它们。

什么是微服务?

微服务是一种组织复杂软件系统的技术。它类似于将一个复杂问题分解成一个小问题并解决它。与微服务一样,微服务不会将所有代码都放入一个应用程序中,而是将代码分解为独立部署并相互通信的微服务。

实现微服务框架至关重要。当我们计划开发一个提供关键应用程序的框架时,我们必须确保其健壮且对开发人员友好。

为什么微服务很重要?

假设一个开发人员正在为一家销售多种产品的流行电子商务网站工作。公司有几百名员工。每位开发人员都被分配编写后端功能或某些产品(例如将商品添加到购物车、生成推荐、处理支付交易或处理仓库历史记录)的代码。

现在想象一下,将所有代码放入一个庞大的应用程序有多么困难?有多难理解?需要多长时间来测试?随着业务的快速发展,这无疑是相当具有挑战性的。

将对应于模块化产品功能的代码变得模块化会更好吗?购物车微服务管理购物车。库存微服务管理库存。

让我们了解将 Python 代码分离成微服务的背后原因。

模块化

模块化允许以最小的阻力进行更改。假设 CEO 想添加一项新功能,**“买二赠一”**功能。您是负责尽快推出的团队成员。如果我们把所有的代码都放在一个应用程序里,我们在实现这个功能时会遇到一些严重的问题。

在这里,您向团队提供解决方案——您可以在购物车逻辑中添加一些代码来检查购物车中是否有超过两本书。

产品经理还告诉要跟踪此活动对图书销售的影响。这也很简单。您只需从购物车总价中减去最便宜的书。除了代码中的**“买二赠一”**功能,您还可以更新结账栏中的一行,该行会在事务数据库中更新一个新列,以指示该销售是促销活动的一部分**buy_two_get_one_free_promo** = true。完成。

又一项要求来了:每位客户限用一次。如果您使用此功能,则需要在首页上隐藏此横幅。

几年后,交易数据库变得太大,需要更换为新的共享数据库。这可能会导致数据丢失。所有这些引用都需要更改。

因此,将所有代码放入一个应用程序中,从长远来看可能会太危险。

最佳解决方案是创建事务微服务,并且我们还可以对其进行扩展。代码的另一部分可以通过隐藏实现细节的抽象 API 与事务进行通信。

灵活性

灵活性是微服务最重要的优势。开发人员可以使用多种语言编写代码。我们还可以独立扩展微服务。我们将在下一节中创建示例微服务。

健壮性

如果我们把所有的代码都放在一个应用程序里,我们还需要一次性部署它。这可能是一个大威胁。当我们尝试更改代码时,这意味着整个网站都可能宕机。

所有权

微服务提供了代码的所有权。当一个代码库被多个员工共享,而这些员工来来往往时。代码架构没有明确的愿景。微服务有助于为代码提供清晰的愿景,并且代码将保持干净整洁。它还澄清了谁负责向代码添加功能或在出现问题时进行更改。

微服务示例

我们将为在线图书网站定义一些微服务。我们将创建一个 API 并编写实现它们的 Python 代码作为微服务。

为了使事情简短易懂,我们将只定义两个微服务——

  • Marketplace - 它将是一个最小的 Web 应用程序,向用户显示图书列表。
  • Recommendations - 它将显示用户可能感兴趣的书籍。

用户将通过浏览器与 Marketplace 微服务进行交互,Marketplace 微服务将与 Recommendation 微服务进行交互。

Recommendation API 应具有一些功能——

  • User ID - 它将是随机的用户 ID。
  • Category - 我们将添加一个“shirt”类别,使 API 更有趣。
  • Max results - 我们不想返回所有库存图书,因此我们将限制请求。

响应将是一个图书列表。每本书将包含以下数据。

  • Book ID: 图书的数字 ID。
  • Book title: 图书的标题。

我们只选取了 API 的一些有限功能,使其更简单。现在我们可以使用协议缓冲区(protocol buffers)更正式地定义此 API。

示例 -

我们创建一个包含我们的 API 的 proto 文件。Protobuf 缓冲区由 Google 开发,要了解 protobuf 的概念,您可以访问我们的 如何用 Python 实现 protobuf。乍一看可能有些令人困惑,但让我们逐行分解文件。

  • 首先,我们定义 **proto3** 语法,而不是旧的 **proto2** 版本。
  • 然后我们指定图书类别,每个类别都分配一个数字 ID。
  • 一个消息包含字段,每个字段都有特定的类型。我们将 userID 和 max_result 字段用作 int32(32 位整数)。我们将 enum 字段 BookCategory 用作类别类型。之后,我们将 API 请求定义为 RecommendationRequest。
  • 接下来,我们定义新的消息类型 BookRecommendation,我们可以用它来推荐图书。它由一个 32 位整数 ID 和一个基于字符串的标题组成。
  • 然后我们使用 repeated 关键字定义 Recommendations 微服务的响应。
  • 最后,我们定义 API 的方法。这可以理解为类中的一个函数。

这是关于使用 protobuf 的微服务的一个简要概述。现在我们将了解流行的微服务技术 gRPC。

什么是 gRPC?

根据官方文档——

“gRPC 或 Google Remote Procedure Call 是一种现代的开源高性能 RPC 框架,可以在任何环境中运行。它可以高效地连接数据中心内部及之间服务,并支持可插拔的负载均衡、跟踪、健康检查和身份验证。”

RPC 是 **远程过程调用** 的缩写,它与 Python 中的普通函数非常相似。它们是服务器发送到远程系统以完成任务(或例程)的消息。

Google 的 RPC 提供了服务之间平滑高效通信的功能。它可以用于不同的方式——

  • 生成高效的客户端库。
  • 以微服务风格架构高效连接多语言服务。
  • 将移动设备、浏览器客户端连接到后端服务。

为什么选择 gRPC?

gRPC 相对于其他微服务提供了许多优势。让我们来了解一些优势。

  • 基于 HTTP/2 的传输 - gRPC 使用 HTTP/2 协议而不是 HTTP 1.1。HTTP/2 协议相对于后者提供了各种优势。它提供了多个双向流,可以在 TCP 连接上并行创建和发送。
  • 文档 - 协议缓冲区提供了定义明确的 API 和自描述模式。如果我们使用 JSON 结构,我们必须记录字段及其类型。当我们使用协议缓冲区语言编写代码时,它会自动生成 Python 代码。代码将永远不会与我们的文档不同步。文档有助于理解代码,但自定进度的代码更好。
  • 验证 - 当我们从协议缓冲区生成基本代码时,我们会得到预定义的验证。例如,生成的代码不会接受错误类型的字段。生成的代码还包含了所有内置的 RPC 样板代码。
  • 开发人员友好性 - 这是许多人更喜欢 gRPC 而不是 REST 的最有趣的功能。我们可以用函数来定义我们的 API。有时将功能映射到 REST API 会很麻烦。我们必须决定资源,如何构建路径,以及使用哪些动词。REST vs. gRPC 可能会变成一场关于偏好的辩论。Protocol buffer 指的是微服务之间发送的数据的序列化格式。
  • 语言无关通信 - 如果服务是用 Python 和 Golang 等不同语言编写的。gRPC 可确保 gRPC 服务和 gRPC 客户端之间的平滑通信。它也将其用作消息交换格式。

Protocol Buffers (协议缓冲区)

Protocol buffers 类似于 XML,它们提供了一种高效且自动化的结构化数据序列化机制。它们允许定义要传输的数据的结构。Google 声称它们比 XML 更好。其特点是——

  • 易于使用。
  • 它小三到十倍。
  • 它相当快。
  • 它不那么含糊。
  • 它生成数据访问类,可以更轻松地以编程方式使用它们。

Protobuf 在 .proto 文件中定义。定义它们很简单。

gRPC 实现的类型

gRPC 实现有四种类型。让我们来理解每种实现——

1. Unary RPCs - 这是最简单的 gRPC,它像普通函数调用一样执行。它发送 .proto 文件中声明的单个请求,并从服务器获取单个响应。

上面的代码包含服务集合。在这里,我们实现了一个服务 **GetServerResponse()**。此服务接受 Message 类型的输入并返回 MessageResponse。完成 .proto 文件后,我们需要使用以下命令生成存根。

当我们按 Enter 键时,它将生成两个文件。

在上面的文件中,**GetServerResponse()** 方法从客户端接收 'Message' 并返回 proto 文件中定义的 'MessageResponse'。我们在 **main()** 中调用 **server()** 函数,以确保服务器监听请求。现在,我们运行上面的服务器文件。

实现客户端

下面是客户端的实现。

示例 -

在上面的代码中,__init__func 包含 stub 变量,我们使用 `self.stub = pb2_grpc.UnaryStub(self.channel)`,并且我们有一个 get_url() 函数,该函数使用上面初始化的 stub 调用服务器。

现在我们已经完成了 Unary gRPC 服务。运行服务以检查输出。

输出

message: "Hello Server Are you listening?"
message: "Hello I am up and running. Received 'Hello Server you there?' message from you"
received: true

双向实现

我们也可以如下定义双向服务。

示例 -

在上面的代码中,我们声明了一个名为 Birectional 的服务。它包含一个服务集合。目前,我们只实现了一个服务 **GetServerResponse()**。此服务接受 Message 类型的输入并返回 Message。我们遵循相同的过程来生成存根。要生成存根,我们需要运行以下命令。

上面的命令将生成 bidirectional_pb2.py 和 bidirectional_pb2_grpc.py 这两个文件。这些文件将用于生成 gRPC 服务器和客户端。您可以以上述示例为参考来实现此服务,也可以参考其官方文档。

微服务的优点和缺点

我们已经讨论了微服务的所有重要方面,微服务是什么,还讨论了在项目软件架构中使用微服务的重要性。以下是微服务的优缺点的简短描述。

序号。优点缺点
1.每个服务都是独立的,并自行运行。为了获得最终响应,服务之间的通信存在延迟。
2.由于服务的模块化,开发时间更短。在多个微服务之间进行测试很困难。
3.基础设施扩展取决于各个服务。支持多个实例的成本可能会迅速增加。
4.新功能可以轻松添加或删除。由于额外的数据提供层,存在信息屏障。
5.代码按业务逻辑组织。某些用例可能跨越多个服务。
6.它独立于旧的代码堆栈。它支持一个系统中的多个代码堆栈。
7.出色的故障隔离。创建 DTO 和故障机制需要额外的工作。

结论

微服务是管理复杂系统的最合适方式。它们为组织代码提供了自然的方式。一旦我们熟悉了 gRPC 以及如何在 Python 中有效实现微服务,我们就可以在开发领域更进一步。

在本教程中,我们讨论了微服务,如何使用 gRPC 有效地实现 Python 微服务,微服务类型,以及微服务的优缺点。我们还讨论了 gRPC,这是一个新兴的 RPC 框架,它使得微服务之间的通信更加顺畅和有效。