hbase零碎小记

1)hbase表查行
可以在shell中进行,命令如下:
count ’tablename’,CACHE=>10000,INTERVAL=>10000
CACHE是客户端缓存条数,INTERVAL是分隔多久显示一次结果

上述方法实现是走scan客户端完成,一旦表较大,查起来很慢。

另外一种方式如下:
 bin/hbase org.apache.hadoop.hbase.mapreduce.RowCounter ’tablename’
通过yarn调度mr任务完成查行,速度较快。

2)客户端连接hbase集群时,与zookeeper建立起连接,需要加载两个配置,一个是zookeeper的ip地址,还有是hbase在zookeeper上的根节点。
客户端从zookeeper中获得meta表的地址,然后从meta表中获取表的region在regionserver间的分布,至于数据读写请求则直接发往数据所在的regionserver。
hbase的client端会与zookeeper保持一个长连接,并在其上注册一个watcher,用于检测hbase集群可能发生的变化,包括meta表位置的变化,regionserver的上下线以及region分布的变化等等

3)hbase的bulkload
bulkload是高负载hbase的一种常见的优化方式,简单来说就是先写hdfs文件,然后直接装载到hbase集群,这种数据写入方式不走client端的rpc通信,可以极大地节省集群的I/O
形式上类似于solr的全量创建索引,线下搞定,然后线上只是装载

4)blockcache的大小
  当前blockcache的大小可以从regionserver页的block cache信息栏查看到。
调整参数 hfile.block.cache.size可以修改block cache的大小,默认是0.4,表示使用整个堆大小(hbase-env.sh中配置的-Xmx)的40%作为block cache,当内存紧张时可以考虑调小此值,但是不推荐。
hbase的blockcache机制是采用LRUBlockCache实现的。

5)hbase的IN_MEMORY属性
hbase在LRU缓存基础之上采用了分层设计,整个blockcache分成了三个部分,分别是single、multi和inMemory。三者区别如下:
single:如果一个block第一次被访问,放在该优先队列中;
multi:如果一个block被多次访问,则从single队列转移到multi队列
inMemory:优先级最高,常驻cache,因此一般只有hbase系统的元数据,如meta表之类的才会放到inMemory队列中。普通的hbase列族也可以指定IN_MEMORY属性,方法如下:
create 'table', {NAME => 'f', IN_MEMORY => true}
修改上表的inmemory属性,方法如下:
alter 'table',{NAME=>'f',IN_MEMORY=>true}

6)加载错误的协处理器coprocessor会导致regionserver大面积挂掉
在hbase的源码中,参数hbase.coprocessor.abortonerror默认值是false,当其为true的时候加载了错误的coprocessor后,会导致region server大面积饿down机,为了保证集群的高可用性,可以考虑将参数hbase.coprocessor.abortonerror修改为true

7)一般情况下不建议直接采用kiill -9命令杀死正在运行的regionserver进程,可以采用graceful_stop命令使用优雅重启解决,命令使用姿势如下:
graceful_stop.sh --restart --reload --debug regionserver的host名

如果迫不得已采用kill -9 的方式杀死进程,则应该在杀死进程后尽快采用hbck工具修复集群的region,避免产生数据的不一致:

bin/hbase hbck -repair


8)hbase split的最小单位是rowkey的个数,如果只有少数几个rowkey,即便数据量增上去,但是还是不会发生region split。


9)hbase包含两种coprocessor,分别是observer和endpoint,observer类似于触发器,在发生某些事件(如put、get)的前后触发这些代码执行,

换句话说就相当于用户埋在server端代码的hook。endpoint又可以看做是数据库中的存储过程,它的优势是可以利用服务端的计算资源,有点类似于mapreduce中

移动计算而不是移动数据的设计理念,应用endpoint可以进行数据统计计算,相比传统的方式更加高效。

observer有两种部署方式:

1、全局部署,把jar包路径加入到hbase classpath,并修改hbase-site.xml,这样引入的coprocessor对所有表生效

2、单表部署,通过hbase shell修改表结构,加入coprocessor信息

第二种方式采用alter命令实现,命令格式如下:

alter 'tablename',METHOD=>'table_att','coprocessor'=>'参数列表'

参数列表以|分隔,其依次为:

1、coprocessor jar包的hdfs路径

2、observer主类的完整路径

3、优先级

4、参数(observer主类的输入参数)


10)如果region在做类似于major_compact这种长时间的compact任务时尽量不要执行unassign操作,比如move、split或者disable等等。

这是由于unassign操作涉及到关闭region,如果关闭region时遇到了长时间阻塞的compact或者flush,会导致该region长时间陷入PENDING_CLOSE或者CLOSING状态。


