从Solr卡顿到G1垃圾回收
开源搜索引擎Solr是一款非常优秀的搜素引擎,只要一些简单的配置就能进行使用,大大减少了开发时间。
在我工作的环境中,整站的商品搜索业务都是依托于Solr,在Solr的使用上沉淀了不少宝贵的开发经验。随着公司商品数据规模不断的扩大,针对Solr的二次开发难度也在不断的增大,在过去的几年时间内,我把大量的数据放在索引构建上,从之前的DB模式24小时都无法完成全量的构建,到现在使用hive + avro + mapreduce把全量构建压缩到3小时以内,从之前的DB增量模式经常出现更新失败,更新延迟,到现在使用kafka+redis的模式保证更新数据不丢实,更新的延迟在1分钟以内。整个全量增量的索引架构都是可以横向扩展。
在索引构建告一段落后,查询又出现了问题,经常可以看到Solr每隔20分钟,会有timeout情况的出现。查看了下日志,在那段报错的时间段,正好是slave从master上获取增量数据的时间(replication配置了每隔20分钟slave replication一次数据到master),而Solr中许多内置的缓存都开的比较大。当数据更新后,Solr会对Cache进行重新的预热,在这个时候,有大量的内存对象会被换入换出,可能在这个点触发了full gc。
为了验证是否是full gc的可能,首先第一步获取full的信息,命令:
使用lsof命令根据端口找出pid(当然linux有很多其他方式,条条大路通罗马),然后使用jstat -gc命令获取信息。图中该Solr程序已经运行了196hrs35min,可以看出FGC一共执行了356次,一共花费6331s,平均一次停顿18s,这种停顿在java中有个专有名词——stop the world(STW),顾名思义在这18秒内,所有的业务代码都会stop给GC让出资源。结合程序启动的时间,平均每30分钟有一次18秒的卡顿,无论solr本身的性能再优越18秒足以让client time,问题也就这样终于被发现了。
由于Solr进程没有进行full gc的制定,所以都是java6的默认配置,java6默认的配置对于Solr这种低延迟的场景显然是不适用的,所以需要选择一款合适的GC。GC的两大标准:吞吐量 & 响应时间。就service来说,响应时间优先级要高于吞吐量,对于上述的垃圾回收而言,串行垃圾回收和并行垃圾回收不适合service的场景,对于CMS和G1,虽然都是以响应时间优先,但是在内部实现上差异很大,G1是oracle唯一还在继续开发优化的垃圾回收器,支持并发并行操作,在保证响应时间的前提下,尽可能的提高了吞吐量,所以更建议对于大型service服务使用G1作为默认的垃圾回收。由于G1在jdk6上还是个不稳定的版本,所以需要将JDK升到7.4以上。
关于G1的介绍有很多,就不介绍了,主要介绍下调优的一些思路
1. 请打开gc log日志
gc log日志在gc调优的过程中非常关键,很多参数的调整都需要以gc log日志的反馈作为根据,从而判断参数是否生效。
参数:-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintAdaptiveSizePolicy -Xloggc:./gc.log
2. 根据gc日志的返回,找到full gc的原因
从上述的GC信息中可以看到,是因为无法分配内存导致FGC的触发。在这里先简答介绍下G1的模型,G1和其他GC算法不同的是,G1使用region把内存分为多块,每个region的大小可以根据-XX:G1HeapGegionSize进行设置,最大不超过32m,每个region有唯一一个角色(unused,young,old),由于Solr需要大量的内存作为cache,所以我将该值设置为最大,即:-XX:G1HeapGegionSize=32m,G1当要为对象申请内存空间的时候,回去region列表中找合适的region进行分配,但是这里有个特殊的场景,当一个内存对象很大,大到一个region无法满足之后,G1会查找一片连续的region用于存放该对象,并且这些region标记为old,跳过young gc。在G1算法内,如果一个对象超过了region的1/2,就认为是一个大对象。再回到上面的日志可以发现,Solr需要申请1个G的内存空间,而由于region的大小为32M,即需要32个连续的region。但是我从内存的使用上来看,申请了100G的内存,实际只使用了30G就出现了这种场景,原因是g1内存分配不适连续分配,导致内存碎片,所以即使还有很多余量,但是无法找到32个连续的region,导致强制执行了fgc。找到了根本原因后就简单了。
3. 参数调整
G1对内存的压缩只在两种情况下进行,第一个中情况是fgc,这种事我们应该尽力避免的,第二种是在初始话标记阶段,所以调优的目标是希望能在适当的时间触发该阶段。在补充了G1的整个执行周期,G1首先上来进行young gc,会清理一部分内存数据,把旧的数据迁移到old region,随着内存不断的增加,每次做完一次young gc后,会根据-XX:InitiatingHeapOccupancyPercent判断是否需要进入初始化标记阶段,所以这个参数在G1大对象调优上非常关键,我最后调整为:-XX:InitiatingHeapOccupancyPercent=30,即到达最大内存的30%开始执行初始化标记。当完成标记后,会进行clean up在clean up阶段old区域的内存会被回收压缩,达到目的。在后面会进入mixed gc,反复执行多次满足条件后再返回到young gc,一个周期就这么完成了。
当然还有很多参数的调整没有给出,但是我觉得还是希望大家自己去研究,很多参数的调整需要针对特殊的业务,千万不可生搬硬套。最后的调整也起到了非常好的效果,从一天上万的报错降低到100个以内,也得到了CTO和其他老大们的肯定。
参考资料
https://blogs.oracle.com/g1gc/entry/g1gc_logs_how_to_print
http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/G1GettingStarted/index.html
https://software.intel.com/en-us/blogs/2014/06/18/part-1-tuning-java-garbage-collection-for-hbase
http://www.oracle.com/technetwork/cn/community/developer-day/2-jdk7-g1-2083344-zhs.pdf
从Solr卡顿到G1垃圾回收相关推荐
- G1垃圾回收算法概述
垃圾回收都是基于分区进行的.G1在实现垃圾回收时一共提供了3种回收的方法,分别是新生代回收(称为Young GC, YGC),混合回收(称为Mixed GC),全回收(称为Full GC, FGC). ...
- 万字长文教你看懂java G1垃圾回收日志
文章目录 一.如何在idea打印G1日志 二.G1基础参数 三.G1新生代收集 1. 四个关键信息 2. 列出了新生代收集中并行收集的详细过程 3.列出了新生代GC中的一些任务: 4.包含一些扩展功能 ...
- 什么是G1垃圾回收算法
转载自 什么是G1垃圾回收算法 为解决CMS算法产生空间碎片和其它一系列的问题缺陷,HotSpot提供了另外一种垃圾回收策略,G1(Garbage First)算法,通过参数 -XX:+UseG1GC ...
- G1垃圾回收日志分析
标准 gc 日志 使用G1垃圾回收器最难的地方是读懂回收日志.G1回收虽然也是分代的,但是打印出来的日志却不像其他回收器那样明显.所以需要好好配置JVM参数才行.先看下面一段日志,这段日志是通过配置好 ...
- 垃圾回收之G1收集过程
G1 中提供了 Young GC.Mixed GC 两种垃圾回收模式,这两种垃圾回收模式,都是 Stop The World(STW) 的. G1 没有 fullGC 概念,需要 fullGC 时,调 ...
- 垃圾回收器之 G1 垃圾回收器
4.4 G1 定义:Garbage First 2004论文发布 2009 JDK 6u14 体验 2012 JDK 7u4 官方支持 2019 JDK9 默认 (废弃了之前的 CMS 垃圾回收器) ...
- Java G1 GC 垃圾回收深入浅出
1. G1概览 G1 GC 全称是Garbage First Garbage Collector,垃圾优先垃圾回收器,以下简称G1.G1是HotSpot JVM的短停顿垃圾回收器.其实关于G1的论文早 ...
- G1垃圾回收器在并发场景调优
一.序言 目前企业级主流使用的Java版本是8,垃圾回收器支持手动修改为G1,G1垃圾回收器是Java 11的默认设置,因此G1垃圾回收器可以用很长时间,现阶段垃圾回收器优化意味着针对G1垃圾回收器优 ...
- 一文搞懂G1垃圾回收器
G1是从JDK9之后的默认垃圾回收器,其功能强大,性能优异,不过目前市面的材料不算多,很多都是抄来抄去,讲得也不太清楚.经过仔细阅读oracle官网以及相关的材料,从整体上梳理了G1的过程,希望这一文 ...
最新文章
- 【swjtu】数据结构实验9_多种排序算法的实现
- DAY9-字符串笔记整理2018-1-19
- Codeforces 374A - Inna and Pink Pony
- 可应用于实际的14个NLP突破性研究成果(三)
- 【原创】MySQL里求给定的时间是所在月份的第几个礼拜
- MySQL无法远程连接解决方案
- 前端开发中,对图片的优化技巧有哪些?
- Nginx配置SSL报错 nginx: [emerg] unknown directive ssl
- EasyBert,基于Pytorch的Bert应用
- 基于python的tensorflow_Python深度学习:基于TensorFlow
- 【报告分享】连锁经营行业全面费用管理数字化白皮书-亿欧汇联易(附下载)
- python 递归 和 动态规划 DP算法两种方法求解 最长回文子串问题
- 朱晔的互联网架构实践心得S1E1:Pilot
- 苹果推送通知办事教程 Apple Pushnb
- NetSuite 未实现汇兑损益
- UltraScale Architecture Clocking Resources
- Android Display 之 HAL Gralloc
- oracle数据库报ora-01691错误--表空间容量溢出解决办法
- Java 基础 --- Java 历史背景、体系特点以及实现原理
- 茂名石化BPM应用实践 ——业务协同及服务共享平台建设和应用
热门文章
- C#调用C++接口 -- delegate实现函数指针
- NPDP-《产品组合管理》
- Ubuntu 20.04增加Deepin源以安装应用商城内最新版的微信、钉钉
- 关于NetKeeper(创翼)升级后,无法共享WIFI问题的解决-猎豹、360都可
- pr字幕模板 炫酷科技蓝色流线条动画pr模板
- java关闭ftp 连接_Java语言实现简单FTP软件------gt;连接管理模块的实现:主机与服务器之间的连接与关闭操作(八) - 移动编程 - ITeye博客...
- 车辆管理与购买系统/车辆管理系统/车辆销售系统
- 手机存储卡文件怎么恢复
- OpenAL的Mingw编译
- 2022 WordPress All Pic Local v0.2 下载外链图片到本地