Fork me on GitHub

性能调优方法和原则

        性能优化基本是BAT等一线互联网公司程序员必备的技能,以下的性能优化有:Web网站调优、数据库、JVM调优、架构调优等。

Web网站调优

1、尽可能减少HTTP请求: 图片合并(css sprites),Js脚本文件合并、css文件合并。
2、减少DNS查询
3、将css放在页面最上面,将js放在页面最下面。
4、压缩js和css: 减少文件体积,去除不必要的空白符、格式符、注释(即对代码进行格式化)
5、把js和css提取出来放在外部文件中: 这一条要灵活运用,把jscss提取出来放在外部文件的优点是:减少HTML体积,提高了jscss的复用性,提高日后的可维护性。
缺点:增加了HTTP请求,不过这一点可以通过缓存来解决。
什么情况下将jscss写在页面内呢,可以分为几种情况:jscss代码比较少;这个页面不怎么会访问。
6、避免重定向: 重定向就是用户请求的页面被转移到了别的地方,浏览器向服务请求一个页面,服务器告诉浏览器请求的页面已经被转移到另一个页面,并告知另一个页面地址,浏览器就再发送请求到重定向的地址。这样会增加服务器和浏览器之间的往返次数,影响网站性能。
重定向的状态码有:301永久重定向;302临时重定向;304not modified并不是真的重定向,它是用来告诉浏览器get请求的文件在缓存中,避免重新下载。
7、移除重复脚本
8、使用Ajax缓存:Ajax的getpost方法:只要是浏览器的get请求,浏览器都会使用缓存,对于同一地址的请求,服务器会发送304状态码到浏览器,浏览器就会使用缓存中的数据。
post的请求每次都会被执行,浏览器不会缓存。
9、使用Gzip压缩
10、使用CDN(内容分发网络)

数据库调优

数据库的调优,总的来说分为以下三部分:
1、SQL调优:主要集中在索引、减少跨表与大数据join查询等。
2、数据库端架构设计优化:通过读写分离调整对数据库的写操作,通过垂直拆分以及水平拆分(分库分表)来解决数据库端连接池瓶颈等问题。
3、连接池调优:可以通过熟悉连接池的原理,以及具体的连接池监控数据,来不断调试出最终的连接池参数。

通过缓存减少后端压力

目前分布式缓存已经比较成熟,常见的有redismemcached以及开源的淘宝分布式tair等。

选型考虑

        如果数据量小,并且不会频繁地增长又清空(这会导致频繁地垃圾回收),那么可以选择本地缓存。具体的话,如果需要一些策略的支持(比如缓存满的逐出策略),可以考虑Ehcache;如果不需要,可以考虑HashMap;如果需要考虑多线程并发的场景,可以考虑ConcurentHashMap

缓存是否会满,缓存满了怎么办?

        对于一个缓存服务,理论上来说,随着缓存数据的日益增多,在容量有限的情况下,缓存肯定有一天会满的。如何应对?

  • 给缓存服务,选择合适的缓存逐出算法,比如最常见的LRU。
  • 针对当前设置的容量,设置适当的警戒值,比如10G的缓存,当缓存数据达到8G的时候,就开始发出报警,提前排查问题或者扩容。
  • 给一些没有必要长期保存的key,尽量设置过期时间。

数据请求改造为异步

使用场景

        用户并不关心或者用户不需要立即拿到这些事情的处理结果,这种情况就比较适合用异步的方式处理,这里的原则就是能异步就异步。

常见做法

        一是额外开辟线程,这里可以采用额外开辟一个线程或者使用线程池的做法,在IO线程(处理请求响应)之外的线程来处理相应的任务,在IO线程中让response先返回。如果异步线程处理的任务设计的数据量非常巨大,那么可以引入阻塞队列BlockingQueue作进一步的优化。具体做法是让一批异步线程不断地往阻塞队列里仍数据,然后额外起一个处理线程。循环批量从队列里拿预设大小的一批数据,来进行批处理(比如发一个批量的远程服务请求),这样进一步提高了性能。
        二是使用消息队列(MQ)中间件服务,MQ天生就是异步的。

