`
半点玻璃心
  • 浏览: 26561 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

HBase Memstore配置

阅读更多
HBase Memstore配置
本文为翻译,原英文地址:http://blog.sematext.com/2012/07/16/hbase-memstore-what-you-should-know/
    当regionserver(以下简称RS)收到一个写请求,会将这个请求定位到某个特定的region。每个region存储了一系列的row,每个row对应的数据分散在一个或多个ColumnFamily(以下简称CF)中 。特定CF的数据都存储在对应的store里面,而每个store都由一个memstore和数个storefile组成。memstore存储在RS的内存中,而storefile则存储在HDFS上。当一个写请求到达RS的时候,该请求对应的数据首先会被memstore存储,直到达到一定的临界条件(显然,主存需要良好的控制),memstore里面的数据才会flush到storefile。
    使用memstore的主要原因是为了使存储在DFS上的数据是有序的(按row) 。DFS设计为顺序读写的,已有的文件不能被修改。这就意味着,因为hbase收到的写请求是无序的,所以如果直接将这些数据写到DFS上,以后再对文件里面的内容做排序就是一件极其困难的事情;无序的数据存储方式,又会大大影响后续的读请求性能。为了解决这种问题,hbase会将最近的某些写请求放到内存中(也就是memstore),并将这些数据在flush到storefile之前做好排序。
    当然,除了解决排序的问题,memstore还有其他很多额外的好处,比如:
它能充当memcache的角色,缓存最近写入的数据。鉴于新数据的访问频率和几率都比一般比旧数据高很多,这就大大的提高客户端的读效率。
在数据持久化到DFS之前,还能做一些其他的优化操作。比如,某一个row下面提交了多次数据,而实际上根据表设计,我们只需要持久化存储其中最近一次或几次的内容,在刷新之前,通过memstore就可以把多余的数据屏蔽,提高写数据的性能。   
     
    注意,每个memstore每次刷新时,都会给每个CF生成一个storefile.
    剩下读取就非常容易了,hbase会检查数据是否在memstore里面,否则就去storefile读取,然后返回给客户端。.

What to Care about

    为了更好的使用hbase,开发人员和管理人员必须了解memstore是什么以及它如何工作,因为:

有很多与memstore相关的配置选项会大大提升hbase运行效率,避免出现问题。但是hbase本身不会根据你的使用方式和场景自动优化参数。
频繁的memstore flush会影响到读取的性能,也会给系统带来额外的开销。
memstore的flush机制会影响你的数据表设计。
    让我们进一步的说明下这些问题。
Configuring Memstore Flushes
    一般来说,有两类配置选项(先不关注由于region关闭导致的强制刷新):

首先,何时应该触发flush?
其次,什么时候触发的flush会block写请求
    第一类是关于“常规的”flush,这一类flush触发时还能并行的响应写请求。这一类的配置如下:

hbase.hregion.memstore.flush.size
<property>
    <name>hbase.hregion.memstore.flush.size</name>
    <value>134217728</value>
    <description>
            memstore的大小超过该限制(单位:byte)后将被flush到磁盘。这个大小由一个线程间断性的检查,检查的间隔由
            hbase.server.thread.wakefrequency决定
    </description>
</property>
base.regionserver.global.memstore.lowerLimit
<property>
    <name>hbase.regionserver.global.memstore.lowerLimit</name>
    <value>0.35</value>
    <description>
        一个RS中所有的memstore的总容量超过堆的该百分比限制后,将被强制flush到磁盘。
        Maximum size of all memstores in a region server before flushes are forced. Defaults to 35% of heap. 这个值与
        hbase.regionserver.global.memstore.upperLimit相等,以减小由于到达该值触发flush的几率,因为这种flush会block写请求
    </description>
</property>
    注意,第一条设置是针对于每一个memstore。设置该值的的时候,你需要计算一下每台RS上的region数量。随着RS的数量增加(而且你只在RS数量较少的时候设置了该值),memstore flush可能会由于第二条设置提前触发。Note that the first setting is the size per Memstore. I.e. when you define it you should take into account the number of regions served by each RS. When number of RS grows (and you configured the setting when there were few of them) Memstore flushes are likely to be triggered by the second threshold earlier.

    第二类的设置主要是针对安全性的考虑。有的时候写负载非常高,flush的速度会跟不上。我们也不想memstore无限制的增长,因此这种情况下,写请求会被阻塞,直到memstore回归到一个可控的大小。这些临界值配置如下:Second group of settings is for safety reasons: sometimes write load is so high that flushing cannot keep up with it and since we don’t want memstore to grow without a limit, in this situation writes are blocked unless memstore has “manageable” size. These thresholds are configured with:

hbase.regionserver.global.memstore.upperLimit
<property>
    <name>hbase.regionserver.global.memstore.upperLimit</name>
    <value>0.4</value>
    <description>
        一个region中所有memstore的总大小超过堆的该百分比限制时,会发生强制flush,并block更新请求。
        默认是堆大小的40%。更新会被阻塞,并发生强制flush,直到所有memstore的大小达到
        hbase.regionserver.global.memstore.lowerLimit的限制。
    </description>
</property>
hbase.hregion.memstore.block.multiplier
<property>
    <name>hbase.hregion.memstore.block.multiplier</name>
    <value>2</value>
    <description>
        当一个region的memstore达到hbase.hregion.block.memstore * hbase.hregion.flush.size的指定倍数时,阻塞写请求。
        这是一个避免在写请求高峰时期避免memstore耗尽的有效设置。如果没有上限限制,memstore被填满后发生flush时,
        会消耗大量的时间来处理合并和分割,甚至导致OOM。
    </description>
</property>
    阻塞一个RS上的写请求会导致严重的结果,比你想象得到的更严重。由于hbase设计为一个region仅有一个RS提供,而写负载被均衡的分摊到整个集群(跨region),一个“低速”的RS会降低整个集群的性能。


    注意:留意memstore的大小和memstore flush队列的大小。memstore大小理论上不能超多upperLimit限制,而且不要让memstore flush队列持续增长。

Frequently Memstore Flushes
    既然我们想避免写请求block的发生,那么尽早的触发flush,而不是等待达到产生写阻塞flush的条件不失为一种好的办法。但是,过于频繁的flush也会带来一些读性能的损失,以及集群的额外负载。

    每次,每个memstore flush会为每个CF生成一个storefile,频繁的flush会产生成千上万的storefile,那么每次读请求都需要寻找很多的storefile,读效率就可想而知了。

    storefile合并操作是为了避免打开过多的storefile以致读效率恶化。Hbase会周期性的(或者达到配置的临界值)将较小的storefile合并成一个较大的。显然,flush的时候产生的storefile越多,那么所需的额外工作量和开销也就越多,更甚者,通常合并操作与请求操作并行,hbase如果跟不上合并的速度,同样也会block RS上的写请求。鉴于上面的结果,这是我们非常不愿意见到的情况。

    注意:留意RS上的合并任务队列。某些时候队列持续增长的话你需要多加注意,以免造成问题。

More on HFiles creation & Compaction can be found here.

    理论上,memstore在不超过upperLimit的条件下应该尽可能的使用内存。So, ideally Memstore should use as much memory as it can (as configured, not all RS heap: there are also in-memory caches), but not cross the upper limit.

Multiple Column Families & Memstore Flush
    所有CF的memstore会一起flush,这就意味着每次flush会产生N个storefile,每个CF产生一个。因此,不平衡的CF数据大小会导致产生过多storefile:当memstore中的某一个CF数据量达到阈值,会导致其他所有memstore里面的其他CF也发生flush。过于频繁的flush和过多的storefile会影响集群的性能。

    注意:大多数情况下,一个表只有一个CF是比较良好的设计方案。

HLog (WAL) Size & Memstore Flush
    你可能已经留意到,RS上有一个 Write-ahead Log (以下简称WAL),数据会持续的默认写到这个文件中。它包含了所有已经提交到RS的,已经保留在memstore中但是尚未flush到storefile的数据编辑历史。这些在memstore中的,尚未持久化的数据,在RS发生错误时我们需要借助它进行恢复,它能重现这些尚未持久化的数据的编辑轨迹。.

    当WAL(Hlog)变得非常大时,重现它的记录会花费非常多的时间。因此,我们需要限制WAL的大小,当达到这个大小时,会触发memstore的flush。当数据flush到磁盘后,WAL的大小就会变小,因为我们不需要再保存这些已经完成持久化的数据编辑记录。有两个属性用于配置这个条件:hbase.regionserver.hlog.blocksize 和 hbase.regionserver.maxlogs. 可能你已经发现了,WAL的最大容量由 hbase.regionserver.maxlogs * hbase.regionserver.hlog.blocksize (默认2GB by default) 决定.当达到这个容量的时候,memstore flush 就会被触发。因此,你在调整memstore的的设置的时候,你同样需要调整这些值来适应那些变化。否则,WAL容量达到限制可能是导致memstore flush的罪魁祸首,你专门配置memstore参数所增加的资源可能永远无法被物尽其用。除此以外,用WAL的容量来决定是否触发 memstore flush并不是一种最好的方式,因为一次性大批量flush多个region数据,会给你带来“风暴”一般的感受。

    注意:确保hbase.regionserver.hlog.blocksize * hbase.regionserver.maxlogs 比hbase.regionserver.global.memstore.lowerLimit * HBASE_HEAPSIZE的值只高那么一点点。.

Compression & Memstore Flush
    hbase建议将存储在HDFS上的文件进行压缩,可以节省可观的磁盘存储和网络传输成本。但是当数据flush到storefile的时候,Compression 压缩并不会大幅度降低flush的效率,否则我们遇到上述的很多问题。Data is compressed when it is written to HDFS, i.e. when Memstore flushes. Compression should not slow down flushing process a lot, otherwise we may hit many of the problems above, like blocking writes caused by Memstore being too big (hit upper limit) and such.

注意:当选择压缩的方式时,应当更关心压缩速度而不是压缩率。SNAPPY是一种不错的选择。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics