[第二部:容器和微服务架构] (7)分布式数据管理的挑战与解决方案

本文涉及的产品
AI 网关免费试用,400元 Serverless
简介: [第二部:容器和微服务架构] (7)分布式数据管理的挑战与解决方案

挑战1:如何定义每个微服务的边界


定义微服务边界可能是任何人遇到的第一个挑战。每个微服务都必须是应用程序的一部分,每个微服务都应该是自主的,具有它所传递的所有好处和挑战。但是你如何确定这些界限呢?

首先,您需要关注应用程序的逻辑域模型和相关数据。尝试在同一个应用程序中识别分离的数据孤岛和不同的上下文。每个上下文可以有不同的业务语言(不同的业务术语)。上下文应该独立定义和管理。在这些不同上下文中使用的术语和实体听起来可能类似,但您可能会发现,在特定上下文中,一个业务概念与另一个业务概念用于不同的上下文中,甚至可能有不同的名称。例如,用户可以在身份或成员关系上下文中被称为用户,在CRM上下文中被称为客户,在订购上下文中被称为买方,等等。

为每个上下文标识具有不同域的多个应用程序上下文之间的边界的方式,正是如何标识每个业务微服务及其相关域模型和数据的边界。您总是试图最小化这些微服务之间的耦合。本指南稍后将在《为每个微服务标识域模型边界》一节中详细介绍此标识和域模型设计。


挑战2:如何创建从多个微服务检索数据的查询


第二个挑战是如何实现从多个微服务检索数据的查询,同时避免从远程客户端应用程序与微服务进行聊天。例如,移动应用程序中的一个屏幕需要显示篮子、目录和用户标识微服务所拥有的用户信息。另一个例子是一个复杂的报表,其中包含位于多个微服务中的多个表。正确的解决方案取决于查询的复杂性。但无论如何,如果您想提高系统通信的效率,就需要一种聚合信息的方法。最流行的解决方案如下。


API网关。


对于来自拥有不同数据库的多个微服务的简单数据聚合,建议使用称为API网关的聚合微服务。但是,在实现这个模式时需要小心,因为它可能是系统中的一个瓶颈,并且可能违反微服务自治的原则。为了减少这种可能性,您可以拥有多个细粒度API网关,每个网关侧重于系统的垂直“部分”或业务区域。API网关模式将在后面的API网关部分中进行更详细的解释。


带有查询/读取表的CQRS(命令和查询责任隔离)


从多个微服务聚合数据的另一个解决方案是物化视图模式。在这种方法中,您可以预先(在实际查询发生之前准备非规范化的数据)生成一个只读表,其中包含多个微服务所拥有的数据。该表的格式适合客户端应用程序的需要。

考虑一下类似移动应用程序的屏幕。如果只有一个数据库,则可以使用SQL查询将该屏幕的数据拉到一起,该查询执行涉及多个表的复杂连接。但是,如果您有多个数据库,并且每个数据库都属于不同的微服务,则无法查询这些数据库并创建SQL联接。复杂的查询成为一个挑战。您可以使用CQRS方法来解决需求,您可以在一个仅用于查询的不同数据库中创建一个非规范化的表。该表可以专门为复杂查询所需的数据设计,应用程序屏幕所需的字段与查询表中的列之间具有一对一的关系。它也可用于报告目的。


这种方法不仅解决了最初的问题(如何跨微服务查询和连接),而且与复杂的连接相比,它还大大提高了性能,因为您已经在查询表中拥有应用程序所需的数据。当然,对查询/读取表使用命令和查询责任分离(CQRS)意味着需要额外的开发工作,您需要接受最终的一致性。尽管如此,协作场景(或竞争场景,取决于视角)中的性能和高可伸缩性要求是您应该对多个数据库应用cqr的地方。


中央数据库中的“冷数据”。


