> 文章列表 > HBase架构篇 - Hadoop家族的天之骄子HBase

HBase架构篇 - Hadoop家族的天之骄子HBase

HBase架构篇 - Hadoop家族的天之骄子HBase

HBase的基本组成结构

HBase架构篇 - Hadoop家族的天之骄子HBase

表(table)

HBase 的数据存储在表中。表名是一个字符串。表由行和列组成。

行(row)

HBase 的行由行键(rowkey)和 n 个列(column)组成。行键没有数据类型,可以看作是字节数组,类似于关系型数据库的主键索引,在整个 HBase 表中是唯一的,按照字母顺序排序。

列族(column family)

HBase 的列族由多个列组成,相当于将列进行分组。列的数量没有限制。表中的每一行都有同样的列族。列族必须在表创建的时候指定,不能轻易修改,并且数量不能太多,一般不超过 3 个。列族名的类型是字符串。

列限定符(qualifier)

列限定符用于代表 HBase 表中列的名称,列族中的数据通过列限定符来定位,常见的定位格式为 “family:qualifier”(比如定位列族 cf1 的列 name,则使用 cf1:name)。一个列族下面可以有多个列限定符。列限定符没有数据类型,可以看作是字节数组。

单元格(cell)

单元格通过行键、列族、列限定符一起来定位。单元格包括值和时间戳。值没有数据类型,总是视为字节数组。时间戳代表该值的版本,类型为 long。默认,时间戳表示数据写入服务器的时间,但是当数据放入单元格时,也可以指定不同的时间戳。每个单元格都根据时间戳保存着同一份数据的多个版本,并且按照降序排列,即最新的数据排在前面。对单元格中的数据进行访问的时候会默认读取最新值。

