大数据之HBase总结(上)

什么是HBase

HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统(File System)所提供的分布式数据存储一样,HBase在Hadoop之上提供了类似于Bigtable的能力。HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库,即Nosql。另一个不同的是HBase基于列的而不是基于行的模式。

HBase的体系结构


这是关于hbase体系结构官方的一张图,可以看出,hbase是基于hdfs之上的分布式数据库,hbase上的数据最终还是存到hdfs上。hbase和hdfs对应的存储结构如下:

HBaseHDFS
目录
数据文件(HFile)

也就是说,hbase上的表对应在hdfs上是目录的形式,表中的数据在hdfs上则是以文件的形式存在。

下面对上图做一点简化。

由上面两张图可以看出,和HDFS、YARN类似,HBase也是一个主从结构,主节点为HMaster,从节点为RegionServer。

  • HMaster
    • 负责管理和维护集群,以及数据的各种元信息,恢复regionserver的故障
    • 负责启动一个全新的安装,把region(区域)分配给注册的regionserver
  • RegionServer
    • 负责零个或多个region(区域)的管理
    • 负责管理和存储数据,执行客户端的读/写请求
    • 还负责region(区域)的划分,并把新的子区域通知HMaster
    • 有多个region,一个region在写入数据时先写入内存memstore,写满后写成文件storeFile(一个store对应一个列族),再合并成HFile存储在HDFS中(数据的写入/读取过程见下文)。

此外,与HDFS、YARN不同的是,客户端不能直接与主节点HMaster进行通信,要通过“中间人”zookeeper进行通信或读写请求。在HBase体系中,自带了一个zookeeper,可以直接使用,也可自行安装zookeeper,将其部署到HBase体系中。
ZooKeeper作为一个分布式应用程序协调服务,可以将其看为一个“数据库”。它用于选举一个集群内的主节点HMaster,存储着集群的元信息,包括HMaster的信息、在实现HA(高可用性)时存储着HMaster的active或standby状态(上图中的紫色HMaster就是standby状态)。客户端通过访问zookeeper就可以知道HMaster的位置信息,以及应该访问哪个HMaster,建立客户端到该HMaster的连接。

如果在region的分配过程中某个服务器崩溃了,就可以通过zookeeper来进行分配的协调,在zookeeper上管理分配事务的状态有助于在恢复时能够从崩溃的服务器遗留的状态开始分配;在HA高可用中,如果主节点HMaster崩溃了,zookeeper可以将另一个standby状态的HMaster切换为active的主节点,继续执行集群的管理和任务。

HBase的表结构

先看HBase表和关系型数据库Oracle的对比


和一般的表类似,HBase的表由行和列组成。表格的“单元格”由行和列的坐标交叉决定,是有版本的,默认情况下,版本号是自动分配的,为HBase插入单元格时的时间戳。
表中行的键rowkey也是也是字节数组,所以理论上任何东西都能通过表示成字符串或将二进制形式转化为长整型或直接对数据结构进行序列化,来作为键值。表中的行根据行的键值(也就是表的主键进行排序,默认是升序),所有对表的访问都要通过表的主键。行键rowkey不能为null,可以重复,但是相同的rowkey是同一条数据。

行中的列被分为Column Family(“列族”或“列簇”),Table在水平方向有一个或者多个Column Family组成,一个Column Family中可以由任意多个Column(列)组成,即Column Family支持动态扩展,无需预先定义Column的数量以及类型,所有Column均以二进制格式存储,用户需要自行进行类型转换。同一个列族的所有成员具有相同的前缀,一般为列族的名称。列族和修饰符(即列名)始终以冒号分格。如上图中的列info:name和info:age都是列族info的成员。

用上面的图作例子来说,在创建student表的时候只创建了info和grade两个列族,但是在插入数据的时候,对于Oracle中的一行数据,可以通过指定相同的行键s001来保证插入hbase中的是同一条数据,并且在插入时通过 列族:列名 的格式指定数据插入的位置,如果该列族中没有该列,则会自动创建,并将数据存入,如指定’info:name’在列族info中建立name列,然后再把TOM这个值插入这一列。

所以,一个hbase表的列族必须作为表模式定义的一部分预先给出,不能更改,但是新的列族成员(即新的列)可以随时按需要加入。物理上,所有的列族成员都一起存放在文件系统中。所以,虽然说HBase是面向列的存储器,但是实际上更准确的说法是面向列族的存储器。调优和存储都是在列族这个层次上进行的,所有列族成员都应具有相同的访问模式和大小特征。

到此,对比上图再看HBase和RDBMS中的区别,简单来说两者类似,只是HBase表的单元格有版本,行是排序的,行键(主键)是可以重复的,而只要列族预先存在,就可以随时把新的列添加到列族中去。此外,HBase是一个分布式、面向列的数据存储系统,通过在HDFS上提供随机读/写来解决大规模数据的处理问题。它的表可以很“高”(数十亿个数据行),也可以很宽(数百万个列);水平分区并在上千个普通商用机节点上自动复制。表的模式是物理存储的直接反映,使系统有可能提供高效的数据结构的序列化、存储和检索。

-ROOT- && .META. Table

HBase中有两张特殊的Table,-ROOT-和.META.

.META.:记录了用户表的Region信息,.META.可以有多个regoin

-ROOT-:记录了.META.表的Region信息,-ROOT-只有一个region

