/

初探软件架构

该篇文章首发于boyn.top,转载请声明

初探软件架构

参考书目:https://www.oreilly.com/programming/free/files/software-architecture-patterns.pdf

这是一本比较薄的书,这篇文章是记录从这本书中学到的一些简单的内容,限于能力,理解的水平有限,望海涵.

一个软件,特别是大型软件,在很大代码量的情况下,是需要有一定的规则来定义代码的行为的.这就是软件架构,它如同建筑中的地基,汽车中的车架,虽然使用的时候感受不到,但是没了它是万万不行的.在本文中,我们以这本简短的书中说到的几种软件架构为例,来说说我们要如何去规划一个软件的架构

分层架构

什么是分层架构?

分层架构常见于大部分的业务应用开发,比如我们熟悉的后台应用,以及少部分客户端应用.在分层架构中,每一个组件都存在于某一层中,层与层之前是垂直分布(结构上垂直)的,每一层都有其特定的作用与规则(如包含表现层逻辑或业务逻辑等等).

虽然并没有很严格的定义这种架构有多少层, 每一层的作用是什么.但是一般来说,会包含4层:表现层,业务层,持久层与数据库.

img

分层架构的关键概念

在分层结构中,我们可以看到层与层之间是分开的,这就是分层架构的核心概念:分离.层与层之间职责是分离的,同时,层也是封闭(closed)的,这意味着,我们如果发送了一个请求是需要访问数据库的,这个请求必须从顶层往下到底层

img

为什么这个请求不能直接访问数据库层呢?毕竟直接访问数据库会快很多.

这就涉及到层与层之间隔离的概念了.隔离意味着层与层之间在一个层中作出的变化不会影响其他层的组件.如果表现层可以直接访问数据库的话,则变化会同时影响到业务层和持久层.这样带来的一个严重的问题是以后的代码难以明白也难以维护

同时,隔离也意味着层与层之间是独立的,我们在维护一份代码的时候,可以不需要知道其他层是怎么实现的,只需要专注于我们需要改动的部分就好了.这样无疑可以大大提高我们的效率.

事件驱动架构

事件驱动架构是十分著名的分布式异步架构,可以用于构造高度可伸缩的应用.它由多个高度解耦,仅仅通过事件处理来异步收发事件的组件完成.

事件驱动主要分为两种主要的结构,调解器结构(mediator)和终端结构(broker).他们的区别在于我们的需求是否需要对事件执行的顺序进行编排

调解器结构

调解器结构对于我们执行的事件有多个步骤,并且这些步骤需要按顺序来执行这样的任务十分合适.比如说,我们在交易一件商品的时候,首先需要查阅这件商品的信息,然后查阅这个商品是否有货,接着要创建订单,付款时确认我们余额是否足够,接着再确认订单,最后达到付款成功.同时,这样的场景中每一步都有可能因为错误而终止执行.

类似于上文这样的架构,我们就可以使用调解器结构了.在调解器结构中,又可以分为4个主要组件:

  • 事件队列

  • 事件调解器

  • 事件通道

  • 事件处理器

一个事件首先从客户端发送到事件队列中,它用于将事件从队列传输到调解器中(这样的方式是为了结构解耦).调解器接受到事件后,异步地通过事件通道将传送事件到事件处理器中,事件处理器会监听事件通道,并从中接受事件并执行.

img

需要注意的是,一个成熟,高可用的事件驱动架构项目中,事件队列和事件调解器都会有多个,并且事件队列的实现并不唯一,可以使用消息队列,可以使用web的服务或者任何能够达到目的的技术.

为了更加方便地演示调解器结构是怎么工作的,我们可以看到下图,为了方便,将事件队列省略掉.我们可以看到,当一个事件发送到事件调解器中后,调解器将事件分为多个步骤,发送到处理器中依次执行.

img

终端结构

相比起调解器结构,终端结构最大的特点在于没有事件调解器,它事件的传递是通过事件队列进行传输的.这样的结构有一个好处在于当我们的事件处理关系比较简单并且不需要中心的事件调解器时,这个结构会更加易用(省略调解器进行事件编排的步骤)

终端结构有两种主要的组件,broker和event precessor.

broker包含多个事件通道,它的主要作用就是在event processor之间进行消息的传递.

其结构如下图,如我们所见,它并没有中心的事件调解器,而是通过broker(里面包含多个事件通道)来传递数据,

|img

而broker的工作逻辑就如同接力赛,我们向事件通道中传入一个事件后,相应的处理器会进行处理,然后处理完成后,处理器会提交一个事件到通道中,再由下一个事件通道进行后续的处理.

微内核架构

