HBase原理

目录

                                   

                                            HBase原理

1 HBase架构

2 HBase中的核心概念

3 HBase的存储机制

4 HBase的寻址机制

5 HBase的读写流程

6 HBase的设计

7 HBase和Hive的整合


               

                                            HBase原理

1 HBase架构

HBase的架构为主从架构,HMaster为主节点,HRegionServer为从节点

(1)HMaster职责:

①进行Region的分配,每一个Region分配到哪一个RegionServer上;

②负责RegionServer的负载均衡

③通过zookeeper发小失效的RegionServer并重新分配在它上面的Region

④HDFS上的HBase的垃圾文件回收

⑤处理schema更新请求,表的创建,删除,更改,列簇的增加等,将schema写入到zookeeper中

(2)HRegionserver职责

①管理每个Region

②负责每一个Region的分裂

(3)zookeeper职责

①进行HMaster的active的选举,避免单点故障

②存储HBase的寻址机制

③存储RegionServer的存活状态,HMaster通过zookeeper获取每一个HRegionServer的状态

④存储表的schema表结构

2 HBase中的核心概念

(1)Region

每一个表的数据,都需要进行划分成多个Region,Region对HBase表的划分是在行的方向上的。一个Region代表一个表中的多行数据,一定是行键范围内的数据。

Region是HBase进行分布式存储的最小单位,负载均衡的的存储单位,注意并不是物理存储的最小单位。一个Region是不能再进行分割的,在分布式存储的时候一个Region只能存储在一个HRegionserver即一个节点上,一个HRegionserver是可以存储多个Region的。

一个HBase表刚创建的时候只有一个Region,进行数据插入的时候,写入的都是这一个Region,随着数据插入的,数据量不断的增加当数据量达到一定值的时候(默认为10G)就会进行切分,将一个Region切分为2个Region,一旦切分完成,就会面临Region的重新分配,由HMaster分配每一个Region存储在哪个HRegionServer,原来的那个Region就没用了,进行下线。

配置文件中对切分大小的配置如下:


    hbase.hregion.max.filesize
    10737418240
    
    Maximum HStoreFile size. If any one of a column families' HStoreFiles has
    grown to exceed this value, the hosting HRegion is split in two.

每一个Region中一个列族的物理文件达到10G才进行切分,切分的时候是按照rowkey的中间值进行切分的。

一个表是对应多个Region,多个Region对应多个物理文件的(一个列族一个物理文件)。每一个Region 都有一个全局唯一的一个编号,hdfs位置为:/user/hbase/data/default(namespace)/table_hbase(table)/313c7bb8491d6207ac0153c0392cc392(region编号)

刚开始对Hbase中表数据进行插入操作时候,操作只有一个Region,在这个Region分裂之前  操作的都是这一个Region 操作的只有一个Regionserver ,会出现 数据热点,anemia如何解决呢,下面表设计时再进行介绍。

(2)Store

一个Store对应一个列族,Store是HBase物理存储的最小单位,1个Region对应多个Store,多个Store对应多个列族。一个Store中包含一个MemStore和多个StoreFile。

(3)MemStore

每一个Store中,都有一位于内存中的MemStore存储空间,写入数据的时候,每一个Store中的数据先写入到MemStore,读取数据的时候先从内存中读取MemStore。

(4)StoreFile

每一个Store有多个位于硬盘的StoreFile磁盘文件,当MemStore达到一定阈值(默认为128M)的时候,就会将数据flush,形成一个个的StoreFile,配置文件中的参数如下


    hbase.hregion.memstore.flush.size
    134217728
    
    Memstore will be flushed to disk if size of the memstore
    exceeds this number of bytes.  Value is checked by a thread that runs
    every hbase.server.thread.wakefrequency.
 

(5)HFile

最终StoreFile文件以HFile格式存储在HDFS上。

(6)WAL(HLog)

