引言
在前端优化的第一部分中,主要讲解了对静态资源的一些优化措施,包括图片压缩、CSS Sprites 技术、GZIP 压缩等。这一部分,本文将讲解前端优化里重要的 Flush 机制、动静分离、HTTP 持久链接、HTTP 协议灵活应用、CDN 等。结合这些技术或思想,相信会使 Java Web 应用程序的性能更上一层楼。html
Flush 机制的使用
实际上在 Web 技术中,Flush 机制并不新鲜,它的思想是无需等到网页内容所有加载完毕,一次性写回客户端,而是能够部分逐次的返回。若是网页很大的话,一次性写回所有内容显然是个不明智的选择,由于这会形成网页的长时间空白。Flush 机制容许开发人员将网页的内容按文档流顺序逐步返回给客户端,这样可使得用户知道咱们的系统正在工做,只是等待的时间稍长而已,这样用户也会“心甘情愿”的等下去。Flush 机制是一个经典的提升用户体验的方法,至今也一直在用。若是网页很大,这个机制也是建议使用的。在 Java Web 技术中,实现 Flush 很是简单,只要调用 HttpServletResponse.getWriter 输出流的 flush 方法,就能够将已经完成加载的内容写回给客户端。前端
可是是否每一个网页都要使用该技术呢?笔者固然不这么建议。将网页内容加载完毕后再一次性返回客户端也有它的好处。咱们知道网络传输也有最大的传输单元,内容加载完毕后一次性输出就能够最大程度的利用传输的带宽,减小分块,减小传输次数,也就是说实际上 Flush 机制会增长用户等待时间、增长浏览器渲染时间,可是对于大网页来讲,下降这点效率来加强用户体验,是值得的。java
动静分离
所谓的动静分离,就是将 Web 应用程序中静态和动态的内容分别放在不一样的 Web 服务器上,有针对性的处理动态和静态内容,从而达到性能的提高。本文基于 Java Web 来说解 Web 优化,而 Java Web 的主流服务器软件是 Tomcat。让人遗憾的是,Tomcat 在并发和静态资源处理的能力上较弱,这也是 Tomcat 为人诟病的地方。可是瑕不掩瑜,既然咱们选择了 Java Web,那么就应该发挥咱们程序员的头脑去千方百计的提升性能。而动静分离就是其中一种方法,既然 Tomcat 处理静态资源的能力较弱,那就将静态资源的处理任务交给适合的软件,而让 Tomcat 专一于处理 JSP/Servlet 的请求。jquery
对于静态资源处理的服务器软件,咱们能够选择 Nginx,它是一款俄罗斯人开发的软件,彷佛比 Apache 更加优秀。它支持高并发,对静态资源处理的能力较强,这正是咱们想要的不是吗?事实上,动静分离的方案不少,有人采用 Apache+Tomcat 的组合;也有人使用 Tomcat+Tomcat 的组合,不过两个 Tomcat 分别被放置于不一样的主机,不一样的域名。其中 Apache+Tomcat 的方案与 Nginx 的方案原理上是同样的,它们都是基于反向代理,相对于使用 Nginx 配置动静分离,Apache 的配置就显得略微复杂一些。在 Apache 里,mod_proxy 模块负责反向代理的实现。其中核心配置内容如清单 1 所示,该配置属于本人参与某项目的其中一部分。nginx
清单 1. 动静分离的 Apache 核心配置
<Proxy balancer://proxy> BalancerMember http://192.168.1.178:8080 loadfactor=1 BalancerMember http://192.168.1.145:8080 loadfactor=1 </Proxy> NameVirtualHost *:80 <VirtualHost *:80> ServerAdmin service@xuanli365.com ServerName www.xuanli365.com DocumentRoot /www DirectoryIndex index.shtml <Directory /www> AllowOverride All AddType text/html .shtml AddType application/x-rar .rar AddHandler server-parsed .shtml Options +IncludesNOEXEC </Directory> RewriteEngine on ProxyRequests Off ProxyPass /static/! ProxyPass / balancer://proxy/ ProxyPassReverse / balancer://proxy/ ProxyPreserveHost on </VirtualHost>
从 Apache 官方对 mod_proxy 模块的介绍,咱们能够知道 ProxyPass 属性能够将一个远端服务器映射到本地服务器的 URL 空间中,也就是说这是一个地址映射功能。在清单 1 的配置中,当访问的路径不在 /static/ 下时(!表示非),就转发给后端的服务器(也就是 Tomcat);不然若是是 /static/ 路径就访问本机。例如,当访问 www.xuanli365.com/static/css/index.css 时,实际处理请求的是 Apache 服务器,而访问 www.xuanli365.com/index.jsp,那么 Apache 会将请求转发到后端的 Tomcat 服务器,实际访问的页面是 http:// 192.168.1.178( 或 145):8080/index.jsp,这就实现了动静分离。在清单 1 的配置中实际也包含了简单的负载均衡(loadfactor 因子)。程序员
事实上,咱们能够随便打开一个大型门户网站来看一下,我打开的是腾讯网站,任意查看其中两张图片的地址,我发现一个是:http://mat1.gtimg.com/www/iskin960/qqcomlogo.png,而另外一个则是:http://img1.gtimg.com/v/pics/hv1/95/225/832/54158270.jpg。可见该网站存放图片资源使用了多个的域名,咱们再用 Linux 的 host 命令查看两个域名的 IP 地址,结果如图 1 所示。web
图 1. 某网站的动静分离

