本系列文章通过逐章回答《Fundamentals of Software Architecture》(下文简称 FOSA)一书中的课后思考题,来深入理解书中的核心概念和理论,从而提升我们的软件架构设计能力。本篇为第十七章内容。
本章的课后题是:
-
Why is the bounded context concept so critical for microservices architecture?
为什么限界上下文的概念对于微服务来说如此重要?
-
What are three ways of determining if you have the right level of granularity in a microservice?
在划分微服务粒度的时候,哪三个方面是你需要重点考虑的?
-
What functionality might be contained within a sidecar?
sidecar 有哪些功能?
-
What is the difference between orchestration and choreography? Which does microservices support? Is one communication style easier in microservices?
编舞(orchestration)和编排(choreography)的区别是什么?微服务支持哪种模式?在微服务中,哪种通信方式更简便?
-
What is a saga in microservices?
在微服务中,saga 是什么?
-
Why are agility, testability, and deployability so well supported in microservices?
为什么敏捷性、可测试性和可部署性在微服务架构中表现良好?
-
What are two reasons performance is usually an issue in microservices?
在微服务中,性能问题的两个核心因素是什么?
-
Is microservices a domain-partitioned architecture or a technically partitioned one?
微服务架构是领域分区还是技术分区?
-
Describe a topology where a microservices ecosystem might be only a single quantum.
描述一种拓扑结构,其中微服务生态系统可能仅有一个架构量子。
-
How was domain reuse addressed in microservices? How was operational reuse addressed?
微服务中是如何解决领域复用问题的?又是如何解决运维复用问题的呢?
业务边界
Why is the bounded context concept so critical for microservices architecture?
为什么限界上下文的概念对于微服务来说如此重要?
Is microservices a domain-partitioned architecture or a technically partitioned one?
微服务架构是领域分区还是技术分区?
限界上下文(Bounded Context)是微服务设计理念的核心驱动力。微服务架构与领域驱动设计(DDD)紧密相关,尤其是受限界上下文概念的深刻影响。限界上下文代表了一种解耦风格。在限界上下文内,与特定领域相关的所有内部组件(如代码和数据库模式)都是紧密耦合的,但它们与外部限界上下文的任何内容(如其他数据库或类定义)是解耦的。
微服务架构的首要目标是高度解耦。它通过物理地建模限界上下文的逻辑概念来实现这一目标。这意味着,微服务架构鼓励将系统分解为独立的、自包含的服务,每个服务都对应一个特定的限界上下文。
这种隔离使得每个服务可以独立演进,定义其自身所需的一切,而不必适应其他部分的约束。它避免了传统单体架构中常见的共享类和数据库作为集成点导致的紧密耦合问题。
所以微服务也是一个典型的领域分区架构,并且它倾向于将领域分区推到极致。
服务粒度
What are three ways of determining if you have the right level of granularity in a microservice?
在划分微服务粒度的时候,哪三个方面是你需要重点考虑的?
在划分微服务粒度时,以下三个方面是需要重点考虑的:
- 目的(Purpose):微服务的首要目的应该是捕获一个领域或工作流。理想情况下,每个微服务都应该具有极高的功能内聚性,为整个应用程序贡献一个重要的行为。这意味着,服务应该专注于一个单一的、明确的业务功能。
- 事务(Transactions):限界上下文是业务工作流,通常需要在事务中协作的实体可以为服务边界提供良好的指示。由于分布式事务在分布式架构中会带来复杂性,架构师应尽量设计系统以避免跨服务的事务。如果需要跨服务事务,这可能表明服务粒度过细。事务边界通常是服务粒度的常见指标。
- 通信(Communication):如果一组服务为了完成功能而需要大量通信,那么将这些服务捆绑成一个更大的服务可能有助于避免过度的通信开销。换句话说,如果服务变得过于“多话”(chatty),频繁地相互调用,那么它们的边界可能需要重新评估,以减少不必要的全局复杂性。
书中还强调,迭代是确保良好服务设计的唯一途径,架构师很少能在第一次尝试时就发现完美的粒度、数据依赖和通信风格,只有不断适配业务发展、不断思考改善,才能设计出良好的架构。
此外,业界也有一些其他的常用的判断方法:
- 变更与部署频率一致性:把一起变更/部署的东西放在一个服务,频率不同的拆开。
- 耦合/通信“积分器 vs. 解耦器”指标:如果拆分后跨服务调用暴增(“chattiness”),说明拆太细;反之,如果内部复杂度过高且团队协作困难,可能太粗。
- 团队/认知负荷:一个团队能完全理解并独立维护的范围通常就是一个合理服务边界。
基础设施
What functionality might be contained within a sidecar?
sidecar 有哪些功能?
How was domain reuse addressed in microservices? How was operational reuse addressed?
微服务中是如何解决领域复用问题的?又是如何解决运维复用问题的呢?
Sidecar 模式用于处理微服务中的通用运维关注点(operational concerns),包括但不限于:监控(Monitoring)、日志记录(Logging)、断路器(Circuit Breakers)和服务发现(Service Discovery)。这些功能由一个独立的组件处理,该组件可以由单个团队拥有,也可以由共享的基础设施团队拥有,从而实现了运维方面的复用。
而在领域复用中,由于微服务架构的主要目标是高度解耦。为了实现这一目标,微服务倾向于复制(duplication)而不是传统意义上的复用(reuse)。这意味着,对于通用实体(如 Address
类),微服务会避免共享公共类或数据库模式。相反,每个服务会在其自己的限界上下文内定义和管理其所需的数据和行为,即使这意味着某些概念的重复实现。这种策略牺牲了代码级别的复用,以换取服务之间更高的解耦度和独立演进的能力。
服务协作
What is the difference between orchestration and choreography? Which does microservices support? Is one communication style easier in microservices?
编舞(orchestration)和编排(choreography)的区别是什么?微服务支持哪种模式?在微服务中,哪种通信方式更简便?
-
编舞(Choreography):是指多个服务相互之间直接通信,而没有中央协调器。服务(如同舞者)根据彼此发出的事件或信息自主响应和行动。
-
编排(Orchestration):是指通过一个单独的协调器服务来管理和控制工作流中多个服务的协调。协调器(如同乐队指挥)负责指导每个服务的执行顺序,并处理整个业务流程的状态和错误。在微服务中,架构师可以创建局部化的协调器服务来处理复杂的业务流程。
微服务两者都支持。 不过编舞方式更符合微服务的高度解耦哲学,因为它不依赖于中央协调器,而是通过解耦的事件来实现通信,使用起来更简便。当然,在复杂的业务流程中,编舞环境下的错误处理和协调会变得更加复杂。如果业务流程本质上是耦合的,此时编排可能更为适合。
一致性
What is a saga in microservices?
在微服务中,saga 是什么?
在微服务中,Saga 是一种分布式事务模式,用于管理跨多个服务的业务事务,因为在微服务中,跨服务边界的传统 ACID 事务是不推荐的(甚至不可能的)。
Saga 模式通过将一个业务流程分解为一系列本地事务来实现,每个本地事务由一个服务执行。
- 如果某个本地事务失败,Saga 会通过执行**补偿事务(compensating transactions)**来撤销之前已成功的本地事务所做的更改,从而确保数据的一致性。
- Saga 可以通过**事件溯源(event sourcing)或有限状态机(finite state machines)**来管理事务的状态。
虽然 Saga 可以用于解决分布式事务问题,但也应谨慎使用 Saga 模式,因为它会增加系统的复杂性,并且如果它成为架构中的主导特性,则可能表明服务粒度划分不当,违反了微服务解耦的核心原则。
优点
Why are agility, testability, and deployability so well supported in microservices?
为什么敏捷性、可测试性和可部署性在微服务架构中表现良好?
敏捷性(Agility)、可测试性(Testability)和可部署性(Deployability)在微服务架构中得到良好支持的原因主要有以下几点:
- 高度解耦与小部署单元:微服务架构极力推崇高度解耦。每个服务都是极小的部署单元,且具备高度的独立性。这种解耦使得团队可以独立地开发、测试和部署服务,大大减少了对其他服务的依赖,从而提高了敏捷性。
- DevOps 革命与自动化:微服务架构的成功离不开 DevOps 革命和对操作关注点的自动化。自动化部署、自动化测试等现代工程实践是微服务存在的基础,它们极大地提高了部署频率、降低了部署风险,并保证了测试的完整性。
- 更快的变更响应速度:由于服务范围小且高度解耦,当业务需求发生变化时,团队只需修改受影响的少量服务,而不是整个大型单体。这种增量式的演进能力使得组织能够更快地响应市场变化,提高时间到市场(time-to-market)的速度。
- 单一职责与清晰边界:每个微服务都专注于一个单一的业务功能或领域。这种清晰的职责边界使得开发人员更容易理解、测试和维护代码,因为他们不必处理与服务无关的复杂性
缺点
What are two reasons performance is usually an issue in microservices?
在微服务中,性能问题的两个核心因素是什么?
在微服务中,性能问题通常由以下两个核心因素导致:
- 网络调用开销(Network Call Overhead):微服务是分布式架构。这意味着服务之间(乃至用户界面与服务之间)的通信需要通过网络进行。网络调用比本地方法调用耗时更长。当一个业务请求需要链式调用多个微服务时,累积的网络延迟会显著影响整体响应时间。
- 安全验证开销(Security Verification Overhead):在微服务架构中,由于每个服务都是独立的部署单元,因此每个服务端点都需要进行安全验证。这增加了额外的处理时间。这种“在每个入口处进行安全检查”的模式进一步降低了同步、高度分布式架构(如微服务)的性能。
尽管性能是微服务常见的问题,但可以通过**数据缓存(caching)和数据复制(replication)**等模式来减少不必要的网络调用,从而提高性能。
架构量子
Describe a topology where a microservices ecosystem might be only a single quantum.
描述一种拓扑结构,其中微服务生态系统可能仅有一个架构量子。
通常来讲,微服务架构都意味着存在多个架构量子。但如果其部署或通信模型导致了上述的紧密耦合,例如共享数据库或中央同步协调器,那么整个微服务生态系统仍可能被归类为一个单一量子。
1. 共享单一数据库:
- 如果所有微服务都共享一个单一的、中央化的数据库实例,那么整个系统很可能构成一个单一量子。在这种情况下,尽管服务是独立的部署单元,但数据库模式的任何更改都可能影响所有服务,导致它们无法独立演进和部署。这使得系统在部署和数据一致性方面表现得像一个整体。
- 例如,传统的**分层单体(layered monolith)**即使有多个逻辑层,但由于共享一个数据库,它也是一个单一量子。
2. 强制同步通信与中央协调器:
- 在某些情况下,即使服务是分离的,如果它们之间存在大量强制的同步通信依赖(synchronous connascence),或者存在一个**中央编排引擎(orchestration engine)**作为所有行为的巨大耦合点,那么整个系统也可能被视为一个单一量子。在这种拓扑中,如果一个服务调用另一个服务是同步的,那么这些服务的操作架构特性(例如,性能和可用性)必须在调用期间保持一致。中央协调器会限制架构中任何部分具有不同架构特性的能力。
- 例如,编排驱动的服务导向架构(Orchestration-Driven Service-Oriented Architecture, SOA),即使是分布式架构,也通常只有一个量子,因为它普遍使用单一或少量数据库,并且其编排引擎作为巨大的耦合点,阻止了各个部分独立拥有不同的架构特性。
架构全貌
边界设计:限界上下文、团队边界。
粒度与组件识别:功能内聚 vs. 通信复杂度;量子范围思维。
数据拥有权:每服务独立数据存储(数据库多样性);避免共享表。
通信风格:同步 vs. 异步;编排 vs. 编舞。
一致性策略:最终一致性、Saga、补偿事务。
弹性与可观测性:Sidecar/Service Mesh、熔断、限流、Tracing。
部署与运营:CI/CD、容器编排(K8s)、自动化测试策略。
性能与成本权衡:网络开销、数据复制、缓存策略。
治理与演化:契约测试、架构健身函数、可观测指标驱动重构。