WAL:write-ahead-log预写日志文件,为了防止在MemStore中数据丢失,在写入数据之前,会先将对数据的操作写入到WAL文件中。

一个HRegionServer中只会存储一个WAL文件,一个HREgionServer中的所有的Region共用一个WAL文件,便于管理日志。

3 HBase的存储机制

(1)0.96版本之前的存储机制

①原始表:存储原始数据的

②.meta表:存储原始数据的索引的,按照rowkey创建原始表索引

③-root-表:存储.meta表的索引的表,这个是最终索引,无论多大,只有一个Region不可分割了。-root-表的最终Region的存储位置存储在了zookeeper中,所以zookeeper中存储的是HBase的寻址路径。

(2)0.96版本之后的存储机制

①原始表:存储原始数据的

②.meta表:存储原始数据的索引的,按照rowkey创建原始表索引。.meta无论多大,只存储在一个Region,不可再进行分割了。.meta表的Region的存储位置存储在了zookeeper中。

.meta表中的一条数据相当于原始表至少10个G的数据,所以.meta表很难达到分割范围,除非数据量超级大才能达到。

4 HBase的寻址机制

HBase表最终会被拆分成一个个的Region,每一个Region可能会存储在不同的HRegionServer,每一个Region都是有独立编号的,无论读还是写操作,首先都要定位到在哪一个Region中,到对应的存储了该Region的HRegionServer上找到这个Region进行操作。

(1)0.96版本之前的寻址过程:

①客户端首先访问zookeeper,获取存储了-root-表的RegionServer的位置,以及Region的编号

②访问-root-表的Region,获取存储了.meta表的RegionServer的位置,以及Region的编号

③访问.meta表,获取可需要查询的rk所在的Region位置,获取原始数据的RegionServer的位置,以及Region的编号

④开始真正的访问对应RegionServer上的Region的的表数据

(2)0.96版本之后的寻址过程

①客户端首先访问zookeeper,获取存储.meta表的HRegionServer的位置,以及Region编号

②访问.meta表的Region,获取原始数据表中对应的HRegionServer的Region编号

③开始真正的访问对应RegionServer上的Region的的表数据

5 HBase的读写流程

(1)写流程(put|delete)

①客户端根据rowkey经常3次往返(寻址机制)找到对应的Region所在的RegionServer;

②客户端向RegionServer提交写请求;

③RegionServer找到目标Region

④Region检查数据是否与schema表结构的表名,列簇是否一致,一致则允许写入,不一致则报错直接返回。

⑤如果客户端没有指定版本,则获取当前的时间作为数据版本

⑥将更新操作写入到WAL文件中

⑦将更新写入到对应的Store中的MemSore

⑧判断MemStore是否需要flush刷新为StoreFile文件,默认当阈值MemStore文件大小达到128M的时候开始flush,形成StoreFile文件。

⑨当一个StoreFile的个数达到一定的阈值的时候就会触发compact合并,compact合并有minor compact和major compact:

minor join小合并,触发条件默认为StoreFile文件的个数达到3个的时候触发,将3个StoreFile合并为1个StoreFile文件,这个合并是没有任何逻辑操作的,只是物理操作,简单的将文件进行累加合并,只是在文件的个数上减少了,不会对真正需要删除的数据进行删除,只是打了标记,客户端看不到。

major join:当达到阈值(默认为7天)后,会将7天的多个HFile文件进行合并为1个HFile,这个合并是执行逻辑操作的,进行真正的数据删除,将所有需要删除的数据进行真正的合并删除。需要删除的数据有以下几种:

1)执行delete操作的数据;

2)版本超过给定的需要保存的版本的数据,将过期的数据删除

3)TTL过期的数据

⑩判断一个Store中的所有文件的总大小是否达到Region的切分标准,默认为128M,达到切分标准就会对Region进行切分,HMaster对新的Region进行重新的分配,丢弃旧的Region。

(2)读流程(get|scan)

①客户端根据rowkey经过3次往返(寻址机制)找到对应的Region所在的RegionServer