能够看到,经过查看 IP 地址,咱们发现这些图片极可能存放在不一样的主机上(为何是极可能?由于一个主机能够拥有多个 IP),而图片内容和网页的动态内容并不在同一 IP 下,也极可能是动静分离。多个域名在前面也已经提到,能够增长浏览器的并发下载数,提升下载效率。数据库
本文采用另外一种策略对动静分离进行演示,它的大体结构如图 2 所示。后端
图 2. 本文设计的动静分离结构

在本文中,咱们将静态资源放在 A 主机的一个目录上,将动态程序放在 B 主机上,同时在 A 上安装 Nginx 而且在 B 上安装 Tomcat。配置 Nginx,当请求的是 html、jpg 等静态资源时,就访问 A 主机上的静态资源目录;当用户提出动态资源的请求时,则将请求转发到后端的 B 服务器上,交由 Tomcat 处理,再由 Nginx 将结果返回给请求端。
提到这,可能有您会有疑问,动态请求要先访问 A,A 转发访问 B,再由 B 返回结果给 A,A 最后又将结果返回给客户端,这是否是有点多余。初看的确多余,可是这样作至少有 2 点好处。第一,为负载均衡作准备,由于随着系统的发展壮大,只用一台 B 来处理动态请求显然是是不够的,要有 B1,B2 等等才行。那么基于图 2 的结构,就能够直接扩展 B1,B2,再修改 Nginx 的配置就能够实现 B1 和 B2 的负载均衡。第二,对于程序开发而言,这种结构的程序撰写和单台主机没有区别。咱们假设只用一台 Tomcat 做为服务器,那么凡是静态资源,如图片、CSS 代码,就须要编写相似这样的访问代码:<img src=”{address of A}/a.jpg”>,当静态资源过多,须要扩展出其余的服务器来安放静态资源时,访问这些资源就可能要编写这样的代码:<img src=”{address of C}/a.jpg”>、<img src=”{address of D}/a.jpg”>。能够看到,当服务器进行变动或扩展时,代码也要随之作出修改,对于程序开发和维护来讲很是困难。而基于上面的结构,程序都只要 <img src=”a.jpg”>,无需关心具体放置资源的服务器地址,由于具体的地址 Nginx 为帮您绑定和选择。
按照图 2 所示的架构图,安装好须要的软件 Nginx 和 Tomcat。按照设想,对 Nginx 的配置文件 nginx.conf 进行配置,其中与本文该部分相关的配置如清单 2 所示。
清单 2. 动静分离的 Nginx 配置
# 转发的服务器,upstream 为负载均衡作准备 upstream tomcat_server{ server 192.168.1.117:8080; } server { listen 9090; server_name localhost; index index.html index.htm index.jsp; charset koi8-r; # 静态资源存放目录 root /home/wq243221863/Desktop/ROOT; access_log logs/host.access.log main; # 动态请求的转发 location ~ .*.jsp$ { proxy_pass http://tomcat_server; proxy_set_header Host $host; } # 静态请求直接读取 location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|css)$ { expires 30d; } ……
清单 2 十分简洁,其目的和咱们预期的同样,动态的请求(以 .jsp 结尾)发到 B(192.168.1.117:8080,即 tomcat_server)上,而静态的请求(gif|jpg 等)则直接访问定义的 root(/home/wq243221863/Desktop/ROOT)目录。这个 root 目录我直接将其放到 Linux 的桌面 ROOT 文件夹。
接下来在 Tomcat 中新建 Web 项目,很简单,咱们只为其添加一个 test.jsp 文件,目录结构如图 3 所示。
图 3. B 上的测试项目结构

