系统最近老年代的内存上升的比较快,三到四天会发生一波fullGC。于是开始对GC的情况做一波分析。

线上老年代2.7G,年轻带1.3G老年代上升较快,3天一波fullGC,并且fullGC会把内存回收,有时回收一般,有时回收全部。所以判断是不会有内存泄漏现象的,内存发生泄漏是回收不了的。第二个判断,不存在大对象,一个是基于对程序的理解,一个是对于老年代上升的速率,基本是稳固上升。不存在峰值。

我是先用jstack  命令打印出线程状态的  jstack -l pid  >> 文件名  发现这么操作是无用的。jstack主要是分析线程状态的,尤其是针对占用CPU,死循环,死锁操作等。

一开始确实定位到一个线程,是我们服务每个一分钟拉去配置中心数据的线程,数据量很小,而且基本都是重复的数据。所以那会没有头绪方向不对。

后来老大说打下内存快照啊。于是就开始看下内存快照了。

1、先使用 jmap命令打印出内存快照文件。

jmap  -dump:format=b,file= 文件路径  pid(进程号)

2、使用MemoryAnalyzer(windows下的分析工具)工具分析大对象

分析出来是jdbc连接对象实例太多,因为mysql的jdbc包在每次创建jdbc连接的时候,会对连接进行虚引用包装,最后放到一个ConcurrentHashMap里。而系统1分钟会进行年轻代的GC,而程序配置的链接生命周期为30分钟。所以30分钟MinGC将到达30多次,而JVM默认的配置是15。所以我们推测这个配置的不对,要么减少生命周期要么增加JVM年龄的配置。

经过测试在jdk8的环境下,年龄的阈值是不能超过15的,这就尴尬了。于是只好降低生命周期,同时设置数据源的最大连接和最小连接相等,防止数据源一直创建空闲连接,这样能方式连接数量,同时通过反射,检测ConcurrentHashMap的数量。经过上线后,发现并没有明显效果。于是乎干脆把map的数据直接清空,发现清空了上完线也并没有解决老年代上升的问题。不过老年代每次fullGC都会回收到底。于是判断清空有助于进行回收,并且老年代回收的耗时也变短了,减少到一半时间。

另一方面观测,检查了JVM年轻代 E区和S区的比例,你会认为默认是1:8,但是不是那么简单地。发现程序刚启动时确实是1比8,但是随着程序启动,MinGC,jvm默认的垃圾回收器会自动调节这个比例。只有设置CMS才不会自动调节。于是决策是由于S区分配内存太小导致,当时我们的S区稳定在30M左右,E区差不多有1.3G。于是改成了CMS垃圾回收器,发现也并没有卵用,而且老年代内存到达50%就发生了fullGC,看来CMS是可以设置回收阈值的。实在没办法了,只好换数据源了,把HikairCP换成了druid。发现换了之后就解决了,fullGC频率从4天能到达15天,ConcurrentMap的数量很少,最多也就2百的量。而之前能达到上万的量。总之不知道是因为HikairCP的原因,还是我们配置的原因。据说这个数据源号称比druid速度更优的数据源。

.

.

.

历史是何其的相似,程序性能问题又来了,我们程序为了提高tps,经过压测,发现瓶颈在于redis,当时redis是哨兵模式,读写访问一个master,于是想切换为集群。发现切换为集群后,fullGC的频率又回到了原先的地步,而且把操作切换为读集群时,压力更大,竟然再短短5小时内,打满老年代内存, 并且CPU占用也较大。没办法观测了一会,发现每5分钟上升2个百分点。代码回滚了。于是乎又开始了一波分析,代码优化。

经过分析本次上线只是添加了cluster管道批量操作的代码,代码肯定出现在这里,于是开始进行优化。

首先分析线上内存快照,发现最大占用的是 int 数组,这个不好分析,应为属于基本对象,没法分析。于是乎私底下在本地进行读集群方法的压测,再加上代码的分析,发现每次操作都会对取cluster集群的信息,这个集群的信息包含了所有节点的ip+port,以及他们对应的分槽信息,而这个分槽信息是以LinkedHashSet类型存储的,里面是满满的Integer类型的槽。一共16384个,于是基本确定了,是每次实时查询cluster集群信息导致的。发现Jedis的方法是对集群信息做了缓存的 ,但是只缓存了100毫秒。再加上我们本身程序也包含了大量的业务逻辑。估计这么一连起来就造成了YGC次数过高,或者年轻代S区空间太小。于是从两个方面去提高程序性能。

发现在修改JVM参数配比,提高年轻代S区的内存大小,并且修改垃圾回收器为CMS,发现在本机进行ab压测,最高tps到达了800。并且在并发80,访问量50000的情况下,老年代内存会上升到100M,YGC次数能够到达200。而哨兵的压测结果tps最高到达2000。而且老年代内存50M。YGC次数也在30以内。

于是对cluster的代码进行优化,把每次获取集群节点信息放到了for循环里。tps提高到1300,老年代内存稳定在90M。

我们程序另一条思路是:把集群的信息缓存到JVM,不依靠Jedis的缓存100ms。而是由我们自己缓存。但是存在一个问题,每当集群节点扩容,分槽或者主下线,从上线。我们的程序就检测不到变化了,于是在程序里开启了异步线程每个5秒刷新集群信息,而且对于每次操作cluster做了重试处理,一旦检测到节点连接创建失败,发生MOVED错误,就刷新集群信息,进行操作重试。发现使用静态缓存集群信息的方式,tps提高到2000左右,基本和哨兵持平,而且老年代内存也到达60M左右,YGC次数也降下来了。

在这些过程中,我学到了什么:

