JVM:调优相关

常见垃圾回收器组合参数设定(1.8)

  • -XX:+UseSerialGC = Serial New (DefNew) + Serial Old
    小型程序。默认情况下不会是这种选项,HotSpot会根据计算及配置和JDK版本自动选择收集器

  • -XX:+UseParNewGC = ParNew + SerialOld
    这个组合已经很少用(在某些版本中已经废弃)
    https://stackoverflow.com/questions/34962257/why-remove-support-for-parnewserialold-anddefnewcms-in-the-future

  • -XX:+UseConc(urrent)MarkSweepGC = ParNew + CMS + Serial Old

  • -XX:+UseParallelGC = Parallel Scavenge + Parallel Old (1.8默认) 【PS + SerialOld】

  • -XX:+UseParallelOldGC = Parallel Scavenge + Parallel Old

  • -XX:+UseG1GC = G1

  • Linux中没找到默认GC的查看方法,而windows中会打印UseParallelGC
    java +XX:+PrintCommandLineFlags -version
    通过GC的日志来分辨

  • Linux下1.8版本默认的垃圾回收器到底是什么?
    1.8.0_181 默认(看不出来)Copy MarkCompact
    1.8.0_222 默认 PS + PO

JVM常用命令行参数

  • JVM的命令行参数参考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
  • HotSpot参数分类
    标准: - 开头,所有的HotSpot都支持
    非标准:-X 开头,特定版本HotSpot支持特定命令
    不稳定:-XX 开头,下个版本可能取消

java -version
java -X

GC常用参数

  • -Xmn -Xms -Xmx -Xss
    年轻代 最小堆 最大堆 栈空间
  • -XX:+UseTLAB
    使用TLAB,默认打开
  • -XX:+PrintTLAB
    打印TLAB的使用情况
  • -XX:TLABSize
    设置TLAB大小
  • -XX:+DisableExplictGC
    System.gc()不管用 ,FGC
  • -XX:+PrintGC
  • -XX:+PrintGCDetails
  • -XX:+PrintHeapAtGC
  • -XX:+PrintGCTimeStamps
  • -XX:+PrintGCApplicationConcurrentTime (低)
    打印应用程序时间
  • -XX:+PrintGCApplicationStoppedTime (低)
    打印暂停时长
  • -XX:+PrintReferenceGC (重要性低)
    记录回收了多少种不同引用类型的引用
  • -verbose:class
    类加载详细过程
  • -XX:+PrintVMOptions
  • -XX:+PrintFlagsFinal -XX:+PrintFlagsInitial
    必须会用
  • -Xloggc:opt/log/gc.log
  • -XX:MaxTenuringThreshold
    升代年龄,最大值15
  • 锁自旋次数 -XX:PreBlockSpin 热点代码检测参数-XX:CompileThreshold 逃逸分析 标量替换 …
    这些不建议设置

Parallel常用参数

  • -XX:SurvivorRatio
  • -XX:PreTenureSizeThreshold
    大对象到底多大
  • -XX:MaxTenuringThreshold
  • -XX:+ParallelGCThreads
    并行收集器的线程数,同样适用于CMS,一般设为和CPU核数相同
  • -XX:+UseAdaptiveSizePolicy
    自动选择各区大小比例

CMS常用参数

  • -XX:+UseConcMarkSweepGC
  • -XX:ParallelCMSThreads
    CMS线程数量
  • -XX:CMSInitiatingOccupancyFraction
    使用多少比例的老年代后开始CMS收集,默认是68%(近似值),如果频繁发生SerialOld卡顿,应该调小,(频繁CMS回收)
  • -XX:+UseCMSCompactAtFullCollection
    在FGC时进行压缩
  • -XX:CMSFullGCsBeforeCompaction
    多少次FGC之后进行压缩
  • -XX:+CMSClassUnloadingEnabled
  • -XX:CMSInitiatingPermOccupancyFraction
    达到什么比例时进行Perm回收
  • GCTimeRatio
    设置GC时间占用程序运行时间的百分比
  • -XX:MaxGCPauseMillis
    停顿时间,是一个建议时间,GC会尝试用各种手段达到这个时间,比如减小年轻代

