[透彻]为什么要前后端分离?
前后端分离的意义
前后端分离,已成为互联网项目开发的业界标准使用方式
前后端分离,会为以后的大型分布式架构、弹性计算架构、微服务架构打下坚实的基础。
核心思想: 前端页面调用后端的restuful api接口,并使用json数据进行交互。
服务器种类
- web服务器
例如 nginx,apache
这类服务器,一般只能解析静态资源。
- 应用服务器
例如 tomcat,jetty,resin
这类服务器,可以解析动态资源,也可以解析静态资源,但解析静态资源的速度没有web服务器高效。
一般而言,只有web服务器才能被外网访问,而应用服务器只能通过内网访问。
以前的开发模式
早期的JavaWeb项目并不复杂,业务场景和逻辑都很简单,开发比较便捷。
因此,大多数都是java程序员又当爹又当妈,既搞前端(html/css/javascript/jsp
),又搞后端(java/MySQL/ORM框架/接口开发
)。
随着时代发展,很多公司的规模越来越大,业务场景也越来越复杂,前后端的界限也越来越明确。
前端工程师只负责前端,后端工程师只负责后端。
正所谓术业有专攻,如果一个人什么都会,那他就不可能什么都精通。
职业划分
- 后端java工程师
java基础,设计模式,SpringBoot,Linux,MySQL数据库,ORM框架,多线程,弹性计算架构,微服务架构(Spring Cloud),jvm性能优化,以及相关的项目管理等。
后端追求的是:三高(高并发,高可用,高性能),安全,存储,业务等。
- 前端工程师
html5,css3,javascipt,bootstrap,react,vue,webpack,gulp,node,多线程,模块化,面向切面编程,设计模式,浏览器兼容性,性能优化等。
前端追求的是:页面表现,速度流畅,兼容性,用户体验等。
项目解耦
几曾何时,我们的JavaWeb项目使用若干后台框架,Springmvc + Spring + Mybatis
等
java分层:控制层(controller),业务层(service),持久层(dao)
C层负责接收参数,调用相关业务层,封装数据,以及将数据渲染到Jsp页面
Jsp页面使用各种标签(Jstl/EL表达式/Struts标签)或者手写java表达式(<%=%>)将后台数据展现出来
项目如何发布?
将代码打成war包,然后把war包发布到web容器中(通常是Tomcat),进行启动。
然后通过配置域名,dns等等相关,网站就可以访问了
早期的开发模式,是把前后端代码放在一个地方,也就是war包。
问题:在浏览器中输入网站域名(www.xxx.com),发生了什么?
浏览器通过dns服务器,找到服务器ip,将http请求发送到服务器,在TCP3次握手之后,通过TCP协议开始传输数据,服务器得到请求后,开始提供服务,接收参数,之后响应数据到浏览器,浏览器解析数据,将其呈现给用户。
假设服务器首页中有100张图片,此时,用户点击首页,看似是一次HTTP请求。
其实并不是一次,用户在第一次访问的时候,浏览器中不会有缓存,你的100张图片,浏览器要连着请求100次HTTP请求
你的服务器接收这些请求,都需要耗费内存去创建socket来玩tcp传输(消耗服务器上的计算资源)。
重点来了,这样的话,服务器的压力会非常大。
因为页面中的所有请求都是只请求到你这台服务器上
如果1个人还好,如果10000个人并发访问呢(先不聊服务器集群,这里就说是单实例服务器)
服务器能扛住多少个TCP连接?
带宽有多大?
服务器的内存有多大?
硬盘是高性能的吗?
能抗住多少IO?
web服务器分配的内存有多大?
会不会宕机?
因此,越是大中型的web应用,越要解耦
理论上,可以把数据库+应用服务+消息队列+缓存+用户上传的文件+日志等都扔在一台服务器上
你也不用玩什么服务治理,也不用做什么性能监控,什么报警机制等等,就乱成一锅粥好了。
但是这样,就好像把鸡蛋都放在一个篮子里,隐患非常大。
如果因为一个子应用的内存不稳定导致整个服务器内存溢出,那整个网站就挂了。
如果出意外挂掉,而恰好这时公司的业务处于井喷式,发展高峰期
那么恭喜你,业务成功被技术卡住,很可能会流失大量用户,后果不堪设想。
注意:技术一定要走在业务前面,否则将错过最佳的发展期
应用全部耦合在一起,相当于一个巨石
当服务端负载能力不足时,一般会使用负载均衡的方式,将服务器做成集群
这样,其实是在水平扩展一块块巨石,性能加速度会越来越低
要知道,本身负载就低的功能,完全没必要水平扩展的
本文的例子,你的性能瓶颈不在前端,何必水平扩展前端呢
还有
部署上线的时候,我明明只改了后端的代码,为什么要前端也跟着一起发布?
正常的互联网架构,是要拆开的
web服务器集群,应用服务器集群+文件服务器集群+数据库服务器集群+消息队列集群+缓存集群等。
JSP的痛点
以前的javaWeb项目,大多数使用JSP作为页面层,展示数据给用户
因为流量不高,也没有苛刻的性能要求
但现在是大数据时代,对于互联网项目的性能要求是越来越高
因此原始的前后端耦合在一起的架构模式,已经无法满足业务发展
因此我们需要寻找一种解耦方式,来大幅度提升我们的负载能力。
1.动态资源和静态资源全部耦合在一起,服务器压力大,因为服务器会收到各种HTTP请求,例如css的HTTP请求,js的,图片的等等。
一旦服务器出现状况,前后台一起玩完,用户体验极差。
2.UI出好设计图后,前端工程师只负责将设计图切成html,需要由java工程师来将html套成JSP页面,出错率较高(因为页面中经常会出现大量的js代码)
修改问题时需要双方协同开发,效率低下。
3.JSP必须要在支持java的web服务器里运行(例如tomcat,jetty,resin等),无法使用nginx等(nginx据说单实例HTTP并发高达5w,这个优势要用上)
性能提不上来
4.第一次请求jsp,必须要在web服务器中编译成servlet,第一次运行会较慢。
5.每次请求JSP都是访问servlet再用输出流输出的html页面,效率没有直接使用html高(是每次!)。
6.JSP内有较多标签和表达式,前端工程师在修改页面时会捉襟见肘,遇到很多痛点。
7.如果JSP中的内容很多,页面响应会很慢,因为是同步加载。
8.需要前端工程师使用java的ide(例如eclipse),以及需要配置各种后端的开发环境,你们有考虑过前端工程师的感受吗
基于上述的一些痛点,我们应该把整个项目的开发权重往前移,实现前后端真正的解耦!
开发模式
- 旧的开发模式
1.产品经历/领导/客户提出需求
2.UI做出设计图
3.前端工程师做html页面
4.后端工程师将html页面套成jsp页面( 前后端强依赖,后端必须要等前端的html做好才能套jsp。开发效率低)
5.集成出现问题
6.前端返工
7.后端返工
8.二次集成
9.集成成功
10.交付
- 新的开发模式
1.产品经历/领导/客户提出需求
2.UI做出设计图
3.前后端约定接口&数据&参数
4.前后端并行开发( 如果需求变更,只要接口&参数不变,就不用两边都修改代码,开发效率高)
5.前后端集成
6.前端页面调整
7.集成成功
8.交付
请求方式
- 旧的请求方式
1.客户端请求
2.服务端的servlet或controller接收请求( 后端控制路由与渲染页面,整个项目开发的权重大部分在后端)
3.调用service,dao代码完成业务逻辑
4.返回jsp
5.jsp展现一些动态的代码
- 新的请求方式:
1.浏览器发送请求
2.直接到达html页面( 前端 控制路由与渲染页面 ,整个项目开发的权重前移)
3.html页面负责调用服务端接口产生数据(通过ajax等等,后台返回json格式数据)
4.填充html,展现动态效果,在页面上进行解析并操作DOM。
总结一下,新方式的请求步骤:
大量并发浏览器请求—>web服务器集群(nginx)—>应用服务器集群(tomcat)—>文件/数据库/缓存/消息队列服务器集群
同时又可以玩分模块,还可以按业务拆成一个个的小集群,为后面的架构升级做准备。
前后分离的优势
-
前后端解耦,前端服务器放的是css,js,图片等一系列静态资源(甚至你还可以使用cdn加速),前端负责控制页面引用&跳转&路由,前端页面异步调用后端接口
-
发现bug,可以快速定位,不会出现互相踢皮球的现象,页面逻辑,跳转错误,浏览器兼容性问题,页面样式等问题,全部由前端工程师来负责。接口数据出错,数据没有提交成功,应答超时等问题,全部由后端工程师来解决。
-
大并发情况下,可以同时水平扩展前后端服务器,比如淘宝首页,需要2000+台前端服务器做集群来抗住数亿级别的日均pv。
-
减少后端服务器的并发/负载压力,理论上,除了接口以外的其他HTTP请求,应当全部转移到前端nginx上
-
即使后端服务暂时超时或者宕机了,前端页面也会正常访问,只不过数据刷不出来而已。
-
页面显示的东西再多也不怕,因为是异步加载。
-
nginx支持热部署,不用重启服务器,前端升级更无缝。
-
增加代码的维护性和易读性。
-
提升开发效率(并行开发)。
总结
-
前后端分离并非仅仅只是一种开发模式,而是一种架构模式(前后端分离架构)。
-
前后端工程师需要约定交互接口,实现并行开发,开发结束后需要进行独立部署
-
前端只需要,关注页面样式与动态数据的解析&渲染,而后端专注于业务逻辑。