正在考虑微服务架构的松耦合?小心这些陷阱!

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 本文讲的是正在考虑微服务架构的松耦合?小心这些陷阱!【编者的话】本文阐述了作者在构建松耦合的微服务架构中遇到的一些挑战,并给出了相应的方法,包括:如何处理多个微服务间共享数据的场景,如何演进微服务API,如何处理微服务安全,以及如何组合微服务等。
本文讲的是正在考虑微服务架构的松耦合?小心这些陷阱!【编者的话】本文阐述了作者在构建松耦合的微服务架构中遇到的一些挑战,并给出了相应的方法,包括:如何处理多个微服务间共享数据的场景,如何演进微服务API,如何处理微服务安全,以及如何组合微服务等。

微服务是一种新的架构,它使用简单、轻量、松耦合的服务来构建系统,这些服务彼此可以独立开发和发布。

如果你还不了解这些基础概念,请阅读 Martin Fowler的文章 。如果你想拿它和SOA进行比较,请看 Don Ferguson的演讲 。Martin Fowler还写了“ 微服务的权衡 ”和“ 何时使用微服务 ”,帮你决定什么情况下微服务是有用的。

本文假定你听说或阅读过微服务相关文章,并认同微服务理念。如果你正在实践微服务架构,你会碰到很多挑战。本文将讨论如何处理这些挑战。

没有共享的数据库

每个微服务都应该有自己的数据库,而不是在同一个数据库中共享数据。这条规则可消除常见的导致微服务紧耦合的问题。比如两个服务共享同一个数据库,一旦其中一个改变了数据库的模式(schema),另一个就会无法工作。因此这两个微服务所在项目组必须事先沟通。

我认为这是一条很好的规则,不应该被破坏。然而这里有个问题。如果两个服务共享相同的数据(比如银行账户,购物车),且数据需要被事务性地更新,最简单的方法是将数据存储在同一数据库中,并利用数据库的事务来确保一致性。任何其它的方法都是很困难的。

方案1 :如果更新只发生在一个微服务(比如贷款批准中的余额核对流程),可以使用异步消息机制(消息队列)共享数据。

方案2 :如果两个微服务都有更新,可以考虑合并它们,或者使用事务机制。文章“ 微服务:不止服务的规模,也包括你如何使用服务 ”描述了合并的方法,下一节我们详细讨论事务机制。

处理更新的一致性

考虑多个地方都有对同一数据进行更新的场景。我们在上一节中讨论了一个例子(如果只有一处地方更新,我们已经讨论过如何处理)。

请注意这个使用事务来解决的典型用例。然而有时你也可以不用事务来解决。这里有一些其它的选项。

所有更新放在同一微服务中

只要有可能,都要避免多个跨越微服务边界的更新。然而有时候这么做,你会碰到更大的问题,因此这不通用。

使用补偿和其它更小的抵押物

正如著名文章“ 星巴克不使用两阶段的提交 ”中描述的,普通的生活中不需要用到事务。例如星巴克的咖啡师不会等到你的事务完成才继续其它的事务。相反,他们会同时服务多个客户,一旦有错误立即显式补偿。如果你愿意稍微多做点工作,你也可以像他们这样做。

一个简单的想法是,如果一个选项失败了,你可以做些补偿并继续前进。例如你正在运送书本,首先要扣钱,才能运送,假如运送失败,你退还货款,然后继续。

有时候你也会专注于最终的一致性或者超时。另一个简单的想法是,给一个按钮,假如这个按钮能区分超时,那就让它强制刷新页面。另一些时候,只能忍痛考虑少一点的一致性了(例如 Vogel 的文章 就是个好的起点)。

最后,“ 分布式事务以外的生活:一个背叛者的观点 ”详细讨论了以上所有技巧。

话虽如此,仍旧存在你必须使用事务才能获取正确结果的情况。这时候就必须使用事务了。可参考“ 微服务和事务(更新篇) ”。考虑各种方法的优缺点,明智得选择最合适你的那个。

微服务安全

早期的做法是,当一个服务接收到请求时,调用数据库或者身份认证服务器来做认证。

这里身份认证服务器也可以用一个微服务来替代。在我看来,那样做会生成一个巨大且复杂的依赖图。

