这篇文章是关于网站性能优化体验的,性能优化是一个复杂的话题,牵涉的东西很是多,我只是按照个人理解列出了性能优化整个过程当中须要考虑的种种因素。点到为止,包含的内容以浅显的介绍为主,若是你有看法能告知我那再好不过了。不管如何,但愿阅读它的你有所收获。html
我眼中的网站性能问题都反映了一个网站的“Availability”(中文叫作可用性,可是这个翻译也不足够达意),以往个人认识是,这个网站若是所有或者部分不可用,那是功能问题,可是若是响应慢、负载差,这才是性能问题;但是后来我逐渐意识到,性能问题涵盖的范围更广,我还无法给出一个准肯定义,可是许多非业务逻辑错误引发的网站问题均可能能够算作性能问题,好比可扩展性差,好比单点故障问题。前端
在网站性能优化的最初阶段,也就是所谓的“第一重境界”,作局部的定位、分析和修正,考虑的仅仅是“优化”,这也是初涉性能优化问题的大多数人的认识。在问题发生之后,发现它和业务逻辑没有太大关系,就开始尝试寻找问题产生的缘由并加以解决。java
不管是网站无响应仍是响应缓慢,仍是响应曲线异常波动,好比,能够围绕CPU的使用问本身这样几个问题:程序员
在这些问题中,状况虽然变幻无穷,简单地说,CPU的使用是核心,CPU使用率高,说明系统资源被充分利用,可能系统在实实在在地作事,反之,须要寻找其余瓶颈。经过结合进程、线程的快照,来初步肯定问题的范围。CPU使用率低的状况居多并且容易定位,只须要寻找其余的系统瓶颈;CPU占用率偏高的问题每每比较不容易定位,虽然也有一些办法。关于具体性能问题的定位技术,这里不着过多笔墨,后续有机会详细介绍。数据库
对于一个刚开始作性能优化的网站系统,下面的事情不妨都作一作,会有立竿见影的效果:apache
若是你须要系统的指导,不妨参考这张图(点此下载大图和mmap文件:Site_Performance_Practice_Road_Map):浏览器
从使用的工具上说,性能问题的定位很大程度上是面向操做系统、虚拟机系统的问题定位。从问题定位的时机上说,又能够分为:缓存
了解到这里,再给出这样几个常见问题定位的场景:安全
第一类:请求无响应,浏览器始终处于等待状态。性能优化
定位方法:kill -3或者jstack先分析线程堆栈,找到当前block的线程。
常见于:外部接口调用无返回或者网络IO阻塞无响应;死锁;死循环;……。
第二类:宕机,进程挂掉。
定位方法(这一类问题广泛比较难定位):
(1)寻找hs_err_pidxxx.log这样的JVM日志
(2)使用JVM参数在JVM crash时写入到dump文件中
(3)catalina.out中寻找最后的日志
(4)宕机前环境数据采集
常见于:JDK bug(数次遇到过JIT引发的这一类问题);调用dll的问题;……
第三类:请求响应时间长。
定位方法:kill -3或者jstack先分析线程堆栈,看线程大都停留在什么操做上面,再细化分析。
常见于: 内存不足,可见到连续的Full GC;网络拥塞;LoadRunner等压力客户端瓶颈;数据库瓶颈,可进一步分析DB快照;……
第四类:TPS低;TPS逐渐下降;TPS振荡幅度过大。
定位方法(这一类问题最多见,定位的方法也最复杂):
首先观察在压力增大时,CPU使用率可否上去,若是不能上去,寻找其余瓶颈:网络/内存/磁盘/……;CPU
使用率上去了,观察在无压力时,是否有背景CPU使用(例若有后台定时任务线程消耗了大量CPU资源),若是没有,那能够尝试JProfiler等工具结合线程分析、业务分析,寻找热点。
常见于:其余业务线程干扰;内存泄露;链接句柄用完;缓存命中率低下……
好,暂时说到这里,下面来看第二重境界。达到这重境界意味着已经可以跳出“过后优化”的局限了,在设计和编码的过程中,可以正式和全面地考虑性能的因素,好比:
对于不成熟的团队,建议能安排有经验的程序员把关设计文档和编码中的性能问题,把常见的问题列出来参考学习。
达到第二重境界还有一个明显的特征,就是在软件流程的前中期就开始作性能目标的论证和性能问题的验证:
最后是第三重境界。达到这重境界的团队可以在早期规划构想阶段就将性能做为一个必备因素包含在内,这可不是随口说说的经验的估计,而是要有数据驱动的理论设计,好比作性能建模,根据市场大小、业务量、服务等级等等计算出性能的具体指标,而且在此要求下作合理的架构设计。
这里涉及的东西有不少,除了数据,还须要有大量的思考,对于一个网站来讲,不妨问问以下的问题:
全部的性能问题和其余一切非功能性问题同样,都是必定程度上的trade off,因此越优秀的设计者越须要思考,来规划这些问题的解决方案,在规划中由于性能问题而涉及到的因素有哪些,太多太多了。
而要解决这样在规划中就预料到的性能问题,也有许多内容值得讨论,下面列出一些供参考:
要达到第三重境界还要可以预测性能问题。这就须要成熟的监控体系,监控系统的变化,尽快作出反应。
好比国内发生了重大事件,用户量陡增,监控系统可以及时识别出用户量监控曲线一个很是明显的跳跃过程(好比持续事件超过某个值,且曲线斜率超过某个值),发出告警,而且自动扩容来应付潜在的风险。这些,都是创建在常规的业务运营数据收集基础之上的,而后须要作数据挖掘,给出关键点。
再好比互联网应用“缓存为王”。对于缓存的设计,甚至很大程度上决定了应用的成败(若是你颇有钱,靠大量的CDN这种很是规路线的另说,呵呵)。缓存的设计须要考虑到缓存的大小、分级、队列、命中率计算、生命周期、更新换页、数据分发、数据一致性和数据持久化等等问题,这些东西每每被不少只重视那些页面展现效果和功能的人所忽视,但若是你是优秀的设计者,你须要积累这些思考。
Think big。有这样一个真实的例子,咱们曾经发现页面模板的OGNL性能不高(两次反射之故),遂在项目中把大部分OGNL表达式都改为了EL表达式,花了不少时间精力,性能也确实提升了,可是能提升多少呢?大概只有30%,这是一种细水长流的改进,对系统的破坏性不大,可是收效也不足以使人沾沾自喜,还失去了一些OGNL的灵活性。以后,咱们换了一个思路,从大局入手,给页面划分区域,定制缓存框架,引入页面缓存能力,虽然整套方案有些复杂,可是这种架构上的进化,因为页面的生成或者部分生成直接命中了缓存文件,性能一下有了飞跃,提升了600%~800%。这就是Think big,从大处着想,见获得工程大块的结构,须要足够的视野、足够的经验和积累,能够带来显著的效果。
一般系统容量的设计都会要求到峰值容量以上,若是是像秒杀、抢购之类对性能要求很是高的系统,每每还存在一个问题:设计了这么大的容量,平时大部分时间业务量都比较小,这些资源浪费怎么办?(题外话:这大概也是Amazon涉足云存储和云计算的初始原因吧)
咱们来看这样一个在性能驱动下架构变迁发展的例子:
初期,只有简单的应用服务器和DB服务器分家,使用简单的Jetty容器,系统的瓶颈在DB侧。简单就是美,网站刚刚运营,能访问就是王道:
系统在发展中不断地演化。
有一天发现用户压力愈来愈大,终于没法承受了,系统屡屡到达崩溃的边缘,在现有硬件和架构条件下很难支撑现有的业务,作出了这样的改变:
在此次改变中,作了这几件重要的事情:
网站继续安安静静地发展,悄悄地演化。
终于有一天,用户访问量激增,百万级的PV达到了,WEB2.0业务也增长进来,缓存的命中率愈来愈低,CPU成为了瓶颈,访问异常缓慢。这一次,又要动刀了:
这一次的架构重构作了这么几件重要的事情:
继续、继续……
访问量增加了几十倍,集群的服务器也第一次达到了三位数,系统不稳定,速度从新落下,问题定位也无比困难,一切又开始扑朔迷离起来。
这一次,不可避免地又作了架构上的调整,首要的目标,是以隔离解耦的方式增长系统稳定性,同时,更便于产品化管理:
最后要说的是,如你所见,性能因素是一个网站系统发展的其中一个重要推进力,再细致的思考也难以兼容那么多未知的场景,不妨多在扩展性和兼容性上下下功夫,避免网站冷清痛苦,网站大热更痛苦。