网站性能优化是在网站遇到问题时的解决方案。网站性能问题大多是因为用户高并发访问时引起的,所以网站性能优化的主要工作就是改善用户高并发访问时的响应速度。
web 前端性能优化
减少 HTTP 请求
因为 HTTP 每次的请求的代价都是很昂贵的,所以减少 HTTP 请求的数目可以有效的提高访问性能。
减少 HTTP 请求次数的手段主要是合并 CSS、合并 JavaScript、合并图片。将页面需要的 JavaScript、CSS 合并成一个文件,这样浏览器只需要一次请求即可。
使用浏览器缓存
对于一个网站而言,CSS、JavaScript、Logo、图片这些静态资源文件的更新频率比较低,而这些文件又几乎是每个页面都需要用到的。将这些文件缓存到浏览器中可以很好的改善网站性能。
通过设置 HTTP 响应头中的 Cache-Control 和 Expires 数据可以设定浏览器是否开启缓存,及缓存时间。
如果某些静态文件按需要及时更新,可以通过改变文件名实现。
使用压缩
文本文件的压缩效率可以达到 80% 以上,在服务器对 HTML、CSS、JavaScript 文件使用 GZip 压缩,然后在浏览器中解压,可以有效的减少通信传输的数据量。
但是压缩是很耗费 CPU 资源的,对服务器会产生一定的压力。如果服务器压力大,而带宽足够的情况下建议最好不要启用压缩。优化第一步要做的就是找到性能瓶颈,不然很容易负优化。
CSS 放置在页面最上面,JavaScript 放在网页最下面
浏览器会在下载完所有需要用到的 CSS 之后才会对整个页面进行渲染,因此最后的做法是将 CSS 放在页面最上面,让浏览器尽快下载 CSS。而 JavaScript 刚好相反,浏览器在加载 JavaScript 后会立即执行,有可能会阻塞,造成页面显示缓慢,因此 JavaScript 最好放在页面最下边。
但是,如果页面解析是就需要 JavaScript,那就不适用此条优化建议
减少 Cookie 和 Token 承载的数据量
Cookie 包含在每次请求和响应中,太大的 Cookie 会严重影响数据传输,因此写入数据到 Cookie 时要考虑这个数据是不是必须的。尽量要减少 Cookie 承载的数据量。
现在网站使用 restful 风格,使用 Token 作为用户凭证。如果网站的大部分接口都需要使用 token,那么也需要减少 Token 承载内容。还有 Token 的 payload 部分是没有加密的,只是用了 base64 做了编码,放太多内容可能会导致用户信息泄露。
使用 CDN 加速
CDN 的本质就是一个缓存,让用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度。CDN 能够缓存一些静态文件,如图片、文件、CSS、Script 脚本、静态网页等。
使用 Nginx
使用 Nginx 做静态服务器,反向代理、负载均衡。
后端服务器优化
应用服务器是网开发最复炸,变化最多的地方,优化的手段主要有缓存、集群、异步。
使用缓存
当网站遇到瓶颈的时候,首先想到的应该就是能不能使用缓存优化。在整个网站应用中缓存无处不在,浏览器、服务器、数据库都有使用缓存优化性能。合理的使用缓存对网站性能优化意义重大。
使用缓存为什么可以优化网站性能?
- 缓存是存储在可以高速访问的介质中的,如内存,cpu 的一级二级缓存,所以使用缓存可以提高获取数据的速度。
- 我们可以缓存一些经过复杂计算才能得到的结果。减少计算量,这就是常说的空间换时间。
使用缓存可以提高系统性能,但是不合理的使用缓存非但不能提供系统性能还会成为系统的累赘,甚至风险。在开发中如何合理使用缓存?
- 不缓存频繁修改的数据。如果缓存的事平凡修改的数据,会出现数据写入缓存后,还没有读取就失效了,用了缓存跟没用一样反而还增添了系统负担。
- 不缓存没有热点数据。因为内存有限,不可能将所有数据都缓缓存,我们需要尽可能缓存可能被大量访问的部分。
- 不缓存一致性强的的数据。有的缓存的数据超过的失效时间才会从数据库从新加载,因此要容忍一定时间的数据不一致。
缓存的一些概念解释
- 缓存雪崩:缓存服务器崩溃,或者大量缓存失效导致的请求全落在数据库上导致书库宕机。
- 缓存穿透:因为业务逻辑问题或则恶意攻击持续高并发的请求不存在的数据,所有的请求落在数据苦。
- 缓存预热:新启动的缓存没有任何数据,在建立缓存过程中,系统的新能和负载都不太好。最好的做法是启时先把热点数据加载到缓存。
异步
使用消息队列的异步可以改善服务器性能。
比如,用户请求验证码,我们把用户请求发送给消息队列后立即返回,再由消息队列的消费者从队列获取消息,异步发送验证码。所以使用异步可以有效的提高接口响应速度。
消息队列还具有很好的削峰作用,将短时间高并发产生的消息存储到消息队列中,然后在一一处理。比如在促销开始时涌入的大量订单,如果不适用消息队列可能超出服务器负荷,对服务器造成冲击。
使用集群
使用负载均衡为一个应用构建一个有多台服务器组成的服务器集群讲并发访问请求分发到多台服务器上处理。避免单一服务器因为负载压力过大响应过慢。
代码优化
多线程
从资源利用的角度来看,使用多线程主要的原因有两个, IO 阻塞与多 CPU。
线程 IO 阻塞会释放 CPU 资源,这时候 CPU 可以调度其他线程。
另一个原因是现在的处理器都是多核想要最大限度的使用这些CPU必须使用多线程。
使用多线程需要注意线程安全问题,既多线程并发对共享资源进行修改,导致数据不一致。线程安全产生的 bug 难以测试和重现。
编程上解决线程安全的主要手段有几点
- 将对象设计成无状态对象。就是对象本身不存储状态信息,这样多线程并发访问时就不会出现状态不一致,Java Servlet 对象就设计成了无状态对象。
- 使用局部变量:因为在 Java 中局部变量是存储在栈中的,栈是线程独享的。
- 使用锁:并发访问时使用锁,通过锁将并发访问转换为顺序操作,从而避免资源被并发修改。
资源复用
系统运行时要尽量开销很大的系统资源创建和销毁。比如说数据库连接、网络通信连接、线程和复杂对象。
资源复用主要有两种方式
- 单例,因为目前 web 开发主要使用贫血模式,从 Service 到 DAO 都是无状态对象,无需重复创建,使用单例模式也是自然而然的,事实上如果不特别配置的话 Spring 构造的对象都是单例的。
- 对象池,对象池通过复用实例对象,减少对象的创建和资源消耗。比如数据库连接对象,如果每次使用都创建一个新的,大量的时间耗费在创建和关闭连接上。使用连接池的方式,连接对象统一存储在对象池中,需要连接是就从连接池中获取一个空闲连接,使用完毕归还即可,不需要重复的创建销毁。
存储性能优化
一句话花钱上固态。