相反,我喜欢如下图所描述的基于token的方法。这个想法在“构造微服务”这本书中有描述。首先客户端(或者网关)告诉身份认证服务器谁将过来认证用户,服务器返回给客户端一个token,它描述了这个用户和它对应的角色(你可以用SAML或者OpenIDConnect来达到这个目的)。每个微服务验证这个token,根据token所描述的用户角色来授权访问。

例如,用这种模型,对同一个请求,一个“发布者”角色的用户和一个“管理员”角色的用户可能看到不同的结果,因为他们有不同的权限。

你可以在“ 如何在微服务中控制用户身份 ”这篇文章中找到关于这种方法的更多信息。

微服务组合

这里,“组合”指的是,“如何连接多个微服务为一条工作流,来获取终端用户想要的东西”。

大多数SOA的组合看起来如下所示。中心思想是有个中央服务器来运行整条工作流。

不提倡微服务中使用企业服务总线(ESB)(例如, 第5章DevOps团队关于反对ESB的争论 )。同时,你也可以在“ 好的微服务架构诅咒ESB的死亡? ”中找到某些相反的辩论。

本文不打算深入研究ESB。然而我想讨论是否我们需要一个中央服务器来组合微服务。有很多方法来组合微服务。

方法1:客户端驱动流程

下图展示了一个不用中央服务器来组合微服务的方法。客户端浏览器处理这个工作流。文章“ 域服务的聚合:一种构造微服务组合的结构化方法 ”就是这种方法的一个例子。

这个方法存在一些问题:
  1. 如果客户端在一个很慢的网络里,而这往往是最常见的情况,流程的执行就会变得很慢,因为现在多个调用都需要由客户端来触发。
  2. 可能需要加强安全考虑(我可以侵入我的应用让它给我贷款)。
  3. 以上的例子只考虑了网站。然而,大多数复杂的组合通常来自于其它的用例。因此其它用例下客户端的组合的通用性还需要被证明。
  4. 哪里可以保存状态?客户端可以被信任用来保存工作流的状态吗?用REST模型来保存,是可行的,但是也是复杂的。

方法2:编排

从中心位置来驱动流程称为编制(orchestration)。然而那不是协调多个合作方共同完成任务的唯一方式。例如在舞蹈中,就没有一个指挥整个表演的人,相反,每个跳舞者都跟随她旁边的人并保持同步。编排(choreography)就是把这个想法应用到业务流程中。

事件系统就是编排的一个典型实现。该系统中每个参与者监听不同的事件并执行它所对应的那些事件。每个动作都会生成异步事件,这些事件又触发下游参与者生成对应的动作。这就是RxJava和Node.js等环境使用的编程模型。

例如,我们假定一个贷款过程包括一个请求,信用核查,其它外部贷款核查,领导审批,以及最终结果的通知。下图展示如何使用编排实现这一过程。请求将被放在当前队列中。它的下个阶段处理完结果并将结果放到该阶段所对应的队列后,再从当前队列中取出一个请求继续处理。这个过程会一直持续到请求结束。

就像舞蹈需要排练一样,编排也是复杂的。例如你不知道某个过程什么时候结束,也不知道它是否发生了错误或者被阻塞了。编排需要一个监控系统来追踪过程并恢复或者通知某些错误。

另一方面,编排的优点是,它能创建非常送耦合的系统。例如,你可以频繁添加一个新的参与者,而不需要修改已有的参与者。你可以在“ 使用事件流伸缩微服务 ”中找到更多详细信息。

方法3:集中式服务器

最后一个,也是最简单的一个选项,是使用集中式服务器(也称作编制)。

SOA通常用两种方法来实现集中式服务器:企业服务总线(ESB)或者业务流程。微服务偏好者们建议使用API网关(例如文章“ 微服务:分解应用提高可部署性和可扩展性 ”)。我猜API网关是更轻量级的并且使用REST或者JSON等技术。但是从架构的角度来说,它们都使用编制的风格。

另一个集中式服务器的变种是“backend for frontends”(BEF),它为每种客户端都构造一个服务端的API(如桌面应用的服务端API,iOS应用的服务API等)。这种模式为每种客户端类型都创建不同的API,在每种场景下都最优化。详情请参考:“ backends for frontends ”。

我在这里就不把所有选项都介绍一遍了,仅以API网关为例,因为这是最直白的一种方法。如果你有需求,可以切到更复杂的方法。

避免过度依赖

