10 可扩展架构

软件系统与硬件和建筑系统最大的差异在于软件是可扩展的。架构可扩展模式主要包括分层架构、SOA 架构、微服务和微内核等。

0.1. 可扩展的基本思想

所有的可扩展性架构设计,基本思想都可以总结为一个字:拆!将原本大一统的系统拆分成多个规模小的部分,扩展时只修改其中一部分即可,无须整个系统到处都改,通过这种方式来减少改动范围,降低改动风险。

按照不同的思路来拆分软件系统,就会得到不同的架构。常见的拆分思路有如下三种:

  • 面向流程拆分:将整个业务流程拆分为多个阶段,每个阶段作为一部分。
  • 面向服务拆分:将系统提供的服务拆分,每个服务作为一部分。
  • 面向功能拆分:将系统提供的功能拆分,每个功能作为一部分。

理解这三种思路的关键就在于如何理解“流程”“服务”“功能”三者的联系和区别。

从范围上来看,从大到小依次为:流程 > 服务 > 功能,。以 TCP/IP 协议栈为例,来说明“流程”“服务”“功能”的区别和联系,TCP/IP 协议栈和模型图如下图所示。

image

  • 流程:对应 TCP/IP 四层模型,因为 TCP/IP 网络通信流程是:应用层 → 传输层 → 网络层 → 物理 + 数据链路层。
  • 服务:对应应用层的 HTTP、FTP、SMTP 等服务,例如:
    • HTTP 提供 Web 服务,
    • FTP 提供文件服务,
    • SMTP 提供邮件服务,以此类推。
  • 功能:每个服务都会提供相应的功能。例如:
    • HTTP 服务提供 GET、POST 功能,
    • FTP 提供上传下载功能,
    • SMTP 提供邮件发送和收取功能。

以学生信息管理系统为例,拆分方式是:

  1. 面向流程拆分

    展示层 → 业务层 → 数据层 → 存储层,各层含义是:

    • 展示层:负责用户页面设计,不同业务有不同的页面。例如,登录页面、注册页面、信息管理页面、安全设置页面等。
    • 业务层:负责具体业务逻辑的处理。例如,登录、注册、信息管理、修改密码等业务。
    • 数据层:负责完成数据访问。例如,增删改查数据库中的数据、记录事件到日志文件等。
    • 存储层:负责数据的存储。例如,关系型数据库 MySQL、缓存系统 Memcache 等。

    最终的架构如下:

    image

  2. 面向服务拆分

    将系统拆分为注册、登录、信息管理、安全设置等服务,最终架构示意图如下:

    image

  3. 面向功能拆分

    每个服务都可以拆分为更多细粒度的功能,例如:

    • 注册服务:提供多种方式进行注册,包括手机号注册、身份证注册、学生邮箱注册三个功能。
    • 登录服务:包括手机号登录、身份证登录、邮箱登录三个功能。
    • 信息管理服务:包括基本信息管理、课程信息管理、成绩信息管理等功能。
    • 安全设置服务:包括修改密码、安全手机、找回密码等功能。

    最终架构图如下:

    image

通过学生信息管理系统的案例可以发现,不同的拆分方式,架构图差异很大。但无论哪种方式,最终都是可以实现的。不同的拆分方式,本质上决定了系统的扩展方式

0.2. 可扩展方式

合理的拆分,能够强制保证即使程序员出错,出错的范围也不会太广,影响也不会太大。下面是不同拆分方式应对扩展时的优势。

  1. 面向流程拆分:扩展时大部分情况只需要修改某一层,少部分情况可能修改关联的两层,不会出现所有层都同时要修改。
  2. 面向服务拆分:对某个服务扩展,或者要增加新的服务时,只需要扩展相关服务即可,无须修改所有的服务。
  3. 面向功能拆分:对某个功能扩展,或者要增加新的功能时,只需要扩展相关功能即可,无须修改所有的服务。

不同的拆分方式,将得到不同的系统架构,典型的可扩展系统架构有:

  • 面向流程拆分:分层架构。
  • 面向服务拆分:SOA、微服务。
  • 面向功能拆分:微内核架构。

这些系统架构并不是非此即彼的,而是可以在系统架构设计中进行组合使用的。

以学生管理系统为例,最终可以这样设计架构:

  • 整体系统采用面向服务拆分中的“微服务”架构,拆分为“注册服务”“登录服务”“信息管理服务”“安全服务”,每个服务是一个独立运行的子系统。
  • 其中的“注册服务”子系统本身又是采用面向流程拆分的分层架构。
  • “登录服务”子系统采用的是面向功能拆分的“微内核”架构。

0.3. 分层架构

分层架构(也称为 N 层架构,至少2层)是很常见的架构模式,通常情况下:

  • 2 层架构:例如,C/S 架构、B/S 架构
  • 3 层架构:例如,MVC、MVP 架构
  • 一般是比较复杂的系统才会达到或者超过 5 层,比如操作系统内核架构

