HBase
NoSQL
NoSQL概念
NoSQL理论
- NoSQL理论.pptx
HBase介绍
HBase的起源
-
起源于谷歌论文BigTable
-
高可靠性,高性能,面向列,可伸缩的分布式存储系统
-
列存储的非关系型数据库
-
目标:存储并处理大型数据
-
特点
-
海量存储
-
列式存储
- 列族
-
易扩展
- 基于上层处理能力的扩展(regionServer)
- 基于存储的扩展(HDFS)
-
高并发
-
HBase的架构
-
HDFS
- 底层
-
HBase
-
zookeeper
- 负责master的高可用
- RegionServer的监控
- 元数据的入口
- 集群配置的维护
-
HMaster
-
职责
- 为RegionServer分配Region
- 维护整个集群的负载均衡
- 维护集群的元数据信息
- 发现失效的Region,并分配到正常的RegionServer上
-
-
HRegionServer
-
职责
-
管理master为其分配的region
-
处理来自客户端的读写请求
-
负责和底层HDFS的交互
-
负责Region变大以后的切分
- 指令是master发送,干活的是HRegionServer
-
负责StoreFile的合并
-
-
HLog
-
一台服务器中一个
-
增删改操作记录都写入到HLog
- 预写日志
-
保存在HDFS
-
-
HRegion
-
类似于表
- 表大的时候会切分HRegion
- 一张表可以对应一个或多个HRegion
-
Store
-
列族分开存储
- 一张表可以有多个Store
- 一个Store存储一个列族
- 随着切分,一个列族对应多个store
-
Mem Store
- 存储在内存的部分
-
StoreFile
-
存储到磁盘
- 也就是刷写到HDFS
-
HFile
- StoreFile的存储格式
-
-
-
-
-
client
-
其他组件
- write-ahead logs
- Region
- Store
- MemStore
- HFile
-
HBase部署与使用
部署
- Zookeeper正常部署
- Hadoop正常部署
- HBase的解压
- HBase的配置文件
- HBase需要依赖的Jar包
- HBase软连接Hadoop配置
- HBase远程scp到其他集群
- HBase服务的启动
hbase shell操作
-
hbase shell
-
创建表
-
create ‘user’ ,‘info’
- 包含info列族
-
create ‘user’, ‘info’, ‘data’
- 包含info、data两个列族
-
create ‘user’, {NAME => ‘info’, VERSIONS => ‘3’},{NAME => ‘data’}
- 可指定version
-
-
插入数据
-
put
- put ‘user’, ‘rk0001’, ‘info:name’, ‘zhangsan’
- put ‘user’, ‘rk0001’, ‘info:gender’, ‘female’
- put ‘user’, ‘rk0001’, ‘info:age’, 20
- put ‘user’, ‘rk0001’, ‘data:pic’, ‘picture’
-
-
查看表
-
list
- 列出所有表
-
scan ‘user’
- 扫描查看表数据
- 可全表查询,可添加过滤
-
describe ‘user’
- 查看表结构
-
-
获取数据
-
get
-
获取user表中row key为rk0001的所有信息
- get ‘user’, ‘rk0001’
-
获取user表中row key为rk0001,info列族的name、age列标示符的信息
- get ‘user’, ‘rk0001’, ‘info:name’, ‘info:age’
-
获取user表中row key为rk0001,info、data列族的信息
- get ‘user’, ‘rk0001’, ‘info’, ‘data’
- get ‘user’, ‘rk0001’, {COLUMN => [‘info’, ‘data’]}
- get ‘user’, ‘rk0001’, {COLUMN => [‘info:name’, ‘data:pic’]}
-
获取user表中row key为rk0001
列族为info,版本号最新5个的信息- get ‘user’, ‘rk0001’, {COLUMN => ‘info’, VERSIONS => 5}
- get ‘user’, ‘rk0001’, {COLUMN => ‘info:name’, VERSIONS => 5}
- get ‘user’, ‘rk0001’, {COLUMN => ‘info:name’, VERSIONS => 5, TIMERANGE => [1392368783980, 1392380169184]}
-
获取user表中row key为rk0001,cell的值为zhangsan的信息
- get ‘user’, ‘rk0001’, {FILTER => “ValueFilter(=, ‘binary:zhangsan’)”}
-
获取user表中row key为rk0001,列标示符中含有a的信息
- get ‘user’, ‘rk0001’, {FILTER => “(QualifierFilter(=,‘substring:a’))”}
- put ‘user’, ‘rk0002’, ‘info:name’, ‘fanbingbing’
- put ‘user’, ‘rk0002’, ‘info:gender’, ‘female’
- put ‘user’, ‘rk0002’, ‘info:nationality’, ‘中国’
- get ‘user’, ‘rk0002’, {FILTER => “ValueFilter(=, ‘binary:中国’)”}
-
-
scan
-
查询user表中的所有信息
- scan ‘user’
-
查询user表中列族为info的信息
- scan ‘user’, {COLUMNS => ‘info’}
- scan ‘user’, {COLUMNS => ‘info’, RAW => true, VERSIONS => 5}
- scan ‘user’, {COLUMNS => ‘info’, RAW => true, VERSIONS => 3}
-
查询user表中列族为info和data的信息
- scan ‘user’, {COLUMNS => [‘info’, ‘data’]}
- scan ‘user’, {COLUMNS => [‘info:name’, ‘data:pic’]}
-
查询user表中列族为info、列标示符为name的信息
- scan ‘user’, {COLUMNS => ‘info:name’}
-
查询user表中列族为info、
列标示符为name的信息,并且版本最新的5个- scan ‘user’, {COLUMNS => ‘info:name’, VERSIONS => 5}
-
查询user表中列族为info和data且列标示符中含有a字符的信息
- scan ‘user’, {COLUMNS => [‘info’, ‘data’], FILTER => “(QualifierFilter(=,‘substring:a’))”}
-
查询user表中列族为info,rk范围是[rk0001, rk0003)的数据
- scan ‘user’, {COLUMNS => ‘info’, STARTROW => ‘rk0001’, ENDROW => ‘rk0003’}
-
查询user表中row key以rk字符开头的
- scan ‘user’,{FILTER=>“PrefixFilter(‘rk’)”}
-
查询user表中指定范围的数据
- scan ‘user’, {TIMERANGE => [1392368783980, 1392380169184]}
-
-
-
修改数据
-
put
-
alter
-
alter ‘user’, NAME => ‘f2’
- 添加列族
-
alter ‘user’, ‘delete’ => ‘f1’
- 删除一个列族
-
alter ‘user’, NAME => ‘f1’, METHOD => ‘delete’
- 删除一个列族
-
-
-
删除操作
-
truncate
-
清空表数据
- truncate ‘people’
-
-
drop
- 需要先disable ‘user’
-
delete
-
delete ‘user’, ‘rk0001’, ‘info:name’
- 默认当前时间戳
- 之前数据打delete标记
-
delete ‘user’, ‘rk0001’, ‘info:name’, 1392383705316
-
-
-
启用表
- enable ‘user’
JavaAPI
读写流程
-
HBase读数据流程
1.Client先访问ZooKeeper,从meta表读取Region的位置,然后读取meta表中的数据。meta中又存储了用户表的Region信息;
2.根据namespace、表名和RowKey在meta表中找到对应的Region信息;
3.找到这个Region对应的RegionServer;
4.查找对应的Region;
5.先从MemStore找数据,如果没有,再到BlockCache里面读;
6.BlockCache还没有,再到StoreFile上读(为了读取的效率);
7.如果是从StoreFile里面读取的数据,不是直接返回给客户端,而是先写入BlockCache,再返回给客户端。
-
HBase写数据流程
(1)Client访问ZooKeeper,获取Meta表所处位置(ip)
(2)访问Meta表,然后读取Meta表中的数据。
(3)根据namespace(类似与关系型数据库中的数据库,下一课会介绍)、表名和RowKey在Meta表中找到该RowKey应该写入到哪个Region。
(4)找到这个Region对应的RegionServer,并发送写数据请求
(5)HRegionServer将数据先写到HLog(Write Ahead Log)。为了数据的持久化和恢复;
(6)HRegionServer将数据写到内存(MemStore);
(7)反馈Client写成功。
写数据这一块也可以看出,HBase将数据写入到内存中后,就返回给客户端写入成功,响应非常快。这也是为什么HBase写数据速度快的原因。
与Hive的集成
-
HBase与Hive的对比
1.Hive
(1)数据仓库
Hive的本质其实就相当于将HDFS中已经存储的文件在Mysql中做了一个双射关系,以方便使用HQL去管理查询。
(2)用于数据分析、清洗
Hive适用于离线的数据分析和清洗,延迟较高。
(3)基于HDFS、MapReduce
Hive存储的数据依旧在DataNode上,编写的HQL语句终将是转换为MapReduce代码执行。
2.HBase
(1)数据库
是一种面向列存储的非关系型数据库。
(2)用于存储结构化和非结构化的数据
适用于单表非关系型数据的存储,不适合做关联查询,类似JOIN等操作。
(3)基于HDFS
数据持久化存储的体现形式是Hfile,存放于DataNode中,被ResionServer以region的形式进行管理。
(4)延迟较低,接入在线业务使用
面对大量的企业数据,HBase可以直线单表大量数据的存储,同时提供了高效的数据访问速度。
-
HBase与Hive集成使用
通过两者本身对外的API接口互相通信完成
由Hive的lib目录中hive-hbase-handler-*.jar工具类实现
HBaseStorageHandler
实现Hive与HBase集成的类
对HiveStorageHandler接口的实现
region裂变
一个Region就是一个表的一段Rowkey的数据集合。HBase设计中,当某个Region太大的时候HBase会拆分它。
那么为什么要拆分Region?因为当某个Region太大的时候读取效率太低了。想想我们为什么从MySQL、Oracle转移到NoSQL来?最根本的原因就是这些关系型数据库把数据放到一个地方,查询的本质其实也就是遍历key;而当数据增大到上亿的时候同一个磁盘已经无法应付这些数据的读取了,因为遍历一遍数据的时间实在太长了。我们用NoSQL的理由就是其能把大数据分拆到不同的机器上,然后就像查询一个完整的数据一样查询他们。但是当你的Region太大的时候,此时这个Region一样会遇到跟传统关系型数据库一样的问题,所以HBase会拆分Region。这也是HBase的一个优点,可以说HBase为“一个会自动分片的数据库”。
compaction
HBase是一种Log-Structured Merge Tree架构模式,HBase几乎总是在做新增操作。当你新增一个单元格的时候,HBase在HDFS上新增一条数据。当你修改一个单元格的时候,HBase在HDFS又新增一条数据,只是版本号比之前那个大(或者你自己定义)。 当你删除一个单元格的时候,HBase还是新增一条数据!只是这条数据没有value,类型为DELETE,这条数据叫墓碑标记 (Tombstone)。真正的删除发生在什么时候,由于数据库在使用过程中积累了很多增删查改操作,数据的连续性 和顺序性必然会被破坏。为了提升性能,HBase每间隔一段时间都会进行一次合并(Compaction),合并的对象为HFile文件。另外随着数据写入不断增多,Flush次数也会不断增多,进而HFile数据文件就会越来越多。然而,太多数据文件会导致数据查询IO次数增多,因此HBase尝试着不断对这些文件进行合并。
HBase的优化
HBase优化
- 预分区
- RowKey设计
- 内存优化
- 基础优化