HBase发展到现在,各种优化从未停止,GC优化更是重中之重,比如0.94版本提出的MemStoreLAB,MemStore Chunk Pool策略对写缓存MemStore进行优化开始,到0.96版本提出的BucketCache对外内存方案对读缓存BlockCache的优化等,然而无论什么对外内存,都无法避免使用JVM 内存。

一 CMS GC的工作原理

1.1 整个JVM内存由Young区、Tenured区和Perm区三部分组成,其中Young区又分为一个Eden区和两个Survivor区

1.2 整个对象生命周期简要说明:

Young区:一个对象初始化之后,首先会进入Eden区,当Eden区满之后会触发一次Minor GC,Minor GC会检查Eden区所有对象是否依旧存活(是否有其他对象引用),如果存活,会将其从Eden区拷贝到Survivor区,并将这些存活对象的age加一,而死亡的对象会被作为垃圾回收。此时Eden区又空闲出来,等新对象填充,填充满之后再会触发Minor GC,如此往复。需要注意的是,每执行一次Minor GC,存活对象的age就会加一。

Tenured区:一旦存活对象的age超多一定阈值就会晋升到Tenured区,因此可以理解为Tenured区一般存放长寿对象。很显然,随着时间流逝,Tenured区也会被填充满,此时就会触发CMS GC(old gc),这种GC相对比较复杂,由5个步骤组成,详见参考文章。

1.3 无论是Minor GC还是CMS GC,都会’Stop-The-World’,即停止用户的一切线程,只留下gc线程回收垃圾对象。其中Minor GC的STW时间主要耗费在复制阶段,CMS GC的STW时间主要耗费在标示垃圾对象阶段。

二 GC 调优目标

1. 平均Minor GC时间尽可能短。因为整个Minor GC都处于STW,因此短时间Minor GC会使用户读写更加平稳,延迟可控。

2. CMS GC次数越少越好。时间越短越好。一方面是因为一次CMS GC一般都会引起至少秒级的应用暂停,对用户读写影响较大;另一方面频繁的CMS GC会产生大量的内存碎片,严重的时候会引起Full GC,导致RegionServer宕机。

三 CMS GC优化技巧

3.1 CMS GC所涉及到的相关参数

通过上文对各个GC参数的说明,可以轻松得出第一阶段推荐的参数设置如下,这样的设置基本适用于所有的场景:

-XX:+UseConcMarkSweepGC -XX:+UseParNewGC  -XX:+CMSParallelRemark

Enabled -XX:+UseCMSCompactAtFullCollection -XX:+UseCMSInitiatingOccup

ancyOnly -XX:CMSInitiatingOccupancyFraction=75%-XX:-DisableExplicitGC

3.2 GC 日志分析

GC日志分析

介绍完实验基本条件后,再对GC日志进行简单的解释,方便下文对日志进行分析。需要注意只有在添加参数-XX:+PrintTenuringDistribution才能打印对应日志,强烈建议线上集群开启该参数,日志片段如下:

第一部分:基本信息区,主要有两点需要重点关注,其一是Desired survivor size 268435456 bytes,表示Survivor区大小为256M;其二是new threshold 5 (max 15),表示对象晋级老生代的最大阈值为15,但是因为Survivor区太小导致age大于5的对象会直接溢出晋级老生代(也有可能是阈值设置太大)

第二部分:不同age对象分布区,第一列表示该Young区共分布有age在1~6的对象;第二列表示所在age含有的对象集所占内存大小,比如age为2的所有对象总大小为80236520 bytes;第三列表示小于对应age的所有对象占用内存的累加值,比如age2对应第二列137759704 total表示age为1和age为2的所有对象总大小;

第三部分:内存回收信息区,第一列表示Young区的内存回收情况,1268903K->305311K表示Young区回收前内存为1268903K,回收后变为305311K;第二列表示Jvm Heap的内存回收情况,26598675K->25635082K(66584576K) 表示当前Jvm总分配内存为66584576K,回收前对象占用内存为26598675K,回收后对象占用内存为25635082K;第三列表示回收时间,其中real表示本次gc所消耗的STW时间,即用户业务暂停时间。

3.3 HBase场景内存分析