11)hbase的读写性能
hbase是个写快读慢的系统,写较快的原因是hbase的LSM的数据结构决定的,数据写道hbase时并没有直接写到磁盘,而是先写到内存中skip-list结构的一个memstore中,再由其它线程选择较大的memsotre刷写到磁盘中。每一次磁盘刷写都形成了一个StoreFile,StoreFile分层以及minor_compact和major_compact就是后话了。这种数据结构带来的缺点就是读放大,你读一条数据要遍历多个storeFile才能最终确定位置。所以hbase的随机读性能是比较差的。

12) hbase replication中隐藏的一个坑
replication用于在主从集群间同步数据,包括源集群和目的集群,具体原理不在这里展开,需要注意的是使用了replication再关掉的时候,如果仅仅只是disable peer而没有disable replication table,该table的数据仍然会同步出来,此时同步出来的数据会写到集群的zookeeper中去,供下次enable peer的时候,这个时间差的数据能够准确同步到从集群。zookeeper中会积累大量的wal同步过来的数据,因此如果想要彻底地关掉replication,记住table的replication也要关掉。

13)应用snapshot复制一张表
我们假设要复制的表名为testTable,可以按以下流程复制一张新表newTestTable:
首先,将原表打快照:
hbase> snapshot 'testTable','testTableSnapshot'
可以应用list_snapshots列出所有可用快照:
hbase>list_snapshots
应用打出的snapshot复制到新表:
hbase>clone_snapshot ' testTableSnapshot','testTable'
OK,万事大吉

14)如果截取hbase的metrics信息
我们假设regionserver的ip地址是127.0.0.1,那么这台服务器上的metrics信息都保存在 http://127.0.0.1:16030/jmx。
其中16030是regionserver的web端口,向上述URL发送Http请求,可以获得该regionsever的所有metrics信息,这些信息以Json串的形式返回,解析其中的metrics项便可。

15)hbase上使用hbck的一个小坑
hbase挂掉一台regionserver以后,我们往往需要使用hbck命令来修复因为regionserver挂掉导致的region空洞,这里有个小坑,就是不能刚刚拉起regionserver就立刻运行hbck命令,而应该等到该region已经对外提供正常的服务之后,在运行hbck命令,指令顺序如下:
bin/hbase-daemon.sh start regionserver //拉起regionserver
tail -f XXXX_regionserver.log //监控regionserver,观察是否region迁移已完毕
bin/hbase hbck -repair
如果在regionserver还未完全正常服务时就repair,可能会导致数据不一致。

16)hbase的慢节点
hbase当集群出现慢节点的时候可能拖跪整个集群,这是由于慢节点吞掉大量的服务端线程,导致其它请求不能得到响应,进而线程又进一步被占用,出现慢节点的可能情况包括:节点硬件故障、高并发大量的scan请求同时发生等等。

17)hbase的客户端参数
为防止hbase请求超时过长,拖跪业务方应用,建议在使用hbase的时候合理配置客户端的超时时间,目前涉及到的超时时间包括以下三项:
hbase.client.operation.timeout.period:针对get/put/delete/append等常规请求的超时时间,默认是1200000(单位ms),这个超时时间指代的是从请求发出到结果返回的整段时间;
hbase.client.scanner.timeout.period:针对hbase的scan请求超时时间,默认60000(单位ms)
hbase.rpc.timeout:针对rpc请求的超时时间,一次完整的客户端请求中会包含多次rpc请求,默认60000(单位ms)

18)scan场景下客户端应该及时close
hbase中的一次scan请求是划分成多次RPC请求发往服务端的,一次RPC请求获取的数据由scan函数的setCaching指定,scan的总量和caching两者的比值就是一个scan请求中的rpc次数。
scan过程中后面的rpc请求复用前面rpc请求的资源,因此大的scan中客户端会一直持有服务端的资源,为防止资源泄漏,服务端通过租约机制保证资源及时地释放,如果在超过了租约的时间,而后续的客户端请求并没有发到服务端,此时服务端会销毁掉scan拥有的资源,如果此时客户端的请求陆续到来,服务端会出现LeaseException异常。
租约的超时时间由hbase.regionserver.lease.period控制,默认是60000ms。
因此客户端的scan应该及时close掉,否则会在上面这个时间窗口内持有服务端的资源。在高并发场景下很容易导致服务端内存被占满,进而出现full GC。

19)客户端的重联的避让算法
当regionserver挂掉或由于其它原因导致客户端与服务端失去连接的时候,客户端会重试以恢复与服务端的连接,重试的次数和时间由hbase中的如下两个参数决定,分别是hbase.client.pause和hbase.client.retries.number,其中 hbase.client.retries.number指定了最大重试次数,默认是31次,而hbase.client.pause是两次重试之间的休眠(sleep)时间,默认是100ms,实际实现中休眠时间是随着重试次数的增加而递进增加的,代码如下所示:
public static long getPauseTime(final long pause, final int tries) {
    int ntries = tries;
    if (ntries >= HConstants.RETRY_BACKOFF.length) {
      ntries = HConstants.RETRY_BACKOFF.length - 1;
    }

    long normalPause = pause * HConstants.RETRY_BACKOFF[ntries];
    long jitter =  (long)(normalPause * RANDOM.nextFloat() * 0.01f); // 1% possible jitter
    return normalPause + jitter;
  }

