zoukankan      html  css  js  c++  java
  • Java程序性能优化

    性能优化流程

    资源使用 ---》 访问缓慢 ---》 优化瓶颈 ---》 达到性能目标

    主体就是:降低响应时间,提高吞吐量

    性能指标

    • 响应时间:一次操作完成的时间。包括用于等待和服务的时间,也包括用于返回结果的时间

    • 吞吐量:在数据传输中描述速度,例如字节/秒,在事务系统内中,指操作的速度,每秒操作数

    • 使用率:对于服务所请求的资源,描述在给定时间内的繁忙程度。例如,内存使用率

    • 饱和度:某一资源无法满足服务的排队工作量。

    • 错误:如果资源消费时发生错误,往往意味着出现过载情况

    • 瓶颈:在系统性能中,限制系统性能的资源。识别和移除系统瓶颈是性能优化的主要工作。

    响应时间和吞吐量是核心性能指标,响应时间是一次操作完成的时间,吞吐量是每秒钟完成的事务数。

    使用率、饱和度、错误是系统组成对象的负载描述,性能关注点按照重要程度依次是错误、饱和度、使用率。

    瓶颈是制约系统性能的资源,性能优化的目标就是找到和优化性能瓶颈。

    性能问题的描述
    这个要求客户讲述自己的版本,访问链接,同时对性能进行准确的描述,比如一个请求的响应时间等。这点非常重要。

    资源的种类

    硬件资源:磁盘,CPU,内存,缓存,网络

    软件资源:文件,进程,线程池,互斥锁,连接池,线程

    资源是有限的

    获取资源使用的应该遵守原则

    • 尽可能晚地获取资源

    • 尽可能早地释放资源

    • 尽可能少地分配/访问/移动资源

    资源的分析方法
    资源使用分析法

    监控资源的各种指标,发现资源可能存在的瓶颈。重点关注资源的使用率、饱和度、错误指标。常用于总体性能问题以及特定范围的性能问题。

    时间划片法
    检查一项工作所完成的时间,把时间划分成小的时间段,再对最大延时时间段做再次的划分,最后定位并量化问题的根本原因。会深入到软件栈的各层来找到延时的原因。一个大的步骤可以进一步下钻,分解成更细的步骤并分析优化。

    在分析资源前应该了解一个系统的部署架构,比如一个网站接受http请求,传送到nginx服务器,然后分发到K8S的负载均衡器,再传给K8S的业务容器中调用redis,mysql,mq等容器,处理完成后,原地返回。

    常见的性能问题

    慢sql,频繁地读取数据库,低效的代码,GC,并发异常,错误的配置

    网络分析

    ifconfig命令,查看RX,TX信息栏

     RX errors: 总收包的错误数量
    
     RX dropped: 进入到Ring Buffer的帧在拷贝到内存的过程中被丢弃。
    
     RX overruns: 增大意味着数据包没到 Ring Buffer 就被网卡物理层给丢弃。
    
     RX frame: 表示 misaligned 的 frames。
    
     collisions 则表示由于 CSMA/CD 造成的传输中断。
    

    对于 TX 的来说,出现上述 counter 增大的原因主要包括 aborted transmission, errors due to carrirer, fifo error, heartbeat erros 以及 windown error,而 collisions 则表示由于 CSMA/CD 造成的传输中断。


    MTU: Maximum Transmit Unit,最大传输单元,即物理接口(数据链路层)提供给其上层(通常是IP层)最大一次传输数据的大小;以普遍使用的以太网接口为例,缺省MTU=1500 Byte,这是以太网接口对IP层的约束,如果IP层有<=1500 byte 需要发送,只需要一个IP包就可以完成发送任务;如果IP层有> 1500 byte 数据需要发送,需要分片才能完成发送,这些分片有一个共同点,即IP Header ID相同。


    MSS:Maximum Segment Size ,TCP提交给IP层最大分段大小,不包含TCP Header和 TCP Option,只包含TCP Payload ,MSS是TCP用来限制application层最大的发送字节数。如果底层物理接口MTU= 1500 byte,则 MSS = 1500- 20(IP Header) -20 (TCP Header) = 1460 byte,如果application 有2000 byte发送,需要两个segment才可以完成发送,第一个TCP segment = 1460,第二个TCP segment = 540。

    这是因为数据链路层--》IP层--》传输层--》应用层


    #### 传输层

    tcpdump -i any -nn -G 1800 -s 128 -Z root port 3307 and host 172.17.32.43 -w %Y_%m%d_%H%M_%S.cap

    -G 30 间隔30秒生成文件
    -Z 需要创建新文件时启用
    -s 限定数据大小,在忽略网络数据内容时使用。
    -X 显示包的内容

    例子:
    1、不要抓广播 !broadcast
    2、过滤MAC地址, ether host 00:80:**** 如果IP与端口不停变动,则启用MAC抓包
    3、IP地址过滤: host 192.168.0.120 可以考虑方向
    4、端口:!port 80 不抓80
    5、协议: arp、icmp

    wireshark
    在win10平台,可以与代码联调,但是要启动长链接

    高级功能:
    1、数据流追踪
    作用:将TCP、UDP、SSL等数据流进行重组并完整呈现出来
    操作方法:Analyze->Follow TCP stream 跟踪tcp流

    2、专家信息说明
    作用:对数据包中的特定状态进行警告说明,包括错误、警告、注意、对话
    操作方法:Analyze->Expert Info

    3、统计摘要
    作用:对抓取的数据包进行全局统计
    路径:Statistics->Summary

    应用层

    谷歌http分析,前端性能分析:Chrome->开发者工具->Perfomance页签 ->Record -> 网页操作->Stop

    curl 测量网络延时,计算出各种阶段的花费时间

    Fiddler分析请求


    ==总结== 数据链路层: ifconfig , ethtool 查看传输速度speed和传输介质

    IP层: arp -n, route -n ,ping , tracert tracepath 判断能否直达,关注TTL和跟踪路径

    传输层: TCP握手和抓包,tcpdump

    nginx参数配置 非常重要,记录upstream_connect_time建立连接时间,upstream_response_time服务端处理时间 后面一个参数即服务端处理业务的时间

    nginx 如果不开启HTTP2.0,那么也要求开启长连接 keepalive 1000

    ping命令关注TTL,时间 考虑访问网站的时间和跳转次数,以及丢包率

    进程状态分析--内存

    外在表现: 请求长时间停顿,请求超时,网关504错误

    根本原因: Full GC; Stop the World时间超过ngnix读取时间;OOM的发生;JVM没有启动,没有指定xmx

    寻踪原因: 容器内查看死去应用 docker inspect 关注OOMKilled 和 CpuShares参数;docker stats 监控运行中的容器负载,CPU可以超过100%; docker logs 查看容器的日志

    Java查看内存资源内置的工具,pmap等,尤其是GC日志查看

    依据Java内存结构分配JVM允许内存空间,最好不设置jvm运行内存空间的最大值,这等于限制Java

    进程hang住后,无法用jstack dump栈信息,执行jstack -F后进程恢复服务,minorGC结束。

    关注Java Head堆内存和 非堆内存

    非堆内存有元数据区,Java栈,本地栈,常量池,线程空间,GC

    top -p pid 查看进程内存占用量 , 有两个内存量,虚拟内存和物理内存
    物理内存即系统分配给进程使用的内存空间

    VIRT 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
    RES 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA

    容器内添加-XX:NativeMemoryTracking=detail 参数解析内存占用


    /jdk/bin/jcmd 1 VM.native_memory scale=MB 命令查看虚拟机各区内存占用情况

    Java GC分析

    事后分析,在线分析工具https://gceasy.io/ 和 Gcviewer ,GC分析一般是看老年代和新生代的空间是否充足等,不充足补足足够的内存空间

    Gc日志主要分析full GC情况

    top –H –p 1 ; 一般pid<100为gc线程

    如果GC线程无法使用jmap等命令,hang住了,可以使用 jstack –F –m

    大堆(Xmx>=4G)
    推荐使用G1:-XX:+UseG1GC -XX:G1ReservePercent=5
    小堆(Xmx<4G)
    推荐使用吞吐量优先方式,即默认的GC方式。
    查看所有参数的方法
    $java -XX:+PrintFlagsFinal -version

    OOM问题分析

    OOM问题是非常常见的,主要原因也是那几个原因,比较好解决

    参考链接

    可以在容器内设置挂载目录,做数据映射,容器启动后执行 jdk/bin/jmap -dump:live,format=b,file=/容器内挂载路径/fin_20200822.bin 当发生OOM问题,记录到映射区

    MAT工具
    [参考链接]https://zhuanlan.zhihu.com/p/56110317
    dump文件分析

    JProfiler类似mat在IDEA运行的工具

    进程行为分析--线程

    识别线程

    Monitor、Jstack、Arthas

    使用后面两个

    1、堆栈的局部信息:调用层级关系、锁与等待

    2、一次堆栈的全局信息:锁争用、大多数线程在干什么、线程总数

    3、多个堆栈的前后对比:方法是否长期执行、长期等待某个资源

    监控线程,用上述的三个工具

    阿里工具使用介绍
    官方下载地址
    火焰图,Jprofiler工具查看

    Arthas的使用

    在win系统使用Java自带的VisualVM工具,查看Java进程ID

    下载好Arthas,解压压缩文件,
    as.bat pid

    IDEA开发工具,搭配插件使用,下载地址,这个插件只能帮你制作命令,你需要到选中方法然后点击工具栏,制作命令

    命令讲解

    1. dashboard 查看进程的简要报道

    2. thread 1 将打印 ID 为 1 的线程的堆栈,通常是主函数线程。 $thread 1 | grep 'main('

    3. jad demo.classname 命令反编译类

    4. sc -d *classname 可以打印JVM中加载的类详细信息

    5. vmtool 可以获取JVM中存活的某个类的实例或者强制GC
      vmtool --action getInstances --className java.lang.String --limit 10
      vmtool --action getInstances --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader --className org.springframework.context.ApplicationContext
      vmtool --action forceGc

    6. monitor 监控方法的执行情况
      monitor -c 5 demo.MathGame primeFactors ,-c 表示方法执行几次为一个周期,一个周期统计一次情况

    7. watch 可以观察方法的指定调用情况,可以查看方法的 返回值,异常,方法参数 ,默认的观察维度是{params, target, returnObj} 参数,执行类,返回值,可以观察方法执行前,执行后,异常发生前,异常发生后的信息,默认在方法执行后
      [x:] 指定输出结果的属性遍历深度,默认为 1 ,如果参数是数组,x=2 能观察到数组里面的内容

    watch demo.MathGame primeFactors -x 2
    watch demo.MathGame primeFactors "{params[0],throwExp}" -e -x 2 观察第一个参数和抛出异常
    watch demo.MathGame primeFactors 'target' 观察对象的属性

    1. trace 方法内部调用路径,并输出方法路径上的每个节点上耗时,

    trace demo.MathGame run -n 1 n为捕获结果次数
    trace --skipJDKMethod false demo.MathGame run 方法调用栈默认是不带JDK的方法,但是加上相关参数解除限制

    1. stack 输出当前方法被调用的调用路径,很多时候我们都知道一个方法被执行,但这个方法被执行的路径非常多,或者你根本就不知道这个方法是从那里被执行了,此时你需要的是 stack 命令。

    stack demo.MathGame primeFactors

    1. tt 方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测,主要观察方法是否返回异常或者正常返回
      tt -t demo.MathGame primeFactors -t 这个参数的表明希望记录下类 *Test 的 print 方法的每次执行情况
    IS-RET 方法是否以正常返回的形式结束
    IS-EXP 方法是否以抛异常的形式结束

    解决方法重载
    tt -t *Test print params.length==1
    tt -t *Test print 'params[1] instanceof Integer'
    tt -t *Test print params[0].mobile =="13989838402"

    tt 命令由于保存了当时调用的所有现场信息,所以我们可以自己主动对一个 INDEX 编号的时间片自主发起一次调用
    tt -l 展示全部的数据
    tt -s 'method.name=="primeFactors"'
    tt -i 1003 查看具体的一栏
    tt -i 1004 -p 发起一次调用,因为保留了信息,但是是arthas发起的调用

    1. profiler 生成应用热点的火焰图,格式profiler action [actionArg]

    actionArg属性名模式 [i:]采样间隔(单位:ns)(默认值:10'000'000,即10 ms) [f:]将输出转储到指定路径 [d:]运行评测指定秒 [e:]要跟踪哪个事件(cpu, alloc, lock, cache-misses等),默认是cpu
    一次采样生产火焰图 profiler start,profiler getSamples,profiler status, profiler stop,profiler stop --file /tmp/output.svg, profiler stop --format html,profiler resume 默认是CPU事件
    trace demo.MathGame run '#cost > 10' watch/stack/trace这个三个命令都支持#cost,关注时间过长的或者过短的
    通用的选项 -n 执行次数 '#cost > 10' 执行时间 '{params,target,returnObj,throwExp' 常用的观察维度 'params[1].toLowerCase().contains("from t_sec_user ")' -n 1 更加复杂的参数
  • 相关阅读:
    Ansible
    Ansible
    MySQL
    JS计算时间差(天,时,分钟,秒)
    cookie,localStorage,sessionStorage的区别
    css布局 -双飞翼布局&圣杯布局
    Python批量爬取网站图片
    vue-cli3中引入图片的几种方式和注意事项
    git常用命令
    vue-cli3的打包并在本地查看
  • 原文地址:https://www.cnblogs.com/lin7155/p/15293624.html
Copyright © 2011-2022 走看看