JAVA性能优化参考

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日志分析

文件名与时间:

JAVA性能优化参考_第1张图片
clipboard.png

堆大小

JAVA性能优化参考_第2张图片
clipboard11.png

性能


JAVA性能优化参考_第3张图片
clipboard22.png

gc次数与时间

JAVA性能优化参考_第4张图片
clipboard122.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

JAVA性能优化参考_第5张图片
clipboard1111.png
JAVA性能优化参考_第6张图片
clipboard11111.png

4.4Jvm内存分析

https://www.jianshu.com/p/759e02c1feee

4.4.1命令

jmap -dump:[live,]format=b,file=

通过-dump选项,把java堆中的对象dump到本地文件,然后使用MAT进行分析。

如果添加了live,只会dump活跃的对象。

4.4.2工具:MAT(eclipse memory analyzer)

主页面

JAVA性能优化参考_第7张图片
clipboardssss.png

4.4.3:占用内存比较大的对象或者

可能会memory leak的


JAVA性能优化参考_第8张图片
clipboardsssss.png
JAVA性能优化参考_第9张图片
clipboard111111111.png
JAVA性能优化参考_第10张图片
clipboardssssss.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

线程状态图

JAVA性能优化参考_第11张图片
s.png

相同堆栈的线程分类及堆栈信息

JAVA性能优化参考_第12张图片
clipboarwswswd.png

线程调用堆栈树展示

JAVA性能优化参考_第13张图片
clipbwwwwwoard.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/

locust

https://debugtalk.com/post/head-first-locust-user-guide/

你可能感兴趣的:(JAVA性能优化参考)