求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
构建高性能的web站点
 

作者:jt521xlg,发布于:2012-8-30,来源:博客

 

目录:

构建高性能的web站点学习笔记一

构建高性能的web站点学习笔记二------数据库扩展

构建高性能的web站点学习笔记三------动态内容缓存

构建高性能的web站点学习笔记四------浏览器缓存

构建高性能的web站点学习笔记五------Web服务器缓存

构建高性能的web站点学习笔记六------反向代理缓存

构建高性能的web站点学习笔记一

谈到网站优化,我们必须知道一次交互的过程中都经过哪几个阶段,然后在对应的阶段采取优化措施

一次交互大概经历以下几部分时间:

  1. 数据在网络中传输的时间(响应时间:发送数据的传输时间+返回数据的传输时间)
  2. 站点服务器接收到请求并生成回应数据的时间
  3. 浏览器计算并在本地渲染的时间

根据上述三个时间段,我在这简单的列举一下常用的优化方案

1.增加带宽:

当网页或组件下载速度变慢的话,一些架构师可能会采取增加带宽,因为他们认为是服务器带宽不够用了,这是最省事的一种方法,但是这对于提供下载服务为主的站点来说也许是这样的,对于其他服务的站点未必是好的解决方案

2.减少HTTP请求:

我们知道几乎每一个页面都包含了多个组件,每个组件都需要计算,下载,渲染,这些都是需要时间的,如果我们减少这些行为,那么就可以加快网页的执行速度,但是我们往往需要在优雅的网页以及网页的表现性能之间进行取舍,常见的优化方法是:

  1. 设计简单的网页,里面包含较少的图片和脚本,但是这可能牺牲了美观和用户交互
  2. 将多个图片文件合成一个图片文件,利用CSS偏移技术来呈现网页,这样可以避免多个图片下载
  3. 合并js脚本和css样式表
  4. 利用浏览器缓存策略,避免重复下载

可见这一块属于网页的前端优化

3.加快服务器的脚本执行计算速度

我们大多数涉及到性能的站点中都使用的各种各样额后台脚本语言:PHP,jsp,python,asp.net等等这行脚本都需要相应的解释器进行解释生成中间代码,然后依托解释器的运行环境中运行,所以生成中间代码这段时间又成为我们为获取性能提升瞄准的一大目标,对于一些较强的商业支持的语言比如ASP.net,JSP均有内置的优化方案(比如解释器第一次执行,然后将结果缓存下来),而对于开源的脚本语言则依靠第三方组件来提供类似功能 比如PHP的APC组件

4.使用动态内容缓存

动态内容缓存是指将动态生成HTML页给缓存起来,在以后一段时间内当有用户访问的时候直接跳过计算阶段而直接输出缓存中的内容,听起来的确很好,但是好的东西往往都会有些难度,我们必须考虑:成千上万的缓存文件如何存储,缓存的命中率如何,缓存的过期侧略如何设计,在应用在多台web服务器的分布式站点上我们需要考虑什么?

5.使用数据缓存

动态内容缓存是将数据与表现一起打包缓存,这有时候并不是我们想要的效果,例如一个页面中有一部分是不经常变的(顶部ogo),而所以另外我们可以发现有时候一些动态计算总是消耗在对于一些特殊数据处理上,这些数据更新过于频繁,甚至占用大量的IO时间,如果我们想要提高缓存利用率,提高灵活性,以及性能的需求,所以引入了数据缓存

更加细粒度的缓存似乎可以避免网页的整体更新。有些内容是需要实时更新的(关系型数据的读取),如果采取动态内容缓存的话,如果页面有更新,那么我们必须重新生成缓存,这对网页中不变的内容似乎有点不公平.

我们需要考虑的问题是:如何协调数据缓存和网页缓存,能否将二者结合在一起呢,数据缓存存放在哪?

6.动态内容静态化

在动态网页的内容中虽然避免了可观的重复计算,但是需要每次调用动态脚本解释器判定缓存是否过期以及读取缓存,这似乎有点多余,关键是消耗了不少时间,直接让浏览器访问缓存不是更好么?这种情况下缓存直接暴漏给HTML页,我们普遍称之为静态化。

7.更换web服务器软件

8.页面组件分离

9.合理的部署web服务器

我们知道访问的主机离我们的站点服务器距离越远,那么经过的路由节点越多,如果不在同一个互联网运营商的互联网中,还要经过运行商的顶级节点和骨干网络,可想而知这样要经过多少次存储转发,而且还要受不同运行商的出口带宽限制,显然我们希望我们的用户和站点服务器位于同一个互联网运营商的网络内,怎样实现呢?