②客户端向对应的RegionServer的·Region发送读数据请求

③客户端先在Region的对应的Store的MemStore(Blockcache)中进行读取

④MemStore有数据则直接返回,没有数据则到HFile文件进行读取。

 

6 HBase的设计

(1)表设计

①防止数据热点问题,建表的时候最好进行表的预分区,插入数据的时候,rowkey不要顺序递增。

HBase中你的数据热点:进行读写操作的时候,频繁操作某一个Region造成这个Region所在的RegionServer热点,根源是经常访问的数据集中分配到了个别Region

②列族不建议过多

(2)列族设计

①将具有相同io属性的列放在同一个列簇中;

②列簇不宜过多,不要超过3个,因为不同的列簇需要跨文件访问

(3)行键设计

思路:首先根据业务,需要安装哪一个字段查询,然后要避免热点产生

①保证唯一性

②不宜过长,0-100byte,最好不要超过16byte,最好是8的倍数。原因如下

1)行键存储在每一个列簇文件中的StoreFile,如果太大会造成磁盘空间的浪费

2)行键信息也会写入到每一个Store的MemStore中,如果过长,会造成内存空间的极大浪费

2)大部分计算机的底层存储时8通道的

③散列性

rowkey是按照字典顺序排序的,如果rowkey过于集中,会造成数据操作集中在个别的Region上,造成数据热点

有效措施如下:

1)采用hash

2)加盐:在原生的rowkey前面加上随机数

3)反转:将字符串或时间戳进行反转

4)使用uuid或md5等方法

7 HBase和Hive的整合

HBase:是NoSQL分布式数据库,表结构是四维表。擅长做实时随机查询,没有分析函数join等

Hive:数据仓库,擅长做数据分许,有大量函数可以使用

HBase语法是不支持分析的,想要对HBase中的数据做数据分析就要将HBase和Hive整合,便于对HBase数据做统计分析。Hive读取HBase中的数据,将HBase中的数据转换二维表数据,需要hive-hbase-handler-2.3.2.jar包(整合的核心包)中的HBaseStorageHandler类,将HBase中的数据进行压平。

整个步骤如下:

①设置HBase的zookeeper访问路径:

set hbase.zookeeper.quorum=bigdata01:2181,bigdata02:2181,bigdata03:2181;

②设置HBase在zookeeper的访问路径,存储节点

set zookeeper.znode.parent=/hbase;

③将Hive的解析HBase的jar包添加到Hive的classpath下

add jar /home/refuel/opt/modules/apache-hive-2.3.2-bin/lib/hive-hbase-handler-2.3.2.jar;

 

整合完后在Hive中 读取HBase的表,在Hive建表语句指定解析类,全关联如下

create external table Hive_HBase(rowkey string, base_info map, extra_info map) 
row format delimited fields terminated by '\t' 
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties ("hbase.columns.mapping" = ":key,base_info:,extra_info:")
tblproperties ("hbase.table.name" = "Hive_HBase");

with serdeproperties   指定hbase表和hive的对应关系的
hbase.columns.mapping   指定hbase表和hive表映射   
                和hive中的建表语句一一对应的
                指定hbase 对应值的时候  k(列族名):v(列族下的对应的列和值) 
                key:base_info
                value:  name:zs    age:12              
                :key   获取rowkey 的值
hbase.table.name:  指定对应的表名

部分关联如下

create external table Hive_HBase02(rowkey string,name string,age int,math int) 
row format delimited fields terminated by '\t' 
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties ("hbase.columns.mapping" = ":key,base_info:name,base_info:age,extra_info:math") 
tblproperties ("hbase.table.name" = "Hive_HBase02");

8 HBase的BulkLoad

HBase的数据导入有3种方式:①put方式一条条插入;②MapReduce方式并发导入;③BulkLoad方式

MapReduce与put方式导入数据的过程:文本数据---》HRegionServer---》WAL---》MemStore---》StoreFile---》HFile

