官方文档
参考文档
某些环境可以容忍其HBase群集的定期完全关闭,例如,如果它正在使用后端分析容量而不是服务于前端Web页面。好处是NameNode / Master是RegionServers已关闭,因此没有机会错过对StoreFiles或元数据的任何正在进行的更改。显而易见的是群集已关闭。步骤包括:
1.停止HBase
2.DistCp使用
Distcp可用于将HDFS中HBase目录的内容复制到另一个目录中的同一群集,或复制到另一个群集。
注意:Distcp适用于这种情况,因为群集已关闭,并且没有对文件的正在进行的编辑。通常不建议在实时群集上对HBase目录中的文件进行分拣。
3.恢复(如果需要)
从HDFS备份hbase目录通过distcp复制到’real’hbase目录。复制这些文件的行为会创建新的HDFS元数据,这就是为什么这种恢复不需要从HBase备份时恢复NameNode的原因,因为它是特定HDFS目录的恢复(通过distcp) (即HBase部分)不是整个HDFS文件系统。
Hadoop层数据迁移
简单的distcp参数形式如下:
hadoop distcp hdfs://src-hadoop-address:9000/table_name hdfs://dst-hadoop-address:9000/table_name
如果是独立的MR集群来执行distcp,因为数据量很大,一般是按region目录粒度来传输,同时传输到目标集群时,我们先把文件传到临时目录,最后再目的集群上load表,我们用到的形式如下:
hadoop distcp \
-Dmapreduce.job.name=distcphbase \
-Dyarn.resourcemanager.webapp.address=mr-master-ip:8088 \
-Dyarn.resourcemanager.resource-tracker.address=mr-master-dns:8093 \
-Dyarn.resourcemanager.scheduler.address=mr-master-dns:8091 \
-Dyarn.resourcemanager.address=mr-master-dns:8090 \
-Dmapreduce.jobhistory.done-dir=/history/done/ \
-Dmapreduce.jobhistory.intermediate-done-dir=/history/log/ \
-Dfs.defaultFS=hdfs://hbase-fs/ \
-Dfs.default.name=hdfs://hbase-fs/ \
-bandwidth 20 \
-m 20 \
hdfs://src-hadoop-address:9000/region-hdfs-path \
hdfs://dst-hadoop-address:9000/tmp/region-hdfs-path
在这个过程中,需要注意源端集群到目的端集群策略是通的,同时hadoop/hbase版本也要注意是否一致,如果版本不一致,最终load表时会报错。
迁移方法如下:
如果是迁移实时写的表,最好是停止集群对表的写入,迁移历史表的话就不用了,此处举例表名为test;
flush表, 打开HBase Shell客户端,执行如下命令:
hbase> flush 'test'
拷贝表文件到目的路径,检查源集群到目标集群策略、版本等,确认没问题后,执行如上带MR参数的命令
检查目标集群表是否存在,如果不存在需要创建与原集群相同的表结构
在目标集群上,Load表到线上,在官方Load是执行如下命令:
hbase org.jruby.Main add_table.rb /hbase/data/default/test
对于我们来说,因我们先把文件同步到了临时目录,并不在原表目录,所以我们采用的另一种形式的load,即以region的维度来Load数据到线上表,怎么做呢,这里用到的是org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles这个类,即以bulkload的形式来load数据。上面同步时我们将文件同步到了目的集群的/tmp/region-hdfs-path目录,那么我们在Load时,可以用如下命令来Load region文件:
hbase org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles -Dhbase.mapreduce.bulkload.max.hfiles.perRegion.perFamily=1024 hdfs://dst-hadoop-address:9000/tmp/region-hdfs-path/region-name table_name
这里还用到一个参数hbase.mapreduce.bulkload.max.hfiles.perRegion.perFamily, 这个表示在bulkload过程中,每个region列族的HFile数的上限,这里我们是限定了1024,也可以指定更少,根据实际需求来定。
检查表数据是否OK,看bulkload过程是否有报错
在同步过程中,我们为加块同步速度,还会开个多线程来并发同步文件,这个可根据实际数据量和文件数来决定是否需要使用并发同步。
可复制实用程序可用于将数据从一个表复制到同一个集群上的另一个表,也可以将数据复制到另一个集群上的另一个表。
由于群集已启动,因此存在复制过程中可能遗漏编辑的风险。
copyTable也是属于HBase数据迁移的工具之一,以表级别进行数据迁移。copyTable的本质也是利用MapReduce进行同步的,与DistCp不同的时,它是利用MR去scan 原表的数据,然后把scan出来的数据写入到目标集群的表。这种方式也有很多局限,如一个表数据量达到T级,同时又在读写的情况下,全量scan表无疑会对集群性能造成影响。
来看下copyTable的一些使用参数:
Usage: CopyTable [general options] [--starttime=X] [--endtime=Y] [--new.name=NEW] [--peer.adr=ADR]
Options:
rs.class hbase.regionserver.class of the peer cluster
specify if different from current cluster
rs.impl hbase.regionserver.impl of the peer cluster
startrow the start row
stoprow the stop row
starttime beginning of the time range (unixtime in millis)
without endtime means from starttime to forever
endtime end of the time range. Ignored if no starttime specified.
versions number of cell versions to copy
new.name new table's name
peer.adr Address of the peer cluster given in the format
hbase.zookeeer.quorum:hbase.zookeeper.client.port:zookeeper.znode.parent
families comma-separated list of families to copy
To copy from cf1 to cf2, give sourceCfName:destCfName.
To keep the same name, just give "cfName"
all.cells also copy delete markers and deleted cells
Args:
tablename Name of the table to copy
Examples:
To copy 'TestTable' to a cluster that uses replication for a 1 hour window:
$ bin/hbase org.apache.hadoop.hbase.mapreduce.CopyTable --starttime=1265875194289 --endtime=1265878794289 --peer.adr=server1,server2,server3:2181:/hbase --families=myOldCf:myNewCf,cf2,cf3 TestTable
For performance consider the following general options:
-Dhbase.client.scanner.caching=100
-Dmapred.map.tasks.speculative.execution=false
从上面参数,可以看出,copyTable支持设定需要复制的表的时间范围,cell的版本,也可以指定列簇,设定从集群的地址,起始/结束行键等。参数还是很灵活的。copyTable支持如下几个场景:
相当于一个快照,不过这个快照是包含原表实际数据的,0.94.x版本之前是不支持snapshot快照命令的,所以用copyTable相当于可以实现对原表的拷贝, 使用方式如下:
create 'table_snapshot',{NAME=>"i"}
hbase org.apache.hadoop.hbase.mapreduce.CopyTable --new.name=tableCopy table_snapshot
在集群之间以表维度同步一个表数据,使用方式如下:
create 'table_test',{NAME=>"i"}#目的集群上先创建一个与原表结构相同的表
hbase org.apache.hadoop.hbase.mapreduce.CopyTable --peer.adr=zk-addr1,zk-addr2,zk-addr3:2181:/hbase table_test
hbase org.apache.hadoop.hbase.mapreduce.CopyTable ... --starttime=start_timestamp --endtime=end_timestamp
hbase org.apache.hadoop.hbase.mapreduce.CopyTable ... --families=srcCf1,srcCf2#copy cf1,cf2两个列族,不改变列族名字
hbase org.apache.hadoop.hbase.mapreduce.CopyTable ... --families=srcCf1:dstCf1, srcCf2:dstCf2 #copy srcCf1到目标dstCf1新列族
总的来说,CopyTable支持的范围还是很多的,但因其涉及的是直接HBase层数据的拷贝,所以效率上会很低,同样需要在使用过程中限定扫描原表的速度和传输的带宽,这个工具实际上使用比较少,因为很难控制。
该出口方式转储表到HDFS在同一个集群上的内容。要恢复数据,将使用导入实用程序。
由于群集已启动,因此存在导出过程中可能错过编辑的风险。
此方式与CopyTable类似,主要是将HBase表数据转换成Sequence File并dump到HDFS,也涉及Scan表数据,与CopyTable相比,还多支持不同版本数据的拷贝,同时它拷贝时不是将HBase数据直接Put到目标集群表,而是先转换成文件,把文件同步到目标集群后再通过Import到线上表。主要有两个阶段:
Export阶段: 将原集群表数据Scan并转换成Sequence File到Hdfs上,因Export也是依赖于MR的,如果用到独立的MR集群的话,只要保证在MR集群上关于HBase的配置和原集群一样且能和原集群策略打通(master®ionserver策略),就可直接用Export命令,如果没有独立MR集群,则只能在HBase集群上开MR,若需要同步多个版本数据,可以指定versions参数,否则默认同步最新版本的数据,还可以指定数据起始结束时间,使用如下:
# output_hdfs_path可以直接是目标集群的hdfs路径,也可以是原集群的HDFS路径,如果需要指定版本号,起始结束时间
hbase org.apache.hadoop.hbase.mapreduce.Export
Import阶段: 将原集群Export出的SequenceFile导到目标集群对应表,使用如下:
#如果原数据是存在原集群HDFS,此处input_hdfs_path可以是原集群的HDFS路径,如果原数据存在目标集群HDFS,则为目标集群的HDFS路径
hbase org.apache.hadoop.hbase.mapreduce.Import
要打开快照支持,只需将该hbase.snapshot.enabled 属性设置为true即可。(默认情况下,快照在0.95+中启用,默认情况下在0.94.6+时关闭)
hbase.snapshot.enabled
true
无论是启用还是禁用,您都可以创建表的快照。快照操作不涉及任何数据复制。
$ ./bin/hbase shell
hbase> snapshot'myTable','myTableSnapshot-122112'
默认行为是在拍摄快照之前在内存中执行数据刷新。这意味着内存中的数据包含在快照中。在大多数情况下,这是期望的行为。但是,如果您的设置可以容忍从快照中排除内存中的数据,则可以使用SKIP_FLUSH该snapshot命令的选项在拍摄快照时禁用和刷新。
hbase> snapshot'mytable','snapshot123',{SKIP_FLUSH => true}
$ ./bin/hbase shell
hbase> list_snapshots
$ ./bin/hbase shell
hbase> delete_snapshot 'myTableSnapshot-122112'
$ ./bin/hbase shell
hbase> clone_snapshot'myTableSnapshot-122112','myNewTestTable'
$ ./bin/hbase shell
hbase> disable 'myTable'
hbase> restore_snapshot 'myTableSnapshot-122112'
使用16个映射器将名为MySnapshot的快照复制到HBase集群srv2(hdfs:/// srv2:8082 / hbase):
$ bin/hbase org.apache.hadoop.hbase.snapshot.ExportSnapshot -snapshot MySnapshot -copy-to hdfs://srv2:8082/hbase -mappers 16
限制带宽消耗
您可以通过指定-bandwidth参数来限制导出快照时的带宽消耗,该参数需要一个表示每秒兆字节数的整数。以下示例将上述示例限制为200 MB /秒。
$ bin/hbase org.apache.hadoop.hbase.snapshot.ExportSnapshot -snapshot MySnapshot -copy-to hdfs://srv2:8082/hbase -mappers 16 -bandwidth 200
snapshot的流程主要有三个步骤:
加锁对象是regionserver的memstore,目的是禁止在创建snapshot过程中对数据进行insert,update,delete操作
刷盘是针对当前还在memstore中的数据刷到HDFS上,保证快照数据相对完整,此步也不是强制的,如果不刷会,快照中数据有不一致风险
snapshot过程不拷贝数据,但会创建对HDFS文件的指针,snapshot中存储的就是这些指标元数据
snapshot实际内部是怎么做的呢,上面说到,snapshot只是对元数据信息克隆,不拷贝实际数据文件,我们以表test为例,这个表有三个region, 每个region分别有两个HFile
创建的snapshot放在目录/hbase/.hbase-snapshot/下, 元数据信息放在/hbase/.hbase-snapshot/data.manifest中, snapshot中也分别包含对原表region HFile的引用,元数据信息具体包括哪哪些呢:
1. snapshot元数据信息
2. 表的元数据信息&schema,即原表的.tableinfo文件
3. 对原表Hfile的引用信息
由于我们表的数据在实时变化,涉及region的Hfile合并删除等操作,对于snapshot而言,这部分数据HBase会怎么处理呢,实际上,当发现spit/compact等操作时,HBase会将原表发生变化的HFile拷贝到/hbase/.archive目录,如上图中如果Region3的F31&F32发生变化,则F31和F32会被同步到.archive目录,这样发生修改的文件数据不至于失效
snapshot的应用场景和上面CopyTable描述差不多,我们这里主要考虑的是数据迁移部分。数据迁移主要有以下几个步骤:
在原集群上,用snapshot命令创建快照,命令如下:
hbase> snapshot 'src_table', 'snapshot_src_table'
创建完快照后在/hbase根目录会产生一个目录:
/hbase/.hbase-snapshot/snapshot_src_table
#子目录下有如下几个文件
/hbase/.hbase-snapshot/snapshot_src_table/.snapshotinfo
/hbase/.hbase-snapshot/snapshot_src_table/data.manifest
在上面创建好快照后,使用ExportSnapshot命令进行数据迁移,ExportSnapshot也是HDFS层的操作,本质还是利用MR进行迁移,这个过程主要涉及IO操作并消耗网络带宽,在迁移时要指定下map数和带宽,不然容易造成机房其它业务问题,如果是单独的MR集群,可以在MR集群上使用如下命令:
hbase org.apache.hadoop.hbase.snapshot.ExportSnapshot \
-snapshot snapshot_src_table \
-copy-from hdfs://src-hbase-root-dir/hbase \
-copy-to hdfs://dst-hbase-root-dir/hbase \
-mappers 20 \
-bandwidth 20
上面这些流程网上很多资料都有提到,对于我们业务来说,还有一种场景是要同步的表是正在实时写的,虽然用上面的也可以解决,但考虑到我们表数据规模很大,几十个T级别,同时又有实时业务在查的情况下,直接在原表上就算只是拷贝HFile,也会影响原集群机器性能,由于我们机器性能IO/内存方面本身就比较差,很容易导致机器异常,所以我们采用的其它一种方案,