HBase写入优化--write buff

write buff操作

前两天在观察kafka消费数据的时候,发现HBase偶尔会报一个org.apache.hadoop.hbase.RegionTooBusyException: org.apache.hadoop.hbase.RegionTooBusyException这种错误出来,从描述上看,是HBase写入太过频繁导致的。

首先来看我的写入操作代码:

/**
     * 单条更新hbase数据
     *
     * @param tableName
     *            表名
     * @param put
     *            put对象
     * @return 成功与否
     * @throws IOException
     */
    public synchronized boolean insert(String tableName, Put put) throws IOException {
        Table table = getTable(tableName);
        table.put(put);
        table.close();
        return true;
    }

这种方式写入单条数据,写入情况就是,没过来一条数据,就向HBase的region里面写入一条,操作太频繁。
解决方式:批量写入
首先,在hbase-site.xml配置文件中加入(也可以使用其他配置方式,如代码方式,但是不建议使用代码方式,发布时候还要重新编译,太麻烦):

 <property>
    <name>hbase.client.write.buffer</name>
    <value>5242880</value>
  </property>

设置达到多少时候就行写入。
接着,修改单条写入时候的代码:

public synchronized boolean insert(String tableName, Put put) throws IOException {
        HTable table  = (HTable) getTable(tableName);
        table.setAutoFlushTo(false);
        put.setDurability(Durability.SKIP_WAL);//禁用hbase的预写日志功能
        table.put(put);
        return true;
    }

这样,如果调用这个insert方法,插入数据,虽然成功返回也不报错,但是只是在客户端做一个数据累计,等达到了我设置的5M之后,才进行一次性写入。虽然这样做减少了IO次数和网络传输次数,但是,一旦客户端出错或者HBase有问题,那么这些数据就丢失掉了,对于保证数据绝对不能丢失的这种情况,建议谨慎使用。

write buff分析

  • Put操作
 public void put(Put put) throws IOException {
        this.getBufferedMutator().mutate(put);
        if(this.autoFlush) {
            this.flushCommits();
        }
    }

观察HBase client的api,会发现,这里,如果是autoFlash,会立马执行一个操作,叫做flushCommits,在这个操作里面,会立即将数据写入数据库。
另外,在table进行关闭的时候,也会隐性的将数据写入数据库:

 public void close() throws IOException {
        if(!this.closed) {
            this.flushCommits();
            if(this.cleanupPoolOnClose) {
                this.pool.shutdown();

                try {
                    boolean e = false;

                    do {
                        e = this.pool.awaitTermination(60L, TimeUnit.SECONDS);
                    } while(!e);
                } catch (InterruptedException var2) {
                    this.pool.shutdownNow();
                    LOG.warn("waitForTermination interrupted");
                }
            }

            if(this.cleanupConnectionOnClose && this.connection != null) {
                this.connection.close();
            }

            this.closed = true;
        }
    }

真正的写入操作,其实是发生在:

  public void mutate(List<? extends Mutation> ms) throws InterruptedIOException, RetriesExhaustedWithDetailsException {
        if(this.closed) {
            throw new IllegalStateException("Cannot put when the BufferedMutator is closed.");
        } else {
            long toAddSize = 0L;

            Mutation m;
            for(Iterator i$ = ms.iterator(); i$.hasNext(); toAddSize += m.heapSize()) {
                m = (Mutation)i$.next();
                if(m instanceof Put) {
                    this.validatePut((Put)m);
                }
            }

            if(this.ap.hasError()) {
                this.currentWriteBufferSize.addAndGet(toAddSize);
                this.writeAsyncBuffer.addAll(ms);
                this.backgroundFlushCommits(true);
            } else {
                this.currentWriteBufferSize.addAndGet(toAddSize);
                this.writeAsyncBuffer.addAll(ms);
            }

            while(this.currentWriteBufferSize.get() > this.writeBufferSize) {
                this.backgroundFlushCommits(false);
            }

        }
    }

当当前的数据达到我们设置的buff size的时候,才会进行一个真正的写入操作。

PS:如果想让数据立即写入,可以显示调用flushCommits或者调用close方法。

时间: 2024-08-17 14:53:22

HBase写入优化--write buff的相关文章

hbase 学习(十四)Facebook针对hbase的优化方案分析

使用hbase的目的是为了海量数据的随机读写,但是在实际使用中却发现针对随机读的优化和gc是一个很大的问题,而且hbase的数据是存储在Hdfs,而Hdfs是面向流失数据访问进行设计的,就难免带来效率的下降.下面介绍一下Facebook Message系统在HBase online storage场景下的一个案例(<Apache Hadoop Goes Realtime at Facebook>, SIGMOD 2011),最近他们在存储领域顶级会议FAST2014上发表了一篇论文<An

Hbase写入量大导致region过大无法split问题