G1常用参数

  • -XX:+UseG1GC
  • -XX:MaxGCPauseMillis
    建议值,G1会尝试调整Young区的块数来达到这个值
  • -XX:GCPauseIntervalMillis
    ?GC的间隔时间
  • -XX:+G1HeapRegionSize
    分区大小,建议逐渐增大该值,1 2 4 8 16 32。
    随着size增加,垃圾的存活时间更长,GC间隔更长,但每次GC的时间也会更长
    ZGC做了改进(动态区块大小)
  • G1NewSizePercent
    新生代最小比例,默认为5%
  • G1MaxNewSizePercent
    新生代最大比例,默认为60%
  • GCTimeRatio
    GC时间建议比例,G1会根据这个值调整堆空间
  • ConcGCThreads
    线程数量
  • InitiatingHeapOccupancyPercent
    启动G1的堆空间占用比例

基础概念

吞吐量:用户代码时间 /(用户代码执行时间 + 垃圾回收时间)

响应时间:STW越短,响应时间越好

JVM调优,首先要确定,追求的是吞吐量优先,还是响应时间优先?亦或是在满足一定的响应时间的情况下,要求达到多大的吞吐量…

调优垃圾收集器选择:

  • 吞吐量优先:PS + PO
  • 响应时间优先:G1

JVM调优

  1. 根据需求进行JVM规划和预调优
  2. 优化JVM运行环境(慢,卡顿等问题)
  3. 解决JVM运行过程中出现的各种问题(OOM)

JVM规划调优

步骤:

  1. 熟悉业务,判断吞吐量优先 or 响应时间优先
    1. 响应时间、停顿时间 [CMS G1 ZGC] (需要给用户作响应)
    2. 吞吐量 = 用户时间 /( 用户时间 + GC时间) [PS]
  2. 选择GC组合
  3. 计算内存需求
  4. 选定CPU(配置越高越好)
  5. 设置年代大小,升级年龄
    XMX和XMS设置一样大,MaxPermSize和MinPermSize设置一样大,这样可以减轻伸缩堆大小带来的压力
  6. 设定日志参数
    1. -Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5
    -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
    3. 或者每天产生一个日志文件
  7. 观察日志情况

实战

在高性能硬件上部署程序,目前主要有两种方式:

  • 通过64位JDK来使用大内存。每台机器16G物理内存
  • 使用若干个32位虚拟机建立逻辑集群来利用硬件资源。每台机器1.5G物理内存

现有一个垂直电商,每日最高会产生百万订单,处理订单系统需要什么样的服务器配置?(非专业问法)

分析一下,每日产生的订单基本都集中在了一个时间段,假设有72w的订单产生在晚上9-11点,平均一下即每秒产生100个订单,如果再进一步对一个小时进行高峰预测,可能高峰时刻每秒1000个订单,每个订单所产生的对象一般来说500多KB,那么也仅仅产生500M的内存消耗,另外,即使是这500M的订单对象也并非一定需要500M的内存,因为如果CPU等硬件支持非常高,处理速度非常快的情况下,有可能300M就足够。因此服务器内存上的配置还需要看硬件支持。这种情况下采取32位机器,1.5G内存就足够应付其并发量。

12306春节大规模抢票,号称百万并发

12306应该是中国并发量最大的秒杀网站:

号称并发量100W最高

CDN -> LVS -> NGINX -> 业务系统 -> 每台机器1W并发(10K问题->解决的关键:redis) 100台机器->100个redis -> 网关zuul集群 ->注册中心Eruka/zookeeper -> 微服务集群

普通电商订单 -> 下单 ->订单系统(IO)减库存 ->等待用户付款 同步进行TPS非常少,几十个就撑死了

12306的一种可能的模型: 下单 -> 一个线程减库存 和 一个线程把订单扔到redis或者kafka里,然后返回给用户下单成功,当用户付款完成后,订单处理线程才会从redis中取出订单进行处理 也就是异步进行 ->等付款

减库存最后还会把压力压到一台服务器

可以做分布式本地库存 + 单独服务器做库存均衡

大流量的处理方法:分而治之

怎么得到一个事务会消耗多少内存?

  1. 弄台机器,看能承受多少TPS?是不是达到目标?扩容或调优,让它达到

  2. 用压测来确定

有一个50万PV的资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G的堆,用户反馈网站比较缓慢,因此公司决定升级,新的服务器为64位,16G的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低了

  1. 为什么原网站慢?
    很多用户浏览数据,很多数据load到内存,内存不足,频繁GC,STW长,响应时间变慢
  2. 为什么会更卡顿?
    内存越大,FGC时间越长
  3. 咋办?
    PS -> PN + CMS 或者 G1

