软件架构模式
阅读《clean architecture》也花了较长的时间,大致也了解到整洁的架构要做到以下两点:
- well-isolated components:component是独立部署的最小单元,由一系列遵循SOLID原则的module按照REP、CCP、CEP原则组成。
- dependency rule:低层的detail去依赖高层的police
但感觉并没有对架构设计给出可行的参考。
clean architecture 中的架构实例
在《clean architecture》的第34章 “The Missing Chapter”(由 Simon Brown 编写)给出了一个具体的案例,用四种架构设计来实现一个 “online book store”。
package by layer
这是最常见的方案,从前往后分为:前端、后台(business logic)、持久化DB。
优点是:简单、容易上手,符合大多数公司的组织架构。
存在的问题:
- 软件规模和复杂度增加时,三层架构就不够了,需要重新考虑拆分;
- 分层架构体现不出business domain;
PACKAGE BY FEATURE
垂直切分方案,所有的java代码都放在一个package里面
好处在于凸显domain concept
PORTS AND ADAPTERS
clean architecture这本书推荐的方案, 外层依赖于内层的domain
PACKAGE BY COMPONENT
本章作者 Simon Brown 提出的方案,service-centric view,将所有相关的职责打包称一个粗粒度的Jar包
bundling all of the responsibilities related to a single coarse-grained component into a single Java package
看起来类似现在微服务的部署方式
对于以上四种结构,依赖关系看起来是这样的
值得注意的是
- 虚线箭头表示component之间的依赖关系
-
PORTS AND ADAPTERS这种架构更能体现domain(business logic),即接口命名为
Orders
而不是OrdersRepository
本章的作者最后还指出:++不管架构怎么设计,粗心的implementation都可能违背最初的设计;依赖编译器来保证架构的一以贯之,而不是自我约束或者事后检查。++
五种常见架构模式
看完了clean architecture后,在网上搜索架构设计相关的书籍,发现了software architecture patterns这本小册子,篇幅很短,称不上book,而是一个report。
software architecture patterns 指出缺乏架构设计的软件往往高度耦合,难以改变。因此,这本小册子的目标就是介绍常用架构模式的特点、优点、缺点,帮助我们针对特定的业务需求做出合适的选择。
Layered Architecture
分层架构也称为n-tire architecture,这是最为常见的一种架构模式,一般从前往后分为四层:presentation, business, persistence, and database。如下图所示:
分层架构一般是一个新系统的最佳首选,因为其完美匹配传统IT公司组织架构:一般的公司招人都是前端、后端、数据库。
分层架构的优点在于关注点隔离(separation of concerns),每一层做好自己这一层的职责,并向上一层提供服务即可,最为经典的案例就是七层网络模型,这有利于开发、测试、管理与维护。
分层架构中,需要注意的是两个概念:closed layer、open layer
closed layer的核心就是不要越层访问,比如在上图中,Presentation Layer就不应该跨国Business Layer直接去Persistence Layer访问数据。
A closed layer means that as a request moves from layer to layer, it must go through the layer right below it to get to the next layer below that one
closed layer保证了层隔离( layers of isolation),使得某一层的修改影响的范围尽可能小,比较可控。但closed layer有时候也会带来一个问题:architecture sinkhole anti pattern(污水池反模式),具体是指,为了查简单数据,层层转发请求。比如为了在展示层显示玩家的某个数据,需要通过业务层、再到持久化层、再到DB层;取到数据再一层层传递回来,在这个过程中,业务层并没有对数据有逻辑上的处理。
显示,污水池反模式冲击了closed layer的美好想法。如何衡量这种层层转发的请求是不是问题,可以参考80-20法则。
如果80%是附带逻辑的,那么就是ok的,但如果有80% 是 simple passthrough processing,那么就得考虑让某些layer open。比如在复杂的业务系统中, 经常会有一些可复用的逻辑,这个时候会抽取为通用的服务层(service layer)。如下图所示
open layer 、close layer的概念可以帮助理清楚架构和请求流程之间的关系,让架构师、程序员都清楚架构的边界(boundary)在哪里,重要的是,这个open-closed关系需要明确的文档化,不要随意打破,否则就会一团糟。
Event-Driven Architecture
The event-driven architecture pattern is a popular distributed asynchronous architecture pattern used to produce highly scalable applications.
从上述定义可以看出事件驱动架构的几个特点:分布式、异步、可伸缩。其核心是:高度解耦合、专一职责的事件处理单元(Event Processor)
事件驱动架构有两种常见拓扑结构: the mediator and the broker.
Mediator Topology
需要一个中心化(全局唯一)的协调单元,用于组织一个事件中的多个步骤,这些步骤中有些是可并行的,有些必须是顺序执行的,这就依赖Event Mediator的调度。如下图所示
Broker Topology
这种是没有中心的架构
the message flow is distributed across the event processor components in a chain-like fashion through a lightweight message broker
如下图所示
事件驱动的好处在于,高度可伸缩、便于部署、整体性能较好(得益于某些事件的并发执行)。但由于其分布式异步的本性,其缺点也很明显:开发比较复杂、维护成本较高;而且很难支持事务,尤其是一个逻辑事件跨越多个processor的时候。
Microkernel Architecture
微内核架构又称之为插件式架构(plug-in architecture)。如下图所示:
微内核架构包含两部分组件
- a core system
- plug-in modules.
plug-in modules 是相互独立的组件,用于增加、扩展 core system 的功能。
这种架构非常适用于 product-based applications 即需要打包、下载、安装的应用,比如桌面应用。最经典的例子就是Eclipse编辑器,玩游戏的同学经常下载使用的MOD也可以看出插件。
微内核架构通常可以是其他架构的一部分,以实现特定部分的渐进式设计、增量开发
Microservices Architecture Pattern
微服务架构并不是为了解决新问题而发明的新架构,而是从分层架构的单体式应用和SOA(service-oriented architecture)演化而来。
微服务解决了分层架构潜在的成为单体式应用(Monolithic application)的问题:
through the development of continuous delivery, separating the application into multiple deployable units
同时,微服务还通过简化(泛化)服务的概念,消除编排需求,简化对服务组件的连接访问。从而避免了SOA的各种缺点:复杂、昂贵、重度、难以理解和开发。
The microservices architecture style addresses this complexity by simplifying the notion of a service, eliminating orchestration needs, and simplifying connectivity and access to service components.
微服务架构如下:
其核心是service component,这些服务组件相互解耦,易于独立开发、部署。服务组件的粒度是微服务架构中最难的挑战
- 太大:失去了微服务架构的优势
- 太小:导致需要编排,或者服务组件间的通信、事务。
而微服务架构相比SOA而言,其优势就在于避免依赖和编排 — 编排引入大量的复杂工作。
对于单个请求 如果service之间还要通信,那么可能是就是粒度过小。解决办法:
- 如果通信是为了访问数据:那么可以通过共享db解决
- 如果通信是为了使用功能:那么可以考虑代码的冗余,虽然这违背了DRY原则。在clean architecture中也指出,component的自完备性有时候要高于代码复用。
Space-Based Architecture
基于空间的架构,其核心目标是解决由于数据库瓶颈导致的低伸缩性、低并发问题。
分层架构中,在用户规模激增的情况下,数据层的扩展往往会成为最后的瓶颈(相对而言,前端和业务逻辑都容易做成无状态,比较好水平扩展)。而基于空间的架构的核心是内存复制,根本上解决了这个问题。
High scalability is achieved by removing the central database constraint and using replicated in-memory data grids instead
架构如下:
其核心组件包括
- processing unit,处理单元,其内部又包含一下组成
- business logic
- in-memory data grid
- an optional asynchronous persistent store for failover
- replication engine,用于同步数据修改
- virtualized middleware
- Messaging Grid: 监控processing unit可用性,路由客户端请求到processing unit
- Data Grid: 核心,负责processingunit之间的数据同步,毫秒级同步?
- Processing Grid: 可选组件,如果一个请求需要多个processing unit的服务,那么负责协调分发
- Deployment Manager: 负责processing unit的按需启停
基于空间的架构很少见,而且从上面的核心组件描述来看的话,开发和维护应该都是比较负责的,由于是数据的同步这块。而且由于数据都保存在内存中,那么数据量就不能太大。
基于空间的架构适用于需求变化大的小型web应用,不适用于有大量数据操作的传统大规模关系型数据库应用