本文主要是介绍Hbase2.x新特性Hbase常见问题性优化小总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
在很早之前,我曾经写过两篇关于Hbase的文章:
-
《Hbase性能优化百科全书》
-
《Hbase FAQ热门问答小集合》
如果你没有看过,推荐收藏看一看。另外,在我的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
拒绝连接错误
第一个解决思路:去zookeeper的conf/zoo.cfg配置文件查看:
这里有两个目录:一个是数据目录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.ConnectionFactoryat 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)
解决方法:
-
打jar包的时候直接把相应的jar包打进来,这样能够解决问题,但是jar包会有200多M.
-
在执行jar包前执行
export HADOOP_CLASSPATH=$HBASE_HOME/lib/*:classpath
,简单有效,但是如果创建hbase连接的操作是在map,reduce里,这种方法依然会报错. -
在hadoop-env.sh里面,引入hbase的lib目录:操作如下:
export HADOOP_CLASSPATH=$HBASE_HOME/lib/* :$HADOOP_CLASSPATH
所有的节点都要修改,修改完后要重启集群. -
将
$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 == nullHere is some help for this command:
List all tables in hbase. Optional regular expression parameter could
be used to filter the output. Examples:hbase> listhbase> list 'abc.*'hbase> list 'ns:abc.*'hbase> list 'ns:.*'
可能原因:
-
时间不同步, hbase集群所有莫名其妙的问题都有可能是时间不同步导致的,一定要注意.
-
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_GuangXiat 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 foundat 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
,
这个问题实际上就是data stream操作过程中文件被删掉了。之前也遇到过,通常是因为Mapred多个task操作同一个文件,一个task完成后删掉文件导致,将可能造成这种情况的代码进行修改即可。
遇到这种问题的另一种情形是: 因为mapReduce之前的一些错误,job一直报错,到后面导致的这个问题。这种情况下不要理会这个报错,只需要解决前面的问题这个问题就迎刃而解。
连接Hbase时, 明明
hbase.zookeeper.quorum
和hbase.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 stringat 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 stringif ( 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 fileFileSystem 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 itjob.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
文件删除掉。使用的方法:
-
首先去界面查看相应的job执行的日志,日志里有可能会有出错的.gz文件的id信息,找到将其删除;
-
将入库的文件夹下面的文件按照文件大小进行排序,一般来说,大小为0KB的都是有问题的.将其get下来,查看能否解压,不能正常解压就干掉;
-
可以使用命令:
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版本变迁:
注: 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整体架构如下图:
由于大部分担心来自于压缩带来的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.xml
中hfile.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的应用场景。
八千里路云和月 | 从零到大数据专家学习路径指南
我们在学习Flink的时候,到底在学习什么?
193篇文章暴揍Flink,这个合集你需要关注一下
Flink生产环境TOP难题与优化,阿里巴巴藏经阁YYDS
Flink CDC我吃定了耶稣也留不住他!| Flink CDC线上问题小盘点
我们在学习Spark的时候,到底在学习什么?
在所有Spark模块中,我愿称SparkSQL为最强!
硬刚Hive | 4万字基础调优面试小总结
数据治理方法论和实践小百科全书
标签体系下的用户画像建设小指南
4万字长文 | ClickHouse基础&实践&调优全视角解析
【面试&个人成长】2021年过半,社招和校招的经验之谈
大数据方向另一个十年开启 |《硬刚系列》第一版完结
我写过的关于成长/面试/职场进阶的文章
当我们在学习Hive的时候在学习什么?「硬刚Hive续集」
你好,我是王知无,一个大数据领域的硬核原创作者。
做过后端架构、数据中间件、数据平台&架构、算法工程化。
专注大数据领域实时动态&技术提升&个人成长&职场进阶,欢迎关注。
这篇关于Hbase2.x新特性Hbase常见问题性优化小总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!