通常来讲,每一种应用都有自己的内存对象特征,分类来讲无非两种:

一种是短寿命对象(存活时间较短的对象,比如临时变量居多等);

一种是长寿命对象(存活时间较长的对象,比如TTL设置较长的缓存对象)的系统,比如HBase或者Spark这种大内存工程。以HBase为例:

# RPC请求对象:比如request对象和response对象,一般这些对象会随着短连接RPC的销毁而消亡,这些可以认为是寿命较短的对象

# MemStore对象: HBase中MemStore中对象一般会持续存活较长时间,用户写入数据到MemStore中之后对象就一直在,直到Mem

Store写满之后flush到HDFS.一般写入QPS较高的情况下写满MemStore也通常需要一个小时左右,可见MemStore对象肯定是长寿命对象,另外MemStore对象默认比较大2M

# BlockCache对象: 和MemStore对象一样,BlockCache对象一般也会在内存存货较长时间,属于长寿命对象,这中对象默认64K大小

因此可以看出,HBase系统属于长寿对象居多的工程,因此GC的时候只需要将RPC这类短寿对象在Young区淘汰掉就可以达到最好的GC效果。

四 NewParSize调优

4.1 理论分析

NewParSize表示young区大小,而Young区大小决定了Minor GC的频率,Young区越大,Minor GC越少,GC时间越长,相同时间内晋升到老年代的对象越少;Young区越小,Minor GC越多,GC时间越短,晋升为老年代的对象越多(age不断加1导致很快超过阀值)

# 增大Young区大小,Minor GC频率降低,单次GC时间越长(Young区大了,一次GC复制的对象更多,耗时所以就更长),业务读写操作延迟抖动较大。反之,业务读写操作抖动较小,比较平稳。

# 减小Young区大小,Minor GC频率增加,单次GC时间越短,但会加快晋升老年代的对象总量(每GC一次,对象age就会加一,当age超过阈值就会晋升到老年代,因此GC频率越高,age就增加越快),潜在增加老年代GC 风险

因此设置NewParSize需要进行一定的平衡,不能设置太大,也不能设置太小

4.2 实验结果

三台RegionServer分别设置Xmn为512m、2g、5g,Xmn越大,分配的Young区越大;SurvivorRatio和MaxTenuringThreshold取默认值

测试结果基本和理论分析一致,Xmn设置过小会导致CMS GC性能较差,而设置过大会导致Minor GC性能较差,因此建议在JVM Heap为64g以上的情况下设置Xmn在1~3g之间,在32g之下设置为512m~1g;具体最好经过简单的线上调试;需要特别强调的是,笔者在很多场合都看到很多HBase线上集群会把Xmn设置的很大,比如有些集群Xmx为48g,Xmn为10g,查看日志发现GC性能极差:单次Minor GC基本都在300ms~500ms之间,CMS GC更是很多超过1s。在此强烈建议,将Xmn调大对GC(无论Minor GC还是CMS GC)没有任何好处,不要设置太大。

五 增大Survivor区大小(减小SurvivorRatio) & 增大MaxTenuring

Threshold

5.1 理论分析

我们知道,一次Minor GC会将Eden(伊甸)区包括Survivor from区 复制到 Survivor to区,因此增大Survivor区可以容纳更多的存活对象。这样就会防止因为Survivor区太小导致很多存活对象还没有达到MaxTenuringThreshold阀值就直接进入到了老年代,潜在增大老年代GC的触发频率

但是Survivor区设置太大也有问题,使得对象可以在Young区待很长时间,但是对于一些存活时间较长的对象较多的场景比如HBase,大量的对象待在Young区会做很多无谓的复制,一定程度上增加Minor GC开销

另外,增加MaxTenuringThreshold相当于提高了对象进入老年代的门槛,可以有效的限制进入老年代的数量。和Survivor相似,调整这个参数也需要做一些取舍,设置太小会增加老年代CMS GC触发频率以及耗时,而设置太大大量的对象待在Young区会做很多无谓的复制,一定程度上增加Minor GC开销。一般情况下,默认的MaxTenuringThreshold=15已经很大了,不需要做任何调整。

5.2 实验结果

