# HBASE基础


<!--more-->

## 1. 简介

HBase基于Google的BigTable论文而来，是一个分布式海量列式非关系型数据库系统，可以提供超大规模数据集的实时随机读写。

> 关系型数据库存在空间浪费情况

**特点:**

- 海量存储：底层基于HDFS存储海量数据
- 列式存储：HBase表的数据是基于列族进行存储的，一个列族包含若干列
- 极易扩展：底层依赖HDFS，当磁盘空间不足的时候，只需要动态增加DataNode服务节点就可以
- 高并发：支持高并发的读写请求
- 稀疏：稀疏主要是针对HBase列的灵活性，在列族中，你可以指定任意多的列，在列数据为空的情况下，是不会占用存储空间的。
- 数据的多版本：HBase表中的数据可以有多个版本值，默认情况下是根据版本号去区分，版本号就是插入数据的时间戳
- 数据类型单一：所有的数据在HBase中是以字节数组进行存储

应用:

- 交通方面：船舶GPS信息，每天有上千万左右的数据存储。
- 金融方面：消费信息、贷款信息、信用卡还款信息等
- 电商方面：电商网站的交易信息、物流信息、游览信息等
- 电信方面：通话信息

总结：HBase适合海量明细数据的存储，并且后期需要有很好的查询性能（单表超千万、上亿，且并发要求高）

## 2. 数据模型

HBase的数据也是以表（有行有列）的形式存储