而咱们定义了一张测试用的静态图片,放置在 A 的桌面 ROOT/seperate 目录下。结构如图 4 所示
图 4. A 上的静态资源文件夹结构

注意:这里的 separate 目录名是与 B 的项目文件夹同名的。
再查看图 3 中的 test.jsp 的源码。如清单 3 所示。
清单 3. test.jsp 源码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.Date" %> <%@ page import="java.text.SimpleDateFormat" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/ html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>动静分离的测试</title> </head> <body> <div>这是动态脚本处理的结果</div><br> <% //这是一段测试的动态脚本 Date now=new Date(); SimpleDateFormat f=new SimpleDateFormat("如今是"+"yyyy年MM月dd日E kk点mm分"); %> <%=f.format(now)%> <br><br> <div>这是静态资源的请求结果</div><br><img alt="静态资源" src="jquery.gif"> </body> </html>
清单 3 是一个很是简单的 JSP 页面,主要是使用 img 标签来访问 jquery.gif,咱们知道 test.jsp 在 B 服务器上,而 jquery.gif 在 A 服务器上。用于访问 jquery.gif 的代码里不须要指定 A 的地址,而是直接使用相对路径便可,就好像该图片也在 B 上同样,这就是本结构的一个优势了。咱们在 A 上访问 test.jsp 文件。结果如图 5 所示。
图 5. test.jsp 的结果

很是顺利,彻底按照咱们的想法实现了动静分离!
咱们初步完成了动静分离的配置,可是究竟动静分离如何提升咱们的程序性能咱们还不得而知,咱们将 Tomcat 服务器也迁移到 A 服务器上,同时将 jquery.gif 拷贝一份到 separate 项目目录下,图 3 的结构变为图 6 所示。
图 6. 拷贝 jquery.gif 的 separate 项目