三台RegionServer分别设置SurvivorRatio为2、8、15,SurvivorRatio越大,Survivor区大小越小;MaxTenuringThreshold取默认值;其他:-Xmx64g,-Xmn2g

1. 图一是SurvivorRatio在三种不同场景下对应的GC性能曲线图,大体可以看出蓝线Minor GC次数最多,绿线尖峰太多,即CMS GC性能最差;具体细节再来看图二和图三。

2. 图二主要统计Minor GC主要指标:平均单次Minor GC耗时三者基本相当,SurvivorRatio:2场景下稍微较高,这是因为SurvivorRatio=2对应的Survivor区较大,可以使得对象在Young区’待’的时间很长,在HBase这种长寿对象较多的情况下,可能会增加一些无谓的‘复制’开销(下文会通过日志分析详细解释)。另外,SurvivorRatio=2场景下Minor GC频率也比较高,可能的原因是因为在总Young大小确定的情况下,Survivor越大,Eden自然越小,Minor GC频率就会增大。可见,SurvivorRatio=2场景下Minor GC性能相对稍微较差。

3. 图三主要统计CMS GC主要指标:三者CMS GC次数基本相当,SurvivorRatio=2场景下单次CMS GC耗时最少,相比SurvivorRatio=8的场景耗时减少30%左右,性能最好;而相比之下SurvivorRatio=15场景下耗时最长,性能相当差;这是因为SurvivorRatio=2场景下存活对象可以长时间待在Young区,可以得到充分的淘汰,晋升到老生代的短寿小对象会比较少,因而CMS GC性能较好;相比SurvivorRatio=15会因为Survivor区设置太小,很多短寿小对象因为得不到充分的淘汰就会‘溢出’到老生代,导致CMS性能很差。

可见,测试结果基本和理论分析也基本一致,对于Minor GC来说,SurvivorRatio设置对其影响不是很大。而对于CMS GC来说,将SurvivorRatio设置过大简直就是灾难,性能极其差。而和默认值SurvivorRatio=8相比,将SurvivorRatio调大有利于短寿小对象更充分地淘汰,因此建议将SurvivorRatio=2

六 CMS GC 调优参数结论

缓存模式采用BucketCache策略Offheap模式

对于大内存(大于64G),采用如下配置:

-Xmx64g -Xms64g -Xmn2g -Xss256k

-XX:MaxPermSize=256m

-XX:+SurvivorRatio=2

-XX:+UseConcMarkSweepGC

-XX:+UseParNewGC

-XX:+CMSParallelRemarkEnabled

-XX:+MaxTenuringThreshold=15

-XX:+UseCMSCompactAtFullCollection

-XX:+UseCMSInitiatingOccupancyOnly

-XX:CMSInitiatingOccupancyFraction=75

-XX:-DisableExplicitGC

小于64G的内存

-Xmx32g -Xms32g -Xmn1g -Xss256k

-XX:MaxPermSize=256m

-XX:+SurvivorRatio=2

-XX:+UseConcMarkSweepGC

-XX:+UseParNewGC

-XX:+CMSParallelRemarkEnabled

-XX:+MaxTenuringThreshold=15

-XX:+UseCMSCompactAtFullCollection

-XX:+UseCMSInitiatingOccupancyOnly

-XX:CMSInitiatingOccupancyFraction=75

-XX:-DisableExplicitGC

