系统性能优化并不是一上来就是JVM优化,相反JVM优化几乎是最后的手段了。影响一个系统的性能的因素非常多,如图:
从服务本身来看,影响服务性能的主要包扣:
从整个服务架构上来看还有:
一个请求从提交到响应所耗费的时间,一般比较关注平均响应时间,和最大响应时间。
常用组件的响应时间:
操作 | 响应时间 |
---|---|
打开一个站点 | 几秒 |
数据库查询一条记录(有索引) | 十几毫秒 |
机械磁盘一次寻址定位 | 4毫秒 |
从机械磁盘顺序读取1M数据 | 2毫秒 |
从SSD磁盘顺序读取1M数据 | 0.3毫秒 |
从远程分布式缓存Redis读取一个数据 | 0.5毫秒 |
从内存读取1M数据 | 十几微妙 |
Java程序本地方法调用 | 几微妙 |
从上述表格我们能看出:
为监控而生的多级缓存框架 layering-cache这是我开源的一个多级缓存框架的实现,如果有兴趣可以看一下。
并发数是指同一时刻,对服务器有实际交互的请求数。一般并发数是在在线用户数的5%-15%之间,如在线用户数是1000,那么可以预估并发数在50-150之间。
吞吐量是单位时间内完成的工作量(请求)的数量。如:每分钟的数据库事务,每秒传送的文件千字节数,每分钟的 Web 服务器命中数。
通常,平均响应时间越短,系统吞吐量越大;平均响应时间越长,系统吞吐量越小。但是,系统吞吐量越大, 未必平均响应时间越短。
不应该把大量的时间耗费在小的性能改进上,过早考虑优化是所有噩梦的根源。在开发初期我们的首要目标是完成功能,编写清晰,直接,易懂的代码。
所有调优都应该建立在新能测试的基础上,不要满目靠猜测进行优化。
性能测试后,对整个请求经历的各个环节进行分析,排查出现性能瓶颈的地方,定位问题,分析影响性能的的主要因素是什么?内存、磁盘IO、网络、CPU,还是代码问题?架构设计不足?或者确实是系统资源不足?
CDN,又称内容分发网络,本质仍然是一个缓存,而且是将数据缓存在用户最近的地方。免费的CDN加速器七牛云。
将静态资源文件缓存在反向代理服务器上,一般是Nginx。
浏览器在同一个域名下下载资源存在并发限制,所以,将js,css和图片文件放在不同的域名下,可以提高浏览器在下载web组件的并发数。
缓存的本质是将数据存放在访问速度较高的介质中,可以减少数据访问的时间,同时避免重复计算。
从上面响应时间表格我们可以看出,使用缓存将数据缓存在本地或者redis服务器,将会对查询效率有较大的提升。网站性能优化的第一定律也是使用缓存,为监控而生的多级缓存框架 layering-cache这是我开源的一个多级缓存框架的实现,如果有兴趣可以看一下。
负载均衡服务器(nginx,f5等)使用负责均衡算法,将请求分发到多个节点上进行处理。
同步和异步关注的是结果消息的通信机制:
阻塞和非阻塞主要关注的是等待结果返回调用方的状态:
jdk里的BIO就属于同步阻塞;jdk里的NIO就属于同步非阻塞;jdk里的AIO就属于异步。
如果满足则一般不需要调优:
监控GC的状态
使用各种JVM工具,查看当前日志,分析当前JVM参数设置,并且分析当前堆内存快照和gc日志,根据实际的各区域内存划分和GC执行时间,觉得是否进行优化;
分析结果,判断是否需要优化
如果各项参数设置合理,系统没有超时日志出现,GC频率不高,GC耗时不高,那么没有必要进行GC优化;如果GC时间超过1-3秒,或者频繁GC,则必须优化;
调整GC类型和内存分配
如果内存分配过大或过小,或者采用的GC收集器比较慢,则应该优先调整这些参数,并且先找1台或几台机器进行beta,然后比较优化过的机器和没有优化的机器的性能对比,并有针对性的做出最后选择;
不断的分析和调整
通过不断的试验和试错,分析并找到最合适的参数
全面应用参数
如果找到了最合适的参数,则将这些参数应用到所有服务器,并进行后续跟踪。
以参数-Xms5m -Xmx5m -XX:+PrintGCDetails -XX:+UseSerialGC为例:
[DefNew: 1855K->1855K(1856K), 0.0000148 secs][Tenured: 2815K->4095K(4096K), 0.0134819 secs] 4671K
收集器参数变为-XX:+UseParNewGC,日志变为:
[ParNew: 1856K->1856K(1856K), 0.0000107 secs][Tenured: 2890K->4095K(4096K), 0.0121148 secs]
收集器参数变为-XX:+ UseParallelGC或UseParallelOldGC,日志变为:
[PSYoungGen: 1024K->1022K(1536K)] [ParOldGen: 3783K->3782K(4096K)] 4807K->4804K(5632K)
CMS收集器和G1收集器会有明显的相关字样
-verbose:gc
和-XX:+PrintGC
:打印简单的GC日志-XX:+PrintGCDetails
和+XX:+PrintGCTimeStamps
:打印详细的GC日志-Xlogger:[logpath]
:指定GC日志路径,如Xlogger:log/gc.log
-XX:+PrintHeapAtGC
:打印推信息,获取Heap在每次垃圾回收前后的使用状况-XX:+TraceClassLoading
: 在系统控制台信息中看到class加载的过程和具体的class信息,可用以分析类的加载顺序以及是否可进行精简操作。-XX:+DisableExplicitGC
:禁止在运行期显式地调用System.gc()-XX:-HeapDumpOnOutOfMemoryError
:默认关闭,建议开启,在java.lang.OutOfMemoryError 异常出现时,输出一个dump.core文件,记录当时的堆内存快照。-XX:HeapDumpPath=./java_pid.hprof
:默认是java进程启动位置,用来设置堆内存快照的存储文件路径。