Hbase2.x新特性&Hbase常见问题性优化小总结

本文深入探讨了HBase的性能优化策略,包括使用bulkload加快写入速度、全链路offheap减少GC压力、表结构设计以及HBase2.0的新特性。此外,文章列举了HBase在实际使用中遇到的各种问题,如连接问题、数据丢失、JVM错误、HMaster挂掉等,并给出了详细的解决方案,对于HBase的日常管理和故障排查具有指导意义。
摘要由CSDN通过智能技术生成

在很早之前,我曾经写过两篇关于Hbase的文章:

如果你没有看过,推荐收藏看一看。另外,在我的CSDN有专门的HBase专栏可以系统学习,参考:

《Hbase专栏》 https://blog.csdn.net/u013411339

本文在上面文章的基础上,新增了更多的内容,并且增加了Hbase2.x版本的新功能。

Hbase常见问题集合

问: Hbase大量写入很慢,一个列族,每个200多列,一秒写30000条数据,使用mutate添加数据,clientbuffer缓存大小为10M,四台测试机,128G内存,分配60G给Hbase,该怎么优化?

答:可以使用bulkload方式写入,通过mr程序生产hfile文件,直接用bulkload导入生成的hfile文件,速度非常快。

问: hbase大规模的丢数据,整个数据库系统都挂掉了,然后发错误日志,说Hdfs内部的配置文件,hbase.version,丢失了。大家有遇到过类似的问题吗?自建的集群。

答:检查一下一些服务的端口有没有暴露到公网,是不是集群被攻击了。自建还是有一些风险的。然后检查下自己的hbase配置。看看数据的备份情况。

问: start-hbase.sh中有这么一段:

if [ "$distMode" == 'false' ]
then
"$bin"/hbase-daemon.sh --config "${HBASE_CONF_DIR}" $commandToRun master $@
else
"$bin"/hbase-daemons.sh --config "${HBASE_CONF_DIR}" $commandToRun zookeeper
"$bin"/hbase-daemon.sh --config "${HBASE_CONF_DIR}" $commandToRun master
"$bin"/hbase-daemons.sh --config "${HBASE_CONF_DIR}" \
--hosts "${HBASE_REGIONSERVERS}" $commandToRun regionserver
"$bin"/hbase-daemons.sh --config "${HBASE_CONF_DIR}" \
--hosts "${HBASE_BACKUP_MASTERS}" $commandToRun master-backup
fi

distMode为false时表示单机,true时表示集群,看脚本好像是单机只启动master,是否是说单机环境下不需要zookeeper,regionserver这些的意思,可是网上搜了下又有人说单机环境下master和 zookeeper会运行在同一个jvm。有谁对hbase比较熟悉的可以解答下吗?

答:单机模式所有的服务都是一个jvm 进程启动,底层的文件系统是本地文件系统,该jvm进程包括有zookeeper,hmaster和regionserver。其他模式需要手动分别启动zk,hmaster,regionserver到不同的进程中。

问: Hbase 在大规模用户画像标签,标签有近百个左右,适合吗?

答:hbase就是适用这种几百几千级别的场景,甚至可以支持百万列级别的,但是建议常用的小于10w列。

问: hbase 2 内置现在的事务做的怎么样?支持到什么隔离级别?如果有的话,hbase分布式事务依靠什么做的?答:hbase事务目前还是region级别,hbase是可以做到跨行事务,但是只限于region级别。

问: 批量删除hbase的数据用什么方式比较快

答:最快的方式就是直接设置TTL,如果业务无法满足,建议直接调度delete接口,性能也较快。

问: HBase 2.0 的查询性能怎样优化的?

答:在HBase的读和写链路中,均会产生大量的内存垃圾和碎片。比如说写请求时需要从Connection的ByteBuffer中拷贝数据到KeyValue结构中,在把这些KeyValue结构写入memstore时,又需要将其拷贝到MSLAB中,WAL Edit的构建,Memstore的flush等等,都会产生大量的临时对象,和生命周期结束的对象。随着写压力的上升,GC的压力也会越大。读链路也同样存在这样的问题,cache的置换,block数据的decoding,写网络中的拷贝等等过程,都会无形中加重GC的负担。而HBase2.0中引入的全链路offheap功能,正是为了解决这些GC问题。大家知道Java的内存分为onheap和offheap,而GC只会整理onheap的堆。全链路Offheap,就意味着HBase在读写过程中,KeyValue的整个生命周期都会在offheap中进行,HBase自行管理offheap的内存,减少GC压力和GC停顿。

