利用Arena Allocation避免HBase触发Full GC

Arena Allocation,是一种GC优化技术,它可以有效地减少因内存碎片导致的Full GC,从而提高系统的整体性能。本文介绍Arena Allocation的原理及其在Hbase中的应用-MSLAB。

背景

假设有1G内存,我顺序创建了1百万个对象,每个对象大小1K,Heap会被渐渐充满且每个对象以创建顺序相邻。此时,如果我释放50万个奇数对象,即 1 3 5 7后,剩余空间会多出500M,而这段内存空间就不再连续了。问题出现?
如果我打算new一个2K大小的对象,JVM将无从分配它,因为找不到连续可用的内存空间来容纳这个对象,就算Heap当时还有500M的剩余空间,也无能为力。最终,JVM会选择触发Full GC重新压缩内存使之连续,然后再分配。

结论:触发Full GC,并不只有在内存满或达到触发比例的时候,还有可能是因为内存碎片。

产生内存碎片的主要原因是:

  • 分配的大小不一。
  • 分配的空间不连续。
    如何检测因内存碎片触发了Full GC?
    通过启动java时,添加 -XX:PrintFLSStatistics=1 参数来打印每次gc前后的Heap余量。较大的余量,可以怀疑Heap中存在内存碎片过多。
    另外这篇blog有更详细的图文解释:

http://www.cloudera.com/blog/2011/02/avoiding-full-gcs-in-hbase-with-memstore-local-allocation-buffers-part-2/

HBase中的内存碎片

HBase为了提高写入性能,为每个region添加了一个内存写缓存-Memstore。当单个Memstore的大小达到memstore.size或Heap内存达到hbase.regionserver.global.memstore.upperLimit/lowerLimit百分比限制时,就会触发整个region的flush,最终将所有数据写入HDFS并释放region下所有Memstores占用的内存(GC不一定及时)。

Region flush导致内存碎片的示意图:

左边五颜六色的是不同的region在内存中的位置,它是无序的,因为客户端的请求是无规律的。此时假设黄色的region触发了flush,那么右边将会出现与之对应的多个空洞,即内存碎片。这张图以region为粒度,仅仅是为了更直观地表示这种现象。真实场景中,这些空洞是更细粒度的KeyValue级对象,它能直接导致创建对象时触发Full GC。

Arena Allocation

Arena Allocation是一种非传统的内存管理方法。它通过顺序化分配内存,内存数据分块等特性使内存碎片粗化,有效改善了内存碎片导致的Full GC问题。

它的原理:

  • 创建一个大小固定的bytes数组和一个偏移量,默认值为0。
  • 分配对象时,将新对象的data bytes复制到数组中,数组的起始位置是偏移量,复制完成后为偏移量自增data.length的长度,这样做是防止下次复制数据时不会覆盖掉老数据(append)。
  • 当一个数组被充满时,创建一个新的数组。
  • 清理时,只需要释放掉这些数组,即可得到固定的大块连续内存。
    在Arena Allocation方案中,数组的大小影响空间连续性,越大内存连续性越好,但内存平均利用率会降低。

HBase的解决方案-MSLAB

MSLAB,全称是 MemStore-Local Allocation Buffer,是Cloudera在HBase 0.90.1时提交的一个patch里包含的特性。它基于Arena Allocation解决了HBase因Region flush导致的内存碎片问题。

MSLAB的实现原理(对照Arena Allocation,HBase实现细节):

  • MemstoreLAB为Memstore提供Allocator。
  • 创建一个2M(默认)的Chunk数组和一个chunk偏移量,默认值为0。
  • 当Memstore有新的KeyValue被插入时,通过KeyValue.getBuffer()取得data bytes数组。将data复制到Chunk数组起始位置为chunk偏移量处,并增加偏移量=偏移量+data.length。
  • 当一个chunk满了以后,再创建一个chunk。
  • 所有操作lock free,基于CMS原语。
    优势:
  • KeyValue原始数据在minor gc时被销毁。
  • 数据存放在2m大小的chunk中,chunk归属于memstore。
  • flush时,只需要释放多个2m的chunks,chunk未满也强制释放,从而为Heap腾出了多个2M大小的内存区间,减少碎片密集程度。
    开启MSLAB

hbase.hregion.memstore.mslab.enabled=true // 开启MSALB
hbase.hregion.memstore.mslab.chunksize=2m // chunk的大小,越大内存连续性越好,但内存平均利用率会降低
hbase.hregion.memstore.mslab.max.allocation=256K // 通过MSLAB分配的对象不能超过256K,否则直接在Heap上分配,256K够大了