咱们将 Tomcat 的端口设置为 8080,Nginx 的端口依然是 9090。如今访问 http://localhost:9090/separate/test.jsp(未使用动静分离)和访问 http://localhost:8080/separate/test.jsp(使用了动静分离)的效果是同样的了。只是 8080 端口的静态资源由 Tomcat 处理,而 9090 则是由 Nginx 处理。咱们使用 Apache 的 AB 压力测试工具,对 http://localhost:8080/seperate/jquery.gif、http://localhost:9090/seperate/jquery.gif、http://localhost:8080/seperate/test.jsp、http://localhost:9090/seperate/test.jsp 分别进行压力和吞吐率测试。
首先,对静态资源(jquery.gif)的处理结果如清单 4 所示。
清单 4. 静态资源的 AB 测试
测试脚本:ab -c 100 -n 1000 http://localhost:{port}/seperate/jquery.gif 9090 端口,也就是 Nginx 的测试结果: Concurrency Level: 100 Time taken for tests: 0.441 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Total transferred: 4497000 bytes HTML transferred: 4213000 bytes Requests per second: 2267.92 [#/sec] (mean) Time per request: 44.093 [ms] (mean) Time per request: 0.441 [ms] (mean, across all concurrent requests) Transfer rate: 9959.82 [Kbytes/sec] received 8080 端口,也就是 Tomcat 的测试结果: Concurrency Level: 100 Time taken for tests: 1.869 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Total transferred: 4460000 bytes HTML transferred: 4213000 bytes Requests per second: 535.12 [#/sec] (mean) Time per request: 186.875 [ms] (mean) Time per request: 1.869 [ms] (mean, across all concurrent requests) Transfer rate: 2330.69 [Kbytes/sec] received
清单 4 的测试脚本表明同时处理 100 个请求并下载 1000 次 jquery.gif 文件,您能够只关注清单 4 的粗体部分(Requests per second 表明吞吐率),从内容上就能够看出 Nginx 实现动静分离的优点了,动静分离每秒能够处理 2267 个请求,而不使用则只能够处理 535 个请求,因而可知动静分离后效率的提高是显著的。
您还会关心,动态请求的转发,会致使动态脚本的处理效率下降吗?下降的话又下降多少呢?所以我再用 AB 工具对 test.jsp 进行测试,结果如清单 5 所示。
清单 5. 动态脚本的 AB 测试
测试脚本:ab -c 1000 -n 1000 http://localhost:{port}/seperate/test.jsp 9090 端口,也就是 Nginx 的测试结果: Concurrency Level: 100 Time taken for tests: 0.420 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Total transferred: 709000 bytes HTML transferred: 469000 bytes Requests per second: 2380.97 [#/sec] (mean) Time per request: 42.000 [ms] (mean) Time per request: 0.420 [ms] (mean, across all concurrent requests) Transfer rate: 1648.54 [Kbytes/sec] received 8080 端口,也就是 Tomcat 的测试结果: Concurrency Level: 100 Time taken for tests: 0.376 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Total transferred: 714000 bytes HTML transferred: 469000 bytes Requests per second: 2660.06 [#/sec] (mean) Time per request: 37.593 [ms] (mean) Time per request: 0.376 [ms] (mean, across all concurrent requests) Transfer rate: 1854.77 [Kbytes/sec] received
通过笔者的屡次测试,得出了清单 5 的较为稳定的测试结果,能够看到在使用 Nginx 实现动静分离之后,的确会形成吞吐率的降低,然而对于网站总体性能来讲,静态资源的高吞吐率,以及将来能够实现的负载均衡、可扩展、高可用性等,该牺牲我想也应该是值得的。
我想任何技术都是有利有弊,动静分离也是同样,选择了动静分离,就选择了更为复杂的系统架构,维护起来在必定程度会更为复杂和困难,可是动静分离也的确带来了很大程度的性能提高,这也是不少系统架构师会选择的一种解决方案。
HTTP 持久链接
持久链接(Keep-Alive)也叫作长链接,它是一种 TCP 的链接方式,链接会被浏览器和服务器所缓存,在下次链接同一服务器时,缓存的链接被从新使用。因为 HTTP 的无状态性,人们也一直很清楚“一次性”的 HTTP 通讯。持久链接则减小了建立链接的开销,提升了性能。HTTP/1.1 已经支持长链接,大部分浏览器和服务器也提供了长链接的支持。
能够想象,要想发起长链接,服务器和浏览器必须共同合做才能够。一方面浏览器要保持链接,另外一方面服务器也不会断开链接。也就是说要想创建长链接,服务器和浏览器须要进行协商,而如何协商就要靠伟大的 HTTP 协议了。它们协商的结构图如图 7 所示。
图 7. 长链接协商