系统CPU经常100%,如何调优?CPU100%那么一定有线程在占用系统资源

  1. 找出哪个进程cpu高(top)
  2. 该进程中的哪个线程cpu高(top -Hp)
  3. 导出该线程的堆栈 (jstack)
  4. 查找哪个方法(栈帧)消耗时间 (jstack)
  5. 工作线程占比高 | 垃圾回收线程占比高

系统内存飙高,如何查找问题

  1. 导出堆内存 (jmap) 图形化 jvisualvm
  2. 分析 (jhat jvisualvm mat jprofiler … )

如何监控JVM

jstat jvisualvm jprofiler arthas top…

解决JVM运行中的问题

  1. top命令观察到问题:内存不断增长 CPU占用率居高不下

  2. top -Hp 观察进程中的线程,哪个线程CPU和内存占比高

  3. jps定位具体java进程
    jstack 定位线程状况,重点关注:WAITING BLOCKED
    eg.
    waiting on <0x0000000088ca3310> (a java.lang.Object)
    假如有一个进程中100个线程,很多线程都在waiting on ,一定要找到是哪个线程持有这把锁
    怎么找?搜索jstack dump的信息,找 ,看哪个线程持有这把锁RUNNABLE

  4. 为什么阿里规范里规定,线程的名称(尤其是线程池)都要写有意义的名称 —> 方便排查是哪个线程出问题
    怎么样自定义线程池里的线程名称?(自定义ThreadFactory)

  5. jinfo pid

  6. jstat -gc 动态观察gc情况 / 阅读GC日志发现频繁GC / arthas观察 / jconsole/jvisualVM/ Jprofiler(最好用)
    jstat -gc 4655 500 : 每个500个毫秒打印GC的情况
    1:已经上线的系统不用图形界面用什么?(cmdline arthas)
    2:图形界面到底用在什么地方?测试!测试的时候进行监控!(压测观察)

  7. jmap - histo 4655 | head -20,查找有多少对象产生

  8. jmap -dump:format=b,file=xxx pid :

    线上系统,内存特别大,jmap执行期间会对进程产生很大影响,甚至卡顿(电商不适合)
    1:设定了参数HeapDump,OOM的时候会自动产生堆转储文件
    2:很多服务器备份(高可用),停掉这台服务器对其他服务器不影响
    3:在线定位

  9. java -Xms20M -Xmx20M -XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError com.whitecat.jvm.gc.Test

    通过这个参数 可以在机器宕机时生成 堆转储文件

    如果在线上就想生成堆转储文件 可以使用 jmap jhat 可视化jvisualvm

  10. 使用MAT / jhat /jvisualvm 进行dump文件分析
    https://www.cnblogs.com/baihuitestsoftware/articles/6406271.html
    jhat -J-mx512M xxx.dump -> arthas
    http://192.168.17.11:7000
    拉到最后:找到对应链接
    可以使用OQL查找特定问题对象 有点像sql查询 这是一个比较强大的功能

  11. 找到代码的问题

强大的在线排查工具 —> arthas

  • 为什么需要在线排查?
    在生产上我们经常会碰到一些不好排查的问题,例如线程安全问题,用最简单的threaddump或者heapdump不好查到问题原因。为了排查这些问题,有时我们会临时加一些日志,比如在一些关键的函数里打印出入参,然后重新打包发布,如果打了日志还是没找到问题,继续加日志,重新打包发布。对于上线流程复杂而且审核比较严的公司,从改代码到上线需要层层的流转,会大大影响问题排查的进度。

  • jvm观察jvm信息

  • thread定位线程问题

  • dashboard 观察系统情况 类似top

  • heapdump导出堆文件 + jhat分析 jhat会启动一个server,打开server的服务器页面就可以看到jhat分析出来的内容

  • jad反编译
    动态代理生成类的问题定位
    第三方的类(观察代码)
    版本问题(确定自己最新提交的版本是不是被使用)

  • redefine 热替换
    目前有些限制条件:只能改方法实现(方法已经运行完成),不能改方法名, 不能改属性
    m() -> mm()

    使用:1、修改程序 2、javac编译 3、redefine XX.class

  • sc - search class

  • watch - watch method

  • 没有包含的功能:jmap

猜你喜欢

转载自blog.csdn.net/qq_43186095/article/details/103538919