对于可能不需要实时数据的复杂报表和查询,一种常见的方法是将“热数据”(来自微服务的事务数据)作为“冷数据”导出到仅用于报表的大型数据库中。中央数据库系统可以是一个基于大数据的系统,比如Hadoop,一个基于Azure SQL数据仓库的数据仓库,甚至是一个只用于报表的SQL数据库(如果大小不是问题的话)。


请记住,这个集中式数据库只用于不需要实时数据的查询和报告。原始的更新和事务,作为您的真相来源,必须在您的微服务数据。同步数据的方式可以是使用事件驱动的通信(下一节将介绍)或使用其他数据库基础结构导入/导出工具。如果使用事件驱动的通信,那么集成过程将类似于前面为CQRS查询表所描述的传播数据的方式。


但是,如果您的应用程序设计涉及不断聚合来自多个微服务的信息以进行复杂的查询,则这可能是设计错误的征兆-微服务应尽可能与其他微服务隔离。(这不包括总是应该使用冷数据中心数据库的报表/分析)经常出现此问题可能是合并微服务的一个原因。您需要在每个微服务的演进和部署的自主性与强依赖性、内聚性和数据聚合之间取得平衡。


挑战3:如何跨多个微服务实现一致性


如前所述,每个微服务拥有的数据是该微服务的私有数据,只能使用其微服务API访问。因此,一个挑战是如何实现端到端业务流程,同时保持多个微服务之间的一致性。


为了分析这个问题,让我们看一个来自eShopOnContainers参考应用程序的示例。目录微服务维护所有产品的信息,包括产品价格。Basket microservice管理用户添加到购物篮中的产品项目的时间数据,其中包括添加到购物篮时的项目价格。当产品的价格在目录中更新时,该价格也应该在保存同一产品的活动篮中更新,另外,系统可能应该警告用户,说某个特定项目的价格自从添加到其篮中后已经发生了变化。


在这个应用程序的假设整体版本中,当products表中的价格发生变化时,catalog子系统可以简单地使用ACID事务来更新篮子表中的当前价格。

但是,在基于微服务的应用程序中,产品表和篮子表由各自的微服务拥有。任何微服务都不应该在自己的事务中包括另一个微服务拥有的表/存储,甚至在直接查询中也不应该包括,如图4-9所示。


微服务禁止直接访问另一个微服务中的表


Catalog microservice不应该直接更新Basket表,因为Basket表属于Basket microservice。为了更新Basket microservice,Catalog microservice应该使用可能基于异步通信(如集成事件(基于消息和事件的通信))的最终一致性。这就是eShopOnContainers引用应用程序如何跨微服务执行这种类型的一致性。


如CAP定理所述,您需要在可用性和ACID 强一致性之间进行选择。大多数基于微服务的场景要求可用性和高可伸缩性,而不是强一致性。任务关键型应用程序必须保持正常运行,开发人员可以通过使用处理弱一致性或最终一致性的技术来解决强一致性问题。这是大多数基于微服务的架构所采用的方法。

此外,ACID风格或两阶段提交事务不仅违反微服务原则;大多数NoSQL数据库(如Azure Cosmos DB、MongoDB等)不支持两阶段提交事务,这在分布式数据库场景中是典型的。然而,维护跨服务和数据库的数据一致性是必不可少的。这个挑战还涉及到当某些数据需要冗余时(例如,当您需要在目录微服务和篮子微服务中包含产品名称或描述时),如何在多个微服务中传播更改的问题。


解决这个问题的一个很好的方法是使用事件驱动通信和发布和订阅系统所连接的微服务之间的最终一致性。本指南后面的异步事件驱动通信一节将介绍这些主题。


挑战4:如何设计跨越微服务边界的通信


跨越微服务边界进行通信是一个真正的挑战。在这种情况下,通信并不是指应该使用什么协议(HTTP和REST、AMQP、消息传递等等)。相反,它解决了您应该使用什么样的通信方式,特别是您的微服务应该如何耦合。根据耦合的级别,当发生故障时,该故障对系统的影响将有很大的不同。


