网站从用户提交请求到服务端响应请求再到数据入库,这期间经过了很多环节。要做到性能优化,首先要排查到性能瓶颈的地方,然后才能对症下药,提高性能。
排查网站性能和排查程序的性能的手段基本相同,检查请求处理各个环节的日志,分析哪个环节响应时间不合理、超过预期,然后检查监控数据,分析影响性能的主要因素是内存、网络、磁盘还是CPU,是代码问题还是架构问题,或者的确是系统资源不足。
定位到问题的原因后,就需要性能优化,根据网站分层架构,可分为web前端优化,应用服务优化,以及存储服务优化3大类。
一、Web前端性能优化
Web前端指网站具体业务逻辑之前的部分,包括页面加载,视图模型,图片加载,CDN服务等,主要的优化手段有优化浏览器访问、使用反向代理、CDN等。
浏览器访问优化
1.减少http请求,http请求时无状态的,每次请求都需要建立通信链路,而服务端对于每个http请求都需要启动独立的线程去处理。这些通信和服务的开销都是很昂贵的,减少http请求,能有效提高访问性能
减少http请求主要手段是合并资源,即合并css,合并图片,合并js脚本,浏览器把一次访问需要的资源合并成一个url。
2.使用浏览器缓存
对于网站而言,css和js脚本,图标等静态资源,变化的频率比较低,而这些文件有又是每次http请求必需的,如果将这些资源缓存起来,可极好的改善性能。通过设置http头中的cache-controll和expires属性,来设置浏览器缓存。
CDN加速
CDN(内容分发网络),本质还是缓存。CDN把数据缓存在离用户最近的地方,使用户以最快速度获取数据。
CDN部署在网络运营商的机房,这些运营商有是终端用户的网络服务提供商,因此用户请求路由的第一跳就到达了CDN服务器,当CDN存在浏览器请求的内容,就直接返回,最短路径返回响应,加快用户访问速度,减少数据中心负载压力。
CDN一般缓存都是css,js图片,文件,静态页面等资源,但是这些资源访问频度很高,将其缓存在CDN中可极大改善网页的打开速度。
反向代理
讲道理,对正反向代理概念一直不是很清楚,直到我看了这个图
反向代理服务器可以通过缓存功能加速web请求,还能实现负载均衡功能,比如大名鼎鼎的nginx。
二、应用服务器性能优化
应用服务器就是网站业务处理的服务器,网站的业务代码都部署在这里,是网站开发最复杂,变化最多的地方。优化主要手段有缓存、集群、异步。
1.分布式缓存
网站性能优化第一定律:优先考虑使用缓存优化性能。
在整个网站应用中,缓存几乎无处不在,既存在于浏览器,也存在于应用服务器和数据库服务器,即可以对数据缓存,也可以对文件缓存,还可以对页面片段进行缓存,合理使用缓存,对网站性能优化意义重大。
数据缓存主要存放那些读写比高、很少变化的数据,如商品的条目信息,热门词的搜索列表,热门商品信息等。应用程序读取数据时,先从缓存中去读取,如果读取不到或数据已经失效,再去数据库中去读,同时将数据写入缓存。
网站数据访问通常遵循二八定律,即80%的访问落在20%的数据上,因次利用内存的高速访问特性,将这20%的数据缓存起来,可很好的改善系统性能,提高数据读取速度,降低存储系统压力。
缓存好处很多,但要合理使用。不合理使用缓存不但不能提高系统性能,还会成为系统的累赘,甚至是风险。哪些是不合理的使用缓存呢?
频繁修改的数据
如果缓存中的数据是需要频繁修改的数据,就会出现数据写入缓存后,应用还来不及读取缓存,数据就已经失效,缓存就没有意义,只会增加系统负担。一般来说,放入缓存中的数据,至少读取两次,缓存才有意义。
数据不一致性
一般会对缓存的数据设置失效时间,一旦超过失效时间,就会从数据库中重新加载。因此,应用也要容忍一定时间的数据不一致性。
缓存可用性
缓存是提高数据读取性能的,缓存数据丢失或者缓存不可用不会影响到应用程序的处理-它可以从数据库直接获取数据。但随着业务的发展,缓存会承担大部分数据访问的压力,缓存服务器有一定概率发生宕机,不能因为缓存服务器宕机,然后把压力全部传给数据库服务器,导致数据库服务器也宕机。
通过分布式缓存服务器集群,将缓存服务分布到多台服务器上,一台出现故障,不影响整个集群,不会对应用产生影响,一定程度上提高缓存服务的高可用。
缓存穿透
如果因为不恰当的业务、或者恶意攻击持续高并发第请求某个不存在的数据,由于缓存中没有保存该数据,所有的请求都会落到数据库上,会给数据库服务器造成很大的压力,甚至崩溃。一个很简单的策略是,把不存在的数据也缓存起来(其value为null)。
2.异步操作
使用消息队列将调用异步化,可改善网站的扩展性。事实上,还可以改善网站的性能。
在不使用消息队列的情况下,用户的请求数据直接写入数据库。在高并发的情况下,会对数据库造成巨大的压力,同时也使得响应延迟加剧。在使用消息队列后,用户请求的数据发送给消息队列后立即返回,再由消息队列的消费者进程从消息队列中获取数据,异步写入数据库。由于消息队列服务器处理速度要比数据库服务器快,因此用户的响应延迟可有效得到缓解。
消息队列具有很好的削峰作用--即通过异步处理,将短时间高并发产生的事务消息存储在消息队列中,从而削平高峰的并发事务。电子商务网站在促销活动中,合理使用消息队列,可有效抵御促销活动开始大量涌入的订单对系统造成的冲击。
需要注意的是,由于数据写入消息队列后立即返回给用户,数据在后续的业务校验、写数据库等操作可能失败,因此在使用消息队列进行业务异步处理后,需要适当修改业务流程进行配合,如订单提交后,订单数据写入消息队列,不能立即返回用户订单提交成功,需要在消息队列的订单消费者进程真正处理完该订单,甚至商品出库后,再通过电子邮件或短信告知用户订单成功,以免交易纠纷。
3.使用集群
在网站高并发访问的场景下,使用负载均衡技术为一个应用搭建一个有多台服务器组成的服务器集群,将并发访问请求分发到多台服务器上处理,避免单一服务器负载压力过大而响应缓慢。
4.代码优化
网站的业务逻辑实现代码主要部署在用于应用服务器上,合理优化业务代码,可以很好地改善网络性能。
多线程编程
这是一个老生常谈的话题了,这里不多赘述。多线程变成需要注意的问题是线程安全问题,解决该问题的手段主要有以下几点:
把对象设计为无状态对象,使用局部对象,并发访问资源时使用锁(会对系统性能产生严重影响)
资源复用
系统运行时,要尽量减少那些开销很大的系统资源创建和销毁,比如数据库连接,文件读写,网络通信连接、线程、复杂对象等。从编程角度讲,资源复用主要有两种模式:单例和资源池。
垃圾回收
以JVM为例,其内存主要可分为堆和栈,栈主要用于存储线程上下文信息,,如方法参数、局部变量等。堆则主要是对象的存储空间,对象的创建和销毁、垃圾回收就在这里进行,发现大部分对象的生命周期都极其短暂,这部分对象产生的垃圾应该被更快地收集,以释放内存。
小结:
网站性能优化对最终用户而言是一种主观感受,性能优化的终极目的就是改善用户的体验,使他们感觉访问网站很快。离开这个目的,追求技术上的高性能,都是舍本逐末,没有多大意义。
即使在技术层面,性能优化也需要全面考虑,综合权衡:性能提升一倍,但服务器数量也要增加一倍;或者响应时间缩短,同时数据一致性下降,这样的优化是否可以接受?这类问题的答案不是技术团队能回答的。归根结底,技术是为业务服务的,技术选型和架构决策依赖业务规划乃至企业战略规划,离开业务发展的支撑和驱动,技术走不远,甚至还会迷路。