没有进行架构设计的应用程序通常是紧耦合的、玻璃心,难以改变。没有头绪。如果不理解应用的各个组件的内部工作方式的话很难看清它的架构特征。关于部署和维护的问题都很难回答:架构的规模如何?程序的性能如何?程序容易修改么?程序的部署模型是怎么样?程序的响应如何?
架构模式可以帮助你定义程序的基本特征和行为。例如一些架构模式很自然让程序成为大规模(scalable)的程序。有些模式让程序变得灵巧敏捷(agile)。知道这些架构的特征,优点和缺点,你就可以根据你特定的业务需求和目标从容的选择一种架构模式。
一、分层架构 (Layered Architecture)
它是最通用的架构,也被叫做N层架构模式(n-tier architecture pattern)。这也是Java EE应用经常采用的标准模式。基本上是个程序员都知道它。这种架构模式非常适合传统的IT通信和组织结构,很自然地成为大部分应用的第一架构选择。
在分层架构中的组件被划分成几个层,每个层代表应用的一个功能。分层架构本身没有规定要分成多少层,大部分的应用会分成表现层,业务层,持久层和数据库层。小的应用有时候会将业务层和持久层合在一起,更大规模的应用可能会划分更多的层,比如调用外部服务的层。
分层架构的一个特性就是关注分离(separation of concerns)。在层中的组件只负责本层的逻辑。组件的划分很容易让它们实现自己的角色和职责,也比较容易地开发,测试管理和维护。
关键概念
注意每一层都是封闭的。这意味着Request必须经过每一层才能到达最底下一层。
为什么不允许展示层直接访问数据库层呢,这样不是更快吗?这就是分层架构的另一个特征:层隔离(layers of isolation)。
层隔离的概念意味着你对任何一层的改变都不会影响其它层。这很好理解。
层隔离也意味着一个层的组件并不会了解其它层的实现,或者知道很少。 比如业务层不需知道你持久层是由hibernate还是mybatis实现的。
分层架构也很容易增加新的层。 比如你想将一些通用的服务重构成一个服务层,比如通用图片处理,远程账户审计等,可以在业务层下增加一个服务层。它不会对展示层造成影响,也不会改变持久层的代码。
上面的这个例子带来一个问题,因为每一层丢失封闭的,业务层不得不通过服务层访问持久层,这没有天理啊。 所以有时候你会创建一个开放的层。这意味着上一层可以绕过这一层直接访问下一层。
架构例子
我们看一下淘宝前几年的架构的例子
这是一个标准的分层的架构。每一层中又可以详细的分成更细的层,比如服务层。
模式分析
总体灵活性: 低
发布易用性: 低
可测试性: 高
性能: 低
规模扩展性: 低
开发容易度: 高
二、事件驱动架构(Event-Driven Architecture)
事件驱动架构是流行的一个分布式异步机构模式,可以用来设计规模很大的应用程序。基于这种架构模式应用可大可小。它由高度解耦的,单一目的的事件处理组件组成,可以异步地接口和处理事件。
它包括两个主要的拓扑结构:mediator 和 broker。Mediator拓扑结构需要你在一个事件通过mediator时精心安排好几个步骤,而broker拓扑结构无需mediator,而是由你串联起几个事件。这两种拓扑架构的特征和实现有很大的不同,所以你需要知道哪一个适合你。
Mediator拓扑结构
Mediator拓扑结构适合有多个步骤的事件,需要安排处理层次。
例如购买一只股票,首先会校验这个交易,校验股票交易是否符合各种规定,将它交给一个经纪人,计算佣金,最后确认交易。所有这些都安排好各个步骤的顺序,决定它们是否串行还是并行。
它包括四个组件:event queues, an event mediator, event channels 和 event processors。
事件流是这样开始的: 客户端发送一个事件到事件队列(event queues)中,它用来将事件传送给event mediator。Event mediator收到初始的事件后,会发送额外的一些异步事件给event channels来执行处理的每个步骤。Event processors监听event channels,接收事件并处理一些业务逻辑。
在事件驱动架构中有十几个甚至几百个事件队列都很正常。模式本身没有限定事件队列的实现方式。它可能是一个消息队列,一个web service或者其它。
这里有两种事件:初始事件和处理事件。Mediator会将初始事件编排成处理事件。它没有具体的业务逻辑,只是一个协调者,负责将初始事件转化成一个或者多个处理事件。
event channels 既可以是消息队列,也可以是消息topic,大部分是消息topic,这样可以由多个消息处理器(event processor)处理同一个消息。
消息处理器包含实际的业务逻辑。每个消息处理器都是自包含的,独立的,高度解耦的,执行单一的任务。
这种模式可能有一些变种。作为架构师,你应该理解每个实现的细节,确保这种解决方案适合你的需求。
有一些开源的框架实现了这种架构,如Spring Integration, Apache Camel, 或者 Mule ESB。
Broker拓扑架构
Broker不同于上面的结构,它没有中心的Mediator。所有的事件串联起来通过一个轻量级的消息broker如RabbitMQ,ActiveMQ,HornetQ等。如果你的消息比较简单,不需要重新编排,就可以使用这种结构。
如图所示,它包含两个组件broker和 event processor。
broker中的event channel可以是消息队列,消息topic或者它们的复合形式。
每个event processor负责处理事件,发布新的事件。
架构例子
在新浪微薄的早期架构中,微薄发布使用同步推模式,用户发表微薄后系统会立即将这条微薄插入到数据库所有粉丝的订阅列表中,当用户量比较大时,特别是明星用户发布微博时,会引起大量的数据库写操作,超出数据库负载,系统性能急剧下降,用户响应延迟加剧。后来新浪微薄改用异步推拉结合的模式,用户发表微薄后系统将微薄写入消息队列后立即返回,用户响应迅速,消息队列消费者任务将微薄推送给所有当前在线粉丝的订阅列表中,非在线用户登录后再根据关注列表拉取微薄订阅列表。
架构考量
事件驱动架构模式实现起来相对复杂,主要是由于它的异步和分布式特性。这可能会带来一些分布式的问题,比如远程处理的可用性,缺乏响应,broker重连等问题。
一个考虑是这种模式对于单一的逻辑缺乏原子事务。所以你需要将原子事务交给一个事件处理器执行,跨事件处理器的原子事务是很困难的。
最困难的设计之一是事件处理器的创建,维护和管理。事件通常有特殊的约定(数据值和格式)。
模式分析
总体灵活性: 高
发布易用性: 高
可测试性: 低
性能: 高
规模扩展性: 高
开发容易度: 低
参考:软件架构模式|鸟窝