自己尝试搭建了虚拟机的redis-cluster集群(很早就搭建了,这回正好用上),redis集群分槽。

cluster管道批量操作,jdk的一些常用工具命令,还有ab的简单压测

最后重要的是分析问题的能力和思路

【jvm】来自于线上的fullGC分析的更多相关文章

  1. 关于GC(上):Apache的POI组件导致线上频繁FullGC问题排查及处理全过程

    某线上应用在进行查询结果导出Excel时,大概率出现持续的FullGC.解决这个问题时,记录了一下整个的流程,也可以作为一般性的FullGC问题排查指导. 1. 生成dump文件 为了定位FullGC ...

  2. 记一次线上OOM问题分析与解决

    一.问题情况 最近用户反映系统响应越来越慢,而且不是偶发性的慢.根据后台日志,可以看到系统已经有oom现象. 根据jdk自带的jconsole工具,可以监视到系统处于堵塞时期.cup占满,活动线程数持 ...

  3. 我整理的一份来自于线上的Nginx配置(Nginx.conf),希望对学习Nginx的有帮助

    我整理了一份Nginx的配置文件说明,是真正经历过正式线上考验过.如果有优化的地方,也请朋友们指点一二,整理出一份比较全而实用的配置. 主要包含配置:负载均衡配置,页面重定向,转发,HTTPS和HTT ...

  4. 一次线上mysql死锁分析

    一.现象 发运车次调用发车接口时发生异常,后台抛出数据库死锁日志. 二.原因分析 通过日志可以看出事务T1等待 heap no 8的行锁 (X locks 排他锁) 事务T2持有heap no 8的行 ...

  5. 记一次线上频繁fullGc的排查解决过程

    发生背景 最近上线的一个项目几乎全是查询业务,并且都是大表的慢查询,sql优化是做了一轮又一轮,前几天用户反馈页面加载过慢还时不时的会timeout,但是我们把对应的sql都优化一遍过后,前台响应还是 ...

  6. 快速定位java系统的线上问题--转

    原文地址:http://m.blog.csdn.net/article/details?id=43376943 前言:我们的场景并没有像BAT等大型互联网公司里的系统那么复杂,但是基本上也有一定的规模 ...

  7. 线上故障排查——drools规则引擎使用不当导致oom

    事件回溯 1.7月26日上午11:34,告警邮件提示:tomcat内存使用率连续多次超过90%: 2.开发人员介入排查问题,11:40定位到存在oom问题,申请运维拉取线上tomcat 内存快照dum ...

  8. JVM jmap dump 分析dump文件 / 如何使用Eclipse MemoryAnalyzer MAT 排查线上问题

    jhat简介 jhat用来分析java堆的命令,可以将堆中的对象以html的形式显示出来,包括对象的数量,大小等等,并支持对象查询语言 这个工具并不是想用于应用系统中而是用于"离线" ...

  9. 线上系统/tmp 目录不断增长分析与总结

    1.问题描述 系统配置为单核4G, web 工程配置堆2G,  /tmp目录 二进制文件不断增加,平均一天增加20G, 手动清理/tmp目录,重启系统,问题依旧. 2.分析 /tmp 目录存放系统运行 ...

随机推荐

  1. E - tower HYSBZ - 4657 (网络流割点)

    题目链接:https://cn.vjudge.net/contest/281959#problem/E 题目大意:中文题目 具体思路:首先,有矛盾的时候就是两个导弹的运动轨迹会相交的时候,那么我们可以 ...

  2. Android UI组件之自定义控件实现IP地址控件

    http://www.cnblogs.com/razerlack/p/4273282.html

  3. 【Linux】Linux中Swap与Memory内存简单介绍

    背景介绍 对于Linux来说,其在服务器市场的使用已经占据了绝对的霸主地位,不可动摇.Linux的各种设计思想和使用也被传承(当然不乏各种黑Linux,而且黑的漂亮).Linux的很多独特的设计,对性 ...

  4. 【转载】apache log配置 按日期写日志

    指定apache日志每天生成一个文件 Linux系统配置方法 在apache的配置文件httpd.conf中找到 代码如下1 ErrorLog logs/error_log CustomLog log ...

  5. DMA及cache一致性的学习心得 --dma_alloc_writecombine【转】

    转自:https://www.cnblogs.com/hoys/archive/2012/02/17/2355914.html 来源:http://xmxohy.blog.163.com/blog/s ...

  6. springboot系列七:springboot 集成 MyBatis、事物配置及使用、druid 数据源、druid 监控使用

    一.MyBatis和druid简介 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.M ...

  7. zabbix3.0.4添加对指定进程的监控

    zabbix3.0.4添加对进程的监控: 主要思路: 通过 ps -ef|grep sdk-push-1.0.0.jar |grep -v grep|wc -l 这个命令来判断进程sdk-push是否 ...

  8. 使用第三方工具Xtrabackup进行MySQL备份

    使用Xtrabackup进行MySQL备份: 一.安装 1.简介 Xtrabackup是由percona提供的mysql数据库备份工具,据官方介绍,这也是世界上惟一一款开源的能够对innodb和xtr ...

  9. WebMvcConfigurerAdapter已过时

    Spring Boot2.0的版本(创建的时候自动选择的这个版本),然后编译器告诉我WebMvcConfigurerAdapter已过时了 @Deprecated public abstract cl ...

  10. Python-JS中的事件详解

    目录 fdf!! fefd 一.JS中的事件二.JS中的事件分类: 1.事件初级: 2.事件参数 Event 3.鼠标事件 4.键盘事件 *** 5.表单事件 *** 6.文档事件 * 7.图片事件 ...