put 'Student', '0001', 'StuInfo:Name', 'Tom Green', 1
put 'Student', '0001', 'StuInfo:Age', '18'
put 'Student', '0001', 'StuInfo:Sex', 'Male'
put 'Student', '0001', 'Grades:BigData', '80'
put 'Student', '0001', 'Grades:Computer', '90'
put 'Student', '0001', 'Grades:Math', '85'
如果 put 语句中的单元格是已经存在的,即行键、列簇及列名都已经存在,且不考虑时间戳的情况下,执行 put 语句,则可对数据进行更新操作。
如果在初始创建表时,已经设定了列族 VERSIONS 参数值为 n,则 put 操作可以保存 n 个版本数据,即可查询到行键为 0001 的学生的 n 个版本的姓名数据。
删除数据
delete 命令可以从表中删除一个单元格或一个行集,语法与 put 类似,必须指明表名和列簇名称,而列名和时间戳是可选的。
// 1. 创建单列值的过滤器
SingleColumnValueFilter nameFilter = new SingleColumnValueFilter(
Bytes.toBytes("info"), //列簇
Bytes.toBytes("name"), //列
CompareOp.EQUAL,
new SubstringComparator("刘晨"));
SingleColumnValueFilter ageFilter = new SingleColumnValueFilter(
Bytes.toBytes("info"), //列簇
Bytes.toBytes("age"), //列
CompareOp.LESS_OR_EQUAL,
Bytes.toBytes(33));
// 2. 创建过滤器链 MUST_PASS_ALL = and MUST_PASS_ONE = or
FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
filterList.addFilter(nameFilter);
filterList.addFilter(ageFilter);
// 3. scan 设置过滤器链
scan.setFilter(filterList);
RegexStringComparator
RegexStringComparator 支持用于值比较的正则表达式。
RegexStringComparator comp = new RegexStringComparator("my."); // any value that starts with 'my'
SingleColumnValueFilter filter = new SingleColumnValueFilter(
cf,
column,
CompareOperaor.EQUAL,
comp
);
scan.setFilter(filter);
HBase
HBase 是一个分布式的非关系型数据库。它利用 Hadoop 分布式文件系统 HDFS 提供分布式数据存储。 它不支持 SQL 的跨行事务,也不要求数据之间有严格的关系,同时它允许在同一列的不同行中存储不同类型的数据。
HBase 的特点
HBase 的单表可以有百亿行、百万列。 HBase 采用 LSM 树作为内部数据存储结构,这种结构会周期性地将较小文件合并成大文件,以减少对磁盘的访问。
大部分传统的关系型数据库,都是面向行来组织数据的。如 Mysql,Postgresql。 HBase 是采用列存储的。 行存储和列存储,是数据库底层组织数据的方式。
比如,这样的一套数据
行存储的方式
行存储将会以上面方式将数据存储在磁盘上。它利于数据一行一行的写入,写入一条数据记录时,只需要将数据追加到已有数据记录后面即可。所以数据的写入会更快。对按记录查询数据也更简单。
但是,大量数据集来聚合统计数据时候,首先需要将所有行数据读入内存,在对某个字段集计。
列存储的方式
列存储的聚合集计
因为基于列存储,所以每一列本身就相当于索引。所以在做一些需要索引的操作时,就不需要额外的数据结构来为此列创建合适的索引。
通常在传统的关系性数据库中,每一列的数据类型是事先定义好的,会占用固定的内存空间,在此情况下,属性值为空(NULL)的列也需要占用存储空间。 而在 HBase 中的数据都是以字符串形式存储的,为空的列并不占用存储空间,因此 HBase 的列存储解决了数据稀疏性的问题,在很大程度上节省了存储开销。
HBase 工作在 HDFS 之上,也继承了 HDFS 的可扩展性。 HBase 的扩展是横向的,横向扩展是指在扩展时不需要提升服务器本身的性能,只需添加服务器到现有集群即可。
HBase 表根据 Region 大小进行分区,分别存在集群中不同的节点上,当添加新的节点时,集群就重新调整,在新的节点启动 HBase 服务器,动态地实现扩展。 这里需要指出,HBase 的扩展是热扩展,即在不停止现有服务的前提下,可以随时添加或者减少节点。
HBase 运行在 HDFS 上,HDFS 的多副本存储可以让它在岀现故障时自动恢复,同时 HBase 内部也提供 WAL 和 Replication 机制。
WAL(Write-Ahead-Log)预写日志是在 HBase 服务器处理数据插入和删除的过程中用来记录操作内容的日志,保证了数据写入时不会因集群异常而导致写入数据的丢失;而 Replication 机制是基于日志操作来做数据同步的。
当集群中单个节点出现故障时,协调服务组件 ZooKeeper 通知集群的主节点,将故障节点的 HLog 中的日志信息分发到各从节点进行数据恢复。
HBase 组件
HBase 的客户端
HBase 分布式存储和负载均衡的最小单元,它是表或者表的一部分。
一个 Region 由多个 Store 组成,每一个 Store 对应一个 ColumnFamily (列簇), Store 包含 MemStore 和 StoreFile。
内存缓存区,数据的写操作会先写到 MemStore 中,当 MemStore 中的数增长到一个阈值后,RegionServer 会启动 flashcatch 进程写入到 StoreFile 中,每次写入形成一个单独的 StoreFile。 默认大小是 128M。
和 HFile 是同一个东西,只不过是站在 HDFS 角度称这个文件为 Hfile,在 Hbase 角度就叫 StoreFile。 客户端检索数据,现在 MemStore 找,找不到再找 storeFile。
当一个 Region 所有的 StoreFile 大小和数量增长到超过一定阈值后,会把当前 Regin 分割为两个, 并且由 HMaster 分配到相应的 RegionServer 服务器,实现负载均衡。
对 HBase 的操作进行记录,先写进日志,再写进 MemStore,防止数据丢失
HBase 数据模型
Base 是一种列存储模式与键值对存储模式结合的 NoSQL 数据库。 HBase 可以实现自动的数据分片,用户不需要知道数据存储在哪个节点上,只要说明检索的要求,系统会自动进行数据的查询。 HBase 也是以表的方式组织数据,应用程序将数据存于 HBase 的表中,HBase 的表也由行和列组成。
HBase 有列簇的概念,它将一列或多列组织在一起,HBase 的每个列必须属于某一个列簇。
HBase 中的数据以表的形式存储。 同一个表中的数据通常是相关的,使用表主要是可以把某些列组织起来一起访问。 表名作为 HDFS 存储路径的一部分来使用,在 HDFS 中可以看到每个表名都作为独立的目录结构。
在 HBase 表里,每一行代表一个数据对象,每一行都以行键(Row Key)来进行唯一标识,行键可以是任意字符串。 在 HBase 内部,行键是不可分割的字节数组,并且行键是按照字典排序由低到高存储在表中的。 在 HBase 中可以针对行键建立索引,提高检索数据的速度。
HBase 中的列簇是一些列的集合,列簇中所有列成员有着相同的前缀,列簇的名字必须是可显示的字符串。 列簇支持动态扩展,用户可以很轻松地添加一个列簇或列,无须预定义列的数量以及类型。 所有列均以字符串形式存储,用户在使用时需要自行进行数据类型转换。
列簇中的数据通过列标识来进行定位,列标识也没有特定的数据类型,以二进制字节来存储。 通常以
Column Family:Colunm Qualifier
来确定列簇中的某列。每一个行键、列簇、列标识共同确定一个单元格,单元格的内容没有特定的数据类型,以二进制字节来存储。 每个单元格保存着同一份数据的多个版本,不同时间版本的数据按照时间先后顺序排序,最新的数据排在最前面。 单元格可以用
<RowKey,Column Family: Column Qualifier,Timestamp>
元组来进行访问。在默认情况下,每一个单元格插入数据时都会用时间戳来进行版本标识。 读取单元格数据时,如果时间戳没有被指定,则默认返回最新的数据。 写入新的单元格数据时,如果没有设置时间戳,默认使用当前时间。 每一个列簇的单元数据的版本数量都被 HBase 单独维护,默认情况下 HBase 保留 3 个版本数据。
在 HBase 中,列不是固定的表结构,在创建表时,不需要预先定义列名,可以在插入数据时临时创建。 关系型数据库中表的结构需要预先定义,如列名及其数据类型和值域等内容。 如果需要添加新列,则需要修改表结构,这会对已有的数据产生很大影响。 同时,关系型数据库中的表为每个列预留了存储空间,即空白 Cell 数据在关系型数据库中以 NULL 值占用存储空间。 因此,对稀疏数据来说,关系型数据库表中就会产生很多 NULL 值,消耗大量的存储空间。 在 HBase 中,如图那样空白 Cell 在物理上是不占用存储空间的,即不会存储空白的键值对。
HBase 安装
单机安装
安装 HBase
hbase-env.sh 配置 HBase 运行时的变量,如 Java路径、RegionServer 相关参数等。
单机版的环境,ZooKeeper 可以作为 HBase 的一部分来管理启动,即 ZooKeeper 随着 HBase 的启动而启动,随其关闭而关闭。
ZooKeeper 也可以作为独立的集群来运行,即完全与 HBase 脱离关系,这时需要设置 HBASE_MANAGES_ZK 变量为 false。
hbase-site.xml 它是 HBase 的主要配置文件,在这个文件中可以添加 HBase 的相关配置,如分布式的模式、ZooKeeper 的配置等。
全分布式环境安装
比如,三台机器 machine1,machine2,machine3
首先要确认 HDFS 处于运行状态,使用 jps 命令查看 NameNode 和 DataNode 的服务是否正常启动。 之后也要启动 ZooKeeper 服务。 在 Master 服务器上已经配置了对集群中所有 Slave 机器的无密码登录,使用 start-hbase.sh 脚本即可启动整个集群。
使用 jps 命令查看进程,如果是完全分布式模式,则
HBase Shell
HBase 数据库默认的客户端程序是 HBase Shell,它是一个命令行工具。 用户可以使用 HBase Shell,通过命令行的方式与 HBase 进行交互。 在 HBase 的 HMaster 主机上通过命令行输入
hbase shell
,即可进入 HBase 命令行环境。DDL NameSpace
在 RDBMS 中有 database 的概念,用来对 table 进行分组,那么在 HBase 中当表比较多的时候如何对表分组呢,就是namespace,可以简单的把 namespace 理解为 RDBMS 中的 database。
HBase 有两个内置的 namespace:default 和 hbase。
hbase,用来存放系统相关的一些元数据等。
default,创建表时未指定命名空间的话默认挂在 default 下。
在创建namespace的时候还可以添加一些说明信息
DDL Table
namespace 是 ns1,表名是 t1,列簇 f1 , 保留版本 5 个,列簇 f2,列簇 f3
不指定列簇的其他属性,比如版本,可以使用这样的简写
在 Hbase 中,split 是一个很重要的功能,Hbase 是通过把数据分配到一定数量的 region 来达到负载均衡的。 一个 table 会被分配到一个或多个 region 中,这些 region 会被分配到一个或者多个 regionServer 中。 在自动 split 策略中,当一个 region 达到一定的大小就会自动 split 成两个 region。 table 在 region 中是按照 row key 来排序的,并且一个 row key 所对应的行只会存储在一个region中,这一点保证了 Hbase 的强一致性 。
我们可以自定义切分点,这样就按照 row Key,分了5个 region。
自动 split
当一个 region 达到一定的大小,他会自动split称两个region。 0.94版本之后,默认的策略是,最小的分裂大小和 table 的某个 region server 的 region 个数有关。 当 store file 的大小大于如下公式得出的值的时候就会split,公式如下
R 为同一个 table 中在同一个 region server 中 region 的个数。
直接 list 的话就是查询所有命名空间下的所有表。
HBase 表的结构和表的管理可以通过 alter 命令来完成,使用这个命令可以完成更改列族参数信息、增加列族、删除列族以及更改表的相关设置等操作。
修改列簇
增加列簇
删除列簇
HBase 使用 drop 命令删除表,但是在删除表之前需要先使用 disable 命令禁用表。
例如有一个 Student 表,删除该表的完整流程如下
使用 disable 禁用表以后,可以使用 is_disable 查看表是否禁用成功。
另外,如果只是想清空表中的所有数据,使用 truncate 命令即可。
HBase 使用 put 命令向数据表中插入数据,put 向表中增加一个新行数据,或覆盖指定行的数据。
例如有以上结构的数据表,向其中插入一条数据的写法为。
第二个参数 0001 为行键的名称,最后一个参数 1 为时间戳,如果不设置时间戳,则系统会自动插入当前时间为时间戳。
put 命令只能插入一个单元格的数据,上表中的一行数据需要通过以下几条命令一起完成。
如果 put 语句中的单元格是已经存在的,即行键、列簇及列名都已经存在,且不考虑时间戳的情况下,执行 put 语句,则可对数据进行更新操作。 如果在初始创建表时,已经设定了列族 VERSIONS 参数值为 n,则 put 操作可以保存 n 个版本数据,即可查询到行键为 0001 的学生的 n 个版本的姓名数据。
delete 命令可以从表中删除一个单元格或一个行集,语法与 put 类似,必须指明表名和列簇名称,而列名和时间戳是可选的。
例如,执行以下命令,将删除 Student 表中行键为 0002 的 Grades 列簇的所有数据。
需要注意的是,delete 操作并不会马上删除数据,只会将对应的数据打上删除标记(tombstone),只有在合并数据时,数据才会被删除。
执行以下命令将删除 Student 表中行键为 0001,Grades 列簇成员为 Math,时间戳小于等于 2 的数据。
如需删除表中所有列簇在某一行上的数据,即删除上表中一个逻辑行,则需要使用 deleteall 命令。
手工把 MemStore 写到 Hfile 中
比如,删除所有的数据
每次 flush 都会建一个新的 hfile。
get 命令可以从数据表中获取某一行记录,类似于关系型数据库中的 select 操作。get 命令必须设置表名和行键名,同时可以选择指明列簇名称、时间戳范围、数据版本等参数。
执行以下命令可以获取 Student 表中行键为 0001 的所有列簇数据
获取某个列簇的某个字段
scan 命令,用来查询指定命名空间,指定表的全部数据,使用时只需指定
命名空间:表名
即可。指定列簇,指定列的所有数据
分页
按照时间范围来查询
查询最后三个版本的数据
统计表的行数
JAVA HBase
添加依赖
连接类
Namespace 的 CRUD
Table 的 CRUD
Table 的 DML 操作
过滤器
Hbase提供了高级的查询方法,Filter。 Filter可以根据簇、列、版本等更多的条件来对数据进行过滤,基于Hbase本身提供的三维有序(主键有序、列有序、版本有序),这些Filter可以高效的完成查询过滤的任务。 带有 Filte r条件的 RPC 查询请求会把 Filter 分发到各个 RegionServer,是一个服务器端(Server-side)的过滤器,这样也可以降低网络传输的压力。
要完成一个过滤的操作,至少需要两个参数。一个是抽象的操作符,另外一个就是具体的比较器。
抽象操作符(比较运算符)
比较器(指定比较机制)
相当于
name="刘晨" and age <= 33
RegexStringComparator 支持用于值比较的正则表达式。
SubstringComparator 可用于确定给定的子字符串是否存在于某个值中,比较是不区分大小写的。
二进制前缀标签,判断是不是以某个数据开头
按字节索引顺序比较指定字节数组,相当于字符串比较
列簇的过滤器。过滤出包含列簇的信息
列名的过滤器。
跟上面差不多,以什么列名开头。
多个列名前缀,比如,以 a 为开头,或者 以 b 为开头的。
RowFilter 基于行键进行过滤,在工作中涉及到需要通过HBase Rowkey进行数据过滤时可以考虑使用它。
基于列值进行过滤,在工作中涉及到需要通过HBase 列值进行数据过滤时可以考虑使用它。
布隆过滤器
首先要了解 HBase 的块索引机制。块索引是 HBase 固有的一个特性,因为 HBase 的底层数据是存储在 HFile 中的,而每个 HFile 中存储的是有序的
<key, value>
键值对,HFile 文件内部由连续的块组成,每个块中存储的第一行数据的行键组成了这个文件的块索引,这些块索引信息存储在文件尾部。当 HBase 打开一个 HFile 时,块索引信息会优先加载到内存;HBase首先在内存的块索引中进行二分查找,确定可能包含给定键的块,然后读取磁盘块找到实际想要的键。但实际应用中,仅仅只有块索引满足不了需求,这是因为,块索引能帮助我们更快地在一个文件中找到想要的数据,但是我们可能依然需要扫描很多文件。而布隆过滤器就是为解决这个问题而生。因为布隆过滤器的作用是,用户可以立即判断一个文件是否包含特定的行键,从而帮我们过滤掉一些不需要扫描的文件。
如下图所示,块索引显示每个文件中都可能包含对应的行键,而布隆过滤器能帮我们跳过一些明显不包含对应行键的文件。
Hbase 寻址机制
寻址过程
Client访问Zookeeper,查找
-ROOT-
表,获取.META.
表信息。从
.META
.表查找,获取存放目标数据的 Region 信息,从而找到对应的 RegionServer。通过RegionServer获取需要查找的数据。
Regionserver 的内存分为 MemStore 和 BlockCache 两部分,MemStore 主要用于写数据,BlockCache 主要用于读数据。 读请求先到 MemStore 中查数据,查不到就到 BlockCache 中查,再查不到就会到 StoreFile 上读,并把读的结果放入 BlockCache。
-ROOT-
表表包含
.META.
表所在的region列表,该表只会有一个Region。 Zookeeper中记录了-ROOT-表的location。.META.
表表包含所有的用户空间 region 列表,以及 RegionServer 的服务器地址。