软件体系架构
1.分层架构
1.1 简介
传统分层架构:模块缺乏明确的规则、职责和同其他模块之间的关联;应用程序缺乏合理的架构会导致程序过度耦合、容易被破坏、难以应对变化、没有清晰的版本和方向性。 架构模式帮助你定义应用程序的基本特征和行为。
比如:一些架构模式会让程序自然而然的朝着具有良好伸缩性的方向发展,或者高度灵活的方向发展。
1.2模式分析
分层架构模式里的组件被分成几个平行的层次,每一层都代表应用的一个功能,大多数的结构分为四个层次:展示层,业务层,持久层和数据库层。
- 展示层:处理所有页面展示和交互逻辑(不关心如如何得到用户数据,只需在屏幕上以特定的格式展示信息)
- 业务层:处理请求对应的业务(不关心展示在屏幕上的用户数据格式,也不关心如何得到数据,只需从持久层得到数据)
分层架构的突出特性是:组件间关注点分离(separation of concerns),一个层的组件只会处理本层的逻辑。 - 关键概念:下表中每一层都是封闭的,意味着request必须一层层的传递。比如:从展示层传递来的请求首先传递到业务层,然后持久层,最后数据层!
为何不允许展示层直接访问数据层呢?如果只是获得以及读取数据,展示层直接访问数据层,比穿过一层一层来得到的数据快得多,这因为:层隔离。 - 层隔离(封闭的架构层次):架构的某些一层的改变不会影响其他的层;这些变化仅限于当前的层次。如果展示层直接能够访问持久层,这时持久层的SQL变化了,对业务层以及展示层都有影响,让应用变得紧耦合,组件之间相互依赖,架构难以维护和扩展。
1.3性能评价
分层架构是一个很可靠的架构,适合大多数应用。
- 整体灵活性(低):总体灵活性是响应环境变化的能力。尽管分层模式中的变化可以隔绝起来, 想在这种架构中做一些也改变也是并且费时费力的。 分层模式的笨重以及经常出现的组件之间的紧耦合是导致灵活性降低的原因。
- 可测试性(高):因为组件都处于各自的层次中, 可以模拟其他的层, 或者说直接去掉层, 所以分层模式很容易测试。 开发者可以单独模拟一个展示组件, 对业务组件进行隔绝测试。 还可以模拟业务层来测试某个展示功能
- 性能(低):尽管某些分层架构的性能表现的确不错, 但是这个模式的特点导致它无法带来高性能。 因为一次业务请求要穿越所有的架构层, 做了很多不必要的工作。
- 伸缩性(低):由于这种模式以紧密耦合的趋势在发展, 规模也比较大, 用分层架构构建的程序都比较难以扩展。 你可以把各个层分成单独的物理模块或者干脆把整个程序分成多个节点来扩展分层架构, 但是总体的关系过于紧密, 这样很难扩展。
2.事件驱动架构
2.1简介
事件驱动架构模式是一种主流的异步分发事件架构模式,用于设计高度可扩展的应用,事件驱动架构模式由高度解耦、单一目的的事件处理组件构成,这些组件负责异步接收和处理事件。
事件驱动架构模式包括两种主要的拓扑结构:中介(mediator)拓扑结构和代理(broker)拓扑结构。
- mediator:通常在你需要在事件内使用一个核心中介分配、 协调多个步骤间的关系、 执行顺序时使用;
- broker: 在你想要不通过一个核心中介将多个事件串联在一起时使用.
2.2中介(Mediator)拓扑结构
Mediator适合用于拥有多个步骤,并需要在处理事件时能通过某种程度的协调将事件分层的场景。
在中介拓扑结构中主要有四种组件:事件队列(event queue),事件中介,事件通道(event channel),和事件处理器(event processor)。当事件流需要被处理, 客户端将一个事件发送到某个事件队列中, 由消息队列将其运输给事件中介进行处理和分发。 事件中介接收到该消息后, 并通过将额外的异步事件发送给事件通道, 让事件通道执行该异步事件中的每一个步骤, 使得事件中介能够对事件进行分配、 协调。 同时, 又因为事件处理器是事件通道的监听器, 所以事件通道对异步事件的处理会触发事件处理器的监听事件, 使事件处理器能够接收来自事件中介的事件, 执行事件中具体的业务逻辑, 从而完成对传入事件的处理。
假设你在某家保险公司买了保险, 成为了受保人, 然后你打算搬家。 在这种情
况下, 初始事件就是重定位事件, 或者其他类似的事件。 与重定位事件相关的处理步骤就像下图展示的那样, 处于事件中介
之中。 对每一个初始事件的传入, 事件中介都会创建一个待处理事件(例如: 改变地址, 重新计算保险报价, 等等……) ,
并将它发送给事件通道, 等待发出响应的事件处理器处理待处理事件(例如: 客户改变地址的操作流程、 报价计算流程, 等
等……) 。 直到初始事件中的每一个需要处理的步骤完成了, 这项处理才会继续(例如: 把所有手续都完成之后, 保险公司
才会帮你改变地址) 。 事件中介中, 重新报价和更新理赔步骤上面的直线表示这些步骤可以并行处理。
2.3代理(Broker)拓扑结构
代理拓扑结构与中介拓扑结构不同之处在于: 代理拓扑结构中没有核心的事件中介; 相反, 事件流在代理拓扑结构中通过一
个轻量的消息代理(例如: ActiveMQ, HornetQ, 等等……) 将消息串联成链状, 分发至事件处理器组件中进行处理。 代理
扑结构适用的使用场景大致上具有以下特征: 你的事件处理流相对来说比较简单, 而且你不想(不需要) 使用核心的事件分
配、 调节机制以提高你处理事件的效率。
用一个与讲解中介拓扑结构时类似的例子(受保人旅行的例子) 进行解释。 因为在代理拓扑结构中没有核心事件中介接收初始事件, 那么事件将由客户处理组件直接接收, 改变客户的地址, 并发出一个事件告知系统客户的地址被其进行了改变(例如: 改变地址的事件) 。 在这个例子中: 有两个事件处理器会与改变地址的事件产生关联: 报价处理和索赔处理。 报价事件处理器将根据受保人的新地址重新计算保险的金额, 并发出事件告知系统该受保人的保险金额被其改变。 而索赔事件处理器将接受到相同的改变地址事件, 不同的是, 它将更新保险的赔偿金额, 并发出一个更新索赔金额事件告知系统该受保人的赔偿金额被其改变。 当这些新的事件被其他事件处理器接收、 处理, 使事件链一环扣一环地交由系统处理, 直到事件链上的所有事件都被处理完, 初始事件的处理才算完成.
如上图所示, 代理拓扑结构的设计思想就是将对事件流的处理转换为对事件链的业务功能处理, 把代理拓扑结构看作是接力
比赛是最好的理解方式: 在一场4*100的接力比赛中, 每一位运动员都需要拿着一根接力棒跑100米, 运动员跑完自己的100
米后需要将接力棒传递给下一位运动员, 直到最后一位运动员拿着接力棒跑过终点线, 整场接力比赛才算结束。 根据这样的
逻辑我们还可以知道: 在代理拓扑结构中, 一旦某个事件处理器将事件传递给另一个事件处理器, 那么这个事件处理器不会
与该事件的后续处理产生任何联系
2.4顾虑
在选择事件驱动架构时还有一点需要注意: 在处理单个业务逻辑时, 这种架构模式不能处理细粒度的事务。 因为事件处理器
都高度解耦、 并且广泛分布, 这使得在这些事件处理器中维持一个业务单元变得非常困难。 因此, 当你使用这种架构模式架
构你的应用时, 你必须不断地考虑哪些事件能单独被处理, 哪些不能, 并为此设计相应事件处理器的处理粒度。 如果你发现
你需要将一个业务单元切割成许多子单元, 并一一匹配相应的事件处理器, 那你就要为此进行代码设计; 如果你发现你用多
个不同的事件处理器处理的哪些业务其实是可以合并到一个业务事件之中的, 那么这种模式可能并不适合你的应用, 又或者
是你的设计出了问题。
mediator、broker、proxy的区别:
- 如果我们使用 mediator, 那就意味着我将把事件流交给 mediator, mediator 会帮我把事件分解为多个步骤, 并分析其中的执行逻辑, 调整和分发事件(例如判断哪些事件可以并行, 哪些事件可以串行) , 然后根据 mediator 分解、 调节的结果去执行事件中的每一个步骤, 把所有步骤完成后, 就能把需要处理的事件处理好
- 如果我们使用 broker, 那就意味着我将把事件交给 broker, broker 获得事件后会把事件发出去(在本文中为: 通知架构中所有可用的事件处理器) , 事件处理器们接收到事件以后, 判断处理这个事件是否为自己的职责之一, 如果不是则无视, 与自己有关则把需要完成的工作完成, 完成后如果事件还有后续需要处理的事件, 则通过 broker 再次发布, 再由相关的事件处理器接收、 处理。 以这样的方式将事件不断分解, 沿着事件链一级一级地向下处理子事件, 直到事件链中的所有事件被完成, 我的事件也就处理好了。
- 如果我们使用 proxy, 那就意味着我自己对需要处理的事件进行了分解, 然后把不同的子事件一一委托给不同的 proxy,由被委托的 proxy 帮我完成子事件, 从而完成我要做的事件
3微内核架构
微内核架构模式(也称为插件化应用架构)对于基于产品的应用程序来说是一个很自然的选择。 基于产品的应用是指一个经过
打包的、 可以通过版本下载的一个典型的第三方产品。 然而, 很多公司也会开发和发布他们的内部商业软件, 完整的版本
号、 发布日志和可插拔的新特性, 这些就非常符合微内核架构的思想。 微内核架构模式可以通过插件的形式添加额外的特性
到核心系统中, 这提供了很好的扩展性, 也使得新特性与核心系统隔离开来。
3.1模式描述
微内核架构主要需要考虑两个方面: 核心系统和插件模块。 应用逻辑被划分为独立的插件模块和核心系统, 这样就提供良好的可扩展性、 灵活性, 应用的新特性和自定义处理逻辑也会被隔离。
- 核心系统:一般情况下只包含一个能够使系统运作起来的最小化模块。 很多操作系统的实现就是使用微内核架
构, 因此这也是该架构名字的由来。 从商业应用的角度看, 核心系统通常是为特定的使用场景、 规则、 或者复杂条件处理定
义了通用的业务逻辑, 而插件模块根据这些规则实现了具体的业务逻辑。- 插件模块:一个包含专业处理、 额外特性的独立组件, 自定义代码意味着增加或者扩展核心系统以达到产生附加的业务逻辑
的能力。 通常, 插件模块之间应该是没有任何依赖性的, 但是你也可以设计一个需要依赖另一个插件的插件。 但无论如何,
使得插件之间可以通信的同时避免插件之间产生依赖又是一个特别重要的问题。*核心系统:需要了解插件模块的可用性以及如何获取到它们。 一个通用的实现方法是通过一组插件注册表。 这个插件注册表含有每个插件模块的信息, 包括它的名字、 数据规约和远程访问协议(取决于插件如何与核心系统建立连接)。 例如, 一个税务软件的用于标识高风险的税务审计插件可能会有一个含有插件名(比如AuditChecker)的注册入口, 数据规约(输入数据、 输出数据)和规约格式( 比如xml )。 如果这个插件是通过SOAP服务访问, 那么它可能会包含一个WSDL (Web Services DefinitionLanguage)
*插件模块:插件模块可以通过多种方式连接到核心系统, 包括OSGi ( open service gateway initiative )、 消息机制、 web服务或者直接点对点的绑定 ( 比如对象实例化, 即依赖注入 )。 你使用的连接类型取决于你构建的应用类型和你的特殊需求(比如单机部署还是分布式部署) 。 微内核架构本身没有指定任何的实现方式, 唯一的规定就是插件模块之间不要产生依赖。
4微服务架构
微服务架构模式作为替代单体应用和面向服务架构的一个可行选择,在业内迅速取得进展。
4.1 模式描述
不管你选择哪种拓扑或实现风格,有几种常见的核心概念适用于一般架构模式。 第一个概念是单独部署单元。如下图,微服务架构的每个组件都作为一个独立单元进行部署, 让每个单元可以通过有效、 简化的传输管道进行通信, 同时它还有很
强的扩展性, 应用和组件之间高度解耦, 使得部署更为简单。
- 服务组件(service component)从粒度上讲它可以小到单一的模块, 或者大至一个应用程序。 服务组件包含一个或多个模块(如Java类),这些模块可以提供一个单一功能(如,为特定的城市或城镇提供天气情况),或也可以作为一个大型商业应用的一个独立部分(如, 股票交易布局或测定汽车保险的费率)。在微服务架构中, 正确设计服务组件的粒度是一个很大的挑战。
微服务架构模式的另一个关键概念是它是一个分布式的架构, 这意味着架构内部的所有组件之间是完全解耦的, 并通过某种远程访问协议(如, JMS, AMQP, REST, SOAP, RMI等) 进行访问。 这种架构的分布式特性是它实现一些优越的可扩展性和部署特性的关键所在。
微服务架构另一个令人兴奋的特性是它是由其他常见架构模式存在的问题演化来的,而不是作为一个解决方案被创造出来等待问题出现。 微服务架构的演化有两个主要来源: 使用分层架构模式的单体应用和使用面向服务架构的分布式应用
4.2 模式拓扑
常见和流行的有:基于REST API的拓扑结构,基于REST的应用拓扑结构和集中式消息拓扑结构
- 基于REST的API拓扑:适用于网站, 通过某些API对外提供小型的、 自包含的服务。 这种拓扑结构,如图4 - 2所示,由粒度非常细
的服务组件(因此得名微服务) 组成, 这些服务组件包含一个或两个模块并独立于其他服务来执行特定业务功能。 在这种拓
结构扑中,这些细粒度的服务组件通常被REST-based的接口访问, 而这个接口是通过一个单独部署的web API层实现的。 此
种拓扑的例子包含一些常见的专用的、 基于云的RESTful web service, 大型网站像Yahoo, Google, and Amazon都在使用。
- 基于REST的应用拓扑结构与基于REST API的不同, 它通过传统的基于web的或胖客户端业务应用来接收客户端请求, 而不
是通过一个简单的API层。 如图4-3所示, 应用的用户接口层(user interface layer) 是一个web应用, 可以通过简单的RESTbased接口访问单独部署的服务组件(业务功能) 。 该拓扑结构中的服务组件与API-REST-based拓扑结构中的不同, 这些服
务组件往往会更大、 粒度更粗、 代表整个业务应用程序的一小部分, 而不是细粒度的、 单一操作的服务。 这种拓扑结构常见
于中小型企业等复程度相对较低的应用程序
- 微服务架构模式中另一个常见的方法是集中式消息拓扑。 该拓扑(如图4-4所示) 与前面提到的基于REST的应用拓扑类似,
不同的是, application REST- based拓扑结构使用REST进行远程访问, 而该拓扑结构则使用一个轻量级的集中式消息代理
(如, ActiveMQ, HornetQ等等) 。 不要将该拓扑与面向服务架构模式混淆或将其当做SOA简化版(“SOA-Lite”) , 这点是极
其重要的。 该拓扑中的轻量级消息代理(Lightweight Message Broker) 不执行任何编排,转换,或复杂的路由;相反,它只是一
个轻量级访问远程服务组件的传输工具
5 Android中的微服务架构
这个是典型的分层结构,application、framework、libraries、kernel。要注意的是这是一个更为宏观的架构,在这个分层架构之下还有其他的架构模式,微服务架构就是其中最为明显的一个。Android系统按照职责分为不同的层次,但是在Java层( Java应用程序和应用程序框架) 和 系统服务层( Android运行环境 ) 这两个层之间则是通过本地C/S模式进行通信,也就是我们的微服务架构。