浏览器在请求的头部添加 Connection:Keep-Alive,以此告诉服务器“我支持长链接,你支持的话就和我创建长链接吧”,而假若服务器的确支持长链接,那么就在响应头部添加“Connection:Keep-Alive”,从而告诉浏览器“个人确也支持,那咱们创建长链接吧”。服务器还能够经过 Keep-Alive:timeout=10, max=100 的头部告诉浏览器“我但愿 10 秒算超时时间,最长不能超过 100 秒”。
在 Tomcat 里是容许配置长链接的,配置 conf/server.xml 文件,配置 Connector 节点,该节点负责控制浏览器与 Tomcat 的链接,其中与长链接直接相关的有两个属性,它们分别是:keepAliveTimeout,它表示在 Connector 关闭链接前,Connector 为另一个请求 Keep Alive 所等待的微妙数,默认值和 connectionTimeout 同样;另外一个是 maxKeepAliveRequests,它表示 HTTP/1.0 Keep Alive 和 HTTP/1.1 Keep Alive / Pipeline 的最大请求数目,若是设置为 1,将会禁用掉 Keep Alive 和 Pipeline,若是设置为小于 0 的数,Keep Alive 的最大请求数将没有限制。也就是说在 Tomcat 里,默认长链接是打开的,当咱们想关闭长链接时,只要将 maxKeepAliveRequests 设置为 1 就能够。
绝不犹豫,首先将 maxKeepAliveRequests 设置为 20,keepAliveTimeout 为 10000,经过 Firefox 查看请求头部(这里咱们访问上面提到的 test.jsp)。结果如图 8 所示。
图 8. 服务器打开长链接

接下来,咱们将 maxKeepAliveRequests 设置为 1,而且重启服务器,再次请求网页后查看的结果如图 9 所示。
图 9. 服务器关闭长链接