由此可见 hbase.client.pause定义重试间隔时间的基线。
之所以需要设计上述的避让算法,是为了避免某个regionserver挂掉的时候,所有client都在同一时间发起重连的情况,这会导致启动后的regionserver被大量冲进来的建连重新冲跨。

20)SingleColumnValueFilter的小坑
注意:当某一行没有要过滤的字段时,SingleColumnValueFilter默认这一行是符合过滤条件的,查看源码会发现这样一段话:
 * To prevent the entire row from being emitted if the column is not found
 * on a row, use {@link #setFilterIfMissing}.
 * Otherwise, if the column is found, the entire row will be emitted only if
 * the value passes.  If the value fails, the row will be filtered out.
正确的姿势如下:
SingleColumnValueFilter f1 = new SingleColumnValueFilter(Bytes.toBytes(FAMILY), Bytes.toBytes(QUALIFER), CompareOp.GREATER_OR_EQUAL, Bytes.toBytes(value));
f1.setFilterIfMissing(true);  //true 跳过改行;false 通过该行
filters.add(f1);

21)hlog
hlog中的数据是以key-value的形式组织的,需要注意的是发生多次修改的数据,所有的过往修改记录都会统一写成一条hlog中的记录。对于某些需要实时解析hlog的日志同步hbase新增数据的场景,直接应用该hlog记录会出现错误,需要从中解析出最后写入的那条记录。

22)regionserver的Promotion Failure造成的Full GC问题

regionserver在持续运行了一段时间之后,偶尔会出现宕机挂掉的现象,翻看当时的GC日志可以看到是CMS GC的时候出现了Promotion Failure现象,进而引发Full GC,而Full GC是stop the world的,如果时间较长,zookeeper长期收不到该region server上报上来的心跳就会将该region server判死,造成region server的宕机。

继续探究Promotion Failure的原因,可能的原因是CMS GC不断产生碎片,随着系统运行时间越来越长,碎片逐渐累积,当累积到一定程度,新生代分配过来的对象发现没有空间了,但是老年代的内存使用并没有到XX:CMSInitiatingOccupancyFraction设置的百分比,此时就会触发一次full gc。

避免方法比如调大XX:CMSInitiatingOccupancyFraction,使用堆外内存,使用G1 GC算法,同时也业务上要尽量避免字段过大的数据。


23)zookeeper的连接数
客户端在使用hbase的时候,需要添加zookeeper的ip地址和节点路径,建立起与zookeeper的连接,建立连接的方式如下面的代码所示:
Configuration configuration = HBaseConfiguration.create();
configuration.set("hbase.zookeeper.quorum", "XXXX.XXX.XXX");
configuration.set("hbase.zookeeper.property.clientPort", "2181");
configuration.set("zookeeper.znode.parent", "XXXXX");
Connection connection = ConnectionFactory.createConnection(configuration);
需要注意的坑是上述变量需要在全局初始化,亦或者作为一个单例对外提供服务,切忌在循环中或者在函数的局部方法里反复建立与zookeeper的连接,否则会导致zookeeper的连接数过高,影响服务的稳定性。检查zookeeper服务的连接数可以使用下面的命令:
netstat -na | grep "2181" | wc -l

24)hbase的客户端scan的时候有个配置方法setCacheBlocks,默认是true,表示用户此次scan出来的数据会同时写到服务端的读缓存中一份,如果业务短时间内没有重复读取行为,则建议修改为false;

25)hive读hbase的bytes类型的cell时会出现乱码,解决方式如下:
a mapping entry must be either :key or of the form column-family-name:[column-name][#(binary|string) (the type specification that delimited by # was added in Hive 0.9.0, earlier versions interpreted everything as strings)
If no type specification is given the value from hbase.table.default.storage.type will be used
Any prefixes of the valid values are valid too (i.e. #b instead of #binary)
If you specify a column as binary the bytes in the corresponding HBase cells are expected to be of the form that HBase's Bytes class yields
一个可借鉴的例程如下所示:
CREATE TABLE hbase_table_1 (key int, value string, foobar double)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
"hbase.columns.mapping" = ":key#b,cf:val,cf:foo#b"
);

26)如果表采用prefix-tree编码,有可能会导致表的compact被堵住;

27)archive目录会存放很多临时文件,正常情况下master会每隔一定的时间清理archive中的文件,间隔时间由hbase.master.hfilecleaner.ttl来设置,默认是5分钟;

28)业务导数据这种长时间任务造成gc时间过长,导致客户端和zk的心跳时间超时,表象就是zk的连接数忽高忽低,据此推测是应用因为心跳超时而反复重建连接,在客户端执行netstat -antp | grep 2181,查看客户端到zk的连接状态,可以发现很多处于TIME_WAIT状态的连接;

你可能感兴趣的:(hbase,数据库)