HBase是一种分布式、可扩展、支持海量数据存储的NoSQL数据库
逻辑上,HBase的数据模型同关系型数据库很类似,数据存储在一张表中,有行有列。但从HBase的底层存储物理存储结构(K-V)来看,HBase跟像是一个multi-dimensional map
首先保证Zookeeper集群的正常部署,并启动之:
[ironmanjay@hadoop102 zookeeper-3.4.10]$ bin/zkServer.sh start
[ironmanjay@hadoop103 zookeeper-3.4.10]$ bin/zkServer.sh start
[ironmanjay@hadoop104 zookeeper-3.4.10]$ bin/zkServer.sh start
Hadoop集群的正常部署并启动:注意:Hadoop集群安装部署看我这篇博客
[ironmanjay@hadoop102 hadoop-2.7.2]$ sbin/start-dfs.sh
[ironmanjay@hadoop103 hadoop-2.7.2]$ sbin/start-yarn.sh
在HBase官网下载相应版本,解压HBase到指定目录(目录自己指定):
[ironmanjay@hadoop102 software]$ tar -zxvf hbase-1.3.1-bin.tar.gz -C
/opt/module
修改HBase对应的配置文件
export JAVA_HOME=#/opt/module/jdk1.6.0_144
export HBASE_MANAGES_ZK=false
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://你的Hadoop地址:9000/HBase</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<!-- 0.98 后的新变动,之前版本没有.port,默认端口为 60000 -->
<property>
<name>hbase.master.port</name>
<value>16000</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>你的Hadoop集群名称</value>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>你的Zookeeper安装地址/zkData</value>
</property>
<configuration>
hadoop102
hadoop103
hadoop104
[ironmanjay@hadoop102 module]$ ln -s /opt/module/hadoop-2.7.2/etc/hadoop/core-site.xml /opt/module/hbase/conf/coresite.xml
[ironmanjay@hadoop102 module]$ ln -s /opt/module/hadoop-2.7.2/etc/hadoop/hdfs-site.xml /opt/module/hbase/conf/hdfssite.xml
这里用到了集群远程分发脚本,具体脚本代码看我上面Hadoop部署的博客
[ironmanjay@hadoop102 module]$ xsync hbase/
[ironmanjay@hadoop102 hbase]$ bin/start-hbase.sh
[ironmanjay@hadoop102 hbase]$ bin/stop-hbase.sh
启动成功后,可以通过“host:port”的方式来访问HBase管理页面,例如:
注意:16010端口不可改变,前面的Hadoop名称根据自己的修改即可
http://hadoop102:16010
[ironmanjay@hadoop102 hbase]$ bin/hbase shell
hbase(main):001:0> help
hbase(main):002:0> list
hbase(main):002:0> create 'student','info'
hbase(main):003:0> put 'student','1001','info:sex','male'
hbase(main):004:0> put 'student','1001','info:age','18'
hbase(main):005:0> put 'student','1002','info:name','Janna'
hbase(main):006:0> put 'student','1002','info:sex','female'
hbase(main):007:0> put 'student','1002','info:age','20'
hbase(main):008:0> scan 'student'
hbase(main):009:0> scan 'student',{STARTROW => '1001', STOPROW =>'1001'}
hbase(main):010:0> scan 'student',{STARTROW => '1001'}
hbase(main):011:0> describe 'student'
hbase(main):012:0> put 'student','1001','info:name','Nick'
hbase(main):013:0> put 'student','1001','info:age','100'
hbase(main):014:0> get 'student','1001'
hbase(main):015:0> get 'student','1001','info:name'
hbase(main):021:0> count 'student'
hbase(main):016:0> deleteall 'student','1001'
删除某rowkey的某一列数据:
hbase(main):017:0> delete 'student','1002','info:sex'
hbase(main):018:0> truncate 'student'
hbase(main):019:0> disable 'student'
然后才能drop这个表,如果直接drop表,会报错:ERROR: Table student is enabled. Disable it first
hbase(main):020:0> drop 'student'
hbase(main):022:0> alter 'student',{NAME=>'info',VERSIONS=>3}
hbase(main):022:0> get 'student','1001',{COLUMN=>'info:name',VERSIONS=>3}
由于memstore每次刷写都会生成一个新的HFile,且同一个字段的不同版本(timestamp)和不同类型的(Put/Delete)有可能会分布在不同的HFile中,因此查询时需要遍历所有的HFile。为了减少HFile的个数,以及清理掉过期和删除的数据,会进行StoreFile Compaction
Compaction分为两种,分别是Minor Compaction和Major Compaction。Minor Compaction会将临近的若干较小的HFile合并成一个较大的HFile,但不会清理过期和删除的数据。Major Compaction会将一个Store下的所有HFile合并成一个大HFile,并且会清理掉过期和删除的数据
默认情况下,每个Table起初只有一个Region,随着数据的不断写入,Region会自动进行拆分。刚拆分时,两个子Region都位于当前的Region Server,但出于负载均衡的考虑,HMaster有可能会将某个Region转移给其他的Region Server
Region Split时机:
使用Idea新建Maven项目后在pom.xml添加依赖
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.3.1</version>
</dependency>
public static Configuration conf;
static{
//使用 HBaseConfiguration 的单例方法实例化
conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", "你的集群地址");
conf.set("hbase.zookeeper.property.clientPort", "2181");
}
public static boolean isTableExist(String tableName) throws MasterNotRunningException,ZooKeeperConnectionException, IOException{
//在 HBase 中管理、访问表需要先创建 HBaseAdmin 对象
HBaseAdmin admin = new HBaseAdmin(conf);
return admin.tableExists(tableName);
}
public static void createTable(String tableName, String...columnFamily) throws MasterNotRunningException, ZooKeeperConnectionException,IOException{ HBaseAdmin admin = new HBaseAdmin(conf);
//判断表是否存在
if(isTableExist(tableName)){
System.out.println("表" + tableName + "已存在");
}else{
//创建表属性对象,表名需要转字节
HTableDescriptor descriptor = new HTableDescriptor(TableName.valueOf(tableName));
//创建多个列族
for(String cf : columnFamily){
descriptor.addFamily(new HColumnDescriptor(cf));
}
//根据对表的配置,创建表
admin.createTable(descriptor);
System.out.println("表" + tableName + "创建成功! ");
}
}
public static void dropTable(String tableName) throws MasterNotRunningException,ZooKeeperConnectionException, IOException{
HBaseAdmin admin = new HBaseAdmin(conf);
if(isTableExist(tableName)){
admin.disableTable(tableName);
admin.deleteTable(tableName);
System.out.println("表" + tableName + "删除成功! ");
}else{
System.out.println("表" + tableName + "不存在! ");
}
}
public static void getAllRows(String tableName) throws IOException{
HTable hTable = new HTable(conf, tableName);
//得到用于扫描 region 的对象
Scan scan = new Scan();
//使用 HTable 得到 resultcanner 实现类的对象
ResultScanner resultScanner = hTable.getScanner(scan);
for(Result result : resultScanner){
Cell[] cells = result.rawCells();
for(Cell cell : cells){
//得到 rowkey
System.out.println(" 行 键 :" +
Bytes.toString(CellUtil.cloneRow(cell)));
//得到列族
System.out.println(" 列 族 " +
Bytes.toString(CellUtil.cloneFamily(cell)));
System.out.println(" 列 :" +
Bytes.toString(CellUtil.cloneQualifier(cell)));
System.out.println(" 值 :" +Bytes.toString(CellUtil.cloneValue(cell)));
}
}
}
public static void getRowQualifier(String tableName, String rowKey,String family, String qualifier) throws IOException{
HTable table = new HTable(conf, tableName);
Get get = new Get(Bytes.toBytes(rowKey));
get.addColumn(Bytes.toBytes(family),
Bytes.toBytes(qualifier));
Result result = table.get(get);
for(Cell cell : result.rawCells()){
System.out.println(" 行 键 :" +
Bytes.toString(result.getRow()));
System.out.println(" 列 族 " +
Bytes.toString(CellUtil.cloneFamily(cell)));
System.out.println(" 列 :" +
Bytes.toString(CellUtil.cloneQualifier(cell)));
System.out.println(" 值 :" +
Bytes.toString(CellUtil.cloneValue(cell)));
}
}
通过 HBase 的相关 JavaAPI,我们可以实现伴随 HBase 操作的 MapReduce 过程,比如使用
MapReduce 将数据从本地文件系统导入到 HBase 的表中,比如我们从 HBase 中读取一些原
始数据后使用 MapReduce 做数据分析
bin/hbase mapredcp
export HBASE_HOME=你的HBase安装目录
export HADOOP_HOME=你的Hadoop安装目录
export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:你的HBase安装目录/lib/*
你的hadoop安装目录/bin/yarn jar lib/hbase-server-1.3.1.jar rowcounter student
在 HBase 中 HMaster 负责监控 HRegionServer 的生命周期,均衡 Region Server 的负载,如果 HMaster 挂掉了,那么整个 HBase 集群将陷入不健康的状态,并且此时的工作状态并不会维持太久。所以 HBase 支持对 HMaster 的高可用配置
[ironmanjay@hadoop102 hbase]$ bin/stop-hbase.sh
[ironmanjay@hadoop102 hbase]$ touch conf/backup-masters
[ironmanjay@hadoop102 hbase]$ echo hadoop103 > conf/backup-masters
[ironmanjay@hadoop102 hbase]$ scp -r conf/hadoop103:/opt/module/hbase/
[ironmanjay@hadoop102 hbase]$ scp -r conf/hadoop104:/opt/module/hbase/
http://hadoop102:16010/
每一个 region 维护着 StartRow 与 EndRow,如果加入的数据符合某个 Region 维护的RowKey 范围,则该数据交给这个 Region 维护。那么依照这个原则,我们可以将数据所要投放的分区提前大致的规划好,以提高 HBase 性能。
Hbase> create 'staff1','info','partition1',SPLITS => ['1000','2000','3000','4000']
create 'staff2','info','partition2',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}
aaaa
bbbb
cccc
dddd
然后执行
create 'staff3','partition3',SPLITS_FILE => 'splits.txt'
//自定义算法,产生一系列 hash 散列值存储在二维数组中
byte[][] splitKeys = 某个散列值函数
//创建 HbaseAdmin 实例
HBaseAdmin hAdmin = new HBaseAdmin(HbaseConfiguration.create());
//创建 HTableDescriptor 实例
HTableDescriptor tableDesc = new HTableDescriptor(tableName);
//通过 HTableDescriptor 实例和散列值二维数组创建带有预分区的 Hbase 表
hAdmin.createTable(tableDesc, splitKeys);
HBase 操作过程中需要大量的内存开销,毕竟 Table 是可以缓存在内存中的,一般会分配整个可用内存的 70%给 HBase 的 Java 堆。但是不建议分配非常大的堆内存,因为 GC 过程持续太久会导致 Region Server 处于长期不可用状态,一般16~48G内存就可以了,如果因为框架占用内存过高导致系统内存不足,框架一样会被系统服务拖死
属性:dfs.support.append
解释:开启 HDFS 追加同步,可以优秀的配合 HBase 的数据同步和持久化。默认值为 true
属性:dfs.datanode.max.transfer.threads
解释:HBase一般都会同一时间操作大量的文件,根据集群的数量和规模以及数据动作,设置为 4096 或者更高。默认值:4096
属性:dfs.image.transfer.timeout
解释:如果对于某一次数据操作来讲,延迟非常高,socket需要等待更长的时间,建议把该值设置为更大的值(默认60000 毫秒),以确保socket不会被timeout掉
属性:Hbase.regionserver.handler.count
解释:默认值为30,用于指定RPC监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值
属性:hbase.hregion.max.filesize
解释:默认值10737418240(10GB),如果需要运行HBase的MR任务,可以减小此值,因为一个region对应一个map任务,如果单个region过大,会导致map任务执行时间过长。该值的意思就是,如果HFile的大小达到这个数值,则这个region会被切分为两个Hfile
属性:hbase.client.write.buffer
解释:用于指定Hbase客户端缓存,增大该值可以减少RPC调用次数,但是会消耗更多内存,反之则反之。一般我们需要设定一定的缓存大小,以达到减少RPC次数的目的