我们使用微服务架构就是为了使每个服务都能独立发布和部署,因此必须避免过度依赖。

假定微服务A有一个API“A1”要升级成API“A2”。现在有两种情况:
  1. 微服务B能将发送给“A1”的消息发送给“A2”。这是后向兼容。
  2. 微服务A可能必须回退到“A1”,微服务C要求可以继续将发送给“A2”的消息发送给“A1”。

你必须能够处理上述场景,并使得微服务能独立演进和部署。如果不行,你所有的努力都将付诸东流。

处理这些场景,通常就是添加可选参数,并且不重命名或者删除已有的参数。然而更复杂的场景也是有可能的。文章“ 微服务中改善过度依赖 ”详细描述了这些可能,“ 如何对微服务进行版本控制 ”也是一个很好的例子。

最终,后向和前向兼容的支持都应以时间为界。例如,你可以规定,所有微服务都不应再依赖超过三个月时常的API。这可以让微服务的开发者最终清除某些代码。

最后我将再强调一下,在微服务架构中,你的依赖图应该长啥样。

一种是一旦需要,尽情得调用其它微服务。这将创建一个意大利细面的结构。我不支持这种模型。

另一个极端是微服务不应调用其它微服务,所有连接都应通过API网关或者消息总线来完成。这将生成一棵只有一个层次的树。例如我们不是让微服务A直接调用B,而是让A通过API网关来获取调用B的结果。这其实就是编制模型。如此一来,大部分的商业逻辑都将储存在API网关中,从而使得API网关异常庞大。

我的意见是,要么使用编制模型,要么通过艰苦的工作合理地实现编排模型。是的,不要用意大利细面的结构。

结论

微服务的目标是松耦合。仔细设计微服务架构允许你实现一个使用微服务集合的工程,每个微服务都可以被独立管理,开发和发布。

当你设计微服务的时候,你必须一直盯着那个奖品,既“松耦合”。这将会碰到许多挑战。本文回答了下列问题:
  1. 如何处理两个微服务间需要共享数据的场景。
  2. 如何在保持松耦合的前提下演进微服务API。
  3. 如何处理安全。
  4. 如何组合微服务。

谢谢大家。非常希望听到大家的想法。

原文链接:Walking the Microservices Path towards Loose coupling? Look out for these Pitfalls (翻译:池剑锋)

原文发布时间为:2016-06-25

本文作者:池剑锋

本文来自云栖社区合作伙伴Dockerone.io,了解相关信息可以关注Dockerone.io。

原文标题:正在考虑微服务架构的松耦合?小心这些陷阱!