微内核架构,有的时候也称可拔插架构,是一种基于产品的应用架构.它的特点在于其核心部分是尽可能小和精简,而其他的功能通过插件的方式进行提供,完成额外的能力与隔离.

微内核架构主要有两种组件,核心系统与插件模组.微内核架构的核心逻辑就是将基础的核心系统与插件进行分离,使得他们可以独立出来,这样做使系统更富有可拓展性与灵活性.

在微内核架构中,核心系统只会包含最小的,可以使系统运行的功能,从一个业务应用的角度来看,核心系统通常指的是通用的业务逻辑,不带有特殊条件的代码,没有特定的规则和复杂的状态处理

而对于插件模组,他们是相互独立,相互隔离的组件,只包含对应的处理逻辑,额外的功能和可能用于加强核心系统的定制化的代码.通常来说,这些模组是需要互相独立的,但是我们同样可以来编写一个插件是依赖于另外的插件的.并且允许插件之间通信可以满足最小依赖原则,防止互相依赖的问题

一个简单的微内核架构图如下.

|img

在工作中,核心系统需要知道哪一个插件可用与怎么与其通信,一个简单的方式就是通过一个插件的注册中心,这个注册中心包含每一个插件的信息.其中,最重要的信息是插件的通信方式,包括其接口,与所用的消息结构等.

而插件模组可以通过很多种方式连接到核心系统中,比如通过网络通信,连接的方式取决于我们的核心系统是怎么构成的以及我们的需求.在这篇文章中,我们尽量不包含任何实现的细节,以此我们可以更加抽象,宏观地进行讨论.

微服务架构

终于来到了现在Web开发中十分火热的微服务架构了.在被提出来后,微服务架构以迅雷不及掩耳的速度被工业界作为单体应用架构的一个可行替代品作为面向服务端的架构广泛应用.由于微服务架构比较抽象,也在不断地发展迭代,所以在工业界中仍然有许多关于什么是微服务以及如何实现微服务不同的观点,不过幸好,大家都会有对微服务的一些共识.这一节中我们会介绍关于微服务的核心概念以及推荐的开发模式

在忽略掉微服务本身的拓扑结构之后,有一些概念是十分核心并且被广泛应用,有通用的架构模式的.下面我们就来一一介绍

分离部署单元

|img

如图所示,微服务架构中的每一个组件都被部署为一个单独的单元,这样的好处在于部署的流程可以更短,部署的粒度更小,可以以更有效率,且更加”流式”地进行部署,可伸缩,可解耦.

服务组件

还是如上图所示,每一个服务组件都是独立的,里面包含若干个模块,模块代表着一个符合单一责任原则的函数(此处也可以理解为一个功能)或者是一个大型商业应用中的一个独立的部分.微服务架构中,最大的挑战之一就是设计合理的服务组件的粒度.这个我们会在后面继续说到.

分布式结构

另外一个核心的概念就是分布式的结构.微服务中所有的组件都是分布的,分开部署,完全与其他组件解耦,不依赖与其他组件

微服务的几种拓扑逻辑

我们在前面说到,微服务要如何去实现,目前工业界仍然在不断地探索与发展,目前为止,有公认的几种比较好的实现微服务的拓扑结构,分别是:基于REST API的拓扑结构和基于中心化消息的拓扑结构.

基于REST API

基于RESTful API的的拓扑结构被大量应用在网页端,它可以通过HTTP或者RPC的API暴露出一些比较小且单独的接口.

如图所示,这种拓扑结构的API可以做到细粒度化,每一个微服务的组件中只包含一个到两个模块,同时,他们可以通过一个统一的接口层进行交互,并且这些细粒度的组件可以做成云原生的组件,并分开部署

|img

基于中心化消息

另外一种使用广泛的微服务架构就是中心化消息的拓扑结构了.其实与上面的通过RESTful API的结构相似,不同的是将API通讯层换成了轻量级的消息层,为什么说是轻量级的呢?因为消息层中并没有太多流程的编排,变化和复杂的路由转化等等,它只是用于在组件之间传递消息.

|img

微服务架构的主要挑战

微服务架构的主要挑战在于把握粒度的粗细,合理地设置组件之间的粒度.如果粒度太大了,那么组件之间的耦合度太大,可伸缩性也比较低,以至于我们根本无法体会到微服务的好处,而如果粒度太细的话,我们就会被部署,调用之间的繁杂细节弄得崩溃.

关于图片和转载

知识共享许可协议
本作品采用知识共享署名 4.0 国际许可协议进行许可。 转载时请注明原文链接,图片在使用时请保留图片中的全部内容,可适当缩放并在引用处附上图片所在的文章链接,图片使用 Sketch 进行绘制,你可以在 技术文章配图指南 一文中找到画图的方法和素材。