1.1 水平分层架构
1.1.1 应用架构概述
图1-1 应用无架构与MVC架构图
人会随着生存环境的变化而不断成长,应用架构也一样。应用架构所处的环境是什么呢?答案是很明显的,应用架构所处的环境就是业务。业务由简单到复杂,应用架构也要相应地做出调整来适应业务的变化。任务脱离业务的架构都是耍流氓,因为架构一旦脱离业务,就好像人脱离了生存环境,皮之不存,毛将焉附。最早的应用程序业务比较简单,因此呈现出一种几乎无架构的状态,具体如图1-1所示。
无架构应用包括几十或者几百个功能项,而所有功能项都被打包进了一个单体的应用中,例如传统的OA、ERP、CRM等其他各种各样的软件。对于这种野兽级别的软件应用,其部署、排错、扩展和升级等工作对开发人员来说都是噩梦。
1.1.2 MVC架构/水平分层架构
随着业务不断复杂,我们意识到架构可以做到水平分层,比如展示层、控制层、数据层等。我们将这样的架构称为“MVC架构”。
(1)展示层(View)
视图是用户看到并与之交互的界面。对老式的Web应用程序来说,视图就是由HTML+CSS元素组成的界面,在新式的Web应用程序中,HTML依旧在视图中扮演着重要的角色。
(2)控制层(Controller)
控制层接收用户的输入并调用模型和视图完成用户的需求,所以当单击Web页面中的超链接和发送HTML表单时,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后确定用哪个视图来显示返回的数据,经典的技术有Servlet、Structs、Spring MVC等。
(3)模型层(Model)
模型层是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。一个模型可以同时为多个视图提供数据。标准的MVC框架事实上并不包含模型层,通常需要专门的数据库连接池和统一的数据库访问接口对接数据库。因此,ORM框架逐渐流行起来,常用的有iBatis、MyBatis、Hibernate等。这些ORM框架屏蔽了底层的数据库连接池和数据源的实现,实现程序对象到关系数据库数据的映射。
通过MVC框架开发的项目会统一打成大的War包,部署到Tomcat、Jetty等Web服务器上。传统的MVC框架如何实现高可用和高并发呢?具体原理如图1-2和图1-3所示。
图1-2 传统架构高可用解决方案
传统应用架构一般采用热双机的模式。正常情况下,Master主机提供服务,当Master主机出现故障或者宕机的时候,切换到Slave从机。我们可以通过Linux的WatchDog或者Keepalived检测服务器的状态,如果有一台Web服务器宕机或工作出现故障,Keepalived就会检测到,并将有故障的服务器从系统中剔除,同时使用其他服务器代替该服务器的工作,当服务器工作正常后,Keepalived自动将服务器加入服务器群中。这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的服务器。对于高并发、大流量的场景,传统应用架构一般采用Apache(软负载)或者F5做负载均衡,具体如图1-3所示。
图1-3 传统架构高并发解决方案
随着业务不断发展,业务变得越来越复杂,传统MVC架构下的系统应用代码越来越多,其缺点也渐渐显露出来。
- 部署效率低。业务膨胀导致代码膨胀、测试用例膨胀,编译和部署效率变低,某个功能出问题或者编译异常都得重新打包部署,效率极低。
- 维护困难。由于业务的膨胀,功能越来越复杂,代码修改牵一发而动全身,维护和定制都非常困难。
- 团队协作效率低,代码重复率高。
- 系统可靠性和可用性变差。业务的发展导致访问量、网络流量上升,负载均衡、数据库连接等都会面临巨大压力。由于所有的模块都在一个应用进程里,因此如果某个应用接口发生故障,比如内存泄漏,就会导致整个应用宕机,严重影响业务的正常进行。
- 新功能上线周期变长。新开发的功能需要和老功能一起打包、编译和测试,如果测试出Bug,整个系统就需要重新修改、回归测试、打包和部署,这些强耦合会导致整个交互效率下降。