HBase是一个构建在HDFS上的分布式列存储系统,Hbase内部管理的文件全部存储在HDFS中,HDFS和HBase都具有良好的容错性和扩展性,都可以扩展到成百上千个节点。HBase是Apache Hadoop生态系统中的重要一员,主要用于海量结构化数据存储,从逻辑上讲,HBase将数据按照表、行和列进行存储。
HBase具有以下特点:
大:一个表可以有数十亿行,上百万列;
无模式:每行都有一个可排序的主键和任意多的列,列可以根据需要动态的增加,同一张表中不同的行可以有截然不同的列;
面向列:面向列(族)的存储和权限控制,列(族)独立检索;
稀疏:对于空(null)的列,并不占用存储空间,表可以设计的非常稀疏;
数据多版本:每个单元中的数据可以有多个版本,默认情况下版本号自动分配,是单元格插入时的时间戳;
数据类型单一:Hbase中的数据都是字符串,没有类型
HBase物理模型:
- 1、Table中的所有行都按照row key的字典序排列;
- 2、Table 在行的方向上分割为多个Region;
- 3、Region按大小分割的,每个表开始只有一个region,随着数据增多,region不断增大,当增大到一个阀值的时候,region 就会等分会两个新的region,之后会有越来越多的region (如下图);
- 4 、Region是HBase中分布式存储和负载均衡的最小单元。不同Region分布到不同RegionServer上;
- 5 、Region虽然是分布式存储的最小单元,但并不是存储的最小单元。
Region由一个或者多个Store组成,每个store保存一个columns family。
每个Strore又由一个memStore和0至多个StoreFile组成。
memStore存储在内存中,StoreFile(HFile)存储在HDFS上(如下图)。 - HBase中的所有数据文件都存储在 Hadoop HDFS文件系统上,主要包括述提出的两种文件类型:
HFile :HBase 中KeyValue数据的存储格式, HFile是Hadoop 的二进制格式文件,实际上 的二进制格式文件,实际上 的二进制格式文件,实际上 StoreFile就是对HFile做了轻量级包装,进行数据的存储。
HLog File:HBase 中WAL(Write Ahead Log 类似MySQL中的binlog,用来做灾难恢复) 的存储格式,物理上是 Hadoop 的 Sequence File 。
Hlog 记录数据的所有变更,一旦修改就可以从 log 中进行恢复。每个HRegionServer维护一个 HLog, 而不是每个 HRegion 一个。这样不同 region(来自不同 table)的日志会混在一起,这样做目是不断追加单个文件相对于同 时写多个文件而言,可以减少磁盘寻址次数因此提高对table 的写性能 。
带来 的麻烦是,如果一台 HRegionServer下线,为了恢复其上的region ,需要将 HRegionServer 上的 loglog 进行拆分,然后发到其它HRegionServer上进行恢复。
HBase基本组件
a).Client
包含访问HBase的接口,并维护cache来加快对HBase的访问
b).Zookeeper
保证任何时候,集群中只有一个master;
存贮所有Region的寻址入口;
实时监控Region server的上线和下线信息。并实时通知给Master;
存储HBase的schema和table元数据;
HBase依赖ZooKeeper,默认情况下,HBase管理ZooKeeper实例,比如 启动或者停止ZooKeeper。Master与RegionServers 启动时会向ZooKeeper注册,Zookeeper的引入使得Master不再是单点故障。
c).Master
为Region server分配region;
负责Region server的负载均衡;
发现失效的Region server并重新分配其上的region;
管理用户对table的增删改查操作。
d).Region Server
Region server维护region,处理对这些region的IO请求;
Region server负责切分在运行过程中变得过大的region 。
Memstore & StoreFile
Client写入 -> 存入 MemStore,一直到MemStore满 -> Flush 成一个StoreFile,直至增长到一定阈值 -> 触发Compact 合并操作 -> 多个 StoreFile合并成一个 StoreFile,同时进行版本合并和数据删除 -> 当StoreFiles Compact 后,逐步形成越来大的StoreFile-> 单个StoreFile大小超 过一定阈值后,触发Split操作,把当前 Region Split 成2个Region,Region会下线,新Split出的2个孩子Region会被HMaster分配到相应的HRegionServer 上,使得原先 1个Region的压力得以分流到2个Region上。
HBase只是增加数据,有所得更新和删除操作都在Compact 阶段做的,所以用户写操作只需要进入到内存即可立返回,从而保证 I/O 高性能。
Hbase支持的操作
a).所有操作均是基于rowkey的;
b).支持CRUD(Create、Read、Update和Delete)和Scan;
c).单行操作
Put
Get
Scan
d).多行操作
Scan
MultiPut
e).没有内置join操作,可使用MapReduce解决。
HBase常用操作命令
自带了shell命令行
启动shell:bin/hbase shell
--->help帮助信息
status: 提供HBase的状态,例如,服务器的数量
version: 提供正在使用HBase版本
table_help: 表引用命令提供帮助
whoami: 提供有关用户的信息
使用help命令可以查看命令如下:
HBase DDL(定义语言)
hbase(main):xxx:x> create_namespace 'hbase01' #创建命名空间namespace
hbase(main):xxx:x> list_namespace #查看所有的namespace
hbase(main):xxx:x> drop_namespace 'hbase01' #删除namespace
hbase(main):xxx:x> describe_namespace 'hbase01' #namespace详细信息
hbase(main):xxx:x> create 'hbase01:t1','f1',SPLITS => ['10','20','30','40'] #创建表ti 列簇
为f1 SPLITS分隔(分隔成多个region分区,默认只有一个)
hbase(main):xxx:x> create 'hbase01:t1', 'f1', SPLITS_FILE => '/opt/datas/splits.txt' #根据文件进行分区
hbase(main):xxx:x> create 't1', 'f1', 'f2', 'f3' 表名t1,列簇名f1 f2 f3
hbase(main):xxx:x> create 'hbase01:t1', {NAME => 'f1', VERSIONS => 5} 必须要指定一个列簇{NAME},一对{}只能定义
个列簇,不同的{}定义不同多个列簇,{}中的变量名称必须是大写的。
在建表时把名称建好,最好不要修改,列簇可加,可删,不可改名称。
hbase(main):xxx:x> desc 'hbase01:t1' #查看详细信息 【显示所有列簇的信息,每个{}里的参数可以不一样的,以{}进行区
分,默认的版本号是1,早期的是3个】
hbase(main):xxx:x> alter 't1', NAME => 'f1', VERSIONS => 5(版本可以不要) #新增
hbase(main):xxx:x> alter 't1', 'f2', {NAME => 'f3', IN_MEMORY => true} (也是增加) #新增列簇f2
hbase(main):xxx:x> alter 't1', NAME => 'f3', METHOD => 'delete' #删除列簇f3
hbase(main):xxx:x> alter 't1', 'delete' => 'f2' #删除
hbase(main):xxx:x> disable 't1' #删除表前需要禁用一张表
hbase(main):xxx:x> drop 't1' #删除表t1
HBase DML(操纵语言)
hbase(main):xxx:x> put 'hbase01:t1','10001','f1:name','leo' #插入数据
hbase(main):xxx:x> put 'hbase01:t1','10001','f1:age','18' #插入数据
hbase(main):xxx:x> put 'hbase01:t1','10001','f1:sex','male' #插入数据
get方式:快速查询【不支持全表扫描】
hbase(main):xxx:x> get 'hbase01:t1','10001' 查询某个rowkey的数据
hbase(main):xxx:x> get 'hbase01:t1','10001','f1' 可以指定某个列簇的数据
hbase(main):xxx:x> get 'hbase01:t1','10001','f1:name' 可以指定某个列簇下某个列的数据
hbase(main):xxx:x> get 'hbase01:t1','10001',{COLUMN =>'f1:name',VERSIONS => 3} #显示3个版本的所有值,默认只显示时间戳的最后一个
hbase(main):xxx:x> get 'hbase01:t1', 'f1', {COLUMN => 'c1', TIMESTAMP => ts1} 根据时间戳来查
hbase(main):xxx:x> get 'hbase01:t1','10001',{COLUMN=>'f1',TIMERANGE=>[1531534978598,1531534978712], VERSIONS=>5}
hbase(main):xxx:x> get 'hbase01:t1','10002',{COLUMN=>'f1',TIMERANGE=>[1531902944053,1531902938551], VERSIONS=>3}
scan方式:全表扫描
hbase(main):xxx:x> scan 'hbase01:t1' #查询hbase01里t1表的所有数据
hbase(main):xxx:x> scan 'hbase01:t1', {COLUMNS => ['f1'], LIMIT => 2, STARTROW => '10002'} #f1列簇中从10002开始查询前两行,
LIMIT是限制显示的行数(会把所有的列都显示出来)
hbase(main):xxx:x> scan 'hbase01:t1',{STARTROW => '10002'} #从当前行开始,包括当前行
hbase(main):xxx:x> scan 'hbase01:t1',{STARTROW => '10001',STOPROW => '10003'} #半闭半开 包含10001不包含10003
删除
hbase(main):xxx:x> delete 'hbase01:t1','10001','info' #只删除一个列簇是删除不掉的
hbase(main):xxx:x> delete 'hbase01:t1','10001','info:name' #必须指定到哪个列
hbase(main):xxx:x> delete 'hbase01:t1','10001' #是不行的,参数不行,一般删除某一个列的值
hbase(main):xxx:x> scan 'hbase01:t1',{RAW => true, VERSIONS => 10} #会把刚刚删除的数据也显示出来,说明我们删除的时候
并不是真正的删除,而是打上了一个删除的标记。
type=DeleteColumn(DeleteFamily)
hbase(main):xxx:x> delete 'tt','10001','f1:name',1531538568828 #基于时间:如果时间是最新的时间,就会把这个时间以前的数据都会删除
#如果时间是旧的时间,而且是最原始插入的第一条记录,就只删除第一条记录
#如果指定的时间,是大于前几条的数据时间,那么就会把小于这个时间的数据都删除
修改:修改也是put,就是将新的数据put进去
hbase(main):xxx:x> put 'hbase01:t1','10001','info:age','20' #把年龄改20
清空数据
hbase(main):xxx:x> truncate 'hbase01:t1' #清除了数据,并且清除了分区(region预分区数)(执行时会默认执行disable,在清除)
hbase(main):xxx:x> truncate_preserve 'hbase01:t1' #只清除数据,不清除预分区数
伪分布式环境搭建
1.解压Hbase安装
$ tar -zxvf /opt/software/hbase-1.2.1-bin.tar.gz -C ./
2.更改hbase-env.sh文件
配置JDK
并更改Hbase默认的ZK,改为false,用我们自己安装的Zookeeper
3.配置hbase-site.xml,新增配置如下
<configuration>
<property>
<name>hbase.tmp.dir</name>
<value>/opt/modules/apache/hbase-1.2.1/data</value>
</property>
<property>
<name>hbase.rootdir</name>
<value>hdfs://hadoop01.com:8020/hbase</value>
</property>
<!-- 可选配置 -->
<property>
<name>hbase.fs.tmp.dir</name>
<value>/user/${user.name}/hbase-staging</value>
<description>A staging directory in default file system (HDFS)
for keeping temporary data.
</description>
</property>
<!-- 可选配置 -->
<property>
<name>hbase.bulkload.staging.dir</name>
<value>${hbase.fs.tmp.dir}</value>
<description>A staging directory in default file system (HDFS)
for bulk loading.
</description>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value><!-- 伪分布式 -->
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>hadoop01.com</value>
</property>
</configuration>
4.配置regionservers
hadoop01.com
5.更改默认jar包
为了更好的兼容我们的Hbase,需要更换Hbase里面的jar包
也要换成和我们自己的Zookeeper版本对应的jar包,如果hbase中存在htrace-core.jar则不用拷贝。
hadoop相关的jar换成如下:
配置完成启动Hbase,启动之前需确保hadoop的相关程序启动。
6.启动master主节点
$ bin/hbase-daemon.sh start master
7.启动master从节点
$ bin/hbase-daemon.sh start regionserver
启动完成后可以访问16010web页面
伪分布式环境搭建
如果用户需要在多台主机中运行完全分布式操作,需要进行以下配置。在hbase-site.xml中添加hbase.cluster.distributed厲性并设置为true,添加hbase.rootdir属性并设罝HDFS NameNode的访问地址,这将决定HBase的数据会写到哪里,例如,NameNode 运行在主机名为namenode.foo.com的服务器上,并以9000为服务端口,HBase在HDFS 上使用的根目录为可以做如下配置:
<configuration>
...
<property>
<name>hbase.rootdir</name>
<value>hdfs://hadoop01.com:8020/hbase</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value><!-- 伪分布式 -->
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>hadoop01.com</value>
</property>
...
</configuration>
配置region服务器。此外,完全分布式模式需要修改conf/regionservers文件,该文件列出 了所有运行HRegionServer守护进程的主机,每个主机独立占用一行(类似于Hadoop中的 文件)。HBase集群启动和关闭时会按照该文件中罗列的主机逐一执行。
ZooKeeper安装。分布式的HBase依赖于ZooKeeper集群。所有的节点和客户端都必须能 够正常访问ZooKeeper。HBase默认管理一个单点的ZooKeeper集群(ZooKeeper能够以一个单独的节点启动),用户通过启动和关闭脚本就可以把ZooKeeper当做HBase的一部分 來启动和关闭进程。用户也可以不依赖于HBase管理ZooKeeper集群,只需为HBase指出 需要使用的集群即可。在conf/hbase-env.sh中设置HBASE_MANAGES_ZK变量为true,就可 以将ZooKeeper作为HBase的一部分管理启动(这个参数馱认为true)。
当用户需要通过HBase管理ZooKeeper时,ZooKeeper可以直接使用本地zoo.cfg文件作为依赖的配置文件,或者直接使用conf/hbase-site.xml中的ZooKeeper配罝。ZooKeeper的相关配置可以在hbase-site.xml中通过XML格式设置,属性以hbase.zookeeper.property为前缀,例如,clientPort 可以设置为 hbase.zookeeper.property.clientPort。在HBase中这些参数 都有馱认值,包括ZooKeeper的配罝。
使用己有ZooKeeper集群。HBase采用已有的ZooKeeper集群,因此不能依赖HBase来管理ZooKeeper,用户需要在conf/hbase-env.sh 中将HBASE_HANAGES_ZK属性设置为false。
...
#Tell HBase whether it should nanage it's own instance of Zookeeper or not.
export HBASE.MANAGES_ZK=false
下一步需要在 hbase-site.xml 中设置ZooKeeper的连接地址与客户端端口号,或将在zoo.cfg中配置相关信息,并在HBase的中添加zoo.cfg路径。HBase启动时会读取zoo.cfg居中的配置,并覆盖 hbase-site.xml 中的配置。
使用HBase管理ZooKeeper,ZooKeeper会作为HBase的一部分随着启动/关闭脚本进行启动/关闭。如果葙要独立运行ZooKeeper, 不依赖HBase的启动与关闭,需要执行以下命令:
${HBASE_HOME)/bin/hbase-daenions.sh (start,stop) zookeeper
采取这样的方式可以让ZooKeeper与HBase脱离关系,只有在将HBASE_MANAGES_ZK设
罝为false后,ZooKeeper才不会因HBase的关闭而关闭。
配置示例
下面示例是一个10个节点的集群。节点的名字分别是master.foo.com, hostl.foo.com到 host9.f00.com。HBase master与HDFS NameNode 都运行在master.foo.com 上,region服务器运行在hostl.foo.com到host9.foo.com上。3个节点的ZooKeeper分别运行在zkl.foo.com、zk2.foo.com和zk3.foo.com中。ZooKeeper的元数据月录设置为/var/zookerper。主要的配置文件hbase.site.xml、regionservers、hbase-ertv.sh 都可以在HBase的conf目录下找到,配罝如下所示。
1.hbase-site.xml
2.regionservers
这个文件中记录了所有region服务器的主机列表。在我们的例子中除了运行HbaseMaster和HDFSNameNode的节点master.foo.com之外,所有节点启动了region服务器。
hadoop01.com
hadoop02.com
hadoop03.com
hadoop04.com
hadoop05.com
hadoop06.com
hadoop07.com
hadoop08.com
hadoop09.com
3.hbase-env.sh
修改hbase-env.sh文件内的配置只需要修改内容中的默认信息即可。下面对hbase-env.sh中默认内容做的修改,我们将Hbase的堆设置为4GB,以代替默认的1GB。
...
#export HBASE_HEAPSIZE=1000
export HBASE_HEAPSIZE=4096
...
HBase Master 默认基于 Web的UI服务器端口为60010。HBase region 服务器默认基于Web的UI服务器端口为60030。如果master运行在名为hadoop01.com的主机中,master的主页地址就为http://hadoop01.com:60010。
集群启动后,用户不仅可以通过页面检查region服务器是否都已经正常注册到master,并以期望的主机名显示在页面中(客户端能够连接),还可以检查当前启动的HBase与Hadoop版本是否正确。