JVM调优

什么时候调

        通过监控系统对一些机器关键指标(gc time、gc count、各个分代的内存大小变化、机器的Load值与CPU使用率、JVM的线程数等)的监控报警,也可以看gc log和jstat等命令的输出,再结合线上JVM进程服务的一些关键接口的性能数据和请求体验,基本上就能定位出当前的JVM是否有问题,以及是否需要调优。

调优工具:

JconsolejProfileVisualVM
Jconsole: jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用。对垃圾回收算法有很详细的跟踪。
jProfile: 商业软件,需要付费。功能强大。
VisualVM: jdk自带,功能强大,与Jconsole类似。推荐。

如何调优

观察内存释放情况、集合类检查、对象树。
上面这些调优工具都提供了强大的功能,但是总的来说一般分为以下几类功能。

堆信息查看

可查看堆空间大小分配(年轻代、年老代、持久代分配)
1
提供即时的垃圾回收功能。
垃圾监控(长时间监控回收情况)
2
查看堆内类、对象信息查看:数量、类型等。
对象引用情况查看
有了对信息查看方面的功能,我们一般可以顺利解决以下问题:

  • 年老代年轻代大小划分是否合理。
  • 内存泄漏
  • 垃圾回收算法设置是否合理

线程监控

3
线程信息监控:系统线程数量。
线程状态监控:各个线程都处在什么样的状态下。
Dump线程详细信息:查看线程内部运行情况。
死锁检查
热点分析
CPU热点:检查系统哪些方法占用的大量CPU时间。
内存热点:检查哪些对象在系统中数量最大(一定时间内存活对象和销毁对象一起统计)
这两个东西对于系统优化很有帮助。我们可以根据找到的热点,有针对性的进行系统的瓶颈查找和进行系统优化,而不是漫无目的的进行所有代码的优化。

快照

        快照是系统运行到某一时刻的一个定格。在我们进行调优的时候,不可能用眼睛去跟踪所有系统变化,依赖快照功能,我们就可以进行系统两个不同运行时刻,对象(或类、线程等)的不同,以便快速找到问题。
        举例说,我要检查系统进行垃圾回收以后,是否还有该收回的对象被遗漏下来的了。那么,我可以在进行垃圾回收前后,分别进行一次堆情况的快照,然后对比两次快照的对象情况。

内存泄漏检查

        内存泄漏是比较常见的问题,而且解决方法也比较通用,这里可以重点说一下,而线程、热点方面的问题则是具体问题具体分析了。
        内存泄漏一般可以理解为系统资源(各方面的资源,堆、栈、线程等)在错误使用的情况下,导致使用完毕的资源无法回收(或没有回收),从而导致新的资源分配请求无法完成,引起系统错误。
        内存泄漏对系统危害比较大,因为他可以直接导致系统的崩溃。

性能调优总结

        大型网站的性能瓶颈大部分瓶颈都在数据库端,所以性能调优总是沿着如何减少对后端的压力来操作,数据库端的瓶颈经常会造成应用端的雪崩(比如:sql查询过长,长事务)等,所以需要及时解决后端性能。
1、通过读写分离、垂直拆分、水平拆分降低对数据库后端的压力。
2、通过优化SQL语句,索引等,缩短对SQL的查询时间。
3、通过缓存以及CDN来解决对图片、文件等的操作,避免对数据库产生压力。
4、通过对Web端的优化,js、css等压缩,提高大文件读取时间,尽量依赖CDN。
5、还有一个重点就是监控:对JVM、线程、SQL查询时间等健康指标进行及时监控,通过监控及时发现瓶颈,及时优化。

Your support will encourage me to continue to create!