本文主要是思惟性的总结,是总结优化的方法学,对方面上面的错误进行总结。不会涉及到前端具体的技术,好比对js和css进行压缩、合并,减小http请求,缓存头控制等等。这些那本《高性能建站指南》都有现成的。php
基于本人在多家公司分别遇到的网站速度与性能问题,多年所积累出的干货;有的开发10年经验,在遇到网站速度问题时,也仍然在犯一样的错误。css
1、背景与思惟方式
html
常见的状况:前端
上面都只是猜想出的可能缘由。几种状况都有可能。上面的办法都是能够做为优化的工做内容来作的。好比把js、css文件压缩,确实是能够提升速度,这是一个常识!java
还能够把数据库优化一下啊;能够安装什么zend加速器,对代码减小编译环节。也能够把数据库的数据作一些磁盘级的缓存起来,减小操做数据库。mysql
诸如此类的优化措施,都是可以提升速度的。nginx
但这些都存在思惟方式错误。在之前呆的好几家公司,遇到速度问题,同事都抱着相似思路来优化的。结果都折腾时间和精力,仍是没解决好。web
我发现,身边一些同事的思惟方式是这样子的:sql
我习惯不能靠猜、要以收集的数据为依据(实时记录下来的性能数据),好比作脚本统计每次执行耗时,收集必定量的数据,就知道最耗时间的地方在哪里了,不是看表象认为哪里慢就哪里慢。如今,即使我大致判断性能瓶颈在哪里,我也不会说,我但愿用数据来支持
数据库
我把上面的叫作纯技术思路,纯技术思惟来看待问题。从技术角度,css和js文件压缩、php程序优化、作缓存、数据库优化,都是没有错误的。从技术层面是往好的方面走。
就像解决12306的网上售票问题的时候,不少仅仅是技术思惟来解决。其实某人提出从业务层面调整售票方式,整个性能就会改善,理由是基于:人家现有的窗口售票可以知足平常所需,那自己不是这个系统存在瓶颈。
2、未必与工做年限长有关
从经从来看,我发现,网站速度优化,与多少年开发经验没有直接关联,我之前分别遇到过有10年、20年软件开发经验的同事,在解决速度问题的时候,也是一种纯技术思路。
这是几年前的事了,我亲身经历的一个例子:技术经理是79年的。其实咱们的网站访问速度还不错。而老板看到同行的网站网站怎么快些。(人家才多少个技术,咱们这么多。应该要达到)。
技术经理把一些方法都尝试了:研究同行的no-cache头,唉,他们的怎么有,而咱们的没有。好,咱们也要像他们那样作。咱们还把代码片断给缓存起来,花了很多时间。惋惜,结果速度没有明显提升。有,也只是根据感受:“哦,我刚才加了缓存控制后,发现服务器的负载低了点。可是怎么又变高了呢。”。“我已经开启了压缩,怎么没明显改善呢?”,其实,加服务器缓存控制,代码判断缓存。确定是有效果的。但能提升多少?或者说目前这个不算瓶颈。就算你把其余的优化得再好。也没提升总体。没找到瓶颈所在,结果各自方法都试过了。仍是没用。白忙活。若是一开始可以分析出瓶颈。着力点彻底不一样。
那晚技术部经理拉着技术部同事加班,仍是没搞定。只能收工。瞎折腾。
另外,我记得当时在那个公司,后台涉及不少统计方面功能,常常一点卡死,慢得已经不能正常使用。瓶颈就在数据库。php程序方面没多少能够优化的,即使改写程序,也不会发生本质改变,由于瓶颈不在这。
由于不是专业的运维人员,因此,咱们不知道怎么去分析性能瓶颈。只是根据感受,这样作能够提升点性能。先这样作吧。
后面还会说到我在c公司的例子,开发经验20年。
其实,我有个习惯,不迷信权威,10年、20年工做经验,只要你说的对,我都认同,但我不会不假思索被所谓10年、20年的经验标签所影响,结果接受错误的东西。好比是否使用存储过程来封装业务逻辑,在传统银行、金融领域作开发的人员倾向于使用(也许某些技术会被10年开发经验变得不假思索),但在互联网这种思路不见得是对的。
关于存储过程封装业务逻辑,请参考个人文章:http://www.cnblogs.com/wangtao_20/p/3475184.html
关于权威、头衔对人思考的影响,请参考个人文章:http://www.cnblogs.com/wangtao_20/p/3652225.html
3、优化观念的改善
一、主次矛盾思惟-定位性能瓶颈
在解决网站速度问题经历中,我并非什么都去优化。
个人办法是,找哪一个是瓶颈,也就是主要矛盾。若是主要矛盾没解决。对其余小矛盾不管如何作优化,速度都不会发现明显提升。这种思惟方式,也是某次遇到实际问题,同窗跟我说瓶颈在数据库,所以我获得启发。在后续的优化工做中,我首先不会去作什么优化,我会第一找到速度的瓶颈在哪里,这种方式在实践中与同事的进行对比,差别明显:既解决了问题,又减小了本身的瞎折腾。
不少人听我说到找瓶颈法,可能会以为不觉得然,或者无动于衷。个人技术同事也是对我提出的方式,没有明显的感触。这可能与我无法以口头形式完整描述有关。
其实,这些都是我实践出来的干货,其中有见过一些同事失败的尝试,最终才造成了一种规律性的东西。因为经历过的几家公司遇到一样的问题,后来发现不只仅是个例现象,是不少技术同事没有学会正确的方法论,用试一试的心态,偶尔可能试对了,只是偶尔命中。之后遇到复杂点的,还靠试来试去,就没眉目了。
二、瓶颈法,符合"先抗住再优化"的原则
好比侦测定位到数据库是瓶颈所在,那么优先解决数据库问题,这样可以保证抗住.而至于js、css压缩节省带宽等是属于优化部分,后期再作,即使如今作了,速度并不会明显改善.常常看到很多同事作着"多多益善"的无用功,因此我自信个人瓶颈定位法。与现实中的哲学也是很是符合的。如今再次感悟到,作技术的上升到哲学层面来解决问题,是必要的。这里就是主次矛盾法。
这个观点很受用。之前我写过一篇文章,专门对此作了总结:http://www.cnblogs.com/wangtao_20/p/3243009.html
接触的实际项目:电商网站(当时瓶颈在数据库)、外贸网站(当时发现瓶颈在距离远方面,程序优化作的是无用功,可经过带宽来调整)、生活服务网站(发现瓶颈在程序方面)。定位过几回速度问题的瓶颈,找到瓶颈,避免了无效的折腾。
概括为:找网站目前性能的瓶颈在哪里,把瓶颈解决了,其余方面细微的影响速度,也是很小的.若是不去找瓶颈,把细微而非主要的矛盾去解决了,但因为瓶颈没解决,整个速度也不会快.
4、实际操做的几大方面
依据http请求的原理,我通常习惯使用排除法,排除法依次为:网络带宽缘由(包括距离远)、程序执行速度缘由、数据库缘由。这是依据一次http请求原理来定位的。
实际操做的几大方面,我总结以下:
首先得了解一次http处理请求与响应的过程,不了解这种理论只能是瞎猜,猜b缘由,猜c缘由,而后用a试一试,无效(碰到运气了恰好有效),再用b试一试。
根据http协议,任何一次http请求它的处理过程以下:
一、 浏览器向服务器发出请求。此时浏览器通常左下角会显示:正在请求...
二、服务器接到请求后调用应用程序(php,java等,根据后缀名肯定)执行。服务器接到请求后会立刻返回一个头信息给浏览器,此时通常浏览器左下角会显示:已经链接到服务器(服务器接到请求)
ps:若是速度很快,浏览器左下角这些信息是一闪而过的。若是网络出现延迟,这些信息会一直显示在左下角位置。
三、php,java等代码执行完毕
四、代码执行完毕后,服务器会发一个http头响应浏览器(也就是告诉浏览器你开始接收数据了,准备好吧)。
此阶段浏览器在没有接到这个头信息以前,左下角会显示:正在等待服务器响应...
五、浏览器接到服务器发给响应头,开始接收了数据,浏览器处于接收数据状态,
咱们会看到浏览器左下角会显示:正在传输数据....。也就是这个状态。
六、传输数据结束,完成一次http处理,整个过程http处理结束。
直觉上,根据浏览器左下角显示的状态信息,可以大致预估时间耗费在服务器端仍是带宽层面。这须要了解http请求的过程方面知识。
不过,不是靠猜:感受这个是性能问题,也改善一点点。这样子是多多益善,结果作白费工夫。要找到瓶颈,也就是主要矛盾,问题就容易解决。最好的定位瓶颈方法是用数据来进行侦测,有数据做为支持可以准确的看出瓶颈。具体点就是,放侦测代码,侦测每一个环境耗费的时间多少秒,就能知道瓶颈。
浏览器下方还一直显示"等待响应...",说明服务器那边一直没有给予响应,浏览器一直处于等待服务器给予响应阶段。不涉及到带宽瓶颈(由于尚未到传输数据的阶段,在此以前就已经耗费比较长的时间)。利用这个排除法,把性能定位到服务器端去。因而,进入下一阶段,我要在服务器端写程序来统计程序的执行速度(服务端是php、java、.net均可以本身写代码实现,什么语言就用什么语言来实现)
浏览器概括左下角的状态依次为:正在请求》》已链接到服务器》》等待响应》》服务器已响应》》正在传输数据
我想到几个试验来辅助说明浏览器左下角的状态:
1、 用个php文件(若是你是其余语言也能够照此进行),代码里面循环10万次。看浏览器怎么反应
由于php一直在执行,须要比较长的时间,因此没执行完,web服务器不会发响应头给浏览器。咱们看到浏览器左下角的状态是”等待响应”
二、还记得须要长时间执行的php程序吗。我经常遇到数据库大数据量的时候,一条sql查询了好久,响应出现问题,因此php就一直在等待数据。那么web服务器(apache,nginx)根本没获得php的处理结果(也就是说php脚本耗费时间太多,根本没执行完)。此时在浏览器看到是”正在服务器等待响应"。
一、本身写程序来统计程序执行耗时
服务器端,在php代码层面作一个速度统计:在程序开始执行以前记录一个时间点,结束的时候记录一个时间点。结束时间减去开始时间($end_time-$begin_time),就是php脚本的执行总耗时,这个时间其中包括了查询数据库,等待数据库响应的时间在内。
我在服务器端,对php程序的执行,作了执行耗费时长的统计,动态收集数据。也就不不能靠收集一两次的执行来判断。由于有的时候访问比较多,有的时候服务器状态比较好。网站运行是动态的,通俗的理解:你某个时候发现速度慢到须要5秒,等你去看的时候,速度又不慢了,1秒就打开了。由于速度还能够了,你都没法知道是哪里的缘由。
因此,用数据来收集。收集100次,1000次总能了解哪几个页面速度慢、慢到耗时几秒钟。
方法比较简单:跟什么语言无关,无论是java、.net都差很少。在程序的开始和结束点记录时间,结束时间减去开始时间,就是程序的执行时间。把执行时间写到文本文件里面去。
这个程序须要本身来写的。
php的示范以下:
$begin_time = microtime_float();//执行开始记录时间戳,精确到毫秒 /*中间要执行的代码*/ end_time = microtime_float(); $exec_time = $end_time-$begin_time;//执行时间计算 @save_stat($exec_time);//把执行时间写入到文本文件中 /*下面是定义的两个函数*/ function save_stat($time) { static $call_count=1;//统计调用多少次 $call_limit = 10;//遇到并发问题的时候限制尝试多少次 if(!$time) return ; $exec_stat_file = "./exec_stat_file.txt"; $fp = fopen($exec_stat_file,'ab'); if(flock($fp,LOCK_EX)) { $s = 'access:'.date("Y-m-d H:i:s").',execute time:'.$time.'s,request_url:http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']."||".PHP_EOL; fwrite($fp,$s); flock($fp,LOCK_UN); }else{ usleep(1000); if($call_count<$call_limit) { $call_count++; save_stat($time); } } @fcolse($fp); //var_dump($fp); } function microtime_float() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); }
下面是我上面统计程序收集的数据示范:
经过这种方式。基本上可以判断出,是否是php执行速度慢了。好比在浏览器打开一个网页,我基本上都须要等上5-6秒钟才能彻底看到页面,我要判断是否是程序性能缘由的话,我经过这个数据看出来。程序耗费时间都在2-5秒了,那么web服务器就须要等待这个时间后,才能给浏览器发响应头信息。这涉及到http请求原理,熟悉点这个方面颇有必要,我根据浏览器左下角显示的文字信息来大致判断是否是前端缘由,就是根据http请求过程来的。
二、定位哪一个代码段耗费时长
在php程序方面。究竟是哪一个地方的代码耗费了比较长的时间了,是写得很差吗?不知道某个地方的代码,有专业的工具来定位一段php代码哪些地方各耗时长的。我不清楚java、.net方面的工具,应该都有。php方面的工具我所知道的有两个:一个是开源的xdebug,这个是一个调试php代码的工具。兼带有侦测代码性能统计的功能。另一个是facebook公司的的xhprof,这个是他们公司本身开发的,由于facebook是用php开发的。xhprof如何使用,参考我原创的文章:http://www.cnblogs.com/wangtao_20/p/3320497.html。
这类工具的好处:精确到哪一个函数执行用时多长时间,最耗费时间的代码在某处都能反应出来等等。cpu和内存耗费状况都能记录到的。我用这类工具可以判断程序的执行速度是否为瓶颈所在。
此方法还能够结合http原理来估算:看浏览器左下角的状态显示"正在等待响应..."耗时长,而且结合我放的统计执行时间长短的数据。
若是一直浏览器左下角卡在"正在传输数据....",那就不是服务器缘由了,由于服务器此时已经发送响应给浏览器,浏览器处于接收数据状态。两点可能:传输距离远,或者带宽小。
这里有个知识点:好比php程序(其实java、.net也同样)从开始到结束耗费5秒中。实际上须要查询数据库获取数据,若是数据库压力比较大,程序其实一直在等待数据库给予数据,只有获取数据完毕后,才会接着执行后续代码。
因为上面脚本统计了程序执行耗费了多少时间,这个时间包括了从数据库获取数据的时间在内。
要想定位是数据库层面的,能够经过sql慢日志来记录,记录超过多少秒的sql记录到日志中去。这个在mysql中能够配置。参考:http://www.cnblogs.com/wangtao_20/p/3304645.html
我在实践中发现,服务器级别记录的只能做为参考,由于mysql服务器级别只能记录单条超过多少秒的sql。好比:一次页面会执行5条sql,每条sql都没有超过1秒啊,因此没有一条被记录到慢日志中去。或者一个页面变成是10条sql了
一条 0.1s,10*0.1 就是1秒了。
因此,我想知道a页面执行完毕,数据库层面查询数据到底耗费了多少时间(本质就是sql执行时间),怎么办?我要须要在程序方面作写代码进行统计。就是把每一个页面执行的sql都记录下来,累加,就是a页面数据库层面耗费的时间。
我记得在a公司,遇到常常后台统计的功能,一点击就慢的问题,我当时没什么经验,使劲去优化php程序。想着是否是循环太多了,若是每次循环都须要去查询一次数据库获取数据。那么多少次循环,就须要多少次。这种方式是否是很差,改为一次查询获取全部数据。而后在程序端用php来聚合?
其实当时没有造成如今方法论。因此本身折腾了不少精力,毕竟我当时对后端优化没什么经历。毕业时间短。后来同窗启发了我,不要去优化php程序了,大家的瓶颈在数据库层面。时间耗费在了php一直等待数据库给予数据。
教训:当时的方向应该是往数据库层面去优化。其实我感受,只要定位瓶颈在数据库层面了,解决办法就进入一个新的领域了:数据库优化层面。数据库优化方法比较常规好比表结构调整(分表、大字段拆分)、索引等等方面去。
例子
1、 靠猜想、主观感受。我在C公司的例子
我在c公司遇到两次速度慢的问题。
公司的生活服务网站速度慢了,集中在几个页面慢,不是全部页面都慢。老板反映这个问题,但愿技术解决。网站用户和访问量不多。
此次,由我来解决这个问题。个人思路是要找到速度的瓶颈在哪里。我先不关注要不要作js和css压缩、数据库优化等。
一样仍是在这个公司,第二次遇到网站速度慢的问题。老板开会反映给咱们。一个运营A,他曾经作过程序开发,立刻第一反应说:是带宽缘由,由于咱们网站购买的带宽只有1m。
散会后,其余部门在使用中也再次提到速度慢的问题,这位同事A,也在办公室,跟你们说是带宽小的缘由。
我尽管知道,咱们网站购买的带宽1m,不算大。但因为我没作数据统计,尚未定位到速度慢的瓶颈在哪里,是带宽,仍是程序速度、仍是数据库问题?基于我之前的经验,我都不敢随便去猜想,此时我通常不喜欢直接代表态度是哪里的缘由。我要用数据在支持个人判断。
ps:根据我过去的经验和直接来判断,说是带宽未免太早,由于在此以前呆的两家公司我早就遇到过速度问题,是本身在错误中提高出来的方法。若是瓶颈不在带宽呢?就算把带宽加到4m都不会有改善。我其实也不喜欢这位同事嗷嗷叫,因此内心下决心,我会去私下里侦测一些网站速度的方面的数据来帮助我进行判断缘由。那个时候就能够打他嘴巴的感受。
不过,这次不是我来主导解决速度问题。由于会议期间,技术部有位同事B,他主动跟你们说由他来解决网站速度慢的问题。
B同事拥有将近20年的软件领域从业年限,他对于编码和设计模式方面有很丰富的经验。不过我发现他去解决网站速度的时候,他也没有抓瓶颈,他以为html页面都不够整洁,往html结构调整和js、css压缩方面去下功夫。
虽然不是我负责弄速度这个工做,不过我以为,这位同事也是抱着”看哪些须要优化,就作什么”的思路去改善的,好比html结构确实须要优化,去作这方面优化确定使得网站只会往好的方面发展,不会往更差方面走。
我根据过去的所在公司的教训,我去观察了一下咱们网站慢的的几个页面。仍是会用到找瓶颈法,而后遵循的是“网络速度(http请求耗时)>程序速度>数据库速度”,实际上是”由前端到后端的”逐个排除的思路。
首先、打开网页的时候,确实要五、6秒才彻底打开一个页面。是否是网络带宽缘由?
若是是带宽缘由的话,是带宽不够,或者距离远吗?我注意观察了浏览器左下角,并不会立刻看到”服务器已响应”的文字,左下角状态栏中,耗费时长的状态并非在”正在传输数据….”。发现,耗费时长在于”等待响应…”
其实根据http请求和处理过程,就大致判断,”等待响应..”,服务器其实尚未给予响应。这个只是大致判断,我估算不是带宽缘由。我不但愿靠主管判断,但愿用进一步的数据收集来作出定位。
由于网站不是一两个页面,这个同事B他费了2天时间作这方面优化、因为中途有其余事情。这方面也半停半工的状态。我以为他的方向错误了。
我在服务器端,对php程序的执行,作了执行耗费时长的统计。
下面是我收集的数据。
还有一部分相似的数据我没有贴上。有的耗费时间5秒左右的。
能够看到,php程序执行时长都耗费了好几秒。瓶颈在程序的执行速度上。
经过这一步,能够推翻之前的判断了。
一、瓶颈根本不在带宽1m上,能够排除带宽的缘由了。推翻了以前那个同事主观判断带宽缘由。看来靠猜想,没有数据作支撑来优化是不行的。我看把带宽加到10m,这边程序执行速度也须要好几秒。能改善吗?瓶颈不在带宽。无用功!
二、也不在js和css文件的压缩、html结构优化上,这些不是主要矛盾。优化是能够,但后期去作。
由于,这个程序执行时长包括了操做数据库获取数据的时间(由于要等待嘛)。
那究竟是不是数据库的瓶颈呢?结合数据库压力是否是够大,数据库的数据量多大。
其实
其实使用xhprof这个工具,可以知道那段代码耗费时间比较长了。想弄个图,惋惜图丢了。
记得当时结果是:那段php代码重复调用文件缓存(把数据库数据缓存在文件中了)不少次,xhprof这个工具记录下了这个耗时点。两个页面的,xhprof工具当时统计出耗时5秒多和耗时3秒多的。
2、 b公司,带宽能够改善来提高
由于服务器在国外,距离比较远。公司网站自己不给国内人使用的,根本无法测验(国内访问国外,这么远距离确定慢,很正常,不予理会)。但他们反映的是国外客户访问那个网站也慢。
记得b公司的同事把重点放在各类加速插件上面去,无改善。但是我用脚本统计程序执行时长,发现耗费时间基本上在1s之内,由于这种程序执行速度统计都已经包括了数据库查询的时间在内的了。基于http请求原理和程序执行速度的数据收集,我判断,在数据库优化、php程序性能方面都没有多大的优化空间。根本不是瓶颈所在。
个人方向集中在了:远距离和带宽层面的改善上面。而不是服务器自己性能和程序优化上。好比,由于有n个网站,此网站客户若是是针对英国的,那么租用的服务器最好安放到英国,不要跨到其余国家了。缘由是:
一、 跨国的距离太远。远距离传输损耗快不到哪里去。
二、 国与国之间的网络确定要比本国内各个省份之间的网络繁忙得多。毕竟此通道是一国全部向外数据的通道。好比中国与美国网络通讯,是经过东部海底光缆联系的。意味着整个中国通向美国的数据访问都是通过同一道线路的。
尽管网站的访问量和数据量并不大,但瓶颈仍然定位准确了,从带宽和距离层面入手去解决可以突破瓶颈。
本文完