对比能够发现,Tomcat 关闭长链接后,在服务器的请求响应中,明确标识了:Connection close, 它告诉浏览器服务器并不支持长链接。那么长链接究竟能够带来怎么样的性能提高,咱们用数听说话。咱们依然使用 AB 工具,它可使用一个 -k 的参数,模拟浏览器使用 HTTP 的 Keep-Alive 特性。咱们对 http://localhost:8080/seperate/jquery.gif 进行测试。测试结果如清单 6 所示。
清单 6. AB 测试长链接
测试脚本:ab – k -c 1000 -n 10000 http://localhost:8080/seperate/jquery.gif 关闭长链接时: Concurrency Level: 1000 Time taken for tests: 5.067 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Keep-Alive requests: 0 Total transferred: 44600000 bytes HTML transferred: 42130000 bytes Requests per second: 1973.64 [#/sec] (mean) Time per request: 506.678 [ms] (mean) Time per request: 0.507 [ms] (mean, across all concurrent requests) Transfer rate: 8596.13 [Kbytes/sec] received 打开长链接时,maxKeepAliveRequests 设置为 50: Concurrency Level: 1000 Time taken for tests: 1.671 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Keep-Alive requests: 10000 Total transferred: 44650000 bytes HTML transferred: 42130000 bytes Requests per second: 5983.77 [#/sec] (mean) Time per request: 167.119 [ms] (mean) Time per request: 0.167 [ms] (mean, across all concurrent requests) Transfer rate: 26091.33 [Kbytes/sec] received
结果必定会让您大为惊讶,使用长链接和不使用长链接的性能对比,对于 Tomcat 配置的 maxKeepAliveRequests 为 50 来讲,居然提高了将近 5 倍。可见服务器默认打开长链接是有缘由的。
HTTP 协议的合理使用
不少程序员都将精力专一在了技术实现上,他们认为性能的高低彻底取决于代码的实现,却忽略了已经成型的某些规范、协议、工具。最典型的就是在 Web 开发上,部分开发人员没有意识到 HTTP 协议的重要性,以及 HTTP 协议能够提供程序员另外一条性能优化之路。经过简单的在 JSP 的 request 对象中添加响应头部,每每能够迅速提高程序性能,一切实现代码仿佛都成浮云。本系列文章的宗旨也在于让程序员编最少的代码,提高最大的性能。
本文提出一个这样的需求,在文章前面部分提到的 test.jsp 中,它的一部分功能是显示服务器的当前时间。如今咱们但愿这个动态网页容许被浏览器缓存,这彷佛有点不合理,可是在不少时候,虽然是动态网页,可是却只执行一次(好比有些人喜欢将网页的主菜单存入数据库,那么他确定不但愿每次加载菜单都去读数据库)。浏览器缓存带来的性能提高已经众人皆知了,而不少人却并不知道浏览器的缓存过时时间、缓存删除、什么页面能够缓存等,均可以由咱们程序员来控制,只要您熟悉 HTTP 协议,就能够轻松的控制浏览器。
咱们访问上面说起的 test.jsp。用 Firebug 查看请求状况,发现每次请求都会从新到服务器下载内容,这不难理解,所以 test.jsp 是动态内容,每次服务器必须都执行后才能够返回结果 , 图 10 是访问当前的 test.jsp 的头部状况。如今咱们往 test.jsp 添加清单 7 的内容。
清单 7. 在 test.jsp 的首部添加的代码
<% SimpleDateFormat f2=new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss"); String ims = request.getHeader("If-Modified-Since"); if (ims != null) { try { Date dt = f2.parse(ims.substring(0, ims.length()-4)); if (dt.after(new Date(2009, 1, 1))) { response.setStatus(304); return; } } catch(Exception e) { } } response.setHeader("Last-Modified", f2.format(new Date(2010, 5, 5)) + " GMT"); %>
上述代码的意图是:服务器得到浏览器请求头部中的 If-Modified-Since 时间,这个时间是浏览器询问服务器,它所请求的资源是否过时,若是没过时就返回 304 状态码,告诉浏览器直接使用本地的缓存就能够,
图 10. 修改 test.jsp 前的访问头部状况

修改完 test.jsp 代码后,使用鼠标激活浏览器地址栏,按下回车刷新页面。此次的结果如图 11 所示。
图 11. 修改 test.jsp 后的首次访问

能够看到图 11 和图 10 的请求报头没有区别,而在服务器的响应中,图 11 增长了 Last-Modified 头部,这个头部告诉浏览器能够将此页面缓存。
按下 F5(必须是 F5 刷新),F5 会强制 Firefox 加载服务器内容,而且发出 If-Modified-Since 头部。获得的报头结果如图 12 所示 .
图 12. 修改 test.jsp 后的再次访问