10.使用负载均衡

如果我们已经最大程度上的发挥了单台服务器的处理能力,还不能满足现实需要,那么就需要更多的服务器一起分摊工作,为此我们需要想各种不同的办法实现web负载均衡,可能是简单的HTTP重定向,或是基于DNS的轮回解析,或者通过反向代理服务器来实现负载均衡调度,还可以通过LVS组件服务器集群等方法.

11.优化数据库

如果我们忽略了数据库的优化,如果我们的表结构一塌糊涂,那么可以说前面的工作白干了,web服务器与数据库服务器交互通信一般是基于TCP协议,即便他们是在同一台主机上也是如此,在数据库设计的时候你需要考虑:

  1. 你是否合理的运用这种类型的索引?
  2. 你了解数据库存储引擎的特性么?

12.考虑可扩展性

可扩展性对于我们来说是我们山穷水尽的时候被指引得一条星光大道,一旦扩展无法进行,那就是死路一条

13.减少视觉等待

有时候用户的要求的是你不要不理我,实在不行的话给用户一些提示吧

构建高性能的web站点学习笔记二------数据库扩展

构建高性能的web站点需要考虑很多方面,我们在这了解一下其中一项---------数据库扩展,希望能够让没有接触过这方面知识的朋友对数据库扩展有个认识吧。

随着用户数量的不断增加,数据库将面临着巨大的增删改查,即便我们将sql语句优化的很好,但是数据库服务器仍然抵挡不了千军万马似的select,我们不得不考虑其他方法来解决这个问题。和web站点服务器一样,既然一台服务器不能承受不了,人多力量大,我们首先想到了增加服务器去分担压力。

一个新的解决方案肯定会带来新的问题-

如何扩展?

一般对数据库中的操作中读的(select)操作远远超过写的操作,那么我可以讲读写分离,原理是用一台主服务器专门用来写,多个从服务器同步主服务器中的数据。

多个数据库服务器,我们的程序怎样知道该访问那一台服务器呢?

我们通过代码控制?如果某一台服务器宕掉的话怎么办?这些问题都是我们需要考虑的,于是我们想到了反向代理,他可以向web反向代理一样,为我们按照我们制定的规则访问相应的服务器,如果检测到某一台服务器宕掉的话,它会自动将该台服务器从列表中移除。

现在我们使用一台服务器作为写服务器,由图可知,随着站点的增长,写操作会越来越频繁,如果写的操作占操作中的80%,那么从服务器必须花费80%去同步主服务器中的数据,只有20%的时间去处理用户的读操作了,而且如果写操作再大一些的话,写服务器已经无法承受写的压力了,这个问题是很严重的。

我们应该怎样办呢?

垂直分区:将彼此不经常交互的数据分类分别放在不同服务器数据库中

最简单的方法是将不同的数据库分布到不同的服务器上,你会发现有很多的数据库之间并不存在关系,或者不需要进行join查询,那为什么不把他们放在不同的服务器上呢?

我们将博客数据库与好友数据库分开了,并且从主服务器中独立出来,这样就可以将这两个数据库的操作的负担从主服务器卸下来了,按照这样的思路,随着互联网的发展,越来越多的人写博客了,一台blog服务器可能不能处理现在的工作了于是我们采用同样的方法来扩展,进行读写分离

随着时间的增加,新的问题又来了,博客的写服务器再也承受不了写的压力了(对数据库中的各个表写操作数据量太大了),于是我们想到了将数据库操作的表分离到不同的数据库服务器上,但是如果数据表也达到了写的操作极限呢?现在innodb一个表可以容纳64TB的数据,这只是存储容量

水平分区:将同一个数据表按一定规则分别放在不同的数据库中

例如加入我们拥有10个服务器,我们可以根据userid%10将用户数据分别存放在不同的数据库中,这样的话我们就可以用户分别存放在这10个数据库分区中

那么我们怎样知道数据在哪个数据库中存放呢?按找传统的方式是不行的

传统的方式:

"select *from tablename where blogid="$post_id;

因为我们只能通过userid来确定用户的数据在哪个个数据库,所以我们需要将userID传递过去

<?php

$db = new DataAccess($user_id);

$db->selectDb("db_blog");

$tbl_name = getTblName($user_id);

$sql = "select * from " . $tbl_name . " where post_id=" . $post_id;

