Apache Hbase基本概念及Java API
一、Apache Hbase基本概述Apache Hbase是一个基于Hadoop的数据库,它可靠、数据多版本、分布式适合结构化大数据的存储,Apache Hbase是Google BigTable开源实现,基于列储存的菲关系型数据库。(1)列储存和行储存的区别列储存和行储存是指数据子存储介质中的额储存方式**·**关系型数据库(行储存):Oracle、mysql等**·**非关系型数据库(列储存
一、Apache Hbase基本概述
Apache Hbase是一个基于Hadoop的数据库,它可靠、数据多版本、分布式适合结构化大数据的存储,Apache Hbase是Google BigTable开源实现,基于列储存的菲关系型数据库。
(1)列储存和行储存的区别
列储存和行储存是指数据子存储介质中的额储存方式
**·**关系型数据库(行储存):Oracle、mysql等
**·**非关系型数据库(列储存):Hbase、Redis
(2)Hbase数据模型及概念
(1)主键rowkey:获取数据的唯一标识,不能重复,根据字典顺序自动排序,底层储存时byte【】。
(2)列簇column family:多个列的集合,通常一个列簇中存放的是一组功能相近或者业务相近的集合。
(3)单元格cell:rowkey+column family + column定位一个cell,cell有多版本,默认为1个。
(4)多版本:cell允许有读个数据版本。
(5)版本号:系统当前的时间戳,默认会将时间戳最新的cell数据返回给用户。
(6)列column:colume列簇中的一个字段,用来存放某一类别的数据。
(3)Hbase特点:
(1)大:一个表可以有上百亿行上百万列。
(2)面向列:面向列表(列簇)的存储和控制权限
(3)结构稀疏:对于为空(NULL)的列,并不占用储存空间,因此,表可以设计的非常稀疏。
(4)无模式:每一行都有一个可以排序的主键和任意多的列,列可以根据需要动态增加,同一张表中的不同行可以有截然不同的列。
(5)数据多版本:每个单元格中的数据可以有多个版本,默认情况下,版本号自动分配,版本就是单元格插入时的时间戳。
(6)数据类型单一:Hbase中的数据在底层储存是都是byte【】,可以存放任意类型的数据。
(4)Hbase架构详解及完全分布式结构
完全分布式结构:
zookeeper作为hbase集群的入口(后面java api中从连接hbase的方式就能看出来)
hbase架构详解:
HBase中的每张表都通过rowKey按照一定的范围被分割成多个子表(HRegion),默认一个HRegion超过256M就要被分割成两个,这个过程由HRegionServer管理,而HRegion的分配由HMaster管理。
HMaster的作用:
(1)为HRegionServer分配HRegion
(2)负责HRegionServer的负载均衡
(3)发现失效的HRegionServer并重新分配
(4)HDFS上的垃圾文件回收
(5)处理Schema更新请求
HRegionServer的作用:
(1)维护HMaster分配给它的HRegion,处理对这些HRegion的IO请求
(2)负责切分正在运行过程中变得过大的HRegion
可以看到,Client访问HBase上的数据并不需要HMaster参与,寻址访问ZooKeeper和HRegionServer,数据读写访问HRegionServer, HMaster仅仅维护Table和Region的元数据信息,Table的元数据信息保存在ZooKeeper上,负载很低。HRegionServer存取一个子表时,会创建一个HRegion对象,然后对表的每个列簇创建一个HStore对象,每个HStore都会有一个MemStore和0或多个StoreFile与之对应,每个StoreFile都会对应一个HFile,HFile就是实际的存储文件。因此,一个HRegion有多少列簇就有多少个Store。 一个HRegionServer会有多个HRegion和一个HLog。
HRegion
Table在行的方向上分割为多个HRegion,HRegion是HBase中分布式存储和负载均衡的最小单元,即不同的HRegion可以分别在不同的HRegionServer上,但同一个HRegion是不会拆分到多个HRegionServer上的。HRegion按大小分割,每个表一般只有一个HRegion,随着数据不断插入表,HRegion不断增大,
当HRegion的某个列簇达到一个阀值(默认256M)时就会分成两个新的HRegion。
1、<表名,StartRowKey, 创建时间>
2、由目录表(-ROOT-和.META.)记录该Region的EndRowKey
HRegion定位:HRegion被分配给哪个HRegionServer是完全动态的,所以需要机制来定位HRegion具体在哪个HRegionServer,HBase使用三层结构来定位HRegion:
1、通过zk里的文件/hbase/rs得到-ROOT-表的位置。-ROOT-表只有一个region。
2、通过-ROOT-表查找.META.表的第一个表中相应的HRegion位置。其实-ROOT-表是.META.表的第一个region;
.META.表中的每一个Region在-ROOT-表中都是一行记录。
3、通过.META.表找到所要的用户表HRegion的位置。用户表的每个HRegion在.META.表中都是一行记录。
-ROOT-表永远不会被分隔为多个HRegion,保证了最多需要三次跳转,就能定位到任意的region。Client会将查询的位置信息保存缓存起来,缓存不会主动失效,
因此如果Client上的缓存全部失效,则需要进行6次网络来回,才能定位到正确的HRegion,其中三次用来发现缓存失效,另外三次用来获取位置信息。
HStore
每一个HRegion由一个或多个HStore组成,至少是一个HStore,HBase会把一起访问的数据放在一个HStore里面,即为每个ColumnFamily建一个HStore,如果有几个ColumnFamily,也就有几个HStore。一个Store由一个MemStore和0或者多个StoreFile组成。 HBase以Store的大小来判断是否需要切分HRegion。
MemStore
MemStore 是放在内存里的,保存修改的数据即keyValues。当MemStore的大小达到一个阀值(默认64MB)时,MemStore会被Flush到文件, 即生成一个快照。目前HBase会有一个线程来负责MemStore的Flush操作。
StoreFile
MemStore内存中的数据写到文件后就是StoreFile,StoreFile底层是以HFile的格式保存
HLog
HLog(WAL log):WAL意为write ahead log,用来做灾难恢复使用,HLog记录数据的所有变更,一旦region server 宕机,就可以从log中进行恢复。
简单描述一下Hbase故障恢复的过程:
Hmaster发现某些HregionServer不可用,开始故障恢复,获取故障的HregionServer的Hlog,分离每一个HRegion写指令,重新分配Hregion,在配到HregionServer中恢复HRegion数据,执行分离的HRegion写指令恢复MemStore,持久化完成的数据可以直接从HDFS中获取。
(二)Hbase Java API
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-common</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-protocol</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-common</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-protocol</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
package com.learn;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
public class HbaseAPI {
private Admin admin;
private Connection connection;
@Before
public void doBefore() throws IOException {
Configuration configuration = HBaseConfiguration.create();
configuration.set(HConstants.ZOOKEEPER_QUORUM,"192.168.139.156:2181");
connection = ConnectionFactory.createConnection(configuration);
admin = connection.getAdmin();
}
@Test
public void testCreateNameSpace() throws IOException {
NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create("gaoj").addConfiguration("author", "gaojian").build();
admin.createNamespace(namespaceDescriptor);
}
@Test
public void testCreateTable() throws IOException {
HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf("gaoj:t_order"));
HColumnDescriptor cf1 = new HColumnDescriptor("cf1");
cf1.setMaxVersions(3);
HColumnDescriptor cf2 = new HColumnDescriptor("cf2");
cf2.setTimeToLive(1800);
hTableDescriptor.addFamily(cf1);
hTableDescriptor.addFamily(cf2);
admin.createTable(hTableDescriptor);
}
@Test
public void testInsert() throws IOException {
Table table = connection.getTable(TableName.valueOf("gaoj:t_order"));
Put put = new Put(Bytes.toBytes("order101"));
put.addColumn(Bytes.toBytes("cf1"),Bytes.toBytes("count"),Bytes.toBytes(123));
table.put(put);
}
@Test
public void testSelect() throws IOException {
Table table = connection.getTable(TableName.valueOf("gaoj:t_order"));
Get get = new Get(Bytes.toBytes("order101"));
Result result = table.get(get);
String name = Bytes.toString(result.getValue(Bytes.toBytes("cf1"), Bytes.toBytes("name")));
System.out.println(name);
}
@Test
public void testDelete() throws IOException {
Table table = connection.getTable(TableName.valueOf("gaoj:t_order"));
Delete delete = new Delete(Bytes.toBytes("order101"));
ArrayList<Delete> list = new ArrayList<Delete>();
list.add(delete);
table.delete(list);
}
@Test
public void testScan() throws IOException {
Table table = connection.getTable(TableName.valueOf("gaoj:t_order"));
Scan scan = new Scan();
ResultScanner scanner = table.getScanner(scan);
Iterator<Result> iterator = scanner.iterator();
while (iterator.hasNext()){
Result next = iterator.next();
String row = Bytes.toString(next.getRow());
String name = Bytes.toString(next.getValue(Bytes.toBytes("cf1"), Bytes.toBytes("name")));
System.out.println(row + "*" + name);
}
}
@After
public void doAfter() throws IOException {
if(admin != null){
admin.close();
}
if(connection != null){
connection.close();
}
}
}
以上api实现了数据的增删改查,关于Hbase,更多的掌握的是API的使用,在学习的过程中,我们可以使用help指令帮助学习。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)