Zookeeper中记录了-ROOT-表的location
Client访问用户数据之前需要首先访问zookeeper,然后访问-ROOT-表,接着访问.META.表,最后才能找到用户数据的位置去访问,

HBase Shell

HBase提供了一个shell的终端给用户交互,启动hdfs和hbase后,通过在命令行输入"hbase shell"就可以进入hbase的shell终端,对hbase进行操作,常见的一些操作命令如下:

名称命令表达式
创建表create ‘表名称’,‘列族名称1’,‘列族名称2’,‘列族名称n’
添加记录put ‘表名称’,‘行名称’,‘列族名称:列名称’,‘值’
查看记录get ‘表名称’,‘行名称’
查看表中的记录数count ‘表名称’
删除记录delete ‘表名’,‘行名称’,‘列名称’
删除一张表先要屏蔽该表,才能对该表进行删除,第一步disable ‘表名称’ 第二部 drop ‘表名称’
查看所有记录scan ‘表名称’
查看某个表某个列中所有的数据scan ‘表名称’,{COLUMNS=>‘列族名称:列名称’}
更新记录就是重写一遍进行覆盖

HBase上的过滤器

HBase上的过滤器类似程序中的if条件判断,即将需要的数据提取出来,不需要的数据过滤掉,主要有以下几种:

  • 列值过滤器:就是在某个列中过滤出需要的数值,其API为SingleColumnValueFilter
  • 列名前缀过滤器:在列族的多个列中提出需要的某一列的所有值,就是取出某一列,其API为ColumnPrefixFilter
  • 多个列名前缀过滤器:提取多个列的所有值,其API为MultiplColumnPrefixFilter
  • Rowkey过滤器:取出某个行键的所有记录,其API为RowFilter
  • 多个组合过滤器:同时使用多个过滤器,通过放在同一个list作为“一个”过滤器使用,其API为FilterList

HBase上的MapReduce

HDFS上的MapReduce在运行过程中Mapper的输入<k1,v1>和输出<k2,v2>,以及Reducer的输入<k3,v3>和输出<k4,v4>。但是HBase上的MapReduce不同,其API分别是TableMapper和TableReducer。它的Mapper没有刚刚所说的输入<k1,v1>,只有输出<k2,v2>,因其输入就是HBase上的每一行数据,不需要额外指定。它的Reducer也不需要指定k4,因为处理的结果都是输出至HBase表上的,只需要将其行键k4和结果一起输出即可,具体例子如下(wordcount程序):
先在HBase上创建一张word表作为输入源

create 'word','content'
put 'word','1','content:info','I love Beijing'
put 'word','2','content:info','I love China'
put 'word','3','content:info','Beijing is the capital of China'

再创建一张stat表作为输出源

create 'stat','content'
  • Mapper
//这时候处理的就是HBase表中的一条数据                                                          
// <k1  v1>代表输入,现在输入是:表中的一条记录        k2        v2
public class WordCountMapper extends TableMapper<Text, IntWritable> {

	@Override
	protected void map(ImmutableBytesWritable key, Result value,Context context)
			throws IOException, InterruptedException {
		// 获取数据: I love Beijing
		String data = Bytes.toString(value.getValue(Bytes.toBytes("content"), Bytes.toBytes("info")));
		
		//分词
		String[] words = data.split(" ");
		
		for(String w:words){
			context.write(new Text(w), new IntWritable(1));
		}
	}
}
  • Reducer
//                                                  k3      v3      keyout代表输出的一条记录:指定行键
public class WordCountReducer extends TableReducer<Text, IntWritable, ImmutableBytesWritable> {

	@Override
	protected void reduce(Text k3, Iterable<IntWritable> v3,Context context)
			throws IOException, InterruptedException {
		//对v3求和
		int total = 0;
		for(IntWritable v:v3){
			total = total + v.get();
		}
		
		//输出:也是表中的一条记录
		//构造一个Put对象,把单词作为rowkey
		Put put = new Put(Bytes.toBytes(k3.toString()));
		put.add(Bytes.toBytes("content"),  //列族
				Bytes.toBytes("result"),   // 列
				Bytes.toBytes(String.valueOf(total)));  //值
		
		//输出
		context.write(new ImmutableBytesWritable(Bytes.toBytes(k3.toString())), 
				     put);//得到结果
	}

}

  • main

由于zookeeper的存在和MapReducer的不同,HBase的主程序也有所不同,具体如下:

public static void main(String[] args) throws Exception {
		//指定Zookeeper地址
		//指定的配置信息: ZooKeeper
		Configuration conf = new Configuration();
		conf.set("hbase.zookeeper.quorum", "zookeeper所在ip地址");
		
		//创建一个任务
		Job job = Job.getInstance(conf);
		job.setJarByClass(WordCountMain.class);
		
		//定义一个扫描器只读取 content:info这个列的数据
		Scan scan = new Scan();
		scan.addColumn(Bytes.toBytes("content"), Bytes.toBytes("info"));
		
		//指定mapper
		TableMapReduceUtil.initTableMapperJob(Bytes.toBytes("word"),   //输入的表
				                              scan,    //定义一个扫描器,过滤我们想要处理的数据
				                              WordCountMapper.class, //运行哪个mapper
				                              Text.class, //k2的类型
				                              IntWritable.class, //v2的类型
				                              job);
		
		//指定reducer
		//                                      表名,哪个reducer,任务
		TableMapReduceUtil.initTableReducerJob("stat", WordCountReducer.class, job);
		
		//执行任务
		job.waitForCompletion(true);
	}




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值