微服务的真正价值

模块化

模块化是软件开发最重要的概念之一。模块形成系统的独立组件,由于定义明确的内部和外部接口而变得可交换。模块的内部绑定和模块之间的耦合定义了系统的结构。绑定是模块紧凑性的定性度量。模块元素之间的关系很重要,这些关系应该尽可能不同。

好的架构中的模块都具有非常强的绑定。模块的耦合是它们之间接口的定性度量。重要的特征是耦合机制、接口宽度和通信的性质。模块之间的低耦合使得每个模块都可以独立开发和运行。此外,松散连接的模块更易于交换,简化维护和进一步开发。

正确的切割

定义架构时最重要同时也是最困难的任务是将系统分解为模块。David L. Parnas 在他 1971 年的文章“On the criteria to be used in decomposing systems into modules”[Par71] 中已经涵盖了模块形成标准的重要性。在分解为模块方面,我们现在参考 Eric Evans 的领域驱动设计 [DDD] 中的限界上下文概念。有界上下文将域分成子域,其中定义的模型是有效的。

图1

经常用来说明模块化架构的一个例子是在线商店。通常,有三个模块,如图 1 所示:客户、订单和产品目录。不幸的是,在这个小例子中,两个模块之间已经存在很强的关系:Customer 和 order 相互调用。这导致了一个循环。应该避免循环,因为它们会产生高耦合,导致两个模块只能同时修改。还不清楚模块是否已正确定义,或者将它们组合成一个模块是否会更好。

在分解成模块时,还应该出现理想模块有多大的问题。微服务架构中的“微”意味着模块应该尽可能小。如果我们遵循限界上下文原则,大小似乎并不是决定性的。示例:B2C 网上商店只需要几个实体来描述其客户,例如客户名称、送货地址和付款信息。在 B2B 案例中,一个客户由十几个实体描述。但在这两种情况下,我们都在查看客户模块。

大泥球

模块化软件架构的对立面被描述为“一个大泥球”。“大泥球”描述了一个随着时间的推移而增长的系统,而没有意识到软件架构,它没有显示出可辨别的结构。此类系统难以维护,通常只能整体更换,在进一步开发过程中会产生非常高的成本。

怎样才能避免“一团泥”呢?必须定义和传达目标架构。为此,定义了模块。开发模式语言也有帮助。这将有助于所有参与者更好地沟通。根据我在软件现代化项目中的经验,正确分配职责非常重要。特别是基础设施代码应该与技术代码分开。

验证架构是另一个重要方面。编写第一行代码后,必须立即根据目标体系结构验证代码库。Structure101、Sonargraph、ArchUnit、jqAssistant 等工具有助于可视化和检查依赖关系。由于微服务架构具有分布式依赖的特点,因此应该重视接口管理,反思这种关系是否正确和必要。

面向服务架构 2.0

微服务架构通常表示为 SOA 2.0。围绕面向服务的架构 [SOA] 的炒作早在九十年代中期就已经开始了。SOA 和微服务一样,都是一种架构风格。在 SOA 中,服务可以描述如下:“服务是具有特定结果的可重复业务活动的逻辑表示(例如,检查客户的信用度,查询天气数据)。服务是独立的,可以包含其他服务。该服务代表其用户的黑盒。”

微服务之间的最大区别在于 SOA 没有对分发做出任何声明。应用程序的 SOA 服务通常作为接口提供。根据 SOA 的定义,术语服务可以比作无服务器架构的功能。

微服务与单体

微服务架构的对立面是单体。基于微服务的架构和单体架构在分布方面有所不同。分布式系统不仅具有优势,也带来了网络通信方面的问题。例如,服务可能会出现故障或响应时间过长。熔断、缓存和冗余等概念开始发挥作用,增加了复杂性。在他的文章 [Fow03] 中,Martin Fowler 写道:“分布式对象设计的第一定律:不要分发你的对象!”

要独立分发和扩展模块,必须分发这些模块。在这种情况下,通常会选择通过 RESTH/TTP 的同步通信方式。这可能导致 O/R 映射器可怕的 n+1 选择问题转移到微服务之间的通信层。

 

图 2 显示了一个客户端试图查询一组客户的所有订单。一种天真的方法是在分别查询每个客户的订单之前先与客户服务进行初始查询以获取客户列表。这种通信不可避免地会导致性能问题。 

 

分布式通信的另一个非常重要的方面是所涉及的通信方式。图 3 显示,除了同步通信方式外,还有异步通信方式,从而实现更好的解耦。可以使用请求/回复模型模拟同步通信。然而,问题是我们应该等待多久才能得到答复,如果没有得到答复怎么办?一种可能性是重复查询。但是,如果服务未实现幂等,则查询可能会被处理两次。

事件驱动的通信模型提供了最大可能的解耦。该模型支持服务之间的松散耦合。一个很大的优势是发送者不需要知道接收者处于什么状态,接收者是谁,或者事件是如何处理的(如果有的话)。查询方的责任被消除了,因为不需要等待答案。基于事件的系统的另一个优点是任何数量的服务都可以使用事件,从而允许数据复制。

分布式

在图4中,x轴表示分布度,y轴表示模块化。该图很好地说明了分离成最好的独立模块是良好架构的最重要标准。这些模块是否分发仅受可交换性和独立缩放要求的影响。但是,如果我们放弃模块化,那么这两种架构将形成一个“大泥球”。在亚特兰大 DevNexus 2016 会议期间举行的关于模块化单体的演讲中,Simon Brown 恰当地说:“如果你不能构建模块化单体,那你为什么认为微服务是解决方案?”

不幸的是,分布式的“大泥球”比单体更不利于维护和进一步发展。可以使用分析工具分析和转换单体代码库。然而,对于分布式“大泥球”,需要分析运行时以确定哪些模块相互通信。因此,验证是否满足架构和设计规范在任何架构中都很重要。

特征

过去,微服务架构主要出现在后端,这导致了所谓的前端单体的形成。这抵消了一个优势,即独立性。自包含系统 (SCS) 的想法,即包含所有层的模块,是解决此问题的一种变体。另一方面,微服务架构的原则是每个微服务都有自己的数据管理。然而,在现代化项目中,Fowler 描述为“集成数据库”的数据管理方法通常是打破整体的唯一可能性,因为现有数据模型已高度规范化,并且表具有许多依赖关系 ).

此外,其他系统,如数据仓库,经常使用数据模型,使分解复杂化。将单体转化为微服务通常遵循“扼杀者”模式。Martin Fowler 在他的澳大利亚之行之后,于 2004 年首次描述了这种设计模式 [Fow04]。待转换的系统被新模块接连拥抱,就像被扼杀无花果一样,直到旧系统一无所有。与大爆炸式迁移相比,风险要小得多。

你可能感兴趣的:(微服务,java,架构)