哈Ha!
实践表明,随着微服务范式的持续
相关性,不乏
解释 ,批评甚至
揭穿漏洞的机会 。 因此,回到我们的翻译出版物之后,我们决定专门讨论
微服务 ,或者考虑对文章标题中提出的问题进行详细的回答。
“微服务”一词最早出现在2011/2012年左右。 从那时起,在IT环境中没有微服务,几乎没有。 但是,经过这么多年,我们是否能够正确理解什么是微服务?
首先,让我们看一些定义:
微服务是一种软件开发方法 (...),根据该方法, 应用程序被构造为一组松散耦合的服务。 在微服务架构中,服务非常详细 ,所使用的协议是轻量级的 。 将应用程序分解为单个较小的服务的好处是提高了模块化 。 以这种形式,应用程序更易于理解,开发,测试,并且应用程序本身变得更耐体系结构侵蚀。 通过这种体系结构方法,开发可以并行进行,小型独立团队也有机会独立 开发 , 部署和扩展他们负责的服务。 同样,使用这种方法,可以将连续重构应用于每个服务的体系结构。 微服务体系结构还设计用于连续交付和连续部署 。
zh.wikipedia.org/wiki/微服务
这是马丁·福勒的另一段话:
过去几年来,“微服务架构”一词已经牢固地植根于描述设计此类应用程序的特定方式,每种方式都是一组独立部署的服务 。 尽管没有对该体系结构样式的确切定义,但是围绕应用程序的业务功能,自动部署,终端上的信息收集以及语言和数据的分散管理 ,存在许多一般特征。
martinfowler.com/articles/microservices.html
您可能已经注意到,这两种表达方式之间的主要相似之处是服务和选项的独立性。 现在,让我们尝试回答一些问题,并尝试找出您实际实现的系统是否具有微服务基础!
您的系统是否允许您独立重新启动服务?还是需要按特定顺序重新启动服务? 如果未正确处理节点,则该行为可由节点连接到种子节点的特定群集系统(例如,在Akka群集中)决定。 其他情况可能与长期使用的连接或只能在一侧打开的插座有关。 请记住,沟通应保持简单而轻巧。 如果它是完全异步且基于消息的,那就更好了。 导致服务长期相互依赖的所有限制都可能在支持方面变成困难。 其中一项服务的问题可能会在依赖于该服务的所有其他服务中引发问题,有一天可能会导致严重的全局故障。
您可以独立部署服务吗?在某些情况下,系统中所有服务的发布和部署应同时发生。 这个过程需要几天的时间。 当然,在这种情况下,引入连续部署的可能性是有限的,会出现延迟,并且响应性会变差。 仅仅由于与部署过程相关的成本,处理紧急错误需要花费太多时间。 当不同的团队忙于支持不同的服务时,任何部署依赖性都可能阻止其他团队部署他们的服务,这将导致工作被暂停并且其有效性将降低。
修改是否需要对其他服务进行同步修改?可以想象导致这种现象的许多原因。 首先,这些是API更改。 恰好可以在API请求中添加一个新字段,从而破坏了服务之间的兼容性。 但是,有一些变通办法可以帮助处理以下情况:
- 也许您想保持对API所做的所有更改的强制性向后兼容性; 也就是说,无论何时进行基本更改,都会添加新版本的API。 这并不意味着您将需要始终支持许多版本的API。 在迁移完成之前的一段时间内,您将只需要它们。 您可以简单地与其他团队交谈,并确保每个人都已完成迁移,或者打开指标来判断是否仍在使用特定的API。
- 您还可以考虑以下选项:一次部署应用程序的多个版本,允许其他服务切换到最新版本,然后禁用旧版本。
- 还请尝试使用支持电路演进的格式,例如Avro ,在添加新的字段兼容性时不会违反这种格式。 如果缺少字段值,则可以使用默认值。
同步部署的另一个原因是不同服务使用共享代码。 根据代码共享部分中发布过程的构建方式,任何更改都可能需要更新所有服务。
数据库更改会导致许多服务发生更改吗?是的,通过数据库进行通信是众所周知的反模式。 在这种情况下,有必要更新方案并同时更改几个微服务的代码。 最好确保只有一项服务负责管理电路。 在这种情况下,维护数据库(即执行其更新)和实施发布变得更加容易。 如果您已经处于共享数据库使用情况下,请尝试限制写操作的数量,以便另一个服务仅可用于消耗。
您可以在单个服务中更新Java的依赖项或版本吗?从理论上讲,应该总是有可能的,对吧? 但实际上不是。 有许多“共享”库的示例,或者只是包含系统中所有依赖项定义的项目。 微服务范式的目标是确保每个微服务都是一个独立的实体,此外,甚至不必将不同的微服务编写在同一技术堆栈中。 在开始新项目时,您应该能够自行决定哪种技术最适合它。 任何绑定都会引起新的问题。 在某些时候,您可能需要升级到Scala或JDK,但是当然您不想立即在整个系统中执行此操作。 在正确观察到详细程度的系统中,您可以更新单个服务,部署它,测试和监视它几天或几周,然后,如果一切正确,则可以在系统的其余部分执行更新。 但是,当存在
common
或其他强大的统一机制时,这种可能性就受到严重限制。
您选择的框架或库是否会迫使您专注于其他服务的相同选择?一些库具有很大的侵入性。 当您决定将它们与外部系统集成时,可能突然发现,当您打算在其他技术堆栈中实施新服务时,您的选择不是那么重要。 以与其他服务相同的精神进行集成所带来的成本可能简直难以承受。
例如,假设您有一些用
NodeJS编写的服务,这些服务积极使用
JSON:API 。 接下来,您想在Scala上实施一项新服务,似乎没有合适的客户端库(几年前,我们有一个类似的案例,但是现在该领域的情况已经有了一些改善)。
一项服务的故障会导致整个系统故障吗?假设系统中的通信是完全同步的。 一种服务向另一种服务发出请求,然后等待它的响应。 如果第一个服务失败,那么第二个服务将根本无法工作。 如果您的系统出现这种情况,请尝试在其中实现基于异步消息的通信。 模拟所有过程可能会有些困难,但是这种方法可以消除故障的影响。
如果无法做到这一点,您可以尝试暂时限制应用程序的功能集。 例如,在线商店的页面上显示有关产品的信息并对其进行评论,此外,产品信息和评论来自两个不同的来源。 如果评论微服务不起作用,您仍然可以通过简单地通知用户评论系统暂时不可用来显示产品页面。
您的系统上是否有任何共享组件?您有共享代码吗? 配置? 有什么事吗 是的,这是一个不平凡的问题。 提倡微服务清洁度的人认为,最好根本不要在系统中允许共享实体! 最好只复制而不是拆分代码。 实际上,有时具有几个
共享库是可以接受的,但是有严格的限制。 也许它将是包含
协议缓冲区 proto
文件或仅普通POJO对象的库。 最好避免此类库中的依赖项。 我们曾遇到过这样一个情况,即一个简单的客户端库在大型系统中引起了依赖冲突。 从某个时候开始,似乎应用程序的最旧元素正在使用旧的HTTP库,该库无法更新。 幸运的是,可以通过在构建过程中使用重命名依赖项来避免这些情况(依赖项阴影),但是要非常小心。
服务过度聚合所带来的危害要远远超过代码可重复性所引起的问题。
Sam Newman, 创建微服务
结论实现完美的基于微服务的系统绝非易事。 人们倾向于“偷工减料”,将共享代码引入系统中的紧密联系,有时在实践中,这种系统变成了分布式整体。 如果微服务在项目开始时就已经开始使用,而对主题领域的研究还不够深入,并且在DevOps中没有扎实的现成背景,那么通常会发生这种情况。 最好从
结构正确的整体开始,在该
整体中 ,所有责任领域都是众所周知的,并且可以轻松地将它们彼此分开。 但是,从一开始,您就需要确保系统设计
整洁 ,并认真遵循软件包的组织结构,这将为您轻松地将代码迁移到新服务(例如,单个“几乎顶级”软件包可以作为新微服务的基础) 。
ArchUnit可以帮助分析软件包之间出现的依赖性。
(...)即使确定应用程序足够大以使微服务证明自己合理性,也不应随引入微服务而立即开始新项目的工作。
martinfowler.com/bliki/MonolithFirst.html
请记住,微服务应该简化开发和支持! 您需要的只是松散耦合的服务,每种服务都可以独立于其他服务进行部署。