可扩展架构的基本思想和模式¶
软件系统与硬件和建筑系统最大的差异在于软件是可扩展的,一个硬件生产出来后就不会再进行改变、一个建筑完工后也不会再改变其整体结构。例如,CPU 生产出来;金字塔建成完工。相比之下,软件系统就完全相反,如果一个软件系统开发出来后,再也没有任何更新和调整,反而说明了这套软件系统没有发展、没有生命力。
备注
软件系统的这种天生和内在的可扩展的特性,既是魅力所在,又是难点所在。魅力体现在我们可以通过修改和扩展,不断地让软件系统具备更多的功能和特性,满足新的需求或者顺应技术发展的趋势。而难点体现在如何以最小的代价去扩展系统,因为很多情况下牵一发动全身,扩展时可能出现到处都要改,到处都要推倒重来的情况。这样做的风险不言而喻:改动的地方越多,投入也越大,出错的可能性也越大。因此,如何避免扩展时改动范围太大,是软件架构可扩展性设计的主要思考点。
可扩展的基本思想¶
备注
可扩展性架构的设计方法很多,但万变不离其宗,所有的可扩展性架构设计,背后的基本思想都可以总结为一个字:拆!
常见的拆分思路有如下三种:
1. 面向流程拆分
说明: 分层架构,数据流程非业务流程
将整个业务流程拆分为几个阶段,每个阶段作为一部分。
如:
TCP/IP 网络通信流程是:应用层 → 传输层 → 网络层 → 物理 + 数据链路层
2. 面向服务拆分
说明: 微服务,倾向于站在外部视角而言
将系统提供的服务拆分,每个服务作为一部分。
如:
HTTP 提供 Web 服务,FTP 提供文件服务,SMTP 提供邮件服务
3. 面向功能拆分
说明: 微内核,倾向于站在内部视角而言
将系统提供的功能拆分,每个功能作为一部分。
如:
HTTP 服务提供 GET、POST 功能,FTP 提供上传下载功能,SMTP 提供邮件发送和收取功能
从范围上来看,从大到小依次为:流程 > 服务 > 功能
1. 面向流程拆分¶
展示层 → 业务层 → 数据层 → 存储层,各层含义是:
1. 展示层
负责用户页面设计,不同业务有不同的页面
例如,登录页面、注册页面、信息管理页面、安全设置页面等
2. 业务层
负责具体业务逻辑的处理
例如,登录、注册、信息管理、修改密码等业务
3. 数据层
负责完成数据访问
例如,增删改查数据库中的数据、记录事件到日志文件等
4. 存储层
负责数据的存储
例如,关系型数据库 MySQL、缓存系统 Memcache 等
2. 面向服务拆分¶
将系统拆分为注册、登录、信息管理、安全设置等服务。每个服务是独立的子系统,有各自独立的数据库,缓存,服务器
3. 面向功能拆分¶
每个服务都可以拆分为更多细粒度的功能,例如:
a. 注册服务
提供多种方式进行注册,包括手机号注册、身份证注册、学生邮箱注册三个功能。
b. 登录服务
包括手机号登录、身份证登录、邮箱登录三个功能。
c. 信息管理服务
包括基本信息管理、课程信息管理、成绩信息管理等功能。
d. 安全设置服务
包括修改密码、安全手机、找回密码等功能。
可扩展方式¶
备注
不同的拆分方式,本质上决定了系统的扩展方式。不同拆分方式应对扩展时有不同的优势。
面向流程拆分:
扩展时大部分情况只需要修改某一层,少部分情况可能修改关联的两层,不会出现所有层都同时要修改 以学生管理系统为例: 如果我们将存储层从 MySQL 扩展为同时支持 MySQL 和 Oracle, 那么只需要扩展存储层和数据层即可,展示层和业务层无须变动。
面向服务拆分:
对某个服务扩展,或者要增加新的服务时,只需要扩展相关服务即可,无须修改所有的服务。 以学生管理系统为例: 如果我们需要在注册服务中增加一种 “学号注册” 功能, 则只需要修改 “注册服务” 和 “登录服务” 即可, “信息管理服务” 和 “安全设置” 服务无须修改。
面向功能拆分:
对某个功能扩展,或者要增加新的功能时,只需要扩展相关功能即可,无须修改所有的服务。 以学生管理系统为例: 如果我们增加 “学号注册” 功能, 则只需要在系统中增加一个新的功能模块,同时修改 “登录功能” 模块即可, 其他功能都不受影响。
典型的可扩展系统架构有:
1. 面向流程拆分:分层架构
2. 面向服务拆分:SOA、微服务
3. 面向功能拆分:微内核架构
组合使用可以这样设计架构:
1. 整体系统采用面向服务拆分中的 “微服务” 架构,
拆分为 “注册服务”“登录服务”“信息管理服务”“安全服务”,每个服务是一个独立运行的子系统。
2. “注册服务” 子系统本身又是采用面向流程拆分的分层架构。
3. “登录服务” 子系统采用的是面向功能拆分的 “微内核” 架构。
思考¶
规则引擎是常用的一种支持可扩展的方式,按照今天的分析,它属于哪一类?
规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。
OSGI 通过 bundle 来做物理隔离,bundle 之间用消息来通信,也是可以做到强制隔离的。
一般来说,函数、类、包并不能起到隔离作用,因为仅靠程序员意识是无法精确区分什么时候该用类来隔离,什么时候该用包来隔离。
规则引擎vs流程编排¶
流程编排和规则引擎都有一个 “中央处理器” 的大脑,但是设计上不太一样。 规则引擎的核心是规则抽象和规则编写;流程编排的核心是数据流设计和流程扩展。 流程编排一般会将流程固定为几个步骤,然后每个步骤定义好输入输出,处理过程可以通过插件来实现,这样支持不同的流程。