最近在线上往hbase导数据,因为hbase写入能力比较强,没有太在意写的问题.让业务方进行历史数据的导入操作,中间发现一个问题,写入速度太快,并且业务数据集中到其中一个region,这个region无法split掉,处于不可用状态.这里描述一整个过程--         事情的起因:业务方按照userid和商品id作为rowkey前缀,并没有进行hash散列.我当时咨询过业务方,认为:1.业务方式按照oracle的rowid顺序来进行迁移的,相对来说对应到rowkey里面就不会集中化:2.即使

Hbase客户端优化

Scan Caching scanner一次缓存多少数据来scan(从服务端一次抓多少数据回来scan). 默认值是 1,一次只取一条. Scan Attribute Selection scan时建议指定需要的Column Family,减少通信量,否则scan操作默认会返回整个row的所有数据(所有Coulmn Family). Close ResultScanners 通过scan取完数据后,记得要关闭ResultScanner,否则RegionServer可能会出现问题(对应的Serve

HBase数据库性能优化总结笔记

垃圾回收优化 master基本不会遇到垃圾回收的问题.由于memstore的刷写机制是不连续的,所以java虚拟机的堆内存会出现孔洞.快速刷写到磁盘的数据会被划分到新生代,这种空间会被优先回收数据停留的时间太长,会被划分到老生代甚至终生代.而且老生代和终生代一般占据了好几个G,而新生代一般就几百M而已 新生代空间由此得出新生代的空间一般的分配如下     -XX:MaxNewSize=128m -XX:NewSize=128m   可以缩写为     -Xmn128m   设定好之后观察是否合理

HBase最佳实践-写性能优化策略

本篇文章来说道说道如何诊断HBase写数据的异常问题以及优化写性能.和读相比,HBase写数据流程倒是显得很简单:数据先顺序写入HLog,再写入对应的缓存Memstore,当Memstore中数据大小达到一定阈值(128M)之后,系统会异步将Memstore中数据flush到HDFS形成小文件. HBase数据写入通常会遇到两类问题,一类是写性能较差,另一类是数据根本写不进去.这两类问题的切入点也不尽相同,如下图所示: 写性能优化切入点 1. 是否需要写WAL?WAL是否需要同步写入? 优化原理

HBase学习笔记——基于HBase的日志系统的性能优化

我之前参与过一个日志系统的开发,存储用HBase.我简单罗列下用到的HBase优化,备忘.以后把它整理成更友好的介绍性文章. 系统简介 有一张大的日志数据表,保存所有日志.row key是 hash + app id + log-severity + timestamp + host等,cell保存日志正文数据. 可以看到row key的hash保证日志散列在各个region中,写入.查询的负载均衡.但是无法通过它进行范围查询,所以为不同查询模式,建立了多张索引表. 为不同的日志级别(DEBUG

HBase最佳实践-读性能优化策略

任何系统都会有各种各样的问题,有些是系统本身设计问题,有些却是使用姿势问题.HBase也一样,在真实生产线上大家或多或少都会遇到很多问题,有些是HBase还需要完善的,有些是我们确实对它了解太少.总结起来,大家遇到的主要问题无非是Full GC异常导致宕机问题.RIT问题.写吞吐量太低以及读延迟较大. Full GC问题之前在一些文章里面已经讲过它的来龙去脉,主要的解决方案目前主要有两方面需要注意,一方面需要查看GC日志确认是哪种Full GC,根据Full GC类型对JVM参数进行调优,另一方

HBase最佳实践-列族设计优化

随着大数据的越来越普及,HBase也变得越来越流行.会用HBase现在已经变的并不困难,然而,怎么把它用的更好却并不简单.那怎么定义'用的好'呢?很简单,在保证系统稳定性.可用性的基础上能够用最少的系统资源(CPU,IO等)获得最好的性能(吞吐量,读写延迟)就是'用的好'.HBase是一个庞大的体系,涉及到很多方面,很多因素都会影响到系统性能和系统资源使用率,根据场景对这些配置进行优化会很大程度上提升系统的性能.笔者总结至少有如下几个方面:HDFS相关配置优化,HBase服务器端优化(GC优化.

HBase - 数据写入流程解析

众所周知,HBase默认适用于写多读少的应用,正是依赖于它相当出色的写入性能:一个100台RS的集群可以轻松地支撑每天10T的写入量.当然,为了支持更高吞吐量的写入,HBase还在不断地进行优化和修正,这篇文章结合0.98版本的源码全面地分析HBase的写入流程,全文分为三个部分,第一部分介绍客户端的写入流程,第二部分介绍服务器端的写入流程,最后再重点分析WAL的工作原理. 客户端流程解析 (1)用户提交put请求后,HBase客户端会将put请求添加到本地buffer中,符合一定条件就会通过A