$result = $db->query($sql);

?>

哪些数据数据应该分区呢?用户信息,好友关系这些很难回答,必须根据具体情况而定,很多时候对那些数据进行分区不是我们可以选择的,对那些频繁访问导致网站接近崩溃的数据我们必须对其进行分区

分区的会不会给我们带来不便么?

答案是肯定的,比如,原本你可能通过一条联合查询就可能搞定任务,分区之后我们必须根据用户ID来确定分区,然后通过好友ID找到好友数据所在的分区。。。很不灵活吧

常见的分区算法

哈希算法 user_id%10 这种就是

范围 1-10000存放在分区1 10001-20000存放在分区2中

映射关系 还不是太理解,以后理解了再补充上

OK,今天只讲一些mysql扩展的常用几种方法和使用情况给介绍了,以后等我的知识增加了,将实现也和大家分享一下。

构建高性能的web站点学习笔记三------动态内容缓存

缓存分为:整页缓存,局部缓存,数据缓存,还有代码解释器缓存,web服务器缓存

缓存和缓冲的区别:二者相似之处都是解决速度不一致,而且都需要一块存储区域,缓冲主要为了减缓压力,比如内存的读写速度远远大于磁盘的读写速度,所以我们设置了磁盘缓冲区,常见的又在线看视频的时候视频缓冲区,但是缓存注重的是策略,需要考虑的是缓存命中率,每次都能找到我们想要的数据那是最理想的结果

缓存的本质:就是将那些需要昂贵开销的计算结果保存起来,下次使用直接读取,而避免重复的计算。

缓存可以存放的位置

1.存放在文件中,这样的话每次读取缓存会涉及到文件IO操作,

2.保存到内存中,形式为Key-value的形式,我们不必担心在内存中查找速度的问题,即便是有很多key,查找速度也是非常快的,使用内存缓存方法必须使用php的APC模块,或者使用XCache,

将文件放到内存中的好处是可以减少IO操作,对于数据库访问密集的服务器,可以让服务器处理更多额数据库IO操作

3.缓存服务器:我们可以将缓存存放到一台独立的缓存服务器中,利用memCached,我们很容易通过TCP将内容存储到缓存服务器中,而且memcached也是通过内存空间保存缓存服务器,减少了不必要的I磁盘IO.另外memcached在内存中给每一个key都维护一个过期时间,过期后自动删除key,这样缓存过期检查非常容易,只需要在缓存数据时制定过期时间即可,

你可能会发现apc方式性能最好,主要原因他是将缓存存放在了本地服务器,既然这样,空间上难免有些限制,假设你的网页有数十万个动态网页需要缓存,如果每个100KB,10万个网页就是1GB,那么我们服务器内存空间容量就会成为系统性能的瓶颈,好吧,购买更多的内存,这有设计到经济问题,一旦本地服务器内存扩展到极限,怎么办,这又是一个技术问题,我们不得不想其他办法去扩展内存,显然memcached分布式缓存使扩展成为了可能。还有一个小原因,我们每个缓存因为我们本次测试是访问的同一个动态页面,而且都在其生存期内,故命中率100%,如果网站页面较多 ,内存无法缓存所有页面那么命中率就会减小,同样吞吐率也会随之减小。

就吞吐率而言,memcached可能没有本地内存缓存速度快,web服务器的内存本身都很宝贵的,他要处理HTTP进程,和脚本解释器开销。但是出于上述多方面考虑,你会觉得他是值得,总之一句话扩展性好

综合考虑:如果你的站点初创,需要缓存的页面较少,而且服务器的内存有足够的空间,APC不失为一个很好的选择,随着站点的增大我们可以更换缓存机制,看一下刚才的代码,其实是很方便的。我们不能预测未来,但要做好充分的准备

构建高性能的web站点学习笔记四------浏览器缓存

1.为什么使用浏览器缓存

以前了解的动态脚本加速,或者动态内容缓存之类,他们的原理都是避免服务器重复计算,结果仍保留在服务器端,这样获取数据还得从服务器检索然后传送到用户浏览器,如果我们把这些结果放在浏览器中,就省去了服务器的查找和网络传输,浏览器缓存很好的实现了这个功能

2.浏览器缓存存放在哪

浏览器一般会在用户主机中创建一个目录,用来保存缓存文件,有的浏览器会将部分缓存放在内存中,这样又对性能有了很大的提升,省去了浏览器向缓存目录的查找工作