在像基于微服务的应用程序这样的分布式系统中,有这么多工件在移动,并且有跨多个服务器或主机的分布式服务,组件最终将失败。部分故障甚至更大的中断都会发生,因此您需要考虑到这种分布式系统中的常见风险,设计您的微服务和它们之间的通信。


一种流行的方法是实现基于HTTP(REST)的微服务,因为它们很简单。基于HTTP的方法是完全可以接受的;这里的问题与您如何使用它有关。如果使用HTTP请求和响应只是为了与来自客户端应用程序或API网关的微服务交互,那就没问题了。但是,如果您跨微服务创建长链的同步HTTP调用,并跨其边界进行通信,就好像微服务是单片应用程序中的对象一样,那么您的应用程序最终将遇到问题。


例如,假设您的客户机应用程序对单个微服务进行HTTP API调用,就像对微服务进行排序一样。如果顺序微服务在同一请求/响应周期内使用HTTP调用其他微服务,则创建一个HTTP调用链。一开始听起来可能很合理。然而,在沿着这条路走下去时,需要考虑的要点有:


  • 阻塞和低性能。由于HTTP的同步特性,原始请求在所有内部HTTP调用完成之前不会得到响应。想象一下,如果这些调用的数量显著增加,同时对微服务的一个中间HTTP调用被阻塞。结果是性能受到影响,并且随着额外的HTTP请求的增加,总体可伸缩性将受到指数级的影响。

  • 将微服务与HTTP耦合。业务微服务不应与其他业务微服务耦合。理想情况下,他们不应该“知道”其他微服务的存在。如果应用程序依赖于耦合微服务(如示例所示),则几乎不可能实现每个微服务的自治。

  • 任何一个微服务出现故障。如果实现了一个由HTTP调用链接的微服务链,那么当任何一个微服务失败(最终它们将失败)时,整个微服务链都将失败。应设计一个基于微服务的系统,以便在部分故障期间尽可能继续工作。即使实现了使用指数退避或断路器机制重试的客户端逻辑,HTTP调用链越复杂,实现基于HTTP的故障策略就越复杂。


事实上,如果您的内部微服务是通过创建所述的HTTP请求链进行通信的,那么可以认为您有一个单片应用程序,但它是基于进程间HTTP而不是进程内通信机制的应用程序。


因此,为了强制微服务自治并具有更好的弹性,您应该尽量减少跨微服务的请求/响应通信链的使用。建议您只使用异步交互进行微服务间通信,可以使用异步消息和基于事件的通信,也可以使用(异步)HTTP轮询,独立于原始HTTP请求/响应周期。


异步通信的使用将在本指南后面的“异步微服务集成实施微服务的自治和基于异步消息的通信”一节中详细说明。


