这是面向成本设计的第一篇——微内核设计模式,也叫插件式服务设计。本章节重点介绍这种模式的架构,其优点和缺点。这一模式兼顾了相互独立和灵活的特性,是一种性价比很高的设计模式。当然这种模式也有其不足,稍后会向大家进行介绍。 在介绍微内核模式和其它的各种模式之前,我们需要一个比较基准。因此在介绍之前,我们来回顾一下我们最熟悉的架构——单体架构(monolithic architecture)。

单体架构

You shouldn't start a new project with microservices, even if you're sure your application will be big enough to make it worthwhile. ——Martin Fowler

不应该在项目一开始就使用微服务架构,即使这个系统确定会大到需要拆分为不同的微服务。 ——Martin Fowler

一提到单体架构,我们常常嗤之以鼻,似乎这是一个上古的架构,存在各种缺陷。那么让我们来看看这个上古巨兽到底是什么。

"一个单体式应用程序里面有许多的逻辑、服务(如:使用者服务、文章服务、留言服务),并且都有密不可分的关系。一旦其中一个服务不可用时,就会造成另一个服务也无法使用,因此也常被拿来当作微服务结构的对比,因为微服务独立、自主,并不会有像单体式应用程序这样的问题。"

从上图可以看到,单体架构的所有功能常常聚集在一个系统或/软件中,不同功能之间相互依赖和交互,不同的功能模块可以有相同或者不同的研发(组)进行研发,然后集成在一个软件系统之下。

单体系统的缺点一目了然——功能之间不独立、相互依赖,很难扩展,随着系统功能和范围不断演进,将会变的臃肿而难以维护。

然而这种架构有一个最大的优点——容易实现!任何复杂的架构最好都以单体服务为起点,这也是为什么Martin Fowler会有以下的观点:

  • 几乎所有成功的微服务系统都是以单体系统为起点,在开发过程中因为过于庞大而拆分为微服务。
  • 几乎所有一开始就使用微服务架构的系统都会遇到严重的问题。

下面我们就来看看本文的重点——微内核架构。

微内核架构

事实上,微内核架构和单体架构的输出都是一个单独的系统,所有的功能都存在于该系统的内部。而和单体架构不同之处在于,微内核架构由两部分组成——核心模块(core)和组件模块(plugin)。

核心系统是微内核的核心系统,这个系统提供系统公用的核心功能,且核心系统的功能几乎不会发生变化。核心功能提供了整套系统运行的基础,只要核心功能能够运行,那么整个系统就可以正常的运行起来。然而核心系统并不保证功能的完整性。

组件模块保证了系统各个功能的可用性和正确性,每一个组件都是一个独立的模块或者子系统,各个组件附着于核心系统之上,从而提供相应的功能。

每一个模块都需要实现相同的结构和规约,才能提供相应的功能,否则无法执行。各个模块和核心系统之间只有符合接口规范的数据交互,通过这种强接口的约束才能保证不管模块如何变化,核心系统都不用修改,从而保证了整个系统的可运行性。

那么各个模块怎么和核心系统有机组合成可插拔的功能模块呢?这就要提到核心系统的重要组成模块——注册表(registry)。注册表是连接核心系统和模块/插件系统的桥梁。每一个模块在使用前都需要在注册表中进行注册,当模块过期时也会在注册表中动态的移除。注册表的结构可以是一个简单的list,map或者其它复杂的结构。注册表可以提供简单的接口检查功能,保证每个模块都是用复合约定的接口,也可以仅仅进行注册和注销,而使用其它的模块来进行验证功能。

在具体的开发实践中,我们经常还会遇到一个问题:使用第三方库。这个时候还怎么能保证第三方库遵循接口规约呢?这时插件(plugin)的好处就体现了出来,每个插件可以有一个或多个适配器(Adapter)来进行接口之间的转换。具体可以参考GoF设计模式之适配器模式。

微内核模式在系统开发中十分常见,只是名头没有近些年火爆的"微服务"、"服务网格"那么大罢了。一个著名的例子就是Eclipse,其采用插件模式提供各种功能增强,然而其本身只负责提供一个鲁棒的IDE环境。

面向成本

约定

在开篇我们说到,架构师心中要有成本的概念,那么我们就来看看微内核的成本比较。

我们用$的个数来表示成本的高低,$的数据越多表示所需要的综合成本就越大,反之则越小。

除了成本耗费之外,作为架构师,我们还需要考量很多其它因素,例如开发的敏捷性、部署的成本、测试的成本(没错,部署和测试也很重要!也会花钱!)、性能、扩展性(面向未来)和复杂程度进行评估。我们也会对开发过程的整个流程进行一个评估。

比较

相较于单体架构,微内核强调了各个模块间的独立性,接口的统一性以及核心的不变性,从而既保证了整体系统的可用性,还提供了灵活的可插拔的组件系统。由于整个系统最终的输出是一个完整的单体,因此部署和测试相对也不会太复杂。

然而正是由于整个系统最终的输出形式还是一个庞大的单体系统,因此不可避免的会带来性能及扩展性的问题。

具体如下表。

模式敏捷部署测试性能扩展性复杂度成本
单体$
微内核$$

小结

微内核的概念由来已久。不管是在系统内核设计还是分布式系统都能看到它的影子。"小"到"鸿蒙"的微内核架构,"大"到例如istio或者linkerd等服务网格架构,都可以看到微内核的概念。

微内核模式避免了单体模式内部混乱的结构,采用核心系统和组件系统解耦的方式保证了开发的流畅性和功能的独立性,从而在保证成本几乎不变的前提下,提供了开发和测试的灵活性。然而由于其本身"完整"的输出形式,依然会有性能和扩展不足的问题。

在下面的章节中,作者会介绍其它主流分布式服务的架构,期待您的关注和留言!