3.不管是服务器端缓存还是浏览器端缓存,都需要创建,判断是否过期等一系列工作;那么浏览器缓存是怎样完成这些工作的呢?

我们只掉动态内容缓存的内容创建,存储,以及过期检查等一系列操作都是在服务器端完成,但是浏览器缓存是由服务器生成内容,有浏览器存储到本地,任何一方都不能完成所有操作,他们需要一种沟通机制,这就是HTTP的“缓存协商”

缓存协商

缓存协商的过程,用户通过浏览器向服务器端发送请求页面,服务器端返回请求结果,并告诉浏览器,哪些内容可以缓存,浏览器将可以缓存的内容存储起来,下次请求这个内容时,他便不会直接向服务器请求完整的内容,而是询问服务器是否可以使用本地缓存,服务器接受到浏览器的询问,然后决定是否允许客户端使用本地缓存,不可以的话就将最新内容传送给浏览器

几个问题

服务器怎样,在哪规定哪些内容可以缓存,哪些不可以? 这个问题我没弄清楚,希望哪位牛人能给讲解一下

服务器根据什么判定浏览器是否可以使用本地缓存?

比较常用的方法是通过最后修改时间来判断缓存是否过期,静态网页一般Web服务器会自动为其生成过期时间,动态页面必须我们通过代码控制,我们需要在被请求的页面中添加header("Last-Modified:".gmdate("D,d M Y H:i:s")."GMT");这意味这我们给动态内容增加了一些HTTP响应头信息,我们通过HTTP Watch工具刷新浏览器看一下服务器端返回的请求里面多出了

我们再此请求该页面,看一下浏览器发出的请求

可见浏览器接收到服务器端的暗示,并在下次请求内容首先询问“我请求的内容在这个时间之后是否有更新”,这是服务器就需要根据这个时间判断文件是否更新(是否修改),可是web服务器却无法胜任这些工作,还得我们通过代码控制,我们再访问的页面中添加

可能大家的发现了这里的修改并非真正的文件修改,而是在原来的基础上加一个时间值

彻底消灭请求

可能大家发现了,虽然上面提到根据Last_Modified判断缓存是否过期,我们还是需要向服务器端发送询问,可不可以在本地判断缓存是否过期呢?其实HTTP还有一个属性Expires ,它定义了一个绝对过期时间,它更像个授权者,浏览器一旦发现他的存在就会自动验证缓存是否过期,Web服务器默认不开启此功能,我们需要进行相应的配置 Apache配置如下

第二行功能开启Expires功能

后三行设置不同的类型的设定绝对过期时间,都采用access plus语法

添加Expires标记

然后我们再跟踪浏览器请求

目前还存在一个问题,Expires指定的过期时间使用的是服务器端的过期时间,如果和客户端时间不一致的话,就会影响本地缓存的有效期检查

例如如果我们设置的过期时间是1小时,可是客户端的时间比服务器短时间快2个小时,那么直接就过期了。

怎样解决这个问题呢?幸好HTTP/1.1中还有一个标记用于弥补Experis的不足,他就是Cache-Control,他的格式如下

Cache-Control:max-age=<second>

max-age指定了相对过期时间,单位是秒,并且这个时间是相对客户端浏览器而言的

对于静态页面,Web服务器在开启Expires的情况下,会自动响应Cache-Control的,和上面一样,动态页面必须手动代码添加

目前浏览器做的很好,如果HTTP响应头中既有Expires也有Cache-Control的时候会优先考虑Cache-Control,对于没有Cache-Control则会按照expires

下面说下浏览器刷新方式

Ctrl+F5 或者按着Ctrl键单击刷新按钮,强制刷新网页内容,跳过浏览器

构建高性能的web站点学习笔记五------Web服务器缓存

前面提到的一些缓存技术都是有我们的动态才程序控制的,现在的web服务器功能越来越强大,常用的web服务器软件也都内置了缓存功能,下面我们就简单的说下服务器端缓存的应用.

首先,我们先来介绍一下URL映射,对于所有web服务器我们向其发送Http请求,他解析后将结果返回给我们客户端,这听起来很简单么?真的是这样么,真相是web服务器还有很多“暗操作”,大家都知道Url重写技术吧,比如apache的mod_rewrite,这样的话我们请求的地址,很可能不是真正文件所存放的地址,取个简单的例子,我们请求

htt p://www.fuwuqi1.com/book/index.html页面,

这时候web服务器的也许会给他定位到 www/book/index.html,就是请求www文件夹下的book文件夹下的index.html 如果我们使用了URL 重写技术

