HBase从入门到放弃
HBase解决了什么问题:
1)HBase主要解决在Hdfs上可以随机读写的问题
2)Hive只能查询,不能随机读写
一、HBase依赖于Zookeeper和HDFS
1)Zookeeper
HBase通过Zookeeper来做master的高可用、RegionServer的监控、元数据的入口以及集群配置的维护等工作。具体工作如下:
通过Zoopkeeper来保证集群中只有1个master在运行,如果master异常,会通过竞争机制产生新的master提供服务
通过Zoopkeeper来监控RegionServer的状态,当RegionSevrer有异常的时候,通过回调的形式通知Master RegionServer上下线的信息
通过Zoopkeeper存储元数据的统一入口地址
2)HDFS
HDFS为Hbase提供最终的底层数据存储服务,同时为HBase提供高可用(Hlog存储在HDFS)的支持,具体功能概括如下:
提供元数据和表数据的底层分布式存储服务
数据多副本,保证的高可靠和高可用性
二、HBase中的角色
1.3.1 HMaster
功能
1.监控RegionServer
2.处理RegionServer故障转移
3.处理元数据的变更
4.处理region的分配或转移
5.在空闲时间进行数据的负载均衡
6.通过Zookeeper发布自己的位置给客户端
1.3.2 RegionServer
功能
1、HregionServer直接对接用户的读写请求,是真正的“干活”的节点。它的功能概括如下:
2、管理master为其分配的Region
3、处理来自客户端的读写请求
4、负责和底层HDFS的交互,存储数据到HDFS
5、负责Region变大以后的拆分
6、负责Storefile的合并工作
1.2.3相关名词
1. Hlog:写数据时会先把操作写到Hlog,可以数据恢复,如果某一台RegionServer宕机了,Hmaster通过Hlog的备份,把这台RegionServer的表负载到不同的RegionServer上
2. Region:Hbase表的分片,HBase表会根据RowKey值被切分成不同的region存储在RegionServer中,在一个RegionServer中可以有多个不同的region。
3. Store:HFile存储在Store中,一个Store对应HBase表中的一个列族。
4. MemStore:读缓存
5. BlockCache:写缓存
5. HFile:这是在磁盘上保存原始数据的实际的物理文件,是实际的存储文件。StoreFile是以Hfile的形式存储在HDFS的。
三、HBase表的数据结构
一、rowkey每张表的唯一主键
RowKey是用来检索的主键
二、column family列族
Hbase表中的每个列,都归属于某个列族,列族是表schema的一部分(而列不是),必须在使用表之前定义,列名都以列族为前缀。例如:courses:history,courses:math;都属于course这个列族
三、Cell单元格
Hbase中通过rowkey和columns确定的一个存储单元称为cell,每个cell保存着同一份数据的多个版本。版本通过时间戳来索引,cell中的数据是没有类型的,全都是字节码形式存储
关键字:无类型,字节码
四、TimeStamp时间戳
Hbase中通过rowkey和columns确定的一个存储单元称为cell,每个cell保存着同一份数据的多个版本。版本通过时间戳来索引
四、HBase的读写流程
① HBase的读数据流程:
1) Client向Zookeeper发送请求,得到meta表所在位置(如regionServer hadoop102)
2) Client获取mate表数据
3) 读取的rowKey所在的regionServer,先读取缓存,缓存没有读取磁盘
4) 返回读取到数据
② Hbase写数据流程
1) Client向Zookeeper发送请求,得到meta表所在位置(如regionServer hadoop102)
2) Client获取mate表数据,得到要写到哪个region
3) 先写数据到Hlog(为了数据的恢复)
4) 在写到内存,当内存足够大会溢写到HDFS,溢写文件数量超过三个时,合并文件
③ 数据flush过程
1)当MemStore数据达到阈值(默认是128M,老版本是64M),将数据刷到硬盘,将内存中的数据删除,同时删除HLog中的历史数据;
2)并将数据存储到HDFS中;
3)在HLog中做标记点。
④ 数据合并过程
1)当数据块拆过三块,Hmaster触发合并操作,Region将数据块加载到本地,进行合并;
2)当合并的数据超过256M,进行拆分,将拆分后的Region分配给不同的HregionServer管理;
3)当HregionServer宕机后,将HregionServer上的hlog拆分,然后分配给不同的HregionServer加载,修改.META.;
4)注意:HLog会同步到HDFS。
五、HBase rowkey设计和预分区
Rowkey设计原则:
· 唯一性
· 散列(避免热点)
· 长度
为了<散列>我们引入了预分区:
· HBase默认建表时有一个region,这个region的rowkey是没有边界的,即没有startkey和endkey,在数据写入时,所有数据都会写入这个默认的region,随着数据量的不断增加,此region已经不能承受不断增长的数据量,会进行split,分成2个region。在此过程中,会产生两个问题:
1. 数据往一个region上写,会有写热点问题。
2. region split会消耗宝贵的集群I/O资源。
· 基于此我们可以控制在建表的时候,创建多个空region,并确定每个region的起始和终止rowky,这样只要我们的rowkey设计能均匀的命中各个region,就不会存在写热点问题。自然split的几率也会大大降低。当然随着数据量的不断增长,该split的还是要进行split。像这样预先创建hbase表分区的方式,称之为预分区;
六、Hbase API
1、HbaseAdmin admin = connection.getAdmin( ),获取admin对象
admin:做DDL(数据库定义语言),对命名空间,表,列族的 创建、修改、删除操作
①查看表是否存在:admin.tableExists(tableName)
②创建表:descript对象
HTableDescriptor descriptor = new HTabelDescriptor(TableName.valueOf(tableName)); //创建HTableDescriptor(表描述)对象
descriptor.addFamily(new HColumnDescriptor(columnFamily1)); //表描述 添加 列描述
admin.createTabel(descriptor); //根据描述创建表
③删除表: admin.deleteTbale(tableName);
2、HTable table = connection.getTable( ),获取table对象
table:做DML(数据操纵语言),对数据的增删改查
①插入数据: PUT对象
//根据rowkey创建put对象,Bytes是Utils类中转换字符串为字节数组,因为Hbase存储都是字节数组
Put put = new Put(Bytes.toBytes(rowKey));
put.add(Bytes.toBytes(columnFamily),Bytes.tiBytes(column),Bytes.toBytes(value)); //根据行
table.put(put); //向表中添加数据
table.colse(); //关闭资源,源码中为关闭执行池和关闭连接
②删除数据:delete对象
List deleteList = new ArrayList();
Delete delete1 = new Delete(Bytes.toBytes(rowkey)); //根据rowkey创建delete对象
deleteList.add(delete1);
table.delete(deleteList); //每次删除一组rowkey对应的数据
③获取所有数据scan对象
Scan scan = new Scan(); //得到用于扫描region的对象
ResultScanner resulteScanner = hTable.getScanner(scan); //扫描所有数据的结果
for(Result result : resultScanner){ //Result是一行数据的结果
Cell[] cells = result.rawRow(); //cell是一个单元格对象
for(Cell cell : cells){
CellUtils.cloneValue; //获取单元格的值
}
}
④获取单行数据get对象
Get get = new Get(Bytes.toBytes(rowkey));
get.setMaxVersions(); //显示最后一个版本
get.setTimeStamp(); //显示指定时间戳的版本
get.addColumn(Bytes.toBytes(column_family),Bytes.toBytes(qualifier)); //指定列族:列
hbase周末小总结// 遍历数据集
Result result = table.get(get); //获取一行数据
Cell[] cells = result.rawRow(); //获取所有单元格
for(Cell cell : cells){
CellUtils.cloneValue; //获取单元格的值
}