写链路的offheap包括以下几个优化:

  • 在RPC层直接把网络流上的KeyValue读入offheap的bytebuffer中

  • 使用offheap的MSLAB pool

  • 使用支持offheap的Protobuf版本(3.0+)

读链路的offheap主要包括以下几个优化:

  • 对BucketCache引用计数,避免读取时的拷贝

  • 使用ByteBuffer做为服务端KeyValue的实现,从而使KeyValue可以存储在offheap的内存中

  • 对BucketCache进行了一系列性能优化

问: Hbase的bulkload有全量与增量的概念么?

答:snapshot 做全量 ,然后bulkload 做增量。

问: Hive on hbase 分析10亿以上数据性能问题?

答:性能会损失,hive支持通过类似sql语句的语法来操作hbase中的数据, 但是速度较慢。

问: 直接读HFile与通过Hbase客户端读,性能提升多少?

答:全表扫使用spark读HFile,比直接读hbase性能提升两倍以上,并且不会影响hbase其他读写使用。

问: HBase region个数如何划分?

答:最好是你的regionserver的倍数,会自动的分配到每个服务器,注意rowkey要分散。参考文档:https://help.aliyun.com/document_detail/71787.html

拒绝连接错误

8cff56a1b005595e97a1c4feb6c984b1.png

第一个解决思路:去zookeeper的conf/zoo.cfg配置文件查看:

b0dda19fdc30151b36ec3890c1d37d48.png

这里有两个目录:一个是数据目录dataDir,一个是日志目录dataLogDir。使用cd命令,能不能进入这两个目录下面,如果可以进去,就证明无误。如果提示: 没有那个文件或目录,就使用mkdir命令创建这两个文件夹即可。

第二个思路:vim /etc/hosts 查看主机名配置是否正确,如果使用和配置有误,进行修改。

第三个思路:使用上述办法不能解决:那么关闭防火墙,CentOS6使用

chkconfig iftables off  永久关闭防火墙service iptables stop 临时关闭防火墙

CentOS7 默认的使用firewall作为防火墙,关闭firewall:systemctl stop firewalld.service #停止firewall

systemctl disable firewalld.service #禁止firewall开机启动

firewall-cmd --state #查看默认防火墙状态(关闭后显示notrunning,开启后显示running)

防火墙已经关闭,问题还没有解决,有可能是账户的问题,不妨切换账户试一下。

第三个思路,端口号的问题: zookeeper默认的端口号是2181,但不是所有的都是使用这个端口号。去hbase-site.xml里面查看:

<property>
     <name>hbase.zookeeper.property.clientPort</name>
     <value>4180</value>
     <description>Property from ZooKeeper's config zoo.cfg.
     The port at which the clients will connect.
     </description>
 </property>

改变代码里面设置的端口号,问题得到解决。

一个最坑的可能原因就是集群节点的时间不同步,hbase,和zookeeper对时间的要求很高!!好像是误差要在180s。最好的方式就是对整个集群配置时钟同步,或者是使用date命令为每个节点修改时间。

以上方案都尝试过,问题仍然不能解决,就重启hbase和zookeeper试试吧。zookeeper如果上次没有被正常关闭的话,很容易影响到下一次的使用。

与hbase相关jar包找不到的问题

Error: java.lang.ClassNotFoundException: org.apache.hadoop.hbase.client.ConnectionFactory
        at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
        at mastercom.cn.bigdata.util.hbase.HbaseDBHelper.getConnection(HbaseDBHelper.java:50)
        at mapr.mro.loc.MroLableFileReducers$MroDataFileReducers.setup(MroLableFileReducers.java:43)
        at org.apache.hadoop.mapreduce.Reducer.run(Reducer.java:168)
        at org.apache.hadoop.mapred.ReduceTask.runNewReducer(ReduceTask.java:627)
        at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:389)
        at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:164)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAs(Subject.java:415)
        at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1657)
        at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:158)

