微服务架构实践指南

在现代软件开发中,微服务架构因其带来的诸多好处而受到青睐。独立部署的模块、更集中的测试工作、为每个部分选择正确的技术、以及基于集群部署的弹性增加,都是微服务架构的优势。然而,对于许多人来说,包括在内,最难的部分是如何构建微服务,以及每个部分应该有多小,它们如何协同工作。以下是发现的一些有用的实践,如果开始在解决方案中利用微服务架构。

一个服务等于一个工作

首先,面临的问题是容器应该有多小。有没有太小的问题?一个好的经验法则是专注于分离关注点。如果将每个用例分解为单一目的,很快就会得到一个好的微服务设计。

以最近与同事合作的一个解决方案为例,它最终从一个API拉取数据,然后将这些信息提取到数据模型中。在单体架构的思维方式中,这将是一个API调用。传入数据,然后循环处理。但问题是吞吐量,如果拉取67个不同区域,每个区域300多条记录,并将其作为一批处理,那将是一个巨大的API调用的混乱。

因此,有一个函数循环遍历区域,并将它们全部拉取到blob存储中的json文件中,然后排队一个消息。然后有另一个函数,当一个消息被排队时,将取这个消息,读取该区域的记录,并处理保存到数据库中。这个独立的函数是另一个微服务。

这种方法有几个好处,但最主要的是,第二个函数可以独立于第一个函数进行扩展,可以响应排队的消息,使用异步处理。

三个词……领域驱动设计

领域驱动设计(Domain-Driven Design,简称DDD)是一种软件设计方法,它强调以业务领域为中心进行软件开发。这意味着微服务应该反映它们试图做的事情。以电子商务为例,如果需要跟踪订单,并在订单提交后有一个处理流程,包括:

  • 订单提交。
  • 验证库存。
  • 处理订单支付。
  • 向供应商发送通知以进行处理。
  • 向客户发送确认。
  • 订单履行并发货。

根据上述步骤,一种实现方式可能是:

  • OrderService: 从开始到结束管理订单。
  • OrderRecorderService: 在跟踪系统中记录订单,以便在整个过程中跟踪订单。
  • OrderInventoryService: 取订单内容并检查库存。
  • OrderPaymentService: 处理订单支付。
  • OrderSupplierNotificationService: 与第三方API交互,提交订单给供应商。
  • OrderConfirmationService: 发送电子邮件确认订单已收到并正在处理。
  • OrderStatusService: 继续检查第三方API的订单状态。

如果注意到上述情况,除了编排之外,它们与业务步骤完全匹配。这提供了一种简化的方法,使得变更更容易,对新团队成员来说也更容易理解。服务之间的通信很可能是通过队列进行的。

使它们独立部署

这是最重要的一点,如果想看到微服务的好处,它们必须是独立部署的。这意味着,如果看上面的例子,可以部署这些独立的服务,并在不进行全面应用程序部署的情况下对其中一个进行更改。

以上述场景为例,如果想添加一种新的支付方式,应该能够更新OrderPaymentService,提交这些更改,然后将其部署到开发环境,通过生产环境,而不需要部署整个应用程序。

第一次听到这个想法时,觉得这是最荒谬的事情,但有一些方法可以使这成为可能。

  • 每个服务应该有它自己的数据存储:如果确保每个服务都有自己的数据存储,那么管理版本变更就容易得多。即使要使用像SQL Server这样的系统,也要确保每个微服务使用的表只由该服务使用。这可以通过使用模式来实现。
  • 在服务通信之间放置抽象层:例如,一个常见的例子是排队或事件。如果有一个消息被传递,那么只要离开的消息没有变化,就不需要更新接收者。
  • 如果进行直接API通信,请使用版本控制。如果必须有API连接这些服务,请利用版本控制,以允许微服务被部署和更改,而不会破坏应用程序的其他部分。

构建具有弹性的系统

如果采用这种方法构建微服务,很快就会注意到的一件事是每个微服务都变成了它自己的黑盒子。因此,发现构建这些组件时考虑到弹性是很好的。像利用Polly进行重试,或断路器模式这样的事情。这些是确保服务保持弹性的好方法,并且会对应用程序产生累积效应。

以OrderPaymentService为例,知道队列消息应该包含订单和支付细节。可以对这个服务进行微观分析,并说,它可能在哪里失败,不难得到这样的列表:

  • 消息以错误的格式传来。
  • 无法到达支付服务。
  • 支付被拒绝(原因多种多样)。
  • 服务在等待支付处理时失败。

对于上述一些情况,只是一些简单的错误处理,比如检查消息的格式。还可以构建逻辑来检查支付服务是否可用,并进行指数级重试,直到它可用。

还可以考虑实现一个断路器,如果在多次尝试后无法处理支付,服务切换到不健康状态,并引发通知工作流。

在最后一种情况下,可以实现一个状态存储,指示支付处理的状态,以防服务失败并需要被另一个接管。

尽早考虑监控

这是每个人都容易忘记的一点,但它很好地与前一点相吻合。重要的是要有一个机制来跟踪和监控微服务的状态。发现人们很容易说“哦,服务正在运行,所以它很好。”这就像说,只是因为首页加载了,一个完整的Web应用程序就在工作。

应该在微服务中构建跟踪它们健康的能力,并为操作工具提供一种这样做的方法。让面对现实,最终,所有的代码都会被部署,所有部署的代码都必须被监控。

例如,看看上面的例子。如果在OrderPaymentService中构建了一个断路器模式,并且每次失败都会更新存储在服务内存中的状态,说它是不健康的。然后可以公开一个HTTP端点,返回该断路器的状态。

  • 关闭:服务运行良好且健康。
  • 半开:服务遇到一些错误,但仍在处理。
  • 打开:服务因不健康而离线。

然后可以构建逻辑,当它达到半开,甚至打开特定的事件会发生。

从小开始,不要急于求成

这似乎有点讽刺,因为上述情况。但如果正在处理一个现有的应用程序,永远无法说服管理层允许放弃它并重新开始。所以过去所做的是,当发现应用程序的某个部分需要更改时,抓住机会重新架构并使其更具弹性。解构这些部分,并实现一个微服务响应来解决问题。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485