高并发系统设计(二):架构分层:我们为什么一定要这么做?
本文原链接: https://www.cnblogs.com/wt645631686/p/13190536.html
在系统从0到1的阶段,为了让系统快速上线,我们通常是不考虑分层的。但是随着业务越来越复杂,大量的代码纠缠在一起,会出现逻辑不清晰、各模块相互依赖、代码扩展性差、改动一处就牵一发而动全身等问题。
我们常见的设计方式如MVC分层、ISO七层模型、Linux系统分层、Mysql分层、PHP分层等等...
分层有什么好处
- 分层的设计可以简化系统设计,让不同的人专注做某一层次的事情。想象一下,如果你要设计一款网络程序却没有分层,该是一件多么痛苦的事情。
- 分层之后可以做到很高的复用。比如,我们在设计系统A的时候,发现某一层具有一定的通用性,那么我们可以把它抽取独立出来,在设计系统B的时候使用起来,这样可以减少研发周期,提升研发的效率。
- 分层架构可以让我们更容易做横向扩展。如果系统没有分层,当流量增加时我们需要针对整体系统来做扩展。但是,如果我们按照上面提到的三层架构将系统分层后,那么我们就可以针对具体的问题来做细致的扩展。比如说,业务逻辑里面包含有比较复杂的计算,导致CPU成为性能的瓶颈,那这样就可以把逻辑层单独抽取出来独立部署,然后只对逻辑层来做扩展,这相比于针对整体系统扩展所付出的代价就要小的多了。
如何来做系统分层
参照阿里发布的《阿里巴巴Java开发手册v1.4.0(详尽版)》,我们可以将原先的三层架构细化成下面的样子:
- 终端显示层:各端模板渲染并执行显示的层。当前主要是 Velocity 渲染,JS 渲染, JSP 渲染,移动端展示等。
- 开放接口层:将Service层方法封装成开放接口,同时进行网关安全控制和流量控制等。
- Web层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。
- Service层:业务逻辑层。
- Manager 层:通用业务处理层。这一层主要有两个作用,其一,你可以将原先Service层的一些通用能力下沉到这一层,比如与缓存和存储交互策略,中间件的接入;其二,你也可以在这一层封装对第三方接口的调用,比如调用支付服务,调用审核服务等。
- DAO层:数据访问层,与底层 MySQL、Oracle、Hbase 等进行数据交互。
- 外部接口或第三方平台:包括其它部门 RPC 开放接口,基础平台,其它公司的 HTTP 接口。
在这个分层架构中主要增加了Manager层,它与Service层的关系是:Manager层提供原子的服务接口,Service层负责依据业务逻辑来编排原子接口。
以上面的例子来说,Manager层提供创建用户和获取用户信息的接口,而Service层负责将这两个接口组装起来。这样就把原先散布在表现层的业务逻辑都统一到了Service层,每一层的边界就非常清晰了。
除此之外,分层架构需要考虑的另一个因素,是层次之间一定是相邻层互相依赖,数据的流转也只能在相邻的两层之间流转。
我们还是以三层架构为例,数据从表示层进入之后一定要流转到逻辑层,做业务逻辑处理,然后流转到数据访问层来和数据库交互。那么你可能会问:“如果业务逻辑很简单的话可不可以从表示层直接到数据访问层,甚至直接读数据库呢?”
其实从功能上是可以的,但是从长远的架构设计考虑,这样会造成层级调用的混乱,比方说如果表示层或者业务层可以直接操作数据库,那么一旦数据库地址发生变更,你就需要在多个层次做更改,这样就失去了分层的意义,并且对于后面的维护或者重构都会是灾难性的。
分层架构的不足
任何事物都不可能是尽善尽美的,分层架构虽有优势也会有缺陷,它最主要的一个缺陷就是增加了代码的复杂度。
这是显而易见的嘛,明明可以在接收到请求后就可以直接查询数据库获得结果,却偏偏要在中间插入多个层次,并且有可能每个层次只是简单地做数据的传递。有时增加一个小小的需求也需要更改所有层次上的代码,看起来增加了开发的成本,并且从调试上来看也增加了复杂度,原本如果直接访问数据库我只需要调试一个方法,现在我却要调试多个层次的多个方法。
另外一个可能的缺陷是,如果我们把每个层次独立部署,层次间通过网络来交互,那么多层的架构在性能上会有损耗。这也是为什么服务化架构性能要比单体架构略差的原因。
那我们是否要选择分层的架构呢?答案当然是肯定的。
你要知道,任何的方案架构都是有优势有缺陷的,分层架构固然会增加系统复杂度,也可能会有性能的损耗,但是相比于它能带给我们的好处来说,这些都是可以接受的,或者可以通过其它的方案解决的。我们在做决策的时候切不可以偏概全。