网站静态化之动静整合方案
Posted 架构师联盟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网站静态化之动静整合方案相关的知识,希望对你有一定的参考价值。
上篇文章我简要的介绍了下网站静态化的演进过程,有朋友可能认为这些知识有点过于稀松平常了,而且网站静态化的技术基点也不是那么高深和难以理解,因此它和时下日新月异的web前端技术相比,就显得不伦不类了。其实当我打算写本系列的之前我个人觉得web前端有一个点是很多人都知道重要,但是有常常低估它作用的,那就是web前端和web服务端如何融合的这个点上,这个点再加上我们要做出一个规模庞大,高并发,快速响应的网站时候它对于web前端的架构技术的演进起到了一个不可忽视的作用。
网站的web前端要实现高效,第一个要解决的短板就是网络的延迟性对网站的加载效率的影响,当然很多人会说网速快不快这是网络运营商的问题,不是网站的问题,但是大家肯定也见过就算我们用上了千兆宽带也会有些网站加载速度慢的让人无法忍受,网站本身的确是没法控制网络速度的能力,但是如果我们不降低网络对页面加载效率的影响,其他任何优化网站的手段也就无从谈起,原因就是网络效率对于网页加载效率的影响是起到大头作用的,只有这个大头被解决了,那么解决其他的小头才能发挥作用。
回到上文讲到的网站静态化的关键点动静分离,解决这个关键点的本质就是为了降低网速对网站加载效率的影响,但是我们在处理动静分离问题时候采取的策略不同会对我们整个网站架构产生重大影响,特别是将网页做好动静拆分后,静态的资源尽力向浏览器端推移,这就导致了前端架构出现了以前服务端才有的MVC模式,这就导致web前端架构产生了质的变化,如是一些原来适用于flash这样的重客户端的技术也被传统的web前端所采用,MVC模式在web前端进一步演进由此而出现了MVP(Model-View-Presenter)模式,MVVM(Model-View-ViewModel)模式。也许上篇文章里有人对讲述动静分离的原理有点异议,但是当今日新月异的web前端技术就是这些常见技术不断演化而来,这就是我上篇想表达的内容,我觉得这个系列的特点应该是细节,这是和上个系列存储的瓶颈注重思想是有所不同的。
动态网站最难以动静分离的就是页面了,其他的静态资源例如:图片、外部脚本文件等等这些和静态网站的手法基本一致,其实业界很早就关注了动态网站的动静分离问题,并且为不同的动静分离方案都进行了总结,今天我就介绍下这些技术。本人web服务端的工作语言是java,因此下面服务端的例子是使用java的web技术阐述的,其他语言例如php都有与之对应的技术,所以请那些不是使用java作为服务端工作语言的朋友可以类比学习。
在java的web开发里,页面技术jsp本身就包含了将页面动静分离的手段,例如下面的代码:
<%@ include file=”header.jsp” %>
<body>
……….
<%@ include file=”footer.jsp” %>
一般一个网站的头部和尾部都是一样,因此我们把头部的代码单独放置在一个header.jsp页面里,页面尾部的代码放置下footer.jsp页面里,这样技术人员在开发页面时候就不再需要重复编写这些重复的代码,只需要引用即可,这个做法最大的好处就是可以避免不同页面在相同代码这块的不一致性,假如没有这个统一引用的话,手动编写或者复制和粘贴,出错的概率是非常的高的。
但是这个做法有一个问题,问题就是这种动静分离其实都是作用于单个页面的,也就是说每个页面都要手动的重复这个动静分离的操作,大多数情况这种做法都不会有什么问题,但是对于一个大型网站而言这种做法就有可能会制造不必要的麻烦,这里我截取了一张京东的首页,如下图所示:
讲述前我要事先声明下,京东网站可能不存在我要讲述的问题,我这里只是使用京东网站的首页做例子来说明,看图里的首页和食品两个条目,有些公司做这样的网站时候这些导航进入的页面会是一个独立的工程,每个工程都是由独立的项目组开发维护的,虽然项目组不同但是他们页面的整体结构会是一致的,如果按照上面的动静分离手段,那么每个项目组都要独立维护一份相同的头部尾部资源,这个时候麻烦来了,如果该公司要新增个新的条目,那么每个项目组都要更新自己不变的资源,如果该企业一共分了5个项目组,现在又做了一个新的条目,那么其他与之无关的项目组都得折腾一次更改统一引用文件的工作,要是做的不仔细就有可能出现页面展示不一致的问题,为了解决这个问题,java的web开发里就会考虑使用模板语言替代jsp页面技术,例如模板语言velocity,这些模板语言都包含一个布局的功能,例如velocity就有这样的功能,我们看看velocity的布局模板实例,如下所示(请参考原代码)
页面里我们可以引入这个布局格式,这个布局文件其实就是页面里不变的东西抽取了出来,它完成了页面动静分离,页面只要应用这个布局文件即可,到了这里这个布局文件和前面的include方式区别不大,那么我们再看看下面的代码:
<property name="layoutUrl" value="layout/default.vm"/><!--指定layout文件-->
不管服务端采取何种动静分离,动静资源的整合都是有服务端完成,按照上文提到网站静态化的思想,这些做法不会给网站性能提升带来任何好处,它们只是给开发,运维提供了便利而已,按前文的思路,我们要把动静分离往前移,服务端往前移碰到的第一个点就是静态的web服务器例如apache或ngnix。
在讲解静态的web服务器动静分离前我要先讲一下为什么我们要在服务端前面加个静态web服务器的道理。我个人觉得在每个服务端之前都布置一个静态web服务器,该服务器起到一个反向代理的作用,而且我觉得不管我们是否使用CDN,最好都这么做,这么做有如下好处:
好处一:方便日志的记录。
好处二:在服务端之前设立了一个安全屏障,即静态web服务器可以在必要时候过滤有害的请求。
好处三:可以控制流入到服务端的请求个数,当并发很高时候,可以利用静态web服务器能承担更高并发的能力来缓冲服务端的压力,这里我补充一些实践技巧,以java里常用的web容器tomcat为例,一般官方给出它的最大并发数应该不会超过200,如果我们在tomcat前放置了一个apache服务器,那么我们可以把tomcat的最大并发数设置为无效大,把并发数的控制放置在apache这边控制,这么做会给我们系统运维带来很大的好处,tomcat虽然有一个建议最大并发数,但是实际运行里java的web容器到底能承受多大并发其实要看具体场景了,因此我们如果可以动态控制apache的并发数,这个操作很方便的,那么我们就可以动态的调整tomcat这样容器的承载能力。
好处四:可以便于我们做动静分离。
这里我们以apache为例子讲解将动静分离前移到apache的一些做法,apache有一个功能叫做SSI,英文全称是Server Side Include,页面上我们一般这样使用SSI,SSI有一种标签,例如:
<!--#include file="info.htm"-->
页面一般使用注释的方式引入,这个和jsp的引入有点区别的,SSI的做法其实和服务端的引入类似,只不过使用SSI将本来服务端做的动静整合交由了apache完成了,我们可以把静态文件直接放置在Apache这里,如果这个静态web服务器上升到CDN,那么这些静态资源就可以在靠近用户的地方使用,SSI说白了就是像apache这样的静态资源服务器接收到服务端返回后,将一部分内容插入到页面了,然后将完整页面返回至浏览器。这个做法如果优化的得当,可以很好的提升网站的加载效率。
Apache这样的静态资源服务器还支持一种动静整合的技术,这个技术就是ESi,它的英文全称叫做Edge Side Includes,它和SSI功能类似,它的用法如下所示:
<esi:include max-age="45"/>
它和SSI区别,使用esi标签获取的资源来自于缓存服务器,它和SSI相比有明显的性能优势,其实网页特别是一个复杂的网页我们做了动静分离后静态的资源本身还可以拆分,有的部分缓存的时间会长点,有点会短点,其实网页里某些动态内容本身在一定时间里有些资源也是不会发生变化的,那么这些内容我们可以将其存入到缓存服务器上,这些缓存服务器可以根据页esi传来的命令将各个不同的缓存内容整合在一起,由此我们可以发现使用esi我们会享受如下优点:
优点一:静态资源会存放在缓存里,那么获取静态资源的效率会更高。
优点二:根据静态资源的时效性,我们可以对不同的静态资源设置不同的缓存策略,这就增加了动静分离方案的灵活性。
优点三:缓存的文件的合并交由缓存服务器完成,这样就减少了web服务器本身抓取文件的开销,从而达到提升web服务器的并发处理能力,从而达到提升网站访问效率的目的。
(友情提示:ESI这块我还了解的不太深入,听说它其实可以直接使用在jboss上,相关知识我还要继续收集资料学习)
SSI和ESI是静态web服务器处理动静资源整合的手段,那么我们再把动静整合操作往前移,这个时候就到了浏览器端了。浏览器端的动静整合的技术称之为CSI,英文全称叫做Client Side Includes,这个技术就是时下javascriptMVC、MVVM以及MVP技术采取的手段,实现CSI一般是采用异步请求的方式进行,在ajax技术还没出现的年代我们一般采取iframe的方式,不过使用CSI技术页面加载就会被人为分成两次,一次是加载静态资源,等静态资源加载完毕,启动异步请求加载动态资源,这么一做的确会发生有朋友提到的一种加载延迟的问题,这个延迟我们可以使用适当的策略来解决的,关于CSI的使用是本系列的重点,我会在后面文章里重点讲解。
编辑注:两篇合并,续上文
前文里我讲到了网站静态化的关键点是动静分离,动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思路。由此可见,网站静态化处理的核心就是动静分离和缓存两大方面,上篇我简单讲述了动静整合的基础知识,本篇将会讲述两大核心之一的动静分离策略,只有把动静分离策略做好了,缓存才能发挥出它应有的效果。
下面我们要讨论下动静分离的策略了,一个页面什么内容是动态的,什么内容是静态的,这个我们到底该如何来区分了?这个问题学问非常大,我们的标准不同,最后拆分出来的动静资源就会存在很大的不同。在本系列开篇里,我提到了什么样的页面是静态页面,什么样的页面是动态页面,我是以一个url的角度定义的,每个独立的页面都会有一个url,这个url就好比这个页面的门牌号,我们每次访问这个url时候如果得到的响应页面都是一样的那么我们就认为该页面是静态页面,如果访问某个url,我们访问的时间不同,最后展示的页面也不一样那么这个页面就是动态页面,动态页面就是我们要进行动静分离的载体了,我们可以看到我的定义其实是和时间相关的,也就是说访问时间不同,得到的结果会不一致,所以我们可以根据时间这个维度分析页面里那些内容是静态的,那些是动态,但是这个划分在实际情况里就会变得非常复杂,下面我就讲讲这个复杂度。
场景一:假如我们是一个商户,我们查询自己网店的交易数据,一般这个交易数据我们会放置在页面的右下部分,这个部分我们很自然把它当做动态资源,就算我们的网店交易量很小,我们也不敢把这个部分当做静态资源处理。
场景二:我们网站为了给用户一个友好的体验,会在用户登录网站后在页面某个地方显示欢迎语,例如:上午好,夏天的森林,欢迎使用我们的网站!,到了下午,这个欢迎语可能就变成了下午好,夏天的森林,欢迎使用我们的网站!,那么这块内容我们应该是当做静态内容还是动态内容呢?这个就需要思考了。
场景三:网站页面里会有很多图片,有些图片的确是很久很久都不会发生变化,例如网站的图标,但是有的图片却不同了,例如有一个星期我们要为某个商户做营销活动,那么营销图片这块更新后就会有一个星期的有效期,复杂点的话,我们可能会在营销活动期间在页面的某一块专设给这个商户营销活动的内容区,这个内容区使用一个html片段,但是当营销活动结束了,这个营销的图片可能就要发生变化,营销的内容区可能会被去掉,那么这些东西我们是当做静态内容还是动态内容处理了?
由上面的场景我们可以知道,这个动静分离是要讲究策略的,如果策略设计的不好,可能我们把网站静态化处理后,效果并没有达到我们的预期。其实,我认为动静分离除了以时间维度考虑外,还应该有个维度,就是被拆分的资源是否需要服务端应用加以配合,例如像交易查询这样的动态内容,我们其实需要服务端程序按照一定的业务逻辑处理请求后从存储层获取数据,那么这种动态资源是没法做静态化处理的,还有一部分资源例如场景三里的图片以及营销的html片段,这些资源写好后在有效时间内是不会发生变化的,那么这块内容虽然时效性可能会有差异,但是它却是可以在这段时间做静态化处理的,还有种情形就是场景二了,这个场景虽然使用数据需要服务端参入计算,但是计算结果在一定时间范围内是不变的,也就是说结果是可以被缓存的,那么这块的资源也是可以当做静态化资源进行处理的,为什么说拆分策略要考虑服务端应用的因素了?因为上面这些场景都是由服务端应用参入的形式所决定,在有效时间里服务端应用不需要参入,或者参入一次后,可以长期保存结果,那么我们可以把这些资源当做静态资源处理。
除此之外,服务端应用和结果的密切度也是要当做考虑的因素的。在web开发里,除了需要浏览器处理的,其他技术都可以当做服务端来理解,如果我们网站使用到了CDN,使用到了静态web服务器例如apache,以及服务端的web容器例如jboss,那么按请求的行进路径,我们结果处理越早那么网站响应效率也就越高,所以当请求在CDN返回了,那么肯定比在apache返回效率高,在apache就返回了肯定比jboss返回的效率高,再则服务端的web容器本身因为服务端程序运行要消耗部分系统资源,所以它在处理请求的效率会比CDN和apache差很多,所以当我们按照动静分离策略拆分出了静态资源后,这个资源能不放在最底层的服务端的web容器处理就不要放在服务端的web容器里处理。
由上所述,我们再回过头来看看静态web服务器的SSI技术,这个技术使用起来和我们在服务端使用include类似,但是在SSI使用include一定会比在服务端效率高,因为服务端在整合动静资源时候还会掺杂很多服务端程序处理,因此动静资源的效率就会大打折扣。我们再看看SSI的include的用法,如下所示:
<!--#include file="info.htm"-->
这个写法是使用页面的注释标签,当静态web容器处理请求时候,它会扫描里面的SSI标签,接着就会处理这个标签的内容,如果找到了资源那么web容器会将资源插入到页面里,如果web没有处理这个SSI标签,那么等结果到了浏览器,这个也就是一个注释而已,不会影响页面的展示,而且SSI标签处理的资源也是非常丰富的,不管这个资源是静态的,还是动态的,只要获取时候是个完整的资源都能被正常加入到页面里,所以像前面的场景二这种动态的内容也是可以正常处理的。因此场景二,场景三这样的情况都可以使用SSI来解决。SSI的作用当然不仅仅只是可以做include操作,它的标签也可以做一些逻辑上的操作,讲述如何使用SSI不是本文的重点,有兴趣的朋友可以去研究下。
不过SSI也有自己的局限性,它的第一个局限就是SSI解析是静态web容器来完成,因此它会消耗web容器的性能,如果SSI使用时候还有一定的逻辑,那么这种性能消耗就会更大,其实我觉得更加重要的是如果静态web容器过渡使用SSI,那么就会把自己变成了一个服务端的web容器,除了会影响到请求处理的效率,它还会降低自身的并发处理能力,所以我们希望资源整合策略交给外部服务处理效果会更好些,如是有些大型互联网公司使用ESI技术,ESI技术和缓存关系密切,这个内容我就放到下篇讨论了。
本篇最后我要再讲讲CDN的问题,上篇我讲到静态web容器整合动静资源的好处,由此我说如果CDN可以做动静整合,那么就能做到就近处理,这样效果会更高,今天我对这个做法做了一些考证,觉得该说法有点不妥,至少我现在的公司没有使用到这样的技术,CDN技术应该由三个步骤组成,首先是解析DNS,找到离用户最近的CDN服务器,接下来CDN要做一下负载均衡,根据负载均衡策略将请求落地到最合适的一个服务器上,如果CDN服务器上就有用户所需要的静态资源,那么这个资源就会直接返回给浏览器,如果没有CDN服务器会请求远端的服务器,拉取资源再把资源返回给浏览器,如此同时拉取的资源也被缓存在CDN服务器上,下次访问就不需要在请求远端的服务器了,CDN存储资源的方式使用的是缓存,这个缓存的载体是和apache,nginx类似的服务器,我们一般称之为http加速器,之所以成为http加速器是为了和传统静态web服务器区别开来,传统的静态资源服务器一般都是从持久化设备上读取文件,而http加速器则是从内存里读取,不过具体存储的计算模型会根据硬件特点做优化使得资源读取的效率更高,常见的http加速器有varnish,squid。Ngnix加上缓存模块也是可以当做http加速器使用的,不管使用什么技术CDN的服务器基本都是做一个就近的缓存操作,这也就是说CDN是否可以完成SSI操作是值得商榷的,所以前文的说法还是有点问题的。
原文链接:
http://www.cnblogs.com/sharpxiajun/p/4285085.html
http://www.cnblogs.com/sharpxiajun/p/4287011.html
进阶阅读
以上是关于网站静态化之动静整合方案的主要内容,如果未能解决你的问题,请参考以下文章