逻辑架构: ![img](https://img.zhaojq.top/20260727091749227.png "img")

物理存储: ![img_1](https://img.zhaojq.top/20260727091749427.png "img_1")

| 概念                | 描述                                                         |
| ------------------- | ------------------------------------------------------------ |
| NameSpace(数据库)   | 命名空间，类似于关系型数据库的database概念，每个命名空间下有多个表。HBase两个自带的命名空间，分别是hbase和default，hbase中存放的是HBase内置的表，default表是用户默认使用的命名空间。一个表可以自由选择是否有命名空间，如果创建表的时候加上了命名空间后，这个表名字以:作为区分！ |
| Table               | 类似于关系型数据库的表概念。不同的是，HBase定义表时只需要声明列族即可，数据属性，比如超时时间（TTL），压缩算法（COMPRESSION）等，都在列族的定义中定义，不需要声明具体的列。 |
| Row 一行逻辑数据    | HBase表中的每行数据都由一个RowKey和多个Column（列）组成。一个行包含了多个列，这些列通过列族来分类,行中的数据所属列族只能从该表所定义的列族中选取,不能定义这个表中不存在的列族，否则报错NoSuchColumnFamilyException。 |
| RowKey 行数据主键   | Rowkey由用户指定的一串不重复的字符串定义，是一行的唯一标识！数据是按照RowKey的字典顺序存储的，并且查询数据时只能根据RowKey进行检索，所以RowKey的设计十分重要。如果使用了之前已经定义的RowKey，那么会将之前的数据更新掉！ |
| Colummn Family 列族 | 列族是多个列的集合。一个列族可以动态地灵活定义多个列。表的相关属性大部分都定义在列族上，同一个表里的不同列族可以有完全不同的属性配置，但是同一个列族内的所有列都会有相同的属性。列族存在的意义是HBase会把相同列族的列尽量放在同一台机器上，所以说，如果想让某几个列被放到一起，你就给他们定义相同的列族。 |
| Column Qualifier 列 | Hbase中的列是可以随意定义的，一个行中的列不限名字、不限数量，只限定列族。因此列必须依赖于列族存在！列的名称前必须带着其所属的列族！例如info：name，info：age |
| TimeStamp 版本      | 用于标识数据的不同版本（version）。时间戳默认由系统指定，也可以由用户显式指定。在读取单元格的数据时，版本号可以省略，如果不指定，Hbase默认会获取最后一个版本的数据返回！ |
| Cell                | 一个列中可以存储多个版本的数据。而每个版本就称为一个单元格（Cell）。 |
| Region 表的分区     | Region由一个表的若干行组成！在Region中行的排序按照行键（rowkey）字典排序。Region不能跨RegionSever，且当数据量大的时候，HBase会拆分Region。 |

## 3. 整体架构

![img_2](https://img.zhaojq.top/20260727091749612.png "img_2")

- **Zookeeper**

  实现了HMaster的高可用

  保存了HBase的元数据信息，是所有HBase表的寻址入口

  对HMaster和HRegionServer实现了监控

- **HMaster（Master）** 

  为HRegionServer分配Region

  维护整个集群的负载均衡

  维护集群的元数据信息

  发现失效的Region，并将失效的Region分配到正常的HRegionServer上

- **HRegionServer（RegionServer）**

  负责管理Region

  接受客户端的读写数据请求

  切分在运行过程中变大的Region

- **Region**

  每个HRegion由多个Store构成，

  每个Store保存一个列族（Columns Family），表有几个列族，则有几个Store，

  每个Store由一个MemStore和多个StoreFile组成，MemStore是Store在内存中的内容，写到文件后就是StoreFile。StoreFile底层是以HFile的格式保存。

## 4. HBase集群安装

**hbase 的安装需要依赖 zookeeper集群和hadoop集群**

这里先不作演示, 以后有时间再搭建....

- [x] 搭建hbase环境

## 5. shell基本操作

- 进入hbase客户端命令 `hbase shell`

- 查看帮助命令 `help`

- 查看当前数据库中有哪些表 `list`

- 创建一张表 demo, 包含base_info, extra_info两个列族

  ```sql
  create 'demo', 'base_info', 'extra_info'
  或者(Hbase建表必须指定列族信息)
  create 'lagou', {NAME => 'base_info', VERSIONS => '3'},{NAME => 'extra_info',VERSIONS => '3'} 
  -- VERSIONS 是指此单元格内的数据可以保留最近的 3 个版本
  ```

- 添加数据

  ```sql
   -- 向 demo 表中插入信息，row key为 rk1，列族base_info中添加name列标示符，值为wang
   put 'demo', 'rk1', 'base_info:name', 'wang'
   
   -- 向 demo 表中插入信息，row key为rk1，列族base_info中添加age列标示符，值为30
   put 'demo', 'rk1', 'base_info:age', 30
  
  ```

- 查询数据

  ```sql
  -- 通过rowkey查询rk1所有信息
  get 'demo', 'rk1'
  
  -- 获取rowkey为rk1,base_info列族的所有信息
  get 'demo', 'rk1', 'base_info'
  
  -- 查询rowkey为rk1,base_info列族的name, age列信息
  get 'demo', 'rk1', 'base_info:name', 'base_info:age'
  
  -- 获取row key为rk1，base_info、extra_info列族的信息
  get 'demo', 'rk1', 'base_info', 'extra_info'
  或
  get 'demo', 'rk1', {COLUMN => ['base_info', 'extra_info']}
  或
  get 'demo', 'rk1', {COLUMN => ['base_info:name', 'extra_info:address']}
  
  -- 获取指定rowkey为rk1, cell值为wang的信息
  get 'demo', 'rk1', {FILTER => "ValueFilter(=, 'binary:wang')"}
  
  -- 获取表中row key为rk1，列标示符中含有a的信息
  get 'demo', 'rk1', {FILTER => "(QualifierFilter(=,'substring:a'))"}
  
  -- 查询demo表中所有数据
  scan 'demo'
  
  -- 查询表中列族为 base_info 的信息
  ## Scan时可以设置是否开启Raw模式,开启Raw模式会返回包括已添加删除标记但是未实际删除的数据
  ## VERSIONS指定查询的最大版本数
  scan 'demo', {COLUMNS => 'base_info'}
  scan 'demo', {COLUMNS => 'base_info', RAW => true, VERSIONS => 3}
  
  -- 查询demo表中列族为 base_info 和 extra_info且列标示符中含有a字符的信息
  scan 'demo', {COLUMNS => ['base_info', 'extra_info'], FILTER => "(QualifierFilter(=,'substring:a'))"}
  
  -- rowkey范围查询 [rk1, rk3)
  scan 'demo', {COLUMNS => 'base_info', STARTROW => 'rk1', ENDROW => 'rk3'}
  
  -- rowkey模糊查询, 以rk字符开头的
  scan 'demo',{FILTER=>"PrefixFilter('rk')"}
  ```

- 更新数据

  ```sql
  -- 与插入操作一样,有数据就更新,无数据就插入
  
  -- 更新demo表rowkey为rk1的base_info列族下的name为liang
  put 'demo', 'rk1', 'base_info:name', 'liang'
  ```

- 删除操作

  ```sql
  -- 删除rowkey为rk1, 列标示符为base_info:name的数据
  delete 'demo', 'rk1', 'base_info:name'
  
  -- 删除rokey为rk1, 指定列名和时间戳
  delete 'demo', 'rk1', 'base_info:name',1600660619655
  
  -- 删除列族
  alter 'demo', 'delete' => 'base_info'
  
  -- 清空表数据
  truncate 'demo'
  
  -- 删除表 先disable 再drop
  disable 'demo'
  drop 'demo'
  ```

  






































