BulkLoad方式将文本数据(结构化或半结构化)直接转换为HFile格式的数据,转换完成之后再将这个HFile数据放置在HBase的对应的表的存储目录下

所以BulkLoad的优势是省去了中间的写入数据的复杂的过程,直接得到最终的结果,效率极高。

BulkLoad如何进行海量数据的导入的呢?,如下两个重要的类

(1)HBase中提供了一个进行数据装换的类PutSortReducer将数据封装为HFile需要的格式

ImmutableBytesWritable:行键       Put:需要插入的数据对象       KeyValue:单元格

(2)HBase中还提供了一个输出格式的类HFileOutputFormat2 ,数据的为HFile格式数据,而不是文本。

所以实现如下:

Map端:

            读取每一行文本数据,并封装PutSortReducer需要的数据

            输出的key为ImmutaByteaWritable,输出的value为Put

Reduce端:

            使用PutSortReducer类,进行准备Hfile需要的数据

驱动类:

            文件输出格式采用HFileOutputFormat2

注意:上面的这些操作仅仅是将文本数据转换为HFile格式的数据。转换完成之后,还要将这个HFile数据放置在HBase的对应的表的存储目录下面。

具体实现代码如下:

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.HFileOutputFormat2;
import org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

public class BulkLoadMR {
	static class MyMapper extends Mapper {
		ImmutableBytesWritable mk = new ImmutableBytesWritable();

		@Override
		protected void map(LongWritable key, Text value,
				Mapper.Context context)
				throws IOException, InterruptedException {

			String[] datas = value.toString().split("\t");
			if (datas.length == 3) {
				mk.set(datas[0].getBytes());
				Put p = new Put(datas[0].getBytes());
				p.addColumn("column_faily1".getBytes(), "name".getBytes(), datas[1].getBytes());
				p.addColumn("column_faily2".getBytes(), "age".getBytes(), datas[2].getBytes());
				context.write(mk, p);
			}
		}

	}

	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		conf.set("fs.defaultFS", "hdfs://bigdatagroup/");
		conf.set("hbase.zookeeper.quorum", "bigdata01:2181,bigdata02:2181,bigdata03:2181");

		Job job = Job.getInstance(conf);
		job.setJarByClass(BulkLoadMR.class);

		job.setMapperClass(MyMapper.class);
		job.setMapOutputKeyClass(ImmutableBytesWritable.class);
		job.setMapOutputValueClass(Put.class);

		job.setOutputKeyClass(ImmutableBytesWritable.class);
		job.setOutputValueClass(KeyValue.class);

		FileInputFormat.addInputPath(job, new Path("/data/student"));
		// 指定输出HFileOutputFormat2
		job.setOutputFormatClass(HFileOutputFormat2.class);
		// 进行输出
		HFileOutputFormat2.setOutputPath(job, new Path("/user/hbase/bulkload"));

		Connection conn = ConnectionFactory.createConnection(conf);
		HTable table = (HTable) conn.getTable(TableName.valueOf("table_bulkload"));
		// 设置对应表 参数1 job 参数2 表对象 参数3 加载region相关参数的
		// 准备需要的操作
		HFileOutputFormat2.configureIncrementalLoad(job, table, table.getRegionLocator());

		job.waitForCompletion(true);

		// 上面的这些操作仅仅是将文本数据转换为HFile格式的数据。
		// 转换完成之后,还要将这个HFile数据放置在HBase的对应的表的存储目录下面。
		LoadIncrementalHFiles loadH = new LoadIncrementalHFiles(conf);
		Admin admin = conn.getAdmin();
		// 进行加载
		// 参数1 hdfs 输出hfile 路径 参数2 admin 参数3 table 参数4:regioin信息对象
		loadH.doBulkLoad(new Path("/user/hbase/bulkload"), 
				admin, table, table.getRegionLocator());

	}
}

 

 

你可能感兴趣的:(HBase)