HBase之CMS GC调优相关推荐

  1. 大数据技术之_19_Spark学习_07_Spark 性能调优 + 数据倾斜调优 + 运行资源调优 + 程序开发调优 + Shuffle 调优 + GC 调优 + Spark 企业应用案例

    大数据技术之_19_Spark学习_07 第1章 Spark 性能优化 1.1 调优基本原则 1.1.1 基本概念和原则 1.1.2 性能监控方式 1.1.3 调优要点 1.2 数据倾斜优化 1.2. ...

  2. Java9中的GC 调优

    垃圾收集器与内存分配策略参考目录: 1.判断Java 对象是否死亡 2.Java 中的四种引用 3.垃圾收集算法 4.内存分配与回收策略 在经过了几次跳票之后,Java 9终于在原计划日期的整整一年之 ...

  3. 一张PDF了解JDK9 GC调优秘籍-附PDF下载

    文章目录 简介 Oracle中的文档 JDK9中JVM参数的变化 废弃的JVM选项 不推荐(Deprecated)的JVM选项 被删除的JVM参数 JDK9的新特性Application Class ...

  4. 八张图彻底了解JDK8 GC调优秘籍-附PDF下载

    文章目录 简介 分代垃圾回收器的内存结构 JDK8中可用的GC 打印GC信息 内存调整参数 Thread配置 通用GC参数 CMS GC G1参数 总结 简介 JVM的参数有很多很多,根据我的统计JD ...

  5. 谈谈你的GC调优思路?

    基本的调优思路可以总结为: 理解应用需求和问题,确定调优目标.假设,我们开发了一个应用服务,但发现偶尔会出现性能抖动,出现较长的服务停顿. 评估用户可接受的响应时间和业务量,将目标简化为,希望GC暂停 ...

  6. Java 9 中的 GC 调优基础

    转载自   Java 9 中的 GC 调优基础 在经过了几次跳票之后,Java 9终于在原计划日期的整整一年之后发布了正式版.Java 9引入了很多新的特性,除了闪瞎眼的Module System和R ...

  7. 一文看尽 JVM GC 调优

    一个著名的学习方法论 向橡皮鸭求助 学会提问,提问也是一门艺术 提问前,先投入自己的时间做好功课 发生了什么事情 问题的基本情况 你投入的研究和发现 能正确提出你的问题,你的问题差不多已经解决一半 深 ...

  8. 深入JVM系列(二)之GC机制、收集器与GC调优

    一.回顾JVM内存分配 需要了解更多内存模式与内存分配的,请看 深入JVM系列(一)之内存模型与内存分配 1.1.内存分配: 1.对象优先在EDEN分配 2.大对象直接进入老年代  3.长期存活的对象 ...

  9. GC调优在Spark应用中的实践

    摘要:Spark立足内存计算,常常需要在内存中存放大量数据,因此也更依赖JVM的垃圾回收机制.与此同时,它也兼容批处理和流式处理,对于程序吞吐量和延迟都有较高要求,因此GC参数的调优在Spark应用实 ...

最新文章

  1. 一步一步SharePoint 2007之十二:实现Form认证(2)——创建添加管理帐户的工程
  2. Android Message解析
  3. mysql 查找密码忘记,Mysql的Root密码忘记,查看或修改的解决方法(图文介绍)
  4. POJ 3281 -- Dining(最大流,拆点建图)
  5. C#中的thread和task之 Thread ThreadPool
  6. java精准查询mysql时间_在mysql查询中查找与指定日期时间最接近的日期时间
  7. 批量无损删除项目中的代码注释方法
  8. html中iframe根据子页面内容动态修改高度
  9. Redis安装及配置(Linux)
  10. Node.js webpack 打包的入口与出口
  11. wordpress rest api 漏洞又来了CVE-2017-5487 上次是修改文章内容这次可是泄露用户数据...
  12. 雅虎14条性能优化原则
  13. Django组件 中间件
  14. 【数据结构】顺序线性表的几种常用方法
  15. allure测试报告
  16. 中小企业信息化规划案例--初级篇
  17. 抓取scrapy中文文档 第一个Scrapy项目实现
  18. 201671030113 词频统计软件项目报告
  19. win10升级助手_Win10自带杀毒软件如此强大,大家却不爱用,究竟是为什么呢?...
  20. 【Windows编程】实时捕捉屏幕

热门文章

  1. oracle if 使用函数,Oracle 常见函数用法
  2. JavaScript基本数据类型讲解
  3. levedb 导入 mysql_[LevelDB] 数据库3:循序渐进 —— 操作接口
  4. 常用概率论矩阵论公式
  5. cad坐标归零lisp_「软件技巧」厉害了!输入简单命令轻松解决CAD几类常见问题...
  6. 基于参考点的非支配遗传算法-NSGA-III(二)
  7. c#学习总结(一)---Mr.Zhang
  8. python //运算符
  9. 时序模型预测结果:DM检验含义与python实现
  10. django保存表单数据到数据库中