解决方法:

  1. 打jar包的时候直接把相应的jar包打进来,这样能够解决问题,但是jar包会有200多M.

  2. 在执行jar包前执行 export HADOOP_CLASSPATH=$HBASE_HOME/lib/*:classpath,简单有效,但是如果创建hbase连接的操作是在map,reduce里,这种方法依然会报错.

  3. 在hadoop-env.sh里面,引入hbase的lib目录:操作如下: export HADOOP_CLASSPATH=$HBASE_HOME/lib/* :$HADOOP_CLASSPATH所有的节点都要修改,修改完后要重启集群.

  4. $HBASE_HOME/lib目录下的jar包导入到$HADOOP_HOME/lib目录下,但这样很容易引起jar包冲突,不推荐

JDK版本冲突

本地开发使用的是jdk1.8, 集群上的jdk配置的是1.7,jar包丢到集群上报错:java.lang.UnsupportedClassVersionError: PR/Sort : Unsupported major.minor version 52.0

解决方法: 很简单,使用集群里对应的jdk版本编译就好了,右键项目-->BuildPath -->Configure Build Path --> Java Compiler --->将版本调整成为集群里面对应的版本即可-->apply.重新打jar包,放到集群上跑,问题得到解决.

运行hbase shell输入list,等基本语句报错

ERROR: Can't get master address from ZooKeeper; znode data == null

Here is some help for this command:
List all tables in hbase. Optional regular expression parameter could
be used to filter the output. Examples:
  hbase> list
  hbase> list 'abc.*'
  hbase> list 'ns:abc.*'
  hbase> list 'ns:.*'

可能原因:

  1. 时间不同步, hbase集群所有莫名其妙的问题都有可能是时间不同步导致的,一定要注意.

  2. hbase-site.xml里面的hbase.rootdir对应的ip与core-site.xml中的fs.defaultFS中的路径不同,或者是与hdfs文件系统的端口号不一致.

堆内存溢出

java.lang.OutOfMemoryError,从错误本身可以发现是堆错误,很明显是设置的值太小而导致这样错误。

在hadoop开始配置的时候,在hadoop/etc/hadoop/目录下的hadoop-env.sh文件中export HADOOP_HEAPSIZE=是被注释掉的,查看上面的注释,这个值默认为1000,单位为Mb。

这里去掉注释,修改为4000,需要注意的是这里要根据内存大小来选择值export HADOOP_HEAPSIZE=4000

表名找不到

org.apache.hadoop.hbase.TableNotFoundException: ns_wangyou.simu_out_GuangXi
        at org.apache.hadoop.hbase.client.HBaseAdmin.getTableDescriptor(HBaseAdmin.java:572)
        at org.apache.hadoop.hbase.client.HTable.getTableDescriptor(HTable.java:574)
        at org.apache.hadoop.hbase.mapreduce.HFileOutputFormat2.configureIncrementalLoad(HFileOutputFormat2.java:372)
        at mastercom.cn.hbase.helper.AddPaths.addConfigJob(AddPaths.java:212)
        at mastercom.cn.hbase.config.HbaseBulkloadConfigMain.CreateJob(HbaseBulkloadConfigMain.java:101)
        at mastercom.cn.hbase.config.HbaseBulkloadConfigMain.main(HbaseBulkloadConfigMain.java:109)

很明显是查询的hbase数据库里面没有相应的表名导致的。检查输入的表名是否正确, 如果正确的话,去创建相应的表即可。

类找不到

出现该问题的情形: hbase和hadoop的hdfs,mapreduce整合使用的时候:

18/04/16 18:25:06 INFO mapreduce.JobSubmitter: Cleaning up the staging area /user/mingtong/.staging/job_1522546194099_223330
Exception in thread "main" java.lang.RuntimeException: java.lang.ClassNotFoundException: Class mastercom.cn.bigdata.util.hadoop.mapred.CombineSmallFileInputFormat not found
        at org.apache.hadoop.mapreduce.lib.input.MultipleInputs.getInputFormatMap(MultipleInputs.java:112)
        at org.apache.hadoop.mapreduce.lib.input.DelegatingInputFormat.getSplits(DelegatingInputFormat.java:58)
        at org.apache.hadoop.mapreduce.JobSubmitter.writeNewSplits(JobSubmitter.java:301)
        at org.apache.hadoop.mapreduce.JobSubmitter.writeSplits(JobSubmitter.java:318)
        at org.apache.hadoop.mapreduce.JobSubmitter.submitJobInternal(JobSubmitter.java:196)
        at org.apache.hadoop.mapreduce.Job$10.run(Job.java:1290)
        at org.apache.hadoop.mapreduce.Job$10.run(Job.java:1287)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAs(Subject.java:422)
        at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1724)
        at org.apache.hadoop.mapreduce.Job.submit(Job.java:1287)
        at org.apache.hadoop.mapreduce.Job.waitForCompletion(Job.java:1308)
        at mastercom.cn.hbase.helper.AddPaths.addUnCombineConfigJob(AddPaths.java:261)
        at mastercom.cn.hbase.config.HbaseBulkloadConfigMain.CreateJob(HbaseBulkloadConfigMain.java:98)
        at mastercom.cn.hbase.config.HbaseBulkloadConfigMain.main(HbaseBulkloadConfigMain.java:109)
        ```

经过各种测试,最终将问题定位在这一行代码:

Configuration conf = HBaseConfiguration.create();

只要你的configuration使用的是hbase的,而且后面MapReduce的job用到这个conf,就会报这个问题!

解决方法: 使用Configuration conf = new Configuration(); 来创建conf。但是这种方法创建的conf,不会去加载hbase-site.xml配置文件,hbase-site.xml里面重要的参数需要手动set。否则就无法正确的连接到Hbase!

由于上面介绍的问题还会引发下面的报错:

org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.hdfs.server.namenode.LeaseExpiredException): No lease on /wangyou/mingtong/mt_wlyh/Data/hbase_bulkload/output/4503/inin (inode 1964063475): File does not exist. Holder DFSClient_NONMAPREDUCE_-769553346_1 does not have any open files.
     at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.checkLease(FSNamesystem.java:3521)
     at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.completeFileInternal(FSNamesystem.java:3611)
     at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.completeFile(FSNamesystem.java:3578)
     at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.complete(NameNodeRpcServer.java:905)

按照上述方法改进后,该问题就得到解决!

执行MapReduce遇到的问题:文件租约超期异常

org.apache.hadoop.hdfs.server.namenode.LeaseExpiredException,

6013b1978f7e01179b4810dc49ef8db0.png

这个问题实际上就是data stream操作过程中文件被删掉了。之前也遇到过,通常是因为Mapred多个task操作同一个文件,一个task完成后删掉文件导致,将可能造成这种情况的代码进行修改即可。

遇到这种问题的另一种情形是: 因为mapReduce之前的一些错误,job一直报错,到后面导致的这个问题。这种情况下不要理会这个报错,只需要解决前面的问题这个问题就迎刃而解。

连接Hbase时, 明明hbase.zookeeper.quorumhbase.zookeeper.property.clientPort的设置都是正确的,却总是报错INFO client.ZooKeeperRegistry: ClusterId read in ZooKeeper is null.

首先,这种情况出现在: 使用的configuration 是 new configuration这种方式获得的 这里: 涉及到一个关键的配置:zookeeper.znode.parent,这个值的默认值是/hbase,但是如果集群里面设置的值不是这个的话,就会抛出这个异常。比如说我们的集群因为使用new Configuration()获得的configuration对象是不会读取Hbase的配置文件hbase-site.xml文件的。在代码中将该配置按照hbase-site.xml里面配置的添加进来即可conf.set("zookeeper.znode.parent", "/hbase-unsecure");,问题得到解决!

使用bulkload入库遇到问题

报错信息如下所示:

Exception in thread "main" java.lang.IllegalArgumentException: Can not create a Path from a null string
        at org.apache.hadoop.fs.Path.checkPathArg(Path.java:122)
        at org.apache.hadoop.fs.Path.<init>(Path.java:134)
        at org.apache.hadoop.fs.Path.<init>(Path.java:88)
        at org.apache.hadoop.hbase.mapreduce.HFileOutputFormat2.configurePartitioner(HFileOutputFormat2.java:596)
        at org.apache.hadoop.hbase.mapreduce.HFileOutputFormat2.configureIncrementalLoad(HFileOutputFormat2.java:445)
        at org.apache.hadoop.hbase.mapreduce.HFileOutputFormat2.configureIncrementalLoad(HFileOutputFormat2.java:410)
        at org.apache.hadoop.hbase.mapreduce.HFileOutputFormat2.configureIncrementalLoad(HFileOutputFormat2.java:372)
        at mastercom.cn.hbase.helper.AddPaths.addUnCombineConfigJob(AddPaths.java:272)
        at mastercom.cn.hbase.config.HbaseBulkloadConfigMain.CreateJob(HbaseBulkloadConfigMain.java:129)
        at mastercom.cn.hbase.config.HbaseBulkloadConfigMain.main(HbaseBulkloadConfigMain.java:141)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.hadoop.util.RunJar.run(RunJar.java:233)
        at org.apache.hadoop.util.RunJar.main(RunJar.java:148)

由报错信息上可以看出来:是在HFileOutputFormat2类里面出现的错误,这个类是使用bulkload方式进行入库的很关键的类,我们接下来一步一步的去定位错,抛出来的错误信息是来自于path类的这个方法:

private void checkPathArg( String path ) throws IllegalArgumentException {
    // disallow construction of a Path from an empty string
    if ( path == null ) {
      throw new IllegalArgumentException(
          "Can not create a Path from a null string");
    }
    if( path.length() == 0 ) {
       throw new IllegalArgumentException(
           "Can not create a Path from an empty string");
    }   
  }

根据界面上的报错结合一下可以得到path是null,那么这个空是从何而来,我们继续看源码:

static void configurePartitioner(Job job, List<ImmutableBytesWritable> splitPoints)
      throws IOException {
    Configuration conf = job.getConfiguration();
    // create the partitions file
    FileSystem fs = FileSystem.get(conf);
    Path partitionsPath = new Path(conf.get("hbase.fs.tmp.dir"), "partitions_" + UUID.randomUUID());
    fs.makeQualified(partitionsPath);
    writePartitions(conf, partitionsPath, splitPoints);
    fs.deleteOnExit(partitionsPath);
    
    // configure job to use it
    job.setPartitionerClass(TotalOrderPartitioner.class);
    TotalOrderPartitioner.setPartitionFile(conf, partitionsPath);
  }

分析上面的源码,能够产生null的又和path相关的,显然是这行代码:Path(conf.get("hbase.fs.tmp.dir"), "partitions_" + UUID.randomUUID());我们不妨测试一下,在获得conf对象后,打印一下hbase.fs.tmp.dir的值,果然为空!

那么问题已经确认,只需要在代码里面加上这行:

conf.set("hbase.fs.tmp.dir", "/tmp/hbase-staging");

问题便得到解决,入库工作得以正常运行!

gz压缩文件损坏导致入库失败

ERROR hdfs.DFSClient: Failed to close inode 16886732
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.hdfs.server.namenode.LeaseExpiredException): No lease on /hbase_bulkload/output/inin (inode 16886732): File does not exist. Holder DFSClient_NONMAPREDUCE_1351255084_1 does not have any open files.
        at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.checkLease(FSNamesystem.java:3431)
        at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.completeFileInternal(FSNamesystem.java:3521)
        at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.completeFile(FSNamesystem.java:3488)
        at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.complete(NameNodeRpcServer.java:785)
        at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.complete(ClientNamenodeProtocolServerSideTranslatorPB.java:536)
        at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)
        at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:616)
        at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:969)
        at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2049)
        at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2045)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAs(Subject.java:415)
        at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1657)
        at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2043)

        at org.apache.hadoop.ipc.Client.call(Client.java:1476)
        at org.apache.hadoop.ipc.Client.call(Client.java:1407)
        at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:229)
        at com.sun.proxy.$Proxy9.complete(Unknown Source)
        at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB.complete(ClientNamenodeProtocolTranslatorPB.java:462)
        at sun.reflect.GeneratedMethodAccessor6.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:187)
        at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:102)
        at com.sun.proxy.$Proxy10.complete(Unknown Source)
        at org.apache.hadoop.hdfs.DFSOutputStream.completeFile(DFSOutputStream.java:2257)
        at org.apache.hadoop.hdfs.DFSOutputStream.closeImpl(DFSOutputStream.java:2238)
        at org.apache.hadoop.hdfs.DFSOutputStream.close(DFSOutputStream.java:2204)
        at org.apache.hadoop.hdfs.DFSClient.closeAllFilesBeingWritten(DFSClient.java:951)
        at org.apache.hadoop.hdfs.DFSClient.closeOutputStreams(DFSClient.java:983)
        at org.apache.hadoop.hdfs.DistributedFileSystem.close(DistributedFileSystem.java:1076)
        at org.apache.hadoop.fs.FileSystem$Cache.closeAll(FileSystem.java:2744)
        at org.apache.hadoop.fs.FileSystem$Cache$ClientFinalizer.run(FileSystem.java:2761)
        at org.apache.hadoop.util.ShutdownHookManager$1.run(ShutdownHookManager.java:54)

该问题的场景是在对大量的小的.gz压缩文件进行入库的时候,个别压缩文件损坏导致的,解决的方法就是找到那些出错的.gz文件删除掉。使用的方法:

  1. 首先去界面查看相应的job执行的日志,日志里有可能会有出错的.gz文件的id信息,找到将其删除;

  2. 将入库的文件夹下面的文件按照文件大小进行排序,一般来说,大小为0KB的都是有问题的.将其get下来,查看能否解压,不能正常解压就干掉;

  3. 可以使用命令: hdfs fsck path -openforwrite检测某个文件夹下面文件是否正常。

HMaster启动之后马上挂掉

FATAL [kiwi02:60000.activeMasterManager] master.HMaster: Unhandled exception. Starting shutdown.
  org.apache.hadoop.hbase.util.FileSystemVersionException: HBase file layout needs to be upgraded. 
  You  have version null and I want version 8. 
  Consult http://hbase.apache.org/book.html for further information about upgrading HBase. 
  Is your hbase.rootdir valid? If so, you may need to run 'hbase hbck -fixVersionFile'.

解决方案: 通过在hdfs中删除hbase的目录,然后重启hbase master解决.

那么hbase的目录是哪一个呢?在$HBASE_HOME/conf/hbase-site.xml里面配置,通常为/hbase:

<property>
   <name>hbase.rootdir</name>
   <value>/hbase</value>
 </property>

磁盘故障,RegionServer重启之后,Region offline

可能原因:磁盘故障,在Region 重新分配过程中,被分配的RegionServer重启,Region分配失败,Region offline。具体原因需结合排查磁盘故障原因,以及RegionServer被重启的原因进行分析。

解决方案:排除故障原因,恢复磁盘故障。当磁盘故障恢复,HBase健康状态恢复,执行hbase hbck-fixAssignments使Region恢复上线。

查看HBase 组件日志,发现连接Zookeeper组件失败,若定位HBase组件没有问题,可能是Zookeeper服务存在问题.

可能原因: Zookeeper比较常见的问题就是因其数据存储目录空间不足,导致Zookeeper Server不能够正常提供服务,从而导致其他依赖于Zookeeper的服务如HBase组件连接Zookeeper失败。

解决办法: 查看Zookeeper的数据存储目录所在的分区,清理该分区内无用的文件,释放空间,然后重启Zookeeper服务即可。

Hbase2.0

Hbase版本变迁:

226c2b7c03e9b4ca14d051d717661ca6.png

注: 2.x版本是接下来最受期待的一个版本(升级要慎重,请参考社区中的实践),因为最近一两年社区开发的新功能都将集中在2.x版本发布,2.x包含的核心功能特别多,包括:大幅度减小GC影响的offheap read path/write path工作,极大提升系统稳定性的Procedure V2框架,支持多租户隔离的RegionServer Group功能,支持大对象存储的MOB功能等。

HBase 2.x版本是迄今为止改动最大的一个版本,主要包含的核心功能如下:

  • 基于Procedure v2重新设计了HBase的Assignment Manager和核心管理流程。通过Procedure v2,HBase能保证各核心步骤的原子性,从设计上解决了分布式场景下多状态不一致的问题。

  • 实现了In Memory Compaction功能。该功能将MemStore分成若干小数据块,将多个数据块在MemStore内部做Compaction,一方面缓解了写放大的问题,另一方面降低了写路径的GC压力。

  • 存储MOB数据。2.0.0版本之前对大于1MB的数据支持并不友好,因为大value场景下Compaction会加剧写放大问题,同时容易挤占HBase的BucketCache。而新版本通过把大value存储到独立的HFile中来解决这个问题,更好地满足了多样化的存储需求。

  • 读写路径全链路Offheap化。在2.0版本之前,HBase只有读路径上的BucketCache可以存放Offheap,而在2.0版本中,社区实现了从RPC读请求到完成处理,最后到返回数据至客户端的全链路内存的Offheap化,从而进一步控制了GC的影响。

  • 异步化设计。异步的好处是在相同线程数的情况下,提升系统的吞吐量。2.0版本中做了大量的异步化设计,例如提供了异步的客户端,采用Netty实现异步RPC,实现asyncFsWAL等。

Procedure

在HBase 2.0版本之前,系统存在一个潜在的问题:HBase的元信息分布在ZooKeeper、HBase Meta表以及HDFS文件系统中,而HBase的分布式管理流程并没法保证操作流程的原子性,因此,容易导致这三者之间的不一致。

HBase 2.0引入了Procedure v2的设计。本质上是通过设计一个分布式任务流框架,来保证这个任务流的多个步骤全部成功,或者全部失败,即保证分布式任务流的原子性。

Procedure定义

一个Procedure一般由多个subtask组成,每个subtask是一些执行步骤的集合,这些执行步骤中又会依赖部分Procedure。

Procedure提供的两个接口: execute()和rollback(),其中execute()接口用于实现Procedure的执行逻辑,rollback()接口用于实现Procedure的回滚逻辑。这两个接口的实现需要保证幂等性。

Procedure Yield

Procedure v2框架还提供了另一种处理重试的方式——把当前异常的Procedure直接从调度队列中移走,并将Procedure添加到调度队列队尾。等待前面所有的Procedure都执行完成之后,再执行上次有异常的Procedure,从而达到重试的目的。

In Memory Compaction

为了实现更高的写入吞吐和更低的延迟,社区团队对MemStore做了更细粒度的设计。这里,主要指的就是In Memory Compaction。

Segment概念

Segment本质上是维护一个有序的cell列表。根据cell列表是否可更改,Segment可以分为两种类型。

  • MutableSegment :该类型的Segment支持添加cell、删除cell、扫描cell、读取某个cell等操作。因此一般使用一个ConcurrentSkipListMap来维护列表。

  • ImmutableSegment :该类型的Segment只支持扫描cell和读取某个cell这种查找类操作,不支持添加、删除等写入操作。因此简单来说,只需要一个数组维护即可。

注意:无论是何种类型的Segment,都需要实时保证cell列表的有序性。

开启方式

有两种方式可以开启In Memory Compaction功能。第一种是在服务端的hbase-site.xml添加如下配置,此配置对集群中所有的表有效:

hbase.hregion.compacting.memstore.type=BASIC   #可选择NONE/BASIC/EAGER三种

当然,也可以针对某个表的给定Column Family打开In Memory Compaction,代码如下:

create 'test', {NAME=> 'cf', IN_MEMORY_COMPACTION=> 'BASIC'} #NONE/BASIC/EAGER

1 注意,这里IN_MEMORY_COMPACTION三个取值的含义如下:

  • NONE,系统默认值,表示不开启In-Memory Compaction,仍使用之前默认的DefaultMemstore。

  • BASIC,表示开启In-Memory Compaction,但是在ImmutableSegment做Compaction的时候,并不会走ScanQueryMatcher过滤无效数据,同时cell指向的内存数据不会发生任何移动。可以认为是一种轻量级的内存Compaction。

  • EAGER,表示开启In-Memory Compaction。在ImmutableSegment做Compaction时,会通过ScanQueryMatcher过滤无效数据,并重新整理cell指向的内存数据,将其拷贝到一个全新的内存区域。可以认为是一种开销比BASIC的更大,但是更彻底的Compaction。所谓无效数据包括TTL过期的数据、超过Family指定版本的cell,以及被用户删除的cell。

从原理上说,如果表中存在大量特定行的数据更新,则使用EAGER能获得更高的收益,否则使用BASIC。

MOB

HBase MOB特性是由HBASE-11339这个issue引入的,主要解决的是HBase对中等大小对象(100KB~10MB)的低延时读写支持,提升HBase对象存储的能力。这个特性的引入,使得HBase能够非常适合存储图片、文件、短视频等二进制对象,拓宽了HBase在人工智能、物联网等领域的应用场景。

在MOB特性引入之前,HBase也能够存储大小在100KB以上的二进制对象,但是HBase针对大小100KB以下的数据在读写路径上做了优化,因此在处理大量的大小在100KB以上的数据时,性能其实非常低效,由压缩与分裂带来的I/O压力会使HBase整体性能下降,这也是要引入MOB的原因。当使用MOB特性时,理想的二进制对象大小应该在100KB~10MB之间,超过10MB的文件HBase也能够进行存储但是效率相对比较低,一些较大的文件还是建议直接存放在HDFS上,充分发挥HDFS文件存储的能力。

MOB架构

包含MOB特性的HBase整体架构如下图:

bbe020a07687d53280bfa03ae6cf1360.png

由于大部分担心来自于压缩带来的IO压力,因此HBase 2.0将MOB移出普通region的管理来避免region split和compaction。HBase MOB在架构设计上类似于 HBase + HDFS 的方式,通过分离文件引用和 MOB 对象的 IO 路径来实现。

版本支持

HBase MOB是HBase 2.0 版本引入的特性,详见HBASE-11339,因此原生的Apache HBase要2.0及以上版本才支持。

开启HBase MOB特性有一个先决条件,就是必须支持HFile v3。通过修改hbase-site.xmlhfile.format.version属性值为3得到支持:

<property>
  <name>hfile.format.version</name>
  <value>3</value>
</property>

满足先决条件后,开启MOB其实很简单,创建表时指定以下列族属性或修改列族属性:

  • IS_MOB:设置为true,这项配置是必须的;

  • MOB_THRESHOLD:设置MOB阈值,超过阈值的被当做MOB存储,默认100KB

HBase Shell命令:

hbase> create ‘t1’, {NAME => ‘f1’, IS_MOB => true, MOB_THRESHOLD => 102400}
hbase> alter ‘t1’, {NAME => ‘f1’, IS_MOB => true, MOB_THRESHOLD => 102400}

HBase API代码:

HColumnDescriptor hcd = new HColumnDescriptor(“f”);
hcd.setMobEnabled(true);
hcd.setMobThreshold(102400L);

配置MOB压缩策略

为了减少MOB HFiles的数量以提升性能,HBase会定期做MOB Compaction,默认是按天压缩。

另外,HBASE-16981又引入了按周和月的MOB压缩聚合策略,改善了MOB的存储(CDH HBase自CDH5.11.0开始支持HBASE-16981修复的版本)。

通过属性MOB_COMPACT_PARTITION_POLICY设置不同的压缩聚合策略,可选值有daily、weekly和monthly,例如:

hbase> alter ‘t1’, {NAME => ‘f1’, IS_MOB => true, MOB_THRESHOLD => 102400, MOB_COMPACT_PARTITION_POLICY => ‘weekly’}

配置MOB缓存属性

为了提高MOB读取的性能,服务端会保留一级LRU缓存,相关的参数包含:

  • hbase.mob.file.cache.size:缓存MOB文件的数量,默认1000;

  • hbase.mob.cache.evict.period:缓存清理周期,默认是3600s;

  • hbase.mob.cache.evict.remain.ratio:缓存清理后保留文件的比例,取值范围为0~1,默认0.5f。

MOB功能/性能测试

HBase官网提供一个用于测试MOB功能的工具类org.apache.hadoop.hbase.IntegrationTestIngestMOB,可以通过命令行直接使用,命令如下:

$ hbase org.apache.hadoop.hbase.IntegrationTestIngestWithMOB
-threshold 1024
-minMobDataSize 512
-maxMobDataSize 5120

其中各个参数的含义如下:

  • threshold: MOB阈值,单位字节

  • minMobDataSize: MOB数据大小的最小值,单位字节

  • maxMobDataSize: MOB数据大小的最大值,单位字节

通过该工具类测试,控制台会打印类似下面的信息,供参考:

19/04/08 19:55:23 INFO util.MultiThreadedAction: [W:20] Keys=5248, cols=58.3 K, time=00:00:05 Overall: [keys/s= 1048, latency=18 ms] Current: [keys/s=1049, latency=18 ms], wroteUpTo=199999

总之,Apache HBase 2.0重新定义了中等大小对象随机读写的方式,为HBase对象存储提供了一体化的解决方案,拓展了HBase的应用场景。

461d9a2e57e285e93148b24e8a617880.png

八千里路云和月 | 从零到大数据专家学习路径指南

我们在学习Flink的时候,到底在学习什么?

193篇文章暴揍Flink,这个合集你需要关注一下

Flink生产环境TOP难题与优化,阿里巴巴藏经阁YYDS

Flink CDC我吃定了耶稣也留不住他!| Flink CDC线上问题小盘点

我们在学习Spark的时候,到底在学习什么?

在所有Spark模块中,我愿称SparkSQL为最强!

硬刚Hive | 4万字基础调优面试小总结

数据治理方法论和实践小百科全书

标签体系下的用户画像建设小指南

4万字长文 | ClickHouse基础&实践&调优全视角解析

【面试&个人成长】2021年过半,社招和校招的经验之谈

大数据方向另一个十年开启 |《硬刚系列》第一版完结

我写过的关于成长/面试/职场进阶的文章

当我们在学习Hive的时候在学习什么?「硬刚Hive续集」

你好,我是王知无,一个大数据领域的硬核原创作者。

做过后端架构、数据中间件、数据平台&架构、算法工程化。

专注大数据领域实时动态&技术提升&个人成长&职场进阶,欢迎关注。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王知无(import_bigdata)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值