额外资源

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
相关文章
|
4月前
|
存储 安全 Java
管理 Spring 微服务中的分布式会话
在微服务架构中,管理分布式会话是确保用户体验一致性和系统可扩展性的关键挑战。本文探讨了在 Spring 框架下实现分布式会话管理的多种方法,包括集中式会话存储和客户端会话存储(如 Cookie),并分析了它们的优缺点。同时,文章还涵盖了与分布式会话相关的安全考虑,如数据加密、令牌验证、安全 Cookie 政策以及服务间身份验证。此外,文中强调了分布式会话在提升系统可扩展性、增强可用性、实现数据一致性及优化资源利用方面的显著优势。通过合理选择会话管理策略,结合 Spring 提供的强大工具,开发人员可以在保证系统鲁棒性的同时,提供无缝的用户体验。
100 0
|
5月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
1009 3
|
8月前
|
小程序 前端开发
2025商业版拓展校园圈子论坛网络的创新解决方案:校园跑腿小程序系统架构
校园跑腿小程序系统是一款创新解决方案,旨在满足校园配送需求并拓展校友网络。跑腿员可接单配送,用户能实时跟踪订单并评价服务。系统包含用户、客服、物流、跑腿员及订单模块,功能完善。此外,小程序增设信息咨询发布、校园社区建设和活动组织等功能,助力校友互动、经验分享及感情联络,构建紧密的校友网络。
348 1
2025商业版拓展校园圈子论坛网络的创新解决方案:校园跑腿小程序系统架构
|
3月前
|
Cloud Native Serverless API
微服务架构实战指南:从单体应用到云原生的蜕变之路
🌟蒋星熠Jaxonic,代码为舟的星际旅人。深耕微服务架构,擅以DDD拆分服务、构建高可用通信与治理体系。分享从单体到云原生的实战经验,探索技术演进的无限可能。
微服务架构实战指南:从单体应用到云原生的蜕变之路
|
9月前
|
人工智能 安全 Java
智慧工地源码,Java语言开发,微服务架构,支持分布式和集群部署,多端覆盖
智慧工地是“互联网+建筑工地”的创新模式,基于物联网、移动互联网、BIM、大数据、人工智能等技术,实现对施工现场人员、设备、材料、安全等环节的智能化管理。其解决方案涵盖数据大屏、移动APP和PC管理端,采用高性能Java微服务架构,支持分布式与集群部署,结合Redis、消息队列等技术确保系统稳定高效。通过大数据驱动决策、物联网实时监测预警及AI智能视频监控,消除数据孤岛,提升项目可控性与安全性。智慧工地提供专家级远程管理服务,助力施工质量和安全管理升级,同时依托可扩展平台、多端应用和丰富设备接口,满足多样化需求,推动建筑行业数字化转型。
344 5
|
9月前
|
机器学习/深度学习 并行计算 PyTorch
英伟达新一代GPU架构(50系列显卡)PyTorch兼容性解决方案
本文记录了在RTX 5070 Ti上运行PyTorch时遇到的CUDA兼容性问题,分析其根源为预编译二进制文件不支持sm_120架构,并提出解决方案:使用PyTorch Nightly版本、更新CUDA工具包至12.8。通过清理环境并安装支持新架构的组件,成功解决兼容性问题。文章总结了深度学习环境中硬件与框架兼容性的关键策略,强调Nightly构建版本和环境一致性的重要性,为开发者提供参考。
6265 64
英伟达新一代GPU架构(50系列显卡)PyTorch兼容性解决方案
|
7月前
|
Docker 容器
Docker网关冲突导致容器启动网络异常解决方案
当执行`docker-compose up`命令时,服务器网络可能因Docker创建新网桥导致IP段冲突而中断。原因是Docker默认的docker0网卡(172.17.0.1/16)与宿主机网络地址段重叠,引发路由异常。解决方法为修改docker0地址段,通过配置`/etc/docker/daemon.json`调整为非冲突段(如192.168.200.1/24),并重启服务。同时,在`docker-compose.yml`中指定网络模式为`bridge`,最后通过检查docker0地址、网络接口列表及测试容器启动验证修复效果。
1309 39
|
6月前
|
缓存 Cloud Native Java
Java 面试微服务架构与云原生技术实操内容及核心考点梳理 Java 面试
本内容涵盖Java面试核心技术实操,包括微服务架构(Spring Cloud Alibaba)、响应式编程(WebFlux)、容器化(Docker+K8s)、函数式编程、多级缓存、分库分表、链路追踪(Skywalking)等大厂高频考点,助你系统提升面试能力。
379 0
|
9月前
|
负载均衡 算法 关系型数据库
大数据新视界--大数据大厂之MySQL数据库课程设计:MySQL集群架构负载均衡故障排除与解决方案
本文深入探讨 MySQL 集群架构负载均衡的常见故障及排除方法。涵盖请求分配不均、节点无法响应、负载均衡器故障等现象,介绍多种负载均衡算法及故障排除步骤,包括检查负载均衡器状态、调整算法、诊断修复节点故障等。还阐述了预防措施与确保系统稳定性的方法,如定期监控维护、备份恢复策略、团队协作与知识管理等。为确保 MySQL 数据库系统高可用性提供全面指导。