{"00001": {				                    // 行键"info": {			                    // 列族"username": {	                    // 列限定符												"15335401223674": "zhangsan"	// 时间戳:列值				 },																						 "password": {						   -----"1533540265719": "hello",				|"1533540102020": "123"					| --> 单元格}									    -----}}
}

HBase的架构设计

HMaster

HMaster 节点可以有多个。通过 ZooKeeper 的选举机制保证同一时刻只有一个 HMaster 节点处于活动状态,其它 HMaster 节点处于备用状态。

HMaster 节点的特点如下:

  • HMaster 节点本身不存储 HBase 的任何数据。它主要用于管理 HRegionServer 节点,指定 HRegionServer 节点可以管理哪些 HRegion,以实现其负载均衡。
  • 当某个 HRegionServer 节点宕机时,HMaster 会将其中的 HRegion 迁移到其它的 HRegionServer 上。
  • 管理用户对表的增删改查操作。
  • 管理表的元数据(每个 HRegion 都有一个唯一标识符,元数据主要保存这个唯一标识符与 HRegionServer 的映射关系)。
  • 权限管理。

HRegion、HRegionServer

HBase 通过 rowkey 自动将表水平切分成多个区域,这个区域称为 HRegion。每个 HRegion 由表中的多行数据组成。

最初一个表只有一个 HRegion,随着数据的增多,当数据大到一定的值后,便会在某行的边界上将表分割成两个大小基本相同的HRegion。然后由 HMaster 节点将不同的 HRegion 分配到不同的 HRegionServer 节点上,由 HRegionServer 节点对其进行管理以及响应客户端的读写请求。换言之,分布在集群中的所有 HRegion 按序排列就组成了一张完整的表。

每个 HRegion 记录了 rowkey 的起始行键(startkey)、结束行键(endkey)。第一个 HRegion 的 startkey 为空,最后一个 HRegion 的 endkey 为空。客户端可以通过 HMaster 节点快速定位每个 rowkey 所在的 HRegion。

HBase架构篇 - Hadoop家族的天之骄子HBase

Store

一个 Store 存储 HBase 表的一个列族的数据。由于表被水平分割成多个 HRegion,那么一个 HRegion 中包含一个或者多个 Store。Store 包含一个 MemStore 和多个 HFile 文件。MemStore 相当于一个内存缓冲区,数据存入磁盘之前先存入 MemStore 中。当 MemStore 中的数据大小达到一定值后,会生成一个 HFile 文件,MemStore 中的数据会转移到 HFile 文件中。StoreFile 是对 HFile 文件的封装,HFile 是 HBase 底层的数据存储格式,最终数据以 HFile 的格式存储在 HDFS 中。

值得注意的是,一个HFile 文件只存放某个时刻 MemStore 中的所有数据,一个完整的行数据可能存放于多个 HFile 中。

HLog

HLog 是 HBase 的日志文件,存储于 HDFS 中,用于记录数据的写操作。HBase 在写入数据时会先进行 WAL(预写日志)操作,即将写操作写入到 HLog 文件中,才会将数据写入 Store 的 MemStore 中,只有这两个地方都写入并且确认后,才认为数据写入成功。

ZooKeeper

每个 HRegionServer 节点会在 ZooKeeper 中注册一个自己的临时节点,HMaster 通过这些临时节点发现可用的 HRegionServer 节点,跟踪 HRegionServer 节点的故障等。

HBase 利用 ZooKeeper 确保只有一个活动的 HMaster 节点在运行。

HRegion 应该分配到哪个 HRegionServer 节点上,也是通过 ZooKeeper 得知的。

客户端操作

创建表

public class CreateTableDemo {public static void main(String[] args) throws IOException {Configuration configuration = HBaseConfiguration.create();// 指定ZooKeeper集群地址configuration.set("hbase.zookeeper.quorum", "10.211.55.6:2181,10.211.55.7:2181,10.211.55.8:2181");Connection connection = ConnectionFactory.createConnection(configuration);Admin admin = connection.getAdmin();TableName tableName = TableName.valueOf("t_order3");// 创建表描述HTableDescriptor hTableDescriptor = new HTableDescriptor(tableName);// 创建列描述HColumnDescriptor hColumnDescriptor = new HColumnDescriptor("f1");// 添加列族hTableDescriptor.addFamily(hColumnDescriptor);// 创建表admin.createTable(hTableDescriptor);}
}

接下来进入 HBase shell 命令行模式,执行 list 命令查看当前所有表。

TABLE                                                                           
t_order                                                                         
t_order2                                                                        
t_order3                                                                        
3 row(s)
Took 0.0261 seconds                                                             
=> ["t_order", "t_order2", "t_order3"]

可见,t_order3 表已经创建成功了。

此外也可以执行 create 命令创建表。create 命令指定表名、列族。

hbase:004:0> create 't_order4', 'f1'
Created table t_order4
Took 1.3553 seconds                                                             
=> Hbase::Table - t_order4

添加数据

public class AddDataDemo {public static void main(String[] args) throws IOException {Configuration configuration = HBaseConfiguration.create();configuration.set("hbase.zookeeper.quorum", "10.211.55.6:2181,10.211.55.7:2181,10.211.55.8:2181");Connection connection = ConnectionFactory.createConnection(configuration);TableName tableName = TableName.valueOf("t_order2");Table table = connection.getTable(tableName);// 设置行键Put put = new Put(Bytes.toBytes("row1"));// 添加列族、列名、列值put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("name"), Bytes.toBytes("zhangsan2"));put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("age"), Bytes.toBytes("20"));put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("address"), Bytes.toBytes("beijing"));table.put(put);// 设置行键Put put2 = new Put(Bytes.toBytes("row2"));// 添加列族、列名、列值put2.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("name"), Bytes.toBytes("lisi"));put2.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("age"), Bytes.toBytes("25"));put2.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("address"), Bytes.toBytes("shanghai"));table.put(put2);// 释放资源table.close();}
}

接下来进入 HBase shell 命令行模式,执行 scan 命令扫描 t_order2 表的所有数据。

hbase:006:0> scan 't_order2'
ROW                   COLUMN+CELL                                               
row1                  column=f1:address, timestamp=2023-04-15T21:37:23.457, value=shanghai                                                
row1                  column=f1:age, timestamp=2023-04-15T21:37:23.457, value=25
row1                  column=f1:name, timestamp=2023-04-15T21:37:23.457, value=lisi                                                       
row2                  column=f1:age, timestamp=2023-04-15T21:16:46.128, value=22
row2                  column=f1:name, timestamp=2023-04-15T21:16:35.289, value=wangwu                                                     
2 row(s)
Took 0.0699 seconds    

可以使用 put 命令添加数据。put 命令可以指定表名、行键、列族:列名、列值。

hbase:007:0> put 't_order2', 'row2', 'f1:name', 'wangwu'
Took 0.1126 seconds                                                             
hbase:008:0> put 't_order2', 'row2', 'f1:age', '22'
Took 0.0868 seconds     

修改数据

与添加数据的方式相同。

删除数据

public class DeleteDataDemo {public static void main(String[] args) throws IOException {Configuration configuration = HBaseConfiguration.create();configuration.set("hbase.zookeeper.quorum", "10.211.55.6:2181,10.211.55.7:2181,10.211.55.8:2181");Connection connection = ConnectionFactory.createConnection(configuration);// 指定表名TableName tableName = TableName.valueOf("t_order2");Table table = connection.getTable(tableName);// 指定行键Delete delete = new Delete(Bytes.toBytes("row2"));table.delete(delete);table.close();}
}

可以执行 delete 命令删除指定单元格。delete 命令可以指定表名、行键、列族:列名。

hbase:009:0> delete 't_order2', 'row1', 'f1:address'
Took 0.0834 seconds 

可以执行 deleteall 命令删除一整行数据。delete 命令可以指定表名、行键。

hbase:010:0> deleteall 't_order2', 'row1'
Took 0.0370 seconds    

可以执行 disabledrop 命令删除一张表。disable 命令禁用表,可以指定表名;drop 命令删除表,可以指定表名。

hbase:010:0> disable 't_order2'
Took 0.0375 seconds    
hbase:010:0> drop 't_order2'
Took 0.0375 seconds    

查询数据

public class QueryDataDemo {public static void main(String[] args) throws IOException {Configuration configuration = HBaseConfiguration.create();configuration.set("hbase.zookeeper.quorum", "10.211.55.6:2181,10.211.55.7:2181,10.211.55.8:2181");Connection connection = ConnectionFactory.createConnection(configuration);// 指定表名TableName tableName = TableName.valueOf("t_order2");Table table = connection.getTable(tableName);// 指定行键Get get = new Get(Bytes.toBytes("row1"));Result result = table.get(get);for (Cell cell : result.rawCells()) {// 获取列族String family = new String(CellUtil.cloneFamily(cell));// 获取列名String qualifier = new String(CellUtil.cloneQualifier(cell));// 获取列值String value = new String(CellUtil.cloneValue(cell));System.out.println("列:" + family + ":" + qualifier + "---值:" + value);}}
}

接下来进入 HBase shell 命令行模式,执行 get 命令查询一整行数据。get 命令可以指定表名、行键。

hbase:011:0> get 't_order2', 'row1'
COLUMN                CELL                                                      f1:address           timestamp=2023-04-15T21:10:16.950, value=shanghai         f1:age               timestamp=2023-04-15T21:10:16.950, value=25               f1:name              timestamp=2023-04-15T21:10:16.950, value=lisi             
1 row(s)
Took 0.0684 seconds  

可以执行 count 命令获取表的记录数。count 命令可以指定表名。

hbase:001:0> count 't_order2'
2 row(s)
Took 0.5480 seconds                                                             
=> 2

可以执行 exists 命令查看表是否存在。exists 命令可以指定表名。

hbase:008:0> exists 't_order2'
Table t_order2 does exist                                                       
Took 0.2278 seconds                                                             
=> true