JVM深度学习系列之实践经验(七)

探讨了如何优化高性能服务器的内存使用,包括调整堆内存、建立逻辑集群、避免长时间的GC停顿,以及在线上环境中遇到的老年代增长和OOM问题的解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 如何充分利用高性能服务器(比如:内存16G)
    1. 一般的思路是调大堆内存(12G) 但是同时会引起几个问题
      1. 年轻代GC和老年代GC的时间就会很长,严重的10多s,这样会导致系统不定时的卡顿(GC的stop the world),用户不能操作。
      2. 当发生堆溢出时,无法dump堆 一般快照文件达到十几G,即使dump下来,也很难分析
    2. 解决:
      1. 建立逻辑集群
        1. 在一台机器上,开启多个服务器,修改端口号,每个服务器分配2G内存,然后前端使用nginx均衡分发
      2. 不建立集群 将full GC 调至最低,最好可以一天执行一次,然后在午夜手动触发。
  2. 线上老年代一直在慢速增长(真实线上问题) 
    1. 起源:内存堆使用率超过80%后报警
    2. 处理:
      1. 先通过jinfo 查看当前虚拟机配置 发现是由虚拟机自动动态调节老年代新生代大小比例。GC策略使用的是Paraller Scavenge 以系统吞吐量优先的多线程垃圾回收器。(刚开始觉得这种配置不合理,一般在面向用户时使用并发CMS收集器,平缓GC,后来发现由于是专门用来跑work的服务器,这种配置也是合适的)
      2. 通过jstat -gcutil PID 1000 每1秒打印堆使用情况日志 发现在一次young GC后老年代增长0.16%  年轻代的大部分空间也被回收 于是就想要知道到哪些对象晋升到老年代 
      3. 通过jmap dump一次GC前后的两份快照
      4. 通过jvisual VM 分析大对象 发现晋升的对象只有两个 都是netty对象。从快照看一切正常。 (一般问题到这就能看出来)
      5. 后来发现是由于虚拟机动态调节策略,而且是以吞吐量为优先(以空间换时间,以减小新生代大小从而降低新生代回收时间,保证吞吐率)的垃圾回收策略,导致新生代大小特别小(在报警时存活区大小只有2M),部分对象就会直接进入老年代。
      6. 将动态调节修改为指定新生代大小 将垃圾回收策略改为ParNew策略 程序回复正常。

3. 线上问题2

起源: jvm报警  部分服务器宕机  看日志oom

分析:

  1. 首先看监控系统看到内存的使用率达到99.97%  堆内存设置1024M(偏小)
  2. 使用jmap -dump 下载快照  使用jvisualvm 查看到List中 MessageProcLog 对象有70多万个
  3. 排查代码发现 是一个消息补发的job 查询mongo库 那为啥会有这么多对象呢
  4. 经过分析发现有重复的数据,而且每5分钟翻一倍
  5. 看到代码中是在消息推送后 先修改原始消息状态 后 插入新消息的逻辑
  6. 怀疑是修改未成功,但是插入成功了
  7. 但是修改不成功会抛异常,代码是顺序执行 理论上插入也不会成功 不合道理啊
  8. 后来发现job的配置是轮询策略 每个job执行时,查mongo,然后将数据交给线程池异步执行
  9. 这样的话就会导致 多台机器同时再跑job 而且有可能操作同一条数据,导致数据重复插入
  10. 我们想了很多策略,比如job单机串行执行,但是怕单机时 不同次的job还是执行同一个数据 导致数据还会重复插入(虽然概率比之前小了很多,但是还可能发生)
  11. 本着追求彻底完美的精神,最终把逻辑修改为 消息推送后只修改原始消息状态,这样无论单台还是多台机器执行都不会有问题了(无非是同一种状态修改了多次)

         

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值