本文来源于"阿里中间件团队播客",原文发表时间" 2011-06-22  "

时间: 2024-09-10 13:03:57

利用Arena Allocation避免HBase触发Full GC的相关文章

gc-通过Java RMI的定时GC触发,JVM垃圾回收就无法自动触发FULL GC了吗?

问题描述 通过Java RMI的定时GC触发,JVM垃圾回收就无法自动触发FULL GC了吗? Java RMI的定时GC触发机制,可通过:-XX:+DisableExplicitGC来禁止或通过 -Dsun.rmi.dgc.server.gcInterval=3600000来控制触发的时间. 那么问题来了堆栈内存满了,是否就不会自动触发FULL GC了. 目前系统几次宕机,看内存监控均为堆栈满了,但是没能触发FULL GC. 看应用服务启动配置中有Dsun.rmi.dgc.server.gcI

如何利用mapreduce批量读写hbase数据

package com.mr.test; import java.io.IOException; import java.util.Iterator; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.KeyValue; imp

Hbase 学习(五) 调优

1.垃圾回收器调优 当我们往hbase写入数据,它首先写入memstore当中,当menstore的值大于hbase.hregion.memstore.flush.size参数中设置的值后,就会写入硬盘. 在hbase-env.sh文件中,我们可以设置HBASE_OPTS或者HBASE_REGIONSERVER_OPTS,后者只影响region server进程. export HBASE_REGIONSERVER_OPTS="-Xmx8g -Xms8g -Xmn128m -XX:+UsePar

HBase GC的前生今世 – 演进篇

最原始的HBase CMS GC相当严重,经常会因为碎片过多导致Promotion Failure,严重影响业务的读写请求.幸运的是,HBase并没有止步不前,很多优化方案相继被提出并贡献给社区,本文要介绍的就是几个比较重要的核心优化,分别是针对Memstore所作的两个优化:Thread-Local Allocation Buffer和MemStore Chunk Pool 以及针对BlockCache所作的优化:BucketCache方案.在详细介绍这几个优化之前有必要简单介绍一下HBase

HBase GC的前生今世 – 身世篇

在之前的HBase BlockCache系列文章中已经简单提到:使用LRUBlockCache缓存机制会因为CMS GC策略导致内存碎片过多,从而可能引发臭名昭著的Full GC,触发可怕的'stop-the-world'暂停,严重影响上层业务:而Bucket Cache缓存机制因为在初始化的时候就申请了一片固定大小的内存作为缓存,缓存淘汰不再由 JVM管理,数据Block的缓存操作只是对这篇空间的访问和覆盖,因而大大减少了内存碎片的出现,降低了Full GC发生的频率.那CMS GC策略如何导

触发JVM进行Full GC的情况及应对策略

堆内存划分为 Eden.Survivor 和 Tenured/Old 空间,如下图所示: 从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC,对老年代GC称为Major GC,而Full GC是对整个堆来说的,在最近几个版本的JDK里默认包括了对永生带即方法区的回收(JDK8中无永生带了),出现Full GC的时候经常伴随至少一次的Minor GC,但非绝对的.Major GC的速度一般会比Minor GC慢10倍以上.下边看看有那种情况触发JVM进行Fu

怎么利用 java api 实现 solr+hbase+Lily HBase Indexer 实现全文搜索?

问题描述 怎么利用javaapi实现solr+hbase+LilyHBaseIndexer实现全文搜索?哪位大哥可以给个例子参考参考 解决方案 解决方案二:你好 楼主,你问的问题得到解决了么,我现在也在关注这个啊,交流一下啊

JVM内存管理及GC机制

一.概述 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢.经过这么长时间的发展,Java GC机制已经日臻完善,几乎可以自动的为我们做绝大多数的事情. 虽然java不需要开发人员显示的分配和回收内存,这对开发人员确实降低了不少编程难度,但也可能带来一些副作用: 1. 有可能不知不觉浪费了很多内存 2. JVM花

HBase性能调优

因官方Book Performance Tuning部分章节没有按配置项进行索引,不能达到快速查阅的效果.所以我以配置项驱动,重新整理了原文,并补充一些自己的理解,如有错误,欢迎指正. 配置优化 zookeeper.session.timeout默认值:3分钟(180000ms)说明:RegionServer与Zookeeper间的连接超时时间.当超时时间到后,ReigonServer会被Zookeeper从RS集群清单中移除,HMaster收到移除通知后,会对这台server负责的region