静态页面之间的包含一般有如下一些方案:
1、Client Side Includes(CSI):通过frame、iframe、javascript、javacript+ajax等方式将另外一个页面的内容动态包含进来。像现在流行的jquery等javascript库对此有较好的支持。
优点:能够利用浏览器客户端并行处理及装载的机制;通过浏览器缓存机制可以降低网络传输时间,提高性能;计算放在客户端,能够降低服务器端压力
缺点:搜索引擎优化问题;javascript兼容性问题;客户端缓存可能导致服务器端内容更新后不能及时生效;XSS等安全隐患
2、Server Side Includes(SSI):
优点:SSI技术是通用技术,不受具体语言限制,只需要Web服务器或应用服务器支持即可,Ngnix、Apache、Tomcat、Jboss等对此都有较好的支持
缺点:SSI在语法上不能够直接包含其他服务器的url(当然也可以通过redirect等来变通实现),因此在需要充分利用缓存及负载均衡的环境下相对不是很灵活。
当然如果不使用单独的缓存服务器,而是使用Ngnix,利用Ngnix对SSI及Memcached支持,通过NginxHttpSsiModule、NginxHttpMemcachedModule也可以实现页面缓存,但与专业的缓存服务器(例如Varnish)相比较,Ngnix作为缓存服务器只适合于中小规模的场合。
3、Edge Side Includes (ESI):
Edge Side Includes(ESI) 和Server Side Includes(SSI)和功能类似。SSI需要特殊的文件后缀(shtml,inc)。ESI可以直接通过URI包含远程服务器文件,ESI更适合用于缓存服务器上,缓存整个页面或页面片段,因此ESI特别适合用于缓存。像当下流行的缓存服务器Varnish对此有所支持。
SSI可以很容易满足让所有静态页面include其他静态页面的需求。
大部分的网站都有这样的需求:在整个静态页面的局部有需要动态更新的内容片段,包括:
1、与用户个性化无关的信息,所有用户进来看到的内容都一样。例如最热新闻、最活跃的用户等
2、与用户个性化信息相关。例如用户登录信息、用户好友等
以上两种情况,一般情况下都采用ajax方式来实现静态页面局部信息的刷新,ajax直接提交给Web服务器或应用服务器获取动态数据。或者采用Ajax+Memcached的模式,将动态变化的内容放入Memcached中,ajax直接存取Memcached,这样能够缓解Web服务器或应用服务器压力。但采用ajax的方案,直接绕过了缓存服务器,并没有充分利用缓存服务器对于静态页面的缓存支持。
使用Varnish及其对ESI的支持很容易实现对以上两种需求的较好支持:
1、与用户个性化无关的信息:直接由Varnish+ESI就可以实现。对于动态变化的局部页面,可以在ESI制定的url地址返回的http header的Cache-Control来指定缓存策略,实现局部页面缓存(fragment caching)。
2、与用户个性化信息相关:对于整个页面的缓存策略仍然使用Varnish+ESI方式。而需要fragment caching的局部页面,可以根据用户Cookie信息获得用户身份标识信息(例如userid),然后在ESI的URL中带上用户身份信息提交到后端的Web服务器或应用服务器以获取与用户个性化相关的信息。可以参考:
Caching logged in users 。
简单梳理了一下基于Varnish+ESI实现静态页面缓存的思路,有空再写代码具体测试一下。
Varnish作为一个高性能的缓存服务器,值得好好研究一下。
尽管Varnish和Ngnix都具有Load Balancing的功能,但Ngnix只能根据客户端IP进行负载均衡,不支持基于Session状态维护(session persistence)方式,无法维护Session状态;而Varnish的Load Balancing都不支持。而这正是HAproxy的强项。
由此得到一个相对理想的架构:
Nginx (用于HTTP compression及https) –> Varnish (用于reverse proxy caching) –>HAProxy(用作Load Balancing)–>Ngnix(Web Server)或Tomcat