能够看到,图 12 的底部已经提示全部内容都来自缓存。浏览器的请求头部多出了 If-Modified-Since,以此询问服务器从缓存时间起,服务器是否对资源进行了修改。服务器判断后发现没有对此资源(test.jsp)修改,就返回 304 状态码,告诉浏览器可使用缓存。
咱们在上面的实验中,用到了 HTTP 协议的相关知识,其中涉及了 If-Modified-Since、Last-Modified、304 状态码等,事实上与缓存相关的 HTTP 头部还有许多,诸如过时设置的头部等。熟悉了 HTTP 头部,就如同窗会了如何与用户的浏览器交谈,也能够利用协议提高您的程序性能。这也是本文为什么一直强调 HTTP 协议的重要性。那么对于 test.jsp 这个小网页来讲,基于缓存的方案提高了多少性能呢?咱们用 AB 给您答案。
AB 是个很强大的工具,他提供了 -H 参数,容许测试人员手动添加 HTTP 请求头部,所以测试结果如清单 8 所示。
清单 8. AB 测试 HTTP 缓存
测试脚本:ab -c 1000 – n 10000 – H ‘ If-Modified-Since:
Sun, 05 Jun 3910 00:00:00 GMT ’ http://localhost:8080/seperate/test.jsp
未修改 test.jsp 前 : Document Path: /seperate/test.jsp Document Length: 362 bytes Concurrency Level: 1000 Time taken for tests: 10.467 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Total transferred: 6080000 bytes HTML transferred: 3630000 bytes Requests per second: 955.42 [#/sec] (mean) Time per request: 1046.665 [ms] (mean) Time per request: 1.047 [ms] (mean, across all concurrent requests) Transfer rate: 567.28 [Kbytes/sec] received 修改 test.jsp 后: Document Path: /seperate/test.jsp Document Length: 0 bytes Concurrency Level: 1000 Time taken for tests: 3.535 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Non-2xx responses: 10000 Total transferred: 1950000 bytes HTML transferred: 0 bytes Requests per second: 2829.20 [#/sec] (mean) Time per request: 353.457 [ms] (mean) Time per request: 0.353 [ms] (mean, across all concurrent requests) Transfer rate: 538.76 [Kbytes/sec] received
分别对比 Document Length、Requests per second 以及 Transfer rate 这三个指标。能够发现没使用缓存的 Document Length(下载内容的长度)是 362 字节,而使用了缓存的长度为 0。在吞吐率方面,使用缓存是不使用缓存的 3 倍左右。同时在传输率方面,缓存的传输率比没缓存的小。这些都是用到了客户端缓存的缘故。
CDN 的使用
CDN 也是笔者最近才了解和接触到的东西,耳中也是屡次听到 CDN 这个词了,在淘宝的前端技术报告上、在一个好朋友的创新工场创业之路上,我都听到了这个词,所以我想至少有必要对此技术了解一下。所谓的 CDN,就是一种内容分发网络,它采用智能路由和流量管理技术,及时发现可以给访问者提供最快响应的加速节点,并将访问者的请求导向到该加速节点,由该加速节点提供内容服务。利用内容分发与复制机制,CDN 客户不须要改动原来的网站结构,只需修改少许的 DNS 配置,就能够加速网络的响应速度。当用户访问了使用 CDN 服务的网站时,DNS 域名服务器经过 CNAME 方式将最终域名请求重定向到 CDN 系统中的智能 DNS 负载均衡系统。智能 DNS 负载均衡系统经过一组预先定义好的策略(如内容类型、地理区域、网络负载情况等),将当时可以最快响应用户的节点地址提供给用户,使用户能够获得快速的服务。同时,它还与分布在不一样地点的全部 CDN 节点保持通讯,搜集各节点的健康状态,确保不将用户的请求分配到任何一个已经不可用的节点上。而咱们的 CDN 还具备在网络拥塞和失效状况下,能拥有自适应调整路由的能力。
因为笔者对 CDN 没有亲身实践,不便多加讲解,可是各大网站都在必定程度使用到了 CDN,淘宝的前端技术演讲中就说起了 CDN,可见 CDN 的威力不通常。
图 12. 淘宝的 CDN 前端优化

所以 CDN 也是不得不提的一项技术,国内有免费提供 CDN 服务的网站:http://www.webluker.com/,它须要您有备案的域名,感兴趣的您能够去试试。
小结
本文总结了 HTTP 长链接、动静分离、HTTP 协议等等,在您须要的时候,能够查看本文的内容,相信按照本文的方法,能够辅助您进行前端的高性能优化。笔者将继续写后续的部分,包括数据库的优化、负载均衡、反向代理等。因为笔者水平有限,若有错误,请联系我批评指正。
接下来在第三部分文章中,我将介绍服务器端缓存、静态化与伪静态化、分布式缓存等,而且将它们应用到 Java Web 的开发中。使用这些技术能够帮助提升 Java Web 应用程序的性能。
转自:http://www.ibm.com/developerworks/cn/java/j-lo-javawebhiperf2/