相关文章
|
4天前
|
负载均衡 测试技术 持续交付
高效后端开发实践:构建可扩展的微服务架构
在当今快速发展的互联网时代,后端开发扮演着至关重要的角色。本文将重点探讨如何构建可扩展的微服务架构,以及在后端开发中提高效率的一些实践方法。通过合理的架构设计和技术选型,我们可以更好地应对日益复杂的业务需求,实现高效可靠的后端系统。
|
4天前
|
监控 持续交付 API
构建高效可扩展的微服务架构
在当今快速迭代和竞争激烈的软件市场中,构建一个高效、可扩展且易于维护的后端系统变得尤为重要。微服务架构作为一种流行的分布式系统设计方式,允许开发者将应用程序划分为一系列小型、自治的服务,每个服务负责执行特定的业务功能。本文将探讨如何利用现代技术栈搭建一个符合这些要求的微服务架构,并讨论其潜在的挑战与解决方案。我们将涵盖服务划分策略、容器化、服务发现、API网关、持续集成/持续部署(CI/CD)以及监控和日志管理等关键主题,以帮助读者构建出既可靠又灵活的后端系统。
|
6天前
|
监控 Kubernetes 持续交付
构建高效可扩展的微服务架构:后端开发实践指南
在数字化转型的浪潮中,企业对软件系统的要求日益提高,追求快速响应市场变化、持续交付价值成为核心竞争力。微服务架构以其灵活性、模块化和独立部署的特点,成为解决复杂系统问题的有效途径。本文将深入探讨如何构建一个高效且可扩展的微服务架构,涵盖关键设计原则、技术选型及实践案例,为后端开发者提供一条清晰的指导路线,帮助其在不断变化的技术环境中保持竞争力。
115 3
|
5天前
|
消息中间件 敏捷开发 运维
构建高效可靠的微服务架构:策略与实践
随着现代软件开发的复杂性增加,微服务架构逐渐成为企业解决大型应用系统分解、敏捷开发和持续部署问题的有效手段。本文深入探讨了构建一个高效且可靠的微服务架构的关键策略,包括服务的合理划分、通信机制的选择、数据一致性保障以及容错处理。通过分析这些策略在具体案例中的应用,我们旨在为开发者提供一套可行的微服务设计及实施指南。
115 6
|
5天前
|
监控 数据管理 API
构建高效微服务架构:后端开发的新趋势
在现代软件开发领域,随着业务需求的不断复杂化以及敏捷迭代的加速,传统的单体应用架构逐渐暴露出其局限性。微服务架构作为一种新的解决方案,以其高度模块化、独立部署和可扩展性,正成为后端开发领域的新趋势。本文将探讨微服务架构的核心概念,分析其优势与面临的挑战,并提供实施高效微服务的策略和最佳实践,帮助读者理解如何利用这一架构模式提升系统的可靠性、灵活性和可维护性。
126 5
|
8天前
|
人工智能 运维 监控
构建高性能微服务架构:现代后端开发的挑战与策略构建高效自动化运维系统的关键策略
【2月更文挑战第30天】 随着企业应用的复杂性增加,传统的单体应用架构已经难以满足快速迭代和高可用性的需求。微服务架构作为解决方案,以其服务的细粒度、独立性和弹性而受到青睐。本文将深入探讨如何构建一个高性能的微服务系统,包括关键的设计原则、常用的技术栈选择以及性能优化的最佳实践。我们将分析微服务在处理分布式事务、数据一致性以及服务发现等方面的挑战,并提出相应的解决策略。通过实例分析和案例研究,我们的目标是为后端开发人员提供一套实用的指南,帮助他们构建出既能快速响应市场变化,又能保持高效率和稳定性的微服务系统。 【2月更文挑战第30天】随着信息技术的飞速发展,企业对于信息系统的稳定性和效率要求
|
5天前
|
API 持续交付 开发者
构建高效微服务架构:后端开发的新范式
在数字化转型和技术迭代的浪潮中,微服务架构以其灵活性、可扩展性和独立性成为现代后端开发的重要趋势。本文深入探讨了构建高效微服务架构的关键要素,包括服务划分策略、容器化部署、API网关设计以及持续集成与持续部署(CI/CD)的实践。通过分析这些组件和流程,我们旨在为后端开发者提供一套实用的指南,帮助他们构建和维护一个高性能、可靠的微服务系统。
20 5
|
5天前
|
消息中间件 缓存 API
微服务架构下的API网关性能优化实践
在现代的软件开发中,微服务架构因其灵活性和可扩展性被广泛采用。随着服务的细分与增多,API网关作为微服务架构中的关键组件,承担着请求路由、负载均衡、权限校验等重要职责。然而,随着流量的增长和业务复杂度的提升,API网关很容易成为性能瓶颈。本文将深入探讨API网关在微服务环境中的性能优化策略,包括缓存机制、连接池管理、异步处理等方面的具体实现,旨在为开发者提供实用的性能提升指导。
|
6天前
|
Prometheus 监控 API
构建高效微服务架构:后端开发的新趋势
随着现代软件开发的复杂性增加,传统的单体应用已难以满足快速迭代与灵活部署的需求。微服务架构作为解决这一问题的有效手段,其设计理念和实践方法已成为后端开发领域的热门话题。本文将探讨如何构建一个高效的微服务架构,涵盖设计原则、技术选型、以及实践中可能遇到的挑战,为后端开发者提供一套可行的参考方案。
13 2
|
7天前
|
缓存 负载均衡 监控
构建高效微服务架构:API网关的作用与实践
【2月更文挑战第31天】 在当今的软件开发领域,微服务架构已成为实现系统高度模块化和易于扩展的首选方法。然而,随着微服务数量的增加,确保通信效率和管理一致性变得尤为重要。本文将探讨API网关在微服务架构中的核心角色,包括其在请求路由、安全性、负载均衡以及聚合功能方面的重要性。我们将通过具体案例分析,展示如何利用API网关优化后端服务,并讨论实施过程中的最佳实践和常见挑战。

相关产品

  • 微服务引擎
  • 服务网格