了解通用的架构模式并知道什么时候使用它们。
软件架构定义了软件的基本特点和行为。比如,有些软件架构会让软件变得可扩展,而有些软件架构会让软件变得易于修改。
知道每一种软件架构的特点、优缺点是非常有必要的,因为它们能帮助你选择一种能满足你需求的架构。
这本书介绍了5种常见的软件架构,以及每种架构的优缺点,我们做架构设计时可以参考参考。下面就介绍这5种架构。
Layered architecture(分层架构)
在分层架构模式中,组件以水平分层的方式被组织,每一层都有自己的职责,比如UI层专门负责所有UI的绘制和渲染,业务逻辑层主要处理业务逻辑。虽然分层架构并没有规定分层的数量和类型,但是大多数的分层架构基本是由4层组成(如下图所示):展现层(也称为UI层,对应下图的presentation layer)、业务层(business layer)、持久化层(persistence layer)、数据库层(database layer)。有些架构会把业务层和持久化层合并成一层,比如那些把持久化层的逻辑(比如SQL语句)耦合到了业务层中。
架构中的每一层都有自己的任务需要完成,以便满足业务需求,并且每一层都不需要其它层的内部具体实现细节。比如,UI层不需要知道如何请求服务端的数据,它只需要把要展现的内容绘制出来即可。类似的,业务层不需要关心如何把内容绘制出来或者数据从哪里来,它只需要从持久化层获取数据,然后使用业务逻辑来处理这些数据(比如对数据加减乘除),然后把处理结果交给UI层渲染。
这种架构的好处是分离了关注点(每层只关注某个点),让代码更容易开发、测试和维护。
如下图所示,这种架构中,每一层都是"closed"的,意思是,比如当UI层发生一个请求时,UI层只能调用业务层的接口而不能"跨层"直接调用持久化层的接口。类似的,业务层只能调用持久化层的接口而不能直接调用数据库层的接口来获取数据。
为什么不允许UI层直接访问持久化层或者数据库层呢?毕竟让UI层直接访问数据库层的数据的性能更好。因为每一层都是"closed"(或者称为layers of isolation)。
Layers of isolation的意思是每一层的改变都不会影响到其它不紧挨着自己的层。如果你允许UI层直接访问持久化层,那么持久化层的SQL语句的修改就可能会影响到业务层和UI层,进而让UI层的组件和持久层的组件耦合在一起,这将会让软件变得更加难以修改。layer of isolation的好处是,例如,当我们要把JSP(java server pages)这个UI层的框架替换成JSF(java server faces)时,假如UI层和业务层之间的接口(比如接口中的某个Model)保持不变,那么业务层就不需要做任何改动。
Microkernel architecture(微内核架构)
微内核架构(如下图所示)常常被称为插件式架构,该架构允许你通过插件的方式添加新的功能。
微内核架构由两种类型的组件组成:1 核心系统;2 插件式模块(也称为可插拔模块)。整个软件的逻辑被划分为"独立的且可插拔的模块"和"基础的核心系统",这种架构的可扩展性好,能够把各个功能隔离开,并允许使用方自定义处理逻辑。我们熟知的大多数操作系统都以该架构实现,这也是该架构名字的由来。
核心系统通常只包含最小的功能集以便让整个架构能正常运行。从业务的角度看,核心系统通常包含通用的业务逻辑而不会包含某个具体的或者特殊的业务逻辑。
插件式模块由多个相互独立的插件组成,每个插件都包含某个具体的业务处理逻辑,以便扩展核心系统的功能。通常来说,一个插件通常不依赖别的插件,但你也可以根据需要让某个插件依赖另一个插件,但最好不要让插件之间进行通信以便减少依赖问题。如果插件之间没有依赖,意味着当一个插件添加到核心系统或者从核心系统移除时,就不会对其它插件有影响,当然也不会对核心系统造成影响。
核心系统需要知道从哪里去读取和使用插件。一种比较常见的做法是让核心系统提供一个注册插件和解注册插件的接口。
该架构的应用场景有浏览器(比如chrome)、eclipse等。
Event-driven architecture
事件驱动型架构(event-driven architecture)是一种异步分发的架构,该架构具有很好的可扩展性。该架构由高度解耦且具有单一目的的事件处理组件所组成,这些组件能异步地接受和处理事件。
事件指的是状态发生变化时,软件所发出的通知。
事件驱动型架构有两种类型的拓扑结构:1 mediator(中介者);2 broker(代理者)。
mediator拓扑结构
mediator结构适用于有多个步骤的事件。
mediator结构由4种类型的组件组成:事件队列(event queue),事件分发器(event mediator),事件渠道(event channels),事件处理器(event processors)。如下图所示,事件流从一个client发送一个事件到一个事件队列,该队列用于把事件递给事件分发器,事件分发器收到原始事件后对该事件进行加工,然后把加工后的事件发送给事件渠道,以便事件渠道执行"过程中的每一步",事件处理器监听了事件渠道,当收到由事件分发器发来的事件后,会执行具体的业务逻辑。
事件分为两类:原始事件 和 加工后的事件。原始事件指的是事件分发器收到的事件,而加工后的事件则是由事件分发器创造和初始化的,加工后的事件最终会被事件处理器接收并处理。
事件分发器并不会处理业务逻辑。
事件渠道可以使用事件队列。
broker拓扑结构
broker结构和mediator结构不同的是前者没有中心化的事件分发器,消息流在消息处理器之间转发。比如后台开发里面的ActiveMQ,HornetQ等框架。
brocker结构主要由两种类型的组件组成:1 代理组件(broker component);2 事件处理器组件(event processor component)。
代理组件可以是中心化的也可以是非中心化的,代理组件包含了在一个事件流里面的所有事件渠道。事件渠道指的是消息队列。
Microservice architecture
微服务有几个核心概念需要了解:
- 独立部署单元(seprately deployed units),如下图所示,每个微服务架构的组件都作为一个单独的单元被部署。
- 服务组件(service component),其粒度可大可小,小到你可以理解它为一个小模块,大到你可以认为它实现了软件的绝大部分功能。服务组件包含了1个或者多个模块,每个模块都有一个独特的功能,比如某个模块提供某个具体城市的天气预报数据。在微服务架构设计中,如何定义服务组件的粒度是比较难的。
- 分布式架构,微服务架构就是分布式架构,指的是架构中的每一个组件之间都不会相互耦合,服务之间通过远程访问协议(remote access protocol,比如REST、SOAP)来通信。分布式的特点让微服务架构能够具备非常好的可伸缩性(scalability)和已部署的优点。
微服务架构从使用了layered架构的庞大的单体系统和使用了service-oriented架构的分布式系统演化而来。
虽然微服务架构的具体实现有很多种,但其中有3种拓扑架构比较常见:①基于REST API的拓扑架构;②基于REST应用的拓扑架构;③消息中心化的拓扑架构。
- 基于REST API的拓扑架(如下图所示)对网页系统来说比较实用,因为该架构通过API来暴露小型的、独立的服务。
- 在基于REST应用的拓扑架构(如下图所示)中,client的请求会被传统的基于web或者"fat-client"的应用的UI层接收而不是被一个简单的API层接收。
- 消息中心化的拓扑架构(如下图所示)和上面的基于REST应用的架构比较类似,但消息中心化架构不使用REST协议,而是使用一种lightWeight centralized message broker(轻量级的消息中心化的代理)来进行远程访问,比如ActiveMQ,Hornet等。lightWeight centralized message broker并不进行复杂的路由,而仅仅是一种简单的访问service component。这种拓扑架构相对于上面的基于REST架构来货,有以下优点:更高级的队列机制;异步消息处理;监控,异常处理。
微服务的缺点是很难定义service component的合适的粒度。如果service component的粒度太大,你就很难理解这种架构在部署、伸缩性、可测试下和低耦合的优势。而如果service component的粒度太小,就会变成SOA架构了。
Space-based architecture
很多基于web的业务系统都遵循着相同的请求处理流程:浏览器请求服务端的某个接口,然后web服务器会受到该请求,然后wen服务器转发给应用服务器以便处理请求,而应用服务器往往都会访问数据库服务器以便实现数据的增删改查。这种流程适用于用户较少的场景,然而当用户量激增的时候,瓶颈就出现在了web服务器,然后是应用服务器,最后是数据库服务器。当用户的访问量量增长时,解决服务端响应速度的瓶颈问题的通常方法是增加web服务器,这种方法实现成本低。然而,这种方法仅仅是把响应速度的瓶颈转移到了应用服务器。而增加应用服务器相对于增加web服务器是比较复杂和高成本的,并且这种做法也仅仅是把瓶颈问题转移到数据库服务器而已,但是数据库会因为锁和事务的存在而不能简答地通过增加数据库服务器来解决瓶颈问题。space-base(基于云)的架构就是为了解决这个问题的。
space-base架构的名字来源于分布式共享内存中tuple space。高伸缩性通过解除中心化数据库的限制并且使用可被复制的内存中的数据网格(data grids)来实现的。系统的数据被保存在内存中并且所有活着的处理单元(process units)中都存在着一份拷贝。处理单元的个数能够根据请求数量的增加而增加,减少而减少。因为没有了中心化的数据库,数据库的瓶颈也就没有了,意味着该架构给系统提供了无止境的伸缩能力。
该架构(如下图所示)有两个核心概念:处理单元(processing unit) 和 虚拟中间件(vitualized middleware)。
虚拟中间件主要负责通信,数据同步,请求分发和部署处理单元。如上图所示,虚拟中间件主要包含了消息网格,数据网格,处理网格(processing grid),部署管理器。
处理单元主要包含了业务逻辑。一个大型的系统可能会被以功能维度划分成多个处理单元。如下图所示,一个处理单元通常包括业务模块、内存中的数据网格、可选的异步持久化仓库、数据复制引擎。
消息网格(如下图所示)管理着客户端发来的请求和session信息,比如当收到客户端发来的请求时,消息网格负责把请求转发给某个能处理该请求的处理单元。
数据网格负责和每个处理单元里面的数据复制引擎打交道,以便当数据发生变化时能够进行数据同步。如下图所示,当数据变化时,数据网格会同步复制数据到每个处理单元。
处理网格负责"需要多个处理单元共同处理"的请求的分发,如下图所示,当收到一个客户端的请求时,处理网格会协调两个处理单元来处理该请求。
部署管理器负责根据请求的数量来启动或者关闭处理单元。该管理器会持续地监控响应时间和请求数量,当请求增多时启动新的处理单元,当请求减少时关闭多余的处理单元。
上面5种架构的优缺点对比
下图所示的是,5种架构(layered架构、event-driven架构、microKernel架构、mricroService架构、space-based架构)在灵活性(对应下图的Overall Agility,指的是能够持续不断地快速响应需求变化的能力)、部署、可测试程度、性能、伸缩性、开发难度上的评分。该表格虽然能帮助你在项目上选择合适的架构,但是你还要结合项目的预算、开发周期、系统规模等方面来最终决定选用合适的架构。因为一旦系统按照某个架构被实现了,更换架构的成本就会比较高。如果想要更加深入地了解每种架构的具体优缺点,请看原书:《software architecture patterns》。