转发自博客:http://www.cnblogs.com/birdshover/
原文地址:http://www.cnblogs.com/birdshover/archive/2009/08/03/1537225.html
(一)
最简单的一个网站,可能说是demo更加合适一些,部署上一台计算机上也可以正常运转。通常情况,这种部署方式是效率最高的。但是为什么说需要把web服务器与数据库分开放置呢?这就牵扯到通信效率的问题。
你写一个程序,无论是winform还是webform或者是windows service的,总会有两个对象需要交换数据吧?而数据交换大体上有这么几种方式:
1、通过内存;
2、通过硬盘;
3、通过网卡。
一、通过内存交换数据
图1.1
图1.1是两个类之间的数据交换,取款记录是“引用类型”,那么在“个人”使用的时候就是使用的原对象;而“余额”是值类型,会被拷贝过来使用。但是无论是值类型还是引用类型,这种在一个进程里的通信,都是通过内存进行数据交换的,这种也是速度最快的方式。像我家里的机器,内存的读写速度是6G/s左右。
上面说了进程内部的通信是通过内存来进行的(这里忽略非主流的开发出来的程序),而进程间通信也存在用内存交换数据的情况。比如,内存文件映射。再比如,匿名管道。(这里不详述这些技术。)
二、通过硬盘交换数据
图2.1
进程内也有这种数据交换方式,更多见的是在进程间交换数据时使用。在实现进程间通信时,内存文件映射、管道技术相对来说比读写硬盘上的文件稍微难理解一点,所以对速率要求不高的系统也有采用这种方式的。图2.1表现这种情况。现在的硬盘一般分为三种,IDE、SCSI和SATA(串口)。IDE硬盘的读写速度一般在10~100M/s之间,SCSI的最高速度320M/s左右,SATA有几个版本,1.0规范是150M/s,3.0规范是600M/s。可见硬盘的读写速度要比内存低好多,而且频繁读写硬盘另外一个坏处是硬盘相对内存来说容易坏。
三、通过网卡交换数据
图3.1
图3.1反映了通过网卡交换数据的情况。现在的网卡一般都是百兆千兆的,百兆网卡的实际传输速度大约是12m/s,千兆网卡的传输速度大约是100m/s。
言归正传,为什么要把web服务器与数据库分开放置呢?在单机上放置不是能达到最高效率么?一旦分开放置,即使使用千兆网卡,那么数据传输速度也是大打折扣啊!这就要讲一个规模问题,网站规模小,这样存放当然没有任何问题(这里单从性能上分析,不考虑其它因素)。但是一旦规模比较大的时候就容易出现问题,这是系统瓶颈上的一个考虑。访问量大的时候很可能发生数据库跟web服务器抢cpu,而更糟糕的是,当尝试使用缓存来解决数据库占用大量CPU时,发现内存也被数据库占完了。当web与数据库分离的时候,网站就成长的更像一个网站了。这个时期的网站需要花很多心思考虑性能问题,工作也更加有挑战性了。
可以当我们沾沾自喜的时候,麻烦的问题又来了,现在两台服务器,一台web一台数据库,性能又出现问题了。这个时期出现的问题相对来说还是比较简单的,因为就两个部分,不是数据库瓶颈就是web服务器瓶颈。当然,是数据库瓶颈的可能性更高一些。为什么这么说呢?一般来说,一个公司开发的网站是这种规模的时候,聘用的程序员都是刚入门不久的。而这个时期的程序员更加关心功能如何实现,对性能优化还没有很多经验。要是再去仔细研究数据库如何优化,如何让查询更有效率,学习改造成本还是相当高的。这个时候一般会采用避重就轻的办法——静态化。
(二)
(一)说到为了提高网站负载而进行静态化处理。
一、静态化的处理方案(特指生成文件方式)
图1.1
1、html静态方案
图1.1是最常用的静态化处理方式。IIS得到请求交给ASP.Net,根据路径ASP.Net判断是否已经生成这个请求的静态文件,如果存在,则直接输出文件,如果不存在,则读取数据生成静态页,并输出。这种方式最容易理解,准入门槛低,很容易就想到了。
这样似乎解决了问题,但是新的问题来了。生成静态后的页面,所有人看到的都是一样的,并且现在数据库的数据更新了,现在怎么办?这个时候,如果不想对系统进行大的变动的话,最好的办法是用一段js替换掉需要按用户显示不同的地方,至于数据更新后静态文件更新的方法,制定一套策略就可以了。当然,这样并没有解决所有问题,例如,现在网站的整体风格都需要改变,难道全部生成一遍吗?
前几年出了一个xml+xslt静态方案,可以解决网站风格变化问题。csdn的论坛改版(具体忘记哪年了),就使用过这种方案。这种方案是对html静态方案的发展。不过似乎效果并不是很理想,具体会遇到什么问题,贫道没用过,也说不清楚。==!
2、动态页面作载体的静态方案
这种方案是图1.1衍生品,把静态文件换成aspx文件。现在好了,可以解决更新风格、模板的问题了。因为生成的文件是aspx,就可以使用.net自带的模板解决方案了!当然,像某些部分需要显示用户相关数据的话,那没办法,还是得用js调用的方法。这个方案主要是用来解决统一风格网站更新风格问题的。
经过上面的处理,一台web加一台数据库也能承受一定压力的访问了。压力是多大?按我的经验是15分钟4000PV左右是可以支撑的,再多的话,例如8000,那就很有难度了。当然前提是你的网页中,或者说被主要访问的网页中不能有iframe。当然,还要受具体带宽多少,机器配置是否足够,用户操作是否分布均匀等因素影响。
二、缓存式方案
ASP.Net就提高了现成的页面缓存方案,用起来感觉还不错。这种页面缓存式方案本质上也是静态化处理,不过这部分静态内容是放到了内存中。由上篇文章讲到的内存与硬盘速度的状况,就可以想到这种方案,速度比静态化的快。这种方案也存在局部区域需要特定显示问题,可以用局部静态化,或者也可以用js调用的方式处理。这种方式也不是完美的,主要表现在,一旦缓存了很大的内存,当ASP.Net进程池回收时,IIS容易死掉。
于是乎,衍生出了进程外缓存。进程外缓存,是把缓存的数据放置到另外一个进程中,脱离了IIS。这种应用一般是windows service。本机的话可以用匿名管道,联网机器的话可以用Remoting、socket等方式与ASP.Net交换数据。这种方式效率没有放在IIS内部解决快,但是运行稳定是它的特点。最著名的应用就是MemCached。这种方式是缓存了数据而不是页面,数据在内存中,拿到ASP.Net页面进行数据绑定。这点是这种应用与前面三种最大的区别。
到了这里,该松一口气了,所有问题都让我们解决了。但是随着网站的发展,用户的增加,访问量不断加大,系统又遇到瓶颈了。
(三)
(二)讲了几种静态化方案的利弊,有朋友要讲详细一点,呵呵,这不属于本节的范畴。也有朋友说有些网站不适合搞静态化,是有这种情况。但是在这个时期,网站还处于刚发展的起始阶段。初期的网站用户量往往很小,都是以提供咨询为主,典型的web1.0系统,静态化方案是和这个背景紧密相关的。而随着网站的逐步发展又会遇到些什么样的问题呢?这个要看网站发展的实际情况。大体上分为两类:一、就是做资讯的,用户一般是从搜索引擎过来的,没有多少的交互任务;二、以做SNS或者论坛这类互动性高的产品的(用论坛提供下载或者文字阅读的不在此例)。
一、提供内容为主的系统
对于第一种提供内容的网站而言,会出现两种情况。一种是数据容量过大,由于早期设计失误,造成数据库访问速度很慢;第二种是访问人数过多,造成IIS响应不过来,反映在访问速度慢或者干脆报Service Unavailable错误。或者两种情况都发生了。
对于数据访问慢的情况,需要对数据库进行优化。包括优化查询语句,优化数据库结构,索引优化。而对于单表数据好几千万条的优化则需要进行分表。在SQL2005以前版本中并没有,没有使用内置的表分区功能,需要自己实现。策略一般是按照时间,把数据放到不同的表中。然后再使用视图功能把表查询聚合到一起。这种方式和SQL2005带的表分区相比有很大不同,效率远比SQL2005带的要低。为什么呢?比如SQL2000,建立两张相同结构的表,储存数据。表一和表二都是500万数据。查询时,先从表1筛选到数据,再从表二筛选到数据,然后合并,再按条件排序,还是单线程的,这能不慢吗?而SQL2005是可以把索引放到不同的分区,多线程地去操作,由于是在进程内完成数据的筛选排序,速度还是很快。当然,前提是服务器有很多个核。(SQL2005表分区只在服务器版中可以使用。)
对于IIS响应慢或者Service Unavailable的情况,有可能是带宽太小,也可能是连接数太多了。我记得有人做过测试,IIS的TCP连接数最大大概是8000的样子,Unix下的Apache(还是httpd忘记了。)最大连接数一万多。好像说是操作系统TCP/IP堆栈的限制,我对这方面不太懂。如果超过这个量或者是其它类似的原因造成了web服务不稳定,那么就该加服务器了。
二、互动性高的系统
互动性高的系统容易遇到的问题是数据库高并发。数据库的很多操作是有锁的,锁保存在系统表里,如果系统的吞吐量也满足不了需要,那么锁就会出现问题了。你可以认为,数据库一次至多只能有100个连接(在SQL2005服务器版本上测试)。如果超出了,那么,第101个就会超时。假如有一条语句操作时间很长,也操作频繁,那么应该很容易就引起数据库超时的错误。
这种系统,如果数据库本身已经满足不了了,可以用拦截器来解决。用拦截器也需要考虑怎么设计方案。假设现在每秒钟有100条数据库操作命令,而这100条命令各不相同,并且数据库1秒钟刚好能处理这100条命令。那现在每秒钟有101条命令,并且命令还是各不相同,每秒中与每秒钟产生的命令也是不相同的,那么做拦截器也是毫无用处的。最多只能有一个缓解作用。因为每秒钟都会增加一条无法处理的命令。
图2.1
幸运的是,在处理的语句中有很多是重复的。比如,现在拦截器如图2.1一样工作,在1秒钟内,拦截了101条命令,归并出有20条语句都是查询的同样的内容(一般是列表页),最后整理出实际需要操作40条命令,然后执行命令,拿到数据库后分发给这101个请求。也就是说101个工作被压缩成了40个工作。
还可以对某些不常变动的数据进行缓存。比如文章的分类,用户的名字(这个要看注册用户增长的情况)。图2.1的模型改成图2.2的情况。
图2.2
当然缓存块也可以加在Web应用的部分。主要用来保存一段时间内不更新的数据,当然,这个缓存是有过期策略的。
对于SQL查询的优化,缓存也能帮到一定的忙。比如,有个联合查询,查询的是文章分类表和文章表。完全可以只查文章表,而文章表中只有分类ID,显示的时候怎么办?在内存中,缓存了一个分类字典,键就是分类ID,值就是分类名称。显示的时候,直接用文章内分类ID在字典中找。这样就提高了SQL语句的效率。
而出现大表的情况,还是参考本文的第一部分解决。
现在,本文还有一个问题没解决呢,那是第一部分遗留的。要增加服务器,那怎么部署呢?
(四)
(三)说到该增加服务器了,那要增加多少服务器,增加了服务器网站怎么部署呢?最简单的办法当然是拆分应用。
一、分离应用
图1
如图1所示,把应用拆分开来,根据压力放置到不同的服务器上,数据库也同样如此。访问的时候,设置不同的子域名来访问。图片应该被独立出来。
通过这种方式,用户访问的时候将会分流到不同的服务器上。这样的好处是显而易见的,网站能承受的压力的显著增强了。缺点是不得不对程序进行重新开发。
二、多个副本
图2
如图2所示,使用负载均衡,把压力分担到不同的服务器上。这种方式不需要对程序进行改造。由于压力还不是十分巨大,直接用windows自带的负载均衡就能显示目的了。
至于某些局部问题,那可以用缓存的方式来解决。而数据库对压力的处理则可以分为3种方式。
1.分库分表
原理和网站的分离应用差不多,把各个应用相关的部分拆分开来,放到不同的数据库服务器。
2.分布式计算
把数据库挂接起来,应用也是要拆分的,但是访问的时候只需要访问主数据库,其它数据库就成了黑箱,不需要了解其它数据库的细节。
3.分发
原理上和网站的多个副本同样的原理,把数据也分发成多个副本,分别对不同的副本进行访问。这样的缺点是数据会不同步,需要等一段时间才能实现数据库服务器数据间的同步。
访问量再加大,就需要购买专业的设备,或者开发的复杂的应用来解决问题了。比如bigtable,mapreduce,f5等等。没接触过那些东西,就不再讲下去了。这系列文章是对这几年工作的一个总结,同时希望能对你有所帮助。要是有更好的方法,还希望能赐教,呵呵。
(五)
本节与前四部分文章内容关联不大,将主要讨论网站在压力下演变过程中的一般性。
作为一个网站管理员来说,但网站遇到性能瓶颈,那就会思考,为什么网站遇到的性能问题,有什么样的解决思路。在前四篇中,我们讲到了一些办法,讲得最多的是拆分应用或者叫做垂直划分。那为什么会产生垂直划分这种思路?
来思考下以下的几种场景:
1、任何一台服务器安装Windows操作系统,并没有出现性能瓶颈;
2、全世界有那么多的小网站,如果把它们当作一个整体,那么他们并没有遇到性能瓶颈。
这就表明,性能瓶颈的出现是因为把用户往有限的服务器上集中而产生的。而作为一个网站,一般来说,为了方便我们的用户或者说是打造一个良好的品牌,一般来说只是有一个或者几个域名。那么问题就产生了。如果把大量的用户当作是一条河流,但网站初期的时候,这条河流是干枯的。随着网站的发展,河流里的水位越来越高,而我们的网站实际上起到了一个水闸的作用。但一个水闸不能满足的时候,我们用多个水闸来进行分流,像是98年特大洪水的时候在某些地方进行泄洪。这种应用就是垂直分割。而上面描述的第二中场景可以看成是有N个水闸的情况。但水流量过大,水闸越少,那么压力就越大。
实际上我认为,网站其本身是因为internet的产生而产生的,那其局限性也是由internet的解决方案引起的。假设,我们的一个域名可以绑定到N台服务器上,就不会产生web服务器性能上不能满足的情况。也就是说域名指向的那台服务器就是水闸,水闸能通过的水是有限的。要让水闸能通过尽可能多的水,有一些办法,在其他地方也开水闸,或者扩大这个水闸,或者加快水的流速。
在其他地方加水闸,就是垂直分割,把用户浏览导入到不同的子域名上,而子域名是可以绑定到不同的服务器上的。扩大水闸就是要在硬件上买更好的服务器,服务器就能有更好的性能。加快水的流速就是要让用户连接的时间尽可能短,这个不但是在web上,在网络游戏上也是如此。
实际上目前为止最为终极的解决方案还是让用户连接的时间尽可能短。为什么这么说呢?在理论上,一个网站可以划分为任意个子应用,但是不方便管理。比如你划分了5个应用,而5个应用中某个应用又产生了性能问题,怎么办?
在网络游戏服务端中(曾经作私服,见过传奇的服务端),连接、登录游戏等应用是分开的。用户在使用时并没有感觉,那就像是你把网站的数据库服务器和web服务器分离,并不会让用户察觉道理是一样的。在我们普遍开发中使用缓存等方式,提高用户操作的响应速度,但是用户并没有离开服务器。比如把www.a.com这样的域名,指向到111.111.111.111这样的IP地址(假定为服务器A),虽然这个地址的服务器在局域网内使用了一些办法让用户响应速度更快,但是用户并没有离开这台服务器。而现在像集群这样的方式,是通过4底层TCP/IP协议让其到达A服务器的请求重新执向到B服务器,然后B服务器收到的数据直接回发给client。这样,A服务器实际上的工作量就很小了,从而实现了网站的高负载,而实际上这些负载已经被分发掉了。
要出去和朋友吃饭,就先到这里了....