按照分层架构进行设计时,根据不同的划分维度对象,可以得到多种不同的分层架构。

  1. C/S 架构、B/S 架构:划分的对象是整个业务系统,划分的维度是用户交互,即将和用户交互的部分独立为一层,支撑用户交互的后台作为另外一层。
  2. MVC 架构、MVP 架构:划分的对象是单个业务子系统,划分的维度是职责,将不同的职责划分到独立层,但各层的依赖关系比较灵活。
  3. 逻辑分层架构:划分的对象可以是单个业务子系统,也可以是整个业务系统,划分的维度也是职责。虽然都是基于职责划分,但逻辑分层架构和 MVC 架构、MVP 架构的不同点在于,逻辑分层架构中的层是自顶向下依赖的。典型的有操作系统内核架构、TCP/IP 架构。

无论采取何种分层维度,分层架构设计最核心的是需要保证各层之间的差异足够清晰,边界足够明显,让人看到架构图后就能看懂整个架构,这也是分层不能分太多层的原因。

分层架构能够较好地支撑系统扩展,本质在于隔离关注点(separation of concerns),即每个层中的组件只会处理本层的逻辑。

  • 展示层只需要处理展示逻辑,
  • 业务层只需要处理业务逻辑,

这样在扩展某层时,其他层是不受影响的,通过这种方式可以支撑系统在某层上快速扩展。并不是简单地分层就一定能够实现隔离关注点从而支撑快速扩展,分层时要保证层与层之间的依赖是稳定的,才能真正支撑快速扩展。

分层结构的另外一个特点就是层层传递,一旦分层确定,整个业务流程是按照层进行依次传递的,不能在层之间进行跳跃。最简单的 C/S 结构,用户必须先使用 C 层,然后 C 层再传递到 S 层,用户是不能直接访问 S 层的。

  • 分层结构的这种约束,好处在于强制将分层依赖限定为两两依赖,降低了整体系统复杂度。
  • 分层结构的代价就是冗余,不管这个业务有多么简单,每层都必须要参与处理,甚至可能每层都写了一个简单的包装函数。
  • 分层架构另外一个典型的缺点就是性能,因为每一次业务请求都需要穿越所有的架构分层,有一些事情是多余的,多少都会有一些性能的浪费。这里的性能缺点只是理论的,现在的硬件和网络的性能,这些理论的损失已经可以忽略不计。

0.4. SOA

SOA 的全称是 Service Oriented Architecture,翻译为“面向服务的架构”。

SOA 出现的背景是企业内部的 IT 系统重复建设且效率低下,主要体现在:

  1. 企业各部门有独立的 IT 系统,比如人力资源系统、财务系统、销售系统,这些系统可能都涉及人员管理,各 IT 系统都需要重复开发人员管理的功能。
  2. 各个独立的 IT 系统可能采购于不同的供应商,实现技术不同,企业自己也不太可能基于这些系统进行重构。
  3. 随着业务的发展,复杂度越来越高,更多的流程和业务需要多个 IT 系统合作完成。由于各个独立的 IT 系统没有标准的实现方式(例如,人力资源系统用 Java 开发,对外提供 RPC;而财务系统用 C# 开发,对外提供 SOAP 协议),每次开发新的流程和业务,都需要协调大量的 IT 系统,同时定制开发,效率很低。

为了应对传统 IT 系统存在的问题,SOA 提出了 3 个关键概念。

服务

所有业务功能都是一项服务,服务就意味着要对外提供开放的能力,当其他系统需要使用这项功能时,无须定制化开发。服务可大可小,可简单也可复杂。服务的粒度根据企业实际情况进行判断。

ESB

全称是 Enterprise Service Bus,翻译为“企业服务总线”。ESB 参考了计算机总线的概念。计算机中的总线将各个不同的设备连接在一起,ESB 将企业中各个不同的服务连接在一起。

因为各个独立的服务是异构的,如果没有统一的标准,则各个异构系统对外提供的接口是各式各样的。SOA 使用 ESB 来屏蔽异构系统对外提供各种不同的接口方式,以此来达到服务间高效的互联互通。

松耦合

目的是减少各个服务间的依赖和互相影响。因为采用 SOA 架构后,各个服务是相互独立运行的,甚至都不清楚某个服务到底有多少对其他服务的依赖。

如果做不到松耦合,某个服务一升级,依赖它的其他服务全部故障,这样肯定是无法满足业务需求的。但实际上真正做到松耦合并没有那么容易,要做到完全后向兼容,是一项复杂的任务。

典型的 SOA 架构样例如下:

image

SOA 架构是比较高层级的架构设计理念,一般情况下可以说某个企业采用了 SOA 的架构来构建 IT 系统,但不会说某个独立的系统采用了 SOA 架构。

  • SOA 解决了传统 IT 系统重复建设和扩展效率低的问题,但其本身也引入了更多的复杂性。
  • SOA 最广为人诟病的就是 ESB,ESB 需要实现与各种系统间的协议转换、数据转换、透明的动态路由等功能。

ESB 虽然功能强大,但现实中的协议有很多种,如 JMS、WS、HTTP、RPC 等,数据格式也有很多种,如 XML、JSON、二进制、HTML 等。

ESB 要完成这么多协议和数据格式的互相转换,工作量和复杂度都很大,而且这种转换是需要耗费大量计算性能的,当 ESB 承载的消息太多时,ESB 本身会成为整个系统的性能瓶颈。

SOA 的 ESB 设计也是无奈之举。SOA 的提出背景是各种异构的 IT 系统都已经存在很多年了,完全重写或者按照统一标准进行改造的成本是非常大的,只能通过 ESB 方式去适配已经存在的各种异构系统。

上次修改: 9 June 2020