比如Apache的rewrite,以上的url完全有可能定位到另一个文件路径下,例如可以定位到page/book/index.html路径

上面这属于“小暗操作” 下面我们看一下大一点还是上面的请求地址,服务器完全可以定位到一个动态的网页例如

定位到/reader.php?book=index这种重写很常见,它会使url更优雅,同时也更利于搜索引擎的收录

下面我们看看更变态的,一些大的网站为了实现负载均衡,他们吧URL定位到别的服务器上了

htt p://www.fuwuqi.com/read.php?book=index

这样的话肯定会添加一些网络开销,如果我们能做到让web服务器在第一次定向后就直接把内容给缓存下来,下次访问同一内容,首先检查一下本地缓存是不是有,如果有就不需要重定向到其他路径,或者服务器等这样会节省一些开销

这里只介绍了一些理论上的知识,下面还要考虑怎样配置缓存,缓存文件存放在哪里,缓存过期验证,缓存哪些内容,后续内容我会尽快补充上去。

构建高性能的web站点学习笔记六------反向代理缓存

Web代理服务器的职责是:用来接收浏览器发送的请求,并将请求转发给真正的web服务器(其实就是存放请求资源的web服务器),然后接收web服务器返回来的内容并交给浏览器。

传统代理

代理服务器以前通常用来访问互联网的web站点,现在的浏览器也都有设置代理服务器的选项,包括QQ了飞信之类的,只要局域网中有一台机子可以连外网,局域网中的计算机都可以使用它作为代理服务器进行上网,当然这需要一些配置,配置问题不是我们今天讨论的内容,有兴趣同学可以自己配置一下

反向代理

“反向”,为什么叫做反向代理呢?

我们先分析一下传统代理,局域网中的计算机通过代理服务器访问web服务器,假如局域网中有20台机器都用该代理,那么对于web服务器来说都是同一台主机发送过来的请求,这样局域网中用户计算机对web服务器是透明的,代理服务器是在客户端

反向代理服务器呢?我们看一下反向代理服务器的工作流程,

只有传统代理: (浏览器<---->传统代理服务器(在客户端哦))<----->web服务器 注我用括号括起来代表他们是一家的,<----->代表二者可以互相传输数据。

只有反向代理: 浏览器<---->(反向代理服务器(在服务器端)<----->web服务器 )

既有反向代理也有传统代理 : (浏览器<---->传统代理服务器)<---->(反向代理服务器<----->web服务器 ) 我们通常将后者web服务器成为后端服务器

上面看来 反向代理服务器对用户浏览器透明,代理服务器在服务器端,有web站点的所有者负责配置或找人配置

由上面描述如果使用反向代理,我们知道用户浏览器首先访问的代理服务器,真正的数据放在后端的web服务器中,这样的话代理服务器就可以将web服务器反馈的数据给缓存起来,这样用户就下次请求的时候就不用再向web服务器端请求数据,我们一般以apache,Ngix等作为后端web服务器,代理服务器一般使用Varnish,关于反向代理服务器的配置,这里就不在详述。

反向代理缓存是否可以取代web服务器的动态内容缓存?

这要根据具体情况了,加入你发现他们二者的工作内容相同,那么你可以完全替换掉web动态内容缓存,但是下面几种情况完全可以让两者和睦相处,形成多级缓存。

例如:如果我们站点访问量特别大,我们可能引入多台代理服务器(负载均衡的内容,没了解过的可以看一下我的关于负载均衡的笔记),则每台代理服务器第一次被请求或者缓存过期,都需要向web服务器获取数据,如果web服务器中有动态内容缓存,很好直接就返回了,否则就需要重新计算,假如我们的代理服务器较多,那么web服务器会重复这样的工作,如果我们使用动态内容缓存,那么性能提高一定很可观。

相关文章

深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
相关文档

重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
相关课程

基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程

 
分享到
 
 
     


十天学会DIV+CSS(WEB标准)
HTML 5的革新:结构之美
介绍27款经典的CSS框架
35个有创意的404错误页面
最容易犯的13个JavaScript错误
设计易理解和操作的网站
更多...   


设计模式原理与应用
从需求过渡到设计
软件设计原理与实践
如何编写高质量代码
单元测试、重构及持续集成
软件开发过程指南


东软集团 代码重构
某金融软件服务商 技术文档
中达电通 设计模式原理与实践
法国电信 技术文档编写与管理
西门子 嵌入式设计模式
中新大东方人寿 技术文档编写
更多...