Apache HBase 概述
Hbase是基于hdfs进行数据的存储,具有高可靠. 高性能. 列存储. 可伸缩. 实时读写的nosql数据库。它可以存储海量数据,并且后期查询性能很多,可以实现上亿条数据的秒级返回。
Hbase历史:
- 2006年Google发表BigTable白皮书
- 2006年开始开发HBase
- 2008年北京成功开奥运会,程序员默默地将HBase弄成了Hadoop的子项目
- 2010年HBase成为Apache顶级项目
场景:
- 可利用HBASE技术可在廉价PC Server上搭建起大规模结构化存储集群
- HBase的目标是存储并处理大型的数据,更具体来说是仅需使用普通的硬件配置,就能够处理由成千上万的行和列所组成的大型数据
- HBase是Google Bigtable的开源实现,但是也有很多不同之处。比如:Google Bigtable利用GFS作为其文件存储系统,HBase利用Hadoop HDFS作为其文件存储系统;Google运行MAPREDUCE来处理Bigtable中的海量数据,HBase同样利用Hadoop MapReduce来处理HBase中的海量数据;Google Bigtable利用Chubby作为协同服务,HBase利用Zookeeper作为对应
HBase 特性
-
大:hbase表可以存储海量数据。Hbase适合存储PB级别的海量数据,在PB级别的数据以及采用廉价PC存储的情况下,能在几十到百毫秒内返回数据
-
无模式
- mysql表中每一行数据他 们的字段都是一样
- hbase表中不同的行可以有不同的列(字段)
-
面向列
- mysql表中的数据是基于行进行存储,把每一行数据写入到磁盘文件中
- hbase表中的数据是基于列进行存储,把相同列的数据写入到磁盘文件中、
- 列式存储其实说的是列族(Column Family)存储,Hbase是根据列族来存储数据的。列族下面可以有非常多的列,列族在创建表的时候就必须指定
-
稀疏:hbase表中为null的列,不占用实际的存储空间
-
数据的多版本:hbase表中的数据在进行更新操作的时候,并没有直接把原始数据删除掉,而是保留数据的多个版本,这个数据的版本号就是按照数据插入时的时间戳去确定
-
数据类型单一:无论你的数据是什么,在hbase表中统一使用字节数组进行存储
-
极易扩展:Hbase的扩展性主要体现在两个方面,一个是基于上层处理能力(RegionServer)的扩展,一个是基于存储的扩展(HDFS) 。通过横向添加RegionSever的机器,进行水平扩展,提升Hbase上层的处理能力,提升Hbsae服务更多Region的能力
-
高并发(多核):由于目前大部分使用Hbase的架构,都是采用的廉价PC,因此单个IO的延迟其实并不小,一般在几十到上百ms之间。这里说的高并发,主要是在并发的情况下,Hbase的单个IO延迟下降并不多。能获得高并发、低延迟的服务
Hbase的内部原理
Hbase的寻址机制
HBase架构
Hbase是由Client、Zookeeper、Master、HRegionServer、HDFS等几个组件组成,几个组件的相关功能:
- Client
- Client包含了访问Hbase的接口,另外Client还维护了对应的cache来加速Hbase的访问,比如cache的.META.元数据的信息。
- Zookeeper
- HBase通过Zookeeper来做master的高可用、RegionServer的监控、元数据的入口以及集群配置的维护等工作。具体工作如下:通过Zoopkeeper来保证集群中只有1个master在运行,如果master异常,会通过竞争机制产生新的master提供服务、通过Zoopkeeper来监控RegionServer的状态,当RegionSevrer有异常的时候,通过回调的形式通知Master RegionServer上下线的信息、通过Zoopkeeper存储元数据的统一入口地址。
- Hmaster(NameNode)
- master节点的主要职责如下: 为RegionServer分配Region、维护整个集群的负载均衡、维护集群的元数据信息、发现失效的Region,并将失效的Region分配到正常的RegionServer上、当RegionSever失效的时候,协调对应Hlog的拆分。
- HregionServer(DataNode)
- HregionServer直接对接用户的读写请求,是真正的“干活”的节点。它的功能概括如下: 管理master为其分配的Region、处理来自客户端的读写请求、负责和底层HDFS的交互,存储数据到HDFS、负责Region变大以后的拆分、负责Storefile的合并工作。
- HDFS
- HDFS为Hbase提供最终的底层数据存储服务,同时为HBase提供高可用(Hlog存储在HDFS)的支持,具体功能概括如下:提供元数据和表数据的底层分布式存储服务、数据多副本,保证的高可靠和高可用性。
- 其他组件
- Write-Ahead logs
- HBase的修改记录,当对HBase读写数据的时候,数据不是直接写进磁盘,它会在内存中保留一段时间(时间以及数据量阈值可以设定)。但把数据保存在内存中可能有更高的概率引起数据丢失,为了解决这个问题,数据会先写在一个叫做Write-Ahead logfile的文件中,然后再写入内存中。所以在系统出现故障的时候,数据可以通过这个日志文件重建
- Region
- Hbase表的分片,HBase表会根据RowKey值被切分成不同的region存储在RegionServer中,在一个RegionServer中可以有多个不同的region。
- Store
- HFile存储在Store中,一个Store对应HBase表中的一个列族(列簇, Column Family)。
- MemStore
- 顾名思义,就是内存存储,位于内存中,用来保存当前的数据操作,所以当数据保存在WAL中之后,RegsionServer会在内存中存储键值对。
- HFile
- 这是在磁盘上保存原始数据的实际的物理文件,是实际的存储文件。StoreFile是以Hfile的形式存储在HDFS的。
- Write-Ahead logs
HBase原理
HBase读流程
- Client先访问zookeeper,从meta表读取region的位置,然后读取meta表中的数据。meta中又存储了用户表的region信息
- 根据namespace、表名和rowkey在meta表中找到对应的region信息
- 找到这个region对应的regionserver
- 查找对应的region
- 先从MemStore找数据,如果没有,再到BlockCache里面读
- BlockCache还没有,再到StoreFile上读(为了读取的效率)
- 如果是从StoreFile里面读取的数据,不是直接返回给客户端,而是先写入BlockCache,再返回给客户端
HBase写流程
- Client向HregionServer发送写请求
- HregionServer将数据写到HLog(write ahead log)。为了数据的持久化和恢复
- HregionServer将数据写到内存(MemStore)
- 反馈Client写成功
数据flush过程
- 当MemStore数据达到阈值(默认是128M,老版本是64M),将数据刷到硬盘,将内存中的数据删除,同时删除HLog中的历史数据
- 并将数据存储到HDFS中
- 在HLog中做标记点
数据合并过程
- 当数据块达到3块,Hmaster触发合并操作,Region将数据块加载到本地,进行合并
- 当合并的数据超过256M,进行拆分,将拆分后的Region分配给不同的HregionServer管理
- 当HregionServer宕机后,将HregionServer上的hlog拆分,然后分配给不同的HregionServer加载,修改.META
HLog会同步到HDFS
Hbase Shell
# 查看hbase状态
status
1、启动命令 # /usr/lib/hbase/bin
hbase shell
😊 ################################# 表空间 namespace
2、查看当前Hbase中所有的namespace
list_namespace
3、创建 namespace 并附带表空间属性
create_namespace "test"
create_namespace "test01", {"author"=>"zhj", "create_time"=>"2020-03-10 08:08:08"}
4、查看 namespace
describe_namespace "test01"
5、修改 namespace 的属性值(添加或者修改属性)
alter_namespace "test01", {METHOD => 'set', 'author' => 'wxy'} # 修改
alter_namespace "test01", {METHOD => 'set', 'year' => '2019'} # 新增
5-1、删除 namespace 的属性
alter_namespace 'test01', {METHOD => 'unset', NAME => 'create_time'} # 删除
6、删除 namespace
drop_namespace "test01" # 要删除的namespace必须是空的,其下没有表
😊 ################################# 表 table [ 表空间:表名 ] [ namespace:table ]
DDL 👇
0、查看表空间有哪些表
list # 显示所有表
list_namespace_tables 'test' # 显示指定表空间里的表
1、创建表
create 'student','info' # 指定默认表空间 default ; 'info' 为列族
create 'stu1',{NAME=>'col1'},{NAME=>'col2'} # 指定默认表空间,多个列族col1,col2
# create 'stu2','col1','col2' # 简便写法
create 'test:student','info' # 指定表空间为test ; 'info' 为列族
1-1、修改表信息
alter 'student',NAME=>'info_2',VERSIONS=>'2' # 新增/修改表的列族 ,保留版本的个数为2
# 默认 VERSIONS 为1 , 存储历史几个版本 , 如果有数据写入,那么较老的时间戳的数据会忽略作废。
alter 'student','delete'=>'info_2' # 删除表的列族
alter 'emp', READONLY # 修改表为只读
2、删除表 # 删除表的操作顺序为先disable,然后再drop
disable 'student' # 修改表为disable状态
drop 'student' # 删除表
3、查看表结构
describe 'test:student' # 查看表信息 简写 : desc
DML 👇
1、向表添加数据 # put '表空间:表','rowkey','列族:列名','value' rowkey 会自动排序
put 'student','1001','info:sex','male' # 列族下的列名sex
put 'student','1001','info:age','18'
put 'student','1002','info:name','Janna'
put 'student','1002','info:sex','female'
put 'student','1002','info:age','20'
2、扫描查看表数据 # STARTROW -> STOPROW 排序按照:ASCII
scan 'student'
scan 'student',{RAW=>true,VERSIONS=>2} # 追加显示多版本数据
scan 'student',{STARTROW => '1001', STOPROW => '1001'} # 查看rowkey为1001
# scan 'student',{STARTROW => '1001', STOPROW => '1005!'} # 查看rowkey为1005
# scan 'student',{STARTROW => '1001', STOPROW => '1005|'} # 查看rowkey为1005?
scan 'student',{STARTROW => '1001'} # 1001开始
3、更新指定字段的数据
put 'student','1001','info:name','Nick'
put 'student','1001','info:age','100'
4、查看“指定行”或“指定列族:列”的数据
get 'student','1001'
get 'student','1001','info:name'
get 'student','1001','info:name','info:age'
5、统计表数据行数
count 'student'
6、删除数据
deleteall 'student','1001' # 删除rowkey都为1001 DeletColumn 列 DeleteFamily 列族
delete 'student','1001','info:age' # 删除rowkey为1001列族为info列名为sex的所有版本信息
7、清空表 # 清空表的操作顺序为先disable,然后再truncate
disable 'student' # 修改表为disable状态
truncate 'student'
+++ HBase Shell 执行命令
./hbase shell /zhj/sample_commands.txt # habse shell 调用txt脚本
Hbase API
pom.xml // maven 依赖
<repositories>
<repository>
<id>cloudera</id> // 指定仓库地址
<url>https://repository.cloudera.com/artifactory/cloudera-repos</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.2.0-cdh5.7.0</version> // 选择cdh版本
// <version>2.0.5</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.2.0-cdh5.7.0</version> // // 选择cdh版本
// <version>2.0.5</version>
</dependency>
</dependencies>
++++++++++++++++++++++++++++++++
hbase-site.xml //hbase-site.xml 配置文件参数
<property>
<name>hbase.zookeeper.quorum</name> // API Connection 参数1
<value>quickstart.cloudera</value> // API Connection 参数2
</property>
++++++++++++++++++++++++++++++++
* Connection : 通过ConnectionFactory获取. 是重量级实现.
private static Connection connection ; // 定义连接
Configuration conf = HBaseConfiguration.create(); // 创建配置信息并配置
conf.set("hbase.zookeeper.quorum","quickstart.cloudera");
connection = ConnectionFactory.createConnection(conf); // 创建连接
Admin admin = connection.getAdmin(); // 创建操作对象
admin.close(); // 关闭对象连接
connection.close(); // 关闭对象连接
* Table : 主要负责DML操作
* Admin : 主要负责DDL操作
DDL // 创建NameSpace、创建table、删除table
1、判断表是否存在
boolean exists = admin.tableExists(TableName.valueOf("test:stu"));
2、 创建表
3、 删除表
TableName name = TableName.valueOf("test:stu1");
admin.disableTable(name); //表下线
admin.deleteTable(name); //表删除
4、 创建命名空间
DML // put 、delete 、get 、scan
1、插入数据
2、单条数据查询
3、扫描数据
4、删除数据
Hbase 优化
预分区
每一个region维护着 'Start key' 与 'End Key' # 排序按照:ASCII
1、手动设置预分区 # 建表时候设定预分区
create 'staff1','info',SPLITS => ['1000','2000','3000','4000']
# (-∞,1000),[1000,2000),[2000,3000),[3000,4000),[4000,+∞)
2、生成16进制序列预分区
create 'staff2','info',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}
# 00000000-fffffff
3、按照文件中设置的规则预分区 # 文件使用相对路径,或者绝对路径
create 'staff3','info',SPLITS_FILE => 'splits.txt'
# aaaa
# bbbb
# cccc
# dddd
4、使用JavaAPI创建预分区