架构简洁之道之解耦模式

源码层次:我们可以控制源模块之间的依赖关系,以此来实现一个模块的变更不会导致其他模块也需要变更或者编译。在这种解耦模式下,系统所有的组件都会在同一个地址空间内执行,它们会通过简单的函数调用来进行彼此的交互。 人们经常把这种模式叫作单体模式。从部署的角度来看,最后产生了一个单独的可执行文件。虽然这类系统的架构边界在部署过程中并不可见,但并不意味着它们不存在或者没有意义。因为即使最终所有的组件都被静态链接成了一个可执行文件,这些边界的划分对该系统各组件的独立开发也是非常有意义的。

部署层次: 我们可以控制部署单元(如DLL、共享库等)之间的依赖关系,以此来实现一个模块的变更不会导致其他模块的重新构建和部署。在这种模式下,大部分组件可能依然运行在同一个地址空间内,通过彼此的函数调用通信。但有一些别的组件可能会运行在同一个处理器下的其他进程内,使用跨进程通信,或者通过socket或共享内存进行通信。这里最重要的是,这些组件的解耦产生出许多可独立部署的单元。除此之外,这种部署层次解耦的组件与单体结构几乎是一样的,其所有函数仍然处于同一个进程、同一个地址空间中。

服务层次: 我们可以将组件间的依赖关系降低到数据结构级别,然后仅通过网络数据包来进行通信。这样的系统每个执行单元在源码层和二进制层都会是一个独立的个体,它们的变量不会影响共他地方(例如常见的服务或者微服务都是如此)。这是系统架构中最强的边界形式,一个服务就是一个进程。服务并不依赖于具体的运行位置,两个互相通信的服务可以处于单一物理处理器或多核系统的同一组处理器上,也可以彼此位于不同的处理器上。服务会始终假设它们之间的通信将全部通过网络进行。服务之间的跨边界通信相对于函数调用来说,速度是非常缓慢的,其往返时间可以从几十毫秒到几秒不等。因此我们在划分架构边界时,一定要尽可能地控制通信次数,在这个层次上通信必须能够适应高延时情况。除此之外,我们可以在服务层次上使用与本地进程相同的规则(低层模块成为高层模块的"插件"),即让比较低层次服务成为较高层次服务的“插件”。为此我们要确保高层次服务的源码中没有包含任何与低层服务相关的物理信息。

那哪个模式是最好的呢?

在项目早期很难知道哪种模式是最好的。事实上,随着项目的逐渐成熟,最好的模式可能会发生变化。例如,一个在某台服务器上运行良好的程序发展到一定程度,可能就会需要将其某些组件迁移到其他服务器上才能满足运行要求,当该系统中运行在一台服务器上时,我们进行源码层次的解耦就已经足够了。但在这之后,我们可能需要进行部署单元层次的解耦,甚至服务层次的解耦。

另一个解决方案是,默认就采用服务层次的解耦,这种做法的问题主要在于它的成本很高,并且是在鼓励粗粒度的解耦。毕竟,无论服务多么“微”,其解耦的精细度都可能是不够的。

服务层次解耦的另一个问题是不仅系统资源成本高昂,而且研发成本更高,处理服务边界不仅非常耗费内存、处理器资源,而且更耗费人力。

一个良好的架构应该能允许一个系统从单体结构开始,以单一文件的形式部署,然后逐渐成长为一组相互独立的可部署单元,甚至是独立的服务或者微服务最后还能随着情况的变化,允许系统逐渐回退到单体架构。并且一个设计良好的架构在上述过程中还应该能保护系统的大部分代码源码不受变更影响,对整个系统来说,解耦模式也应该是一个可选项。我们在进程大型部署时可采用一种模式,而在进行小型部署时则可能采用另一种模式。

你可能感兴趣的:(软件架构,系统架构,架构)