大家好,我是易安!
在零碎从 0 到 1 的阶段,为了让零碎疾速上线,咱们通常是不思考分层的。然而随着业务越来越简单,大量的代码纠缠在一起,会呈现逻辑不清晰、各模块相互依赖、代码扩展性差、改变一处就牵一发而动全身等问题。
这时,对系统进行分层就会被提上日程,那么咱们要如何对架构进行分层?明天咱们就来讲一讲
什么是分层架构
软件架构分层在软件工程中是一种常见的设计形式,它是将整体零碎拆分成 N 个档次,每个档次有独立的职责,多个档次协同提供残缺的性能。
咱们在刚刚成为程序员的时候,会被“教育”说零碎的设计要是“MVC”(Model-View-Controller)架构。它将整体的零碎分成了 Model(模型),View(视图)和 Controller(控制器)三个档次,也就是将用户视图和业务解决隔离开,并且通过控制器连接起来,很好地实现了体现和逻辑的解耦,是一种规范的软件分层架构。
另外一种常见的分层形式是将整体架构分为体现层、逻辑层和数据拜访层:
- 体现层,顾名思义嘛,就是展现数据后果和承受用户指令的,是最靠近用户的一层;
- 逻辑层外面有简单业务的具体实现;
- 数据拜访层则是次要解决和存储之间的交互。
这是在架构上最简略的一种分层形式。其实,咱们在不经意间曾经依照三层架构来做零碎分层设计了,比方在构建我的项目的时候,咱们通常会建设三个目录:Web、Service 和 Dao,它们别离对应了体现层、逻辑层还有数据拜访层。
除此之外,如果咱们稍加注意,就能够发现很多的分层的例子。比方咱们在大学中学到的 OSI 网络模型,它把整个网络分成了七层,自下而上别离是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
工作中常常能用到 TCP/IP 协定,它把网络简化成了四层,即链路层、网络层、传输层和应用层。每一层各司其职又互相帮助,网络层负责端到端的寻址和建设连贯,传输层负责端到端的数据传输等,同时相邻两层还会有数据的交互。这样能够隔离关注点,让不同的层专一做不同的事件。
Linux 文件系统也是分层设计的,从下图你能够清晰地看出文件系统的档次。在文件系统的最上层是虚构文件系统(VFS),用来屏蔽不同的文件系统之间的差别,提供对立的零碎调用接口。虚构文件系统的上层是 Ext3、Ext4 等各种文件系统,再向下是为了屏蔽不同硬件设施的实现细节,咱们形象进去的独自的一层——通用块设施层,而后就是不同类型的磁盘了。
咱们能够看到,某些档次负责的是对上层不同实现的形象,从而对下层屏蔽实现细节。比方说 VFS 对下层(零碎调用层)来说提供了对立的调用接口,同时对上层中不同的文件系统规约了实现模型,当新增一种文件系统实现的时候,只须要依照这种模型来设计,就能够无缝插入到 Linux 文件系统中。
那么,为什么这么多零碎肯定要做分层的设计呢?答案是分层设计存在肯定的劣势。
分层设计的益处
分层的设计能够简化零碎设计,让不同的人专一做某一档次的事件。 设想一下,如果你要设计一款网络程序却没有分层,该是一件如许苦楚的事件。
因为你必须是一个精通网络的全才,要晓得各种网络设备的接口是什么样的,以便能够将数据包发送给它。你还要关注数据传输的细节,并且须要解决相似网络拥塞,数据超时重传这样的简单问题。当然了,你更须要关注数据如何在网络上平安传输,不会被他人窥探和篡改。
而有了分层的设计,你只须要专一设计应用层的程序就能够了,其余都能够交给上面几层来实现。
再有,分层之后能够做到很高的复用。 比方,咱们在设计零碎 A 的时候,发现某一层具备肯定的通用性,那么咱们能够把它抽取独立进去,在设计零碎 B 的时候应用起来,这样能够缩小研发周期,晋升研发的效率。
最初一点,分层架构能够让咱们更容易做横向扩大。 如果零碎没有分层,当流量减少时咱们须要针对整体零碎来做扩大。然而,如果咱们依照下面提到的三层架构将零碎分层后,就能够针对具体的问题来做粗疏的扩大。
比如说,业务逻辑外面蕴含有比较复杂的计算,导致 CPU 成为性能的瓶颈,那这样就能够把逻辑层独自抽取进去独立部署,而后只对逻辑层来做扩大,这相比于针对整体零碎扩大所付出的代价就要小得多了。
如何来做零碎分层
说了这么多分层的长处,那么当咱们要做分层设计的时候,须要思考哪些关键因素呢?
在我看来,最次要的一点就是你须要理分明每个档次的边界是什么。你兴许会问:“如果依照三层架构来分层的话,每一层的边界不是很容易就界定吗?”
没错,当业务逻辑简略时,档次之间的边界确实清晰,开发新的性能时也晓得哪些代码要往哪儿写。然而当业务逻辑变得越来越简单时,边界就会变得越来越含糊,给你举个例子。
任何一个零碎中都有用户零碎,最根本的接口是返回用户信息的接口,它调用逻辑层的 GetUser 办法,GetUser 办法又和 User DB 交互获取数据,就像下图右边展现的样子。
这时,产品提出一个需要,在 APP 中展现用户信息的时候,如果用户不存在,那么要主动给用户创立一个用户。同时,要做一个 HTML5 的页面,HTML5 页面要保留之前的逻辑,也就是不须要创立用户。这时逻辑层的边界就变得不清晰,体现层也承当了一部分的业务逻辑(将获取用户和创立用户接口编排起来)。
那咱们要如何做呢?参照阿里巴巴 Java 开发手册,咱们能够将原先的三层架构细化成上面的样子:
我来解释一下这个分层架构中的每一层的作用。
- 终端显示层:各端模板渲染并执行显示的层。以后次要是 Velocity 渲染,JS 渲染,JSP 渲染,挪动端展现等。
- 凋谢接口层:将 Service 层办法封装成凋谢接口,同时进行网关安全控制和流量管制等。
- Web 层:次要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简略解决等。
- Service 层:业务逻辑层。
- Manager 层:通用业务解决层。这一层次要有两个作用,其一,你能够将原先 Service 层的一些通用能力下沉到这一层,比方与缓存和存储交互策略,中间件的接入;其二,你也能够在这一层封装对第三方接口的调用,比方调用领取服务,调用审核服务等。
- DAO 层:数据拜访层,与底层 MySQL、Oracle、HBase 等进行数据交互。
- 内部接口或第三方平台:包含其它部门 RPC 凋谢接口,根底平台,其它公司的 HTTP 接口。
在这个分层架构中次要减少了 Manager 层,它与 Service 层的关系是:Manager 层提供原子的服务接口,Service 层负责根据业务逻辑来编排原子接口。
以下面的例子来说,Manager 层提供创立用户和获取用户信息的接口,而 Service 层负责将这两个接口组装起来。这样就把原先分布在体现层的业务逻辑都对立到了 Service 层,每一层的边界就十分清晰了。
除此之外,分层架构须要思考档次之间肯定是相邻层相互依赖,数据的流转也只能在相邻的两层之间流转。
咱们还是以三层架构为例,数据从表示层进入之后肯定要流转到逻辑层,做业务逻辑解决,而后流转到数据拜访层来和数据库交互。那么你可能会问:“如果业务逻辑很简略的话可不可以从表示层间接到数据拜访层,甚至间接读数据库呢?”
其实从性能上是能够的,然而从久远的架构设计思考,这样会造成层级调用的凌乱,比方说如果表示层或者业务层能够间接操作数据库,那么一旦数据库地址产生变更,你就须要在多个档次做更改,这样就失去了分层的意义,并且对于前面的保护或者重构都会是灾难性的。
分层架构的有余
任何事物都不可能是尽如人意的,分层架构虽有劣势也会有缺点,它最次要的一个缺点就是减少了代码的复杂度。
这是不言而喻的嘛,明明能够在接管到申请后就能够间接查询数据库取得后果,却偏偏要在两头插入多个档次,并且有可能每个档次只是简略地做数据的传递。有时减少一个小小的需要也须要更改所有档次上的代码,看起来减少了开发的老本,并且从调试上来看也减少了复杂度,本来如果间接拜访数据库我只须要调试一个办法,当初我却要调试多个档次的多个办法。
另外一个可能的缺点是,如果咱们把每个档次独立部署,档次间通过网络来交互,那么多层的架构在性能上会有损耗。这也是为什么服务化架构性能要比单体架构略差的起因,也就是所谓的“多一跳”问题。
那咱们是否要抉择分层的架构呢? 答案当然是必定的。
你要晓得,任何的计划架构都是有劣势有缺点的,天地尚且不全何况咱们的架构呢?分层架构固然会减少零碎复杂度,也可能会有性能的损耗,然而相比于它能带给咱们的益处来说,这些都是能够承受的,或者能够通过其它的计划解决的。 咱们在做决策的时候切不可以偏概全。
总结
明天我讲了分层架构的劣势和有余,以及咱们在理论工作中如何来对架构做分层。分层架构是软件设计思维的外在体现,是一种实现形式。咱们熟知的一些软件设计准则都在分层架构中有所体现。把握这些设计思维会自然而然地明确分层架构设计的妙处,同时也能帮忙咱们做出更好的设计方案。
本文由 mdnice 多平台公布