1.性能优化:
Perceived system performance:从开发的角度去衡量,如响应时间,并发数,请求数,错误率等等。
Perceived user experience:从用户角度出发,如首屏时间,白屏时间,完全加载时间,即用户能实际感觉到得网页加载延迟。
System performance:从服务器的角度出发,监测目前服务器的cpu,内存,网络带宽,流量等等物理资源。
1.1.关键点:
Throughput ,吞吐量。也就是每秒钟可以处理的请求数,任务数。
Latency, 系统延迟。也就是系统在处理一个请求或一个任务时的延迟。
Throughput越大,Latency会越差。因为请求量过大,系统太繁忙,所以响应速度自然会低。
Latency越好,能支持的Throughput就会越高。因为Latency短说明处理速度快,于是就可以处理更多的请求。
1.2压测工具
jmeter
locust
2.系统负载
参考地址;
https://linuxtools-rst.readthedocs.io/zh_CN/latest/advance/03_optimization.html
https://blog.csdn.net/ZYC88888/article/details/79027944
《Linux Performance and Tuning Guidelines》。
3.查看操作系统负载
首先,当我们系统有问题的时候,我们不要急于去调查我们代码,这个毫无意义。
我们首要需要看的是操作系统的报告。
看看操>作系统的CPU利用率,看看内存使用率,看看操作系统的IO,还有网络的IO,网络链接数,等等。Windows下的perfmon是一 个很不错的工具,Linux下也有很多相关的命令和工具,比如:SystemTap,
[LatencyTOP]>(https://latencytop.org/),vmstat, sar, iostat, top, tcpdump等等 。通过观察这些数据,我们就可以知道我们的
软件的性能基本上出在哪里。
比如:
1)先看CPU利用率,
如果CPU利用率不高,但是系统的Throughput和Latency上不去了,这说明我们的程序并没有忙于计算,而是忙于别的一些事,>比如IO。(另外,CPU的利用率还要看内核态的和用户态的,内核态的一上去了,整个系统的性能就下来了。而对于多核CPU来>说,CPU 0 是相当关键的,如果CPU 0的负载高,那么会影响其它核的性能,因为CPU各核间是需要有调度的,这靠CPU0完
成)
2)然后,我们可以看一下IO大不大,
IO和CPU一般是反着来的,CPU利用率高则IO不大,IO大则CPU就小。关于IO,我们要看三个事,一个是磁盘文件IO,一个是驱动程序的IO(如:网卡),一个是内存换页率。这三个事都会影响系统性能。
3)然后,查看一下网络带宽使用情况,
在Linux下,你可以使用iftop, iptraf, ntop, tcpdump这些命令来查看。或是用Wireshark来查看。
4)
如果CPU不高,IO不高,内存使用不高,网络带宽使用不高。但是系统的性能上不去。这说明你的程序有问题,比如,你的程序被阻塞了。可能是因为等那个锁,可能是因为等某个资源,或者是在切换上下文。
通过了解操作系统的性能,我们才知道性能的问题,比如:带宽不够,内存不够,TCP缓冲区不够,等等,很多时候,不需要调整程序的,只需要调整一下硬件或操作系统的配置就可以了。
4.java
4.1 jvm优化:
根据jvm参数分析log日志,将log作为性能动态调整的参考。
最初jvm参数比如:
jvm参数:
-server
-XX:+UseG1GC
-Xmx5g
-XX:MaxGCPauseMillis=100
-XX:InitiatingHeapOccupancyPercent=70
-XX:+PrintGCDetails
-XX:+PrintAdaptiveSizePolicy
-XX:G1HeapRegionSize=4m
-XX:+PrintReferenceGC
-XX:+ParallelRefProcEnabled
-XX:MetaspaceSize=300m
-XX:MaxMetaspaceSize=300m
-verbose:gc
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintTenuringDistribution
-Xloggc:/var/log/cas-server-gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=20
-XX:GCLogFileSize=50M "
G1 GC是一个响应时间优先的GC算法,它与CMS最大的不同是,用户可以设定整个GC过程的期望停顿时间,参数-XX:MaxGCPauseMillis指定一个G1收集过程目标停顿时间,默认值200ms,不过它不是硬性条件,只是期望值。那么G1怎么满足用户的期望呢?就需要这个停顿预测模型了。G1根据这个模型统计计算出来的历史数据来预测本次收集需要选择的Region数量,从而尽量满足用户设定的目标停顿时间。
停顿预测模型是以衰减标准偏差为理论基础实现的:
4.2.gc日志分析
文件名与时间:
![](https://img.haomeiwen.com/i3614146/e8c644fcc59850f4.png)
堆大小
![](https://img.haomeiwen.com/i3614146/3e1c4fbec57fb51c.png)
性能
![](https://img.haomeiwen.com/i3614146/41e28b88fa3083dd.png)
gc次数与时间
![](https://img.haomeiwen.com/i3614146/d15d47736b807cf5.png)
4.2.1常见cause:
1. Ergonomics
这里可以到full gc的reason是Ergonomics,是因为开启了UseAdaptiveSizePolicy,jvm自己进行自适应调整引发的full gc
2.Allocation Failure
young gc,看log里头99%都是GC (Allocation Failure)造成的young gc。
Allocation Failure表示向young generation(eden)给新对象申请空间,但是young generation(eden)剩余的合适空间不够所需的大小导致的minor gc。
3.GCLocker Initiated GC
参考: https://www.jianshu.com/p/ecc57a81f73c http://www.10tiao.com/html/698/201710/2247483759/1.html(JNI是终极加速?我们来谈谈副作用)
4.GC pause (G1 Evacuation Pause)
GC pause (G1 Evacuation Pause) — 疏散停顿(Evacuation Pause)是将活着的对象从一个区域(young or young + old)拷贝到另一个区域的阶段。 Evacuation Pause: Fully Young(转移暂停:纯年轻代模式) 在应用程序刚启动时,G1 还未执行过(not-yet-executed)并发阶段,也就没有获得任何额外的信息,处于初始的 fully-young 模式。在年轻代空间用满之后,应用线程被暂停,年轻代堆区中的存活对象被复制到存活区,如果还没有存活区,则选择任意一部分空闲的小堆区用作存活区 复制的过程称为转移(Evacuation),这和前面讲过的年轻代收集器基本上是一样的工作原理
5.meta space
参考:
https://segmentfault.com/a/1190000016036969
https://www.jianshu.com/p/b448c21d2e71
4.3 jdk工具:jvisualvm.exe
![](https://img.haomeiwen.com/i3614146/293a6bfe9d5af15c.png)
![](https://img.haomeiwen.com/i3614146/aadd06d09864f2de.png)
4.4Jvm内存分析
https://www.jianshu.com/p/759e02c1feee
4.4.1命令
jmap -dump:[live,]format=b,file=<filename> <pid>
通过-dump选项,把java堆中的对象dump到本地文件,然后使用MAT进行分析。
如果添加了live,只会dump活跃的对象。
4.4.2工具:MAT(eclipse memory analyzer)
主页面
![](https://img.haomeiwen.com/i3614146/ab1946b2cbf63ff0.png)
4.4.3:占用内存比较大的对象或者
可能会memory leak的
![](https://img.haomeiwen.com/i3614146/1529c89937727c0f.png)
![](https://img.haomeiwen.com/i3614146/675a7c29e0cbf868.png)
![](https://img.haomeiwen.com/i3614146/ca97757f662ce431.png)
4.4.4
等等。
4.4.5 log4j2-disruptor-ringbuffer
https://tech.meituan.com/disruptor.html
设置AsyncLoggerConfig.RingBufferSize的含义是把日志先暂存在内存中,等到一定数值(你设置的209715),就体刷到硬盘上去。
暂存的日志占用过多内存,jvm发现内存不够用,触发gc,gc的过程是很耗cpu资源的。
4.5jstack线程堆栈分析
命令:jstack pid > pidjstack.log
https://blog.csdn.net/liwenxia626/article/details/80791704
线程状态图
![](https://img.haomeiwen.com/i3614146/86f4f7f1ca5c435f.png)
相同堆栈的线程分类及堆栈信息
![](https://img.haomeiwen.com/i3614146/3688b18e4f2c6960.png)
线程调用堆栈树展示
![](https://img.haomeiwen.com/i3614146/487305fdbef1ad01.png)
代码优化:
1.hashmap 、concurrenthashmap
等数据结构的应用;性能问题、原理、使用场景等。
2.线程池等各种池的使用场景;
3.第三方库的使用:
fastjson、guava、Lombok、log4j2等。
4.序列化和反序列化协议
1、对于公司间的系统调用,如果性能要求在100ms以上的服务,基于XML的SOAP协议是一个值得考虑的方案。
2、基于Web browser的Ajax,以及Mobile app与服务端之间的通讯,JSON协议是首选。对于性能要求不太高,或者以动态类型语言为主,或者传输数据载荷很小的的运用场景,JSON也是非常不错的选择。
3、对于调试环境比较恶劣的场景,采用JSON或XML能够极大的提高调试效率,降低系统开发成本。
4、当对性能和简洁性有极高要求的场景,Protobuf,Thrift,Avro之间具有一定的竞争关系。
5、对于T级别的数据的持久化应用场景,Protobuf和Avro是首要选择。如果持久化后的数据存储在Hadoop子项目里,Avro会是更好的选择。
6、由于Avro的设计理念偏向于动态类型语言,对于动态语言为主的应用场景,Avro是更好的选择。
7、对于持久层非Hadoop项目,以静态类型语言为主的应用场景,Protobuf会更符合静态类型语言工程师的开发习惯。
8、如果需要提供一个完整的RPC解决方案,Thrift是一个好的选择。
9、如果序列化之后需要支持不同的传输层协议,或者需要跨防火墙访问的高性能场景,Protobuf可以优先考虑。
5.数据库
索引、
sql语句、
引擎、
连接池、
等等。。。。
6.其他优化
缓存系统
架构层面调优
异步
Nosql 等等
参考:
MAT
https://www.imooc.com/article/16693
ParallelWebAppClassLoader
http://jm.taobao.org/2016/01/29/3721/
网友评论