事件驱动架构中的数据检索与相关模式解析
立即解锁
发布时间: 2025-08-14 00:22:09 阅读量: 4 订阅数: 16 


事件驱动微服务架构实战指南
### 事件驱动架构中的数据检索与相关模式解析
#### 1. 架构中的编排与协调
在架构设计中,每个有界上下文可由多个服务组成。在不同边界之间,我们采用编排(choreography)的方式;而在边界内部,则可应用协调(orchestration),如定价边界所示。对于更广泛的高级流程,使用编排;而对于较小范围和更局部的流程,可采用协调,例如定价计算。
这种设计思路的主要目的是默认在高级流程中使用编排,而在有限范围内应用协调。这样做能实现服务间的高度解耦,在涉及多个团队的高级层面赋予团队自主性;在涉及人员较少的小范围中使用协调,可让团队自主发布功能而不影响多个领域。
#### 2. 分布式架构下的数据聚合挑战
从单体架构向分布式事件驱动的微服务架构转变后,我们面临一个挑战:如何获取数据的聚合视图?在单体架构和单体数据库中,所有数据集中在一处,获取和连接数据相对简单,通常通过同步 API(如 REST 或 SOAP)暴露信息。但这种方式存在扩展限制。
在分布式架构中,每个独立服务拥有其领域的数据,只能返回关于其领域的信息。例如,UI 可能需要列出所有可用产品及其当前库存和价格。一种可能的解决方案是 API 组合模式,即 UI 应用从每个服务获取信息,合并并显示在 UI 中。然而,这种方法存在严重局限性:
- **性能问题**:处理大量数据时,该方法很快会遇到困难。若要显示包含数百万产品的列表页面,UI 可能需要将数千个项目加载到内存中。
- **用户体验差**:额外的请求会增加 UI 的性能开销,导致用户体验不佳。
#### 3. 事件驱动架构的数据检索模式
事件驱动架构为传统的数据检索方式增加了复杂性,因为数据分布在多个服务中,且可能最终一致。为解决数据聚合问题,我们可以利用持久化事件流来创建非规范化模型。
例如,产品服务可以处理库存和定价服务发布的事件,以丰富其信息,创建满足 UI 需求的非规范化数据视图。这样,过滤和排序操作就变得可行,因为存在持久的非规范化模型。
#### 4. CQS 与 CQRS 模式
##### 4.1 CQS(命令查询分离)
CQS 原则由 Bertrand Meyer 提出,该原则指出方法要么是查询,要么是命令,但不能两者兼具。查询返回值但不改变状态,命令改变状态但不返回值。在特定服务中局部应用 CQS 有助于更好地组织服务,特别是在使用 REST 等协议的 API 中,对于检索(GET、HEAD 等)和更改(POST、PUT、PATCH 等)状态有明确的操作。
##### 4.2 CQRS(命令查询责任分离)
CQRS 源于 CQS,将实体分为命令和查询两个主要概念。在代码中清晰分离对象很有用,因为我们可以随意使用查询,确保它们不会改变状态;而对于命令,我们可以更谨慎地使用。
在架构层面应用 CQRS 时,我们可以将命令和查询分离到不同的组件中,例如创建两个不同的服务,一个仅处理命令或状态更改,另一个仅处理查询而不改变数据。
使用 CQRS 的好处包括:
- **模型专业化**:分离读写模型可使每个模型针对其用途进行优化。
- **数据规范化**:可以在写侧应用第三范式,在读侧对数据进行非规范化处理。
- **技术优化**:可以为读写模型分别选择适合的技术,如在写侧使用事件溯源,在读侧使用 ElasticSearch 进行快速复杂搜索。
- **易于实现新功能**:新的 UI 或查询需求可以仅通过更改读模型服务来实现,而不影响处理写操作和业务逻辑的服务。
- **一致性管理**:写侧通常需要更强的一致性保证,而读侧可以更宽松地接受最终一致性。大多数应用的读操作远多于写操作,分离服务可独立优化和扩展读写两侧。
##### 4.3 何时使用 CQRS
CQRS 并非适用于所有用例,它会增加解决方案的复杂性。简单、直接的领域通常从 CQRS 中获益不大,简单的服务使用传统的 CRUD 方法可能更好。
在决定是否采用 CQRS 时,需要有充分的理由,例如:
- 读操作远超过写操作,需要差异化扩展。
- 概念性的写模型与复杂的读模型有很大差异。
当需要构建类似的读模型时,可以应用 CQRS 的理念,思考是否有必要在单独的服务中构建,以及 CQRS 的好处是否适用于当前用例。
#### 5. CQRS 的不同实现方式
CQRS 的核心是分离读写操作。在之前的示例中,我们创建了两个独立的服务和数据库,但这不是唯一的实现方式。
- **使用同一数据库**:可以在两个服务中使用同一数据库,这种方式可以解决分离数据库带来的最终一致性问题。在发布事件之前更新读写模型,可以解决事件与 API 响应之间的不一致性。但这种方式需要处理同一数据库在两个服务中的模式更改问题,适用于读写模型关系密切的情况。
- **代码层面分离**:可以在单个服务中仅在代码层面严格分离读写操作。
- **增加服务**:可以引入第三个服
0
0
复制全文
相关推荐










