HBase 详解

本文深入解析HBase架构,涵盖HBaseShell操作指南,包括表的创建、数据的增删查改,以及HBase数据结构如RowKey、ColumnFamily、Cell的理解。同时,介绍了HBase读写流程、数据flush与合并过程,以及如何使用HBase API进行程序开发。

1.HBase 架构

1222878-20190602190004759-235734166.png


============================================

2. HBase Shell 操作

2.1. 基本操作
  • 进入HBase客户端命令行:bin/hbase shell
  • 查看帮助命令:help
  • 查看当前数据库中有哪些表:list
2.2. 表的操作
// 2.2.1. 创建表
create 'student','info'(列族)

// 2.2.2. 插入数据到表
put 'student','1001','info:sex','male'
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.2.3. 扫描查看表数据
scan 'student'
scan 'student',{STARTROW => '1001', STOPROW => '1004'}
scan 'student',{STARTROW => '1001'}

// 2.2.4. 查看表结构
describe 'student'

// 2.2.5. 更新指定字段的数据
put 'student','1001','info:name','zhangsan'
put 'student','1001','info:age','22'

// 2.2.6. 查看“指定行”或“指定列族:列”的数据
get 'student','1001'
get 'student','1001','info:name'

// 2.2.7. 统计表数据行数
count 'student'

// 2.2.8. 删除数据:
// 删除某rowkey的全部数据
deleteall 'student','1001'
// 删除某rowkey的某一列数据
delete 'student','1002','info:sex'

// 2.2.9. 清空表数据
// 清空表的操作顺序为先disable, 然后再 truncate
truncate 'student'

// 2.2.10. 删除表
// 先让该表为 disable 状态
disable 'student'
// 然后才能 drop 这个表
drop 'student'

// 2.2.11 变更表信息
// 将info列族中的数据存放3个版本
alter 'student',{NAME=>'info',VERSIONS=>3}
get 'student','1001',{COLUMN=>'info:name',VERSIONS=>3}

3. HBase 数据结构

3.1 RowKey
  • RowKey 可以是任意字符串(最大长度是64KB,实际应用中长度一般为10-100bytes),在HBASE内部,RowKey 保存为字节数组。存储时,数据按照 RowKey 的字典序排序存储。设计 RowKey 时,要充分考虑排序存储这个特性,将经常一起读取的行存储在一起。(位置相关性)
  • RowKey 是用来检索记录的主键。访问HBase table中的行,有三种方式:
    • 通过单个 RowKey 访问;
    • 通过 RowKey 的 range(正则)
    • 全表扫描
3.2 Column Family
  • 列族:HBASE 表中的每个列,都归属于某个列族。列族是表的 schema 的一部分(而列不是)。必须在使用表之前定义。列名都以列族作为前缀。例如:courses:history, courses:math 都属于 courses 这个列族。
3.3 Cell
  • 由(rowkey, column Family:column, version)唯一确定的单元。cell 中的数据是没有类型的,全部是字节码形式存储。
3.4 TimeStamp
  • 版本通过时间戳来索引;
3.5 命名空间
  • Table: 表,所有的表都是命名空间的成员,即表必属于某个命名空间,如果没有指定,则在 default 默认的命名空间中;
  • RegionServer group:一个命名空间包含了默认的 RegionServer Group;
  • Permission: 权限。命名空间能够让我们来定义访问控制列表ACL(Access Control List);
  • Quota:限额,可以强制一个命名空间可包含的 region 数量;
  • 常用命令:
    • 查看命名空间:list_namespace;
    • 创建命名空间:create_namespace 'bigdata';
    • 在指定命名空间下,创建表:create 'bigdata:student','info';
    • 删除命名空间:drop_namespace 'bigdata';

4. HBase 原理

4.1 读流程

1222878-20190612212350386-480771948.jpg


=========================

4.2 写流程
  • Client 向 HregionServer 发送写请求;
  • HregionServer 将数据写到 HLog(write ahead log)。为了数据的持久化和恢复;
  • HregionServer 将数据写到内存(MemStore);
  • 反馈 Client 写成功;

1222878-20190612212336483-121255245.jpg


=========================

4.3 数据flush过程
  • 当 MemStore 数据达到阈值(默认是 128M,老版本是 64M),将数据刷到磁盘,将内存中的数据删除,同时删除HLog中的历史数据;
  • 将数据存储到HDFS中;
  • 在HLog中做标记点;
4.4 数据合并过程
  • 当数据块达到4块,Hmaster 触发合并操作, Region 将数据块加载到本地,进行合并;
  • 当合并的数据超过 256M, 进行拆分,将拆分后的 Region 分配给不同的 HregionServer 管理;
  • 当 HregionServer 宕机后,将 HregionServer 上的 hlog拆分,然后分配给不同的 HregionServer 加载,修改 META;
  • 注意:HLog 会同步到 HDFS;

5. HBase API 操作

5.1 环境准备
// pom.xml
  <dependencies>
      <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>RELEASE</version>
      </dependency>
      <dependency>
          <groupId>org.apache.hbase</groupId>
          <artifactId>hbase-server</artifactId>
          <version>1.3.4</version>
      </dependency>
      <dependency>
          <groupId>org.apache.hbase</groupId>
          <artifactId>hbase-client</artifactId>
          <version>1.3.4</version>
      </dependency>
  <dependencies>
5.2 程序编写
public class TestHbase {
    
    private static Admin admin = null;
    private static Connection connection = null;
    private static Configuration configuration = null;
    static {
        // HBase 配置文件
        configuration = HBaseConfiguration.create();
        // zookeeper 配置
        configuration.set("hbase.zookeeper.quorum", "Zookeeper地址");
        configuration.set("hbase.zookeeper.property.clientPort", "2181");
        
        // 获取连接对象
        try {
            connection = ConnectionFactory.createConnection(configuration);
            admin = connection.getAdmin();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    
    private void close(Connection conn, Admin admin) {
        if (conn != null) {
            try {
                conn.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
        if (admin != null) {
            try {
                admin.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
    // 判断表是否存在
    @Test
    public void tableExist() throws IOException {
        
        // 执行操作
        Boolean student = admin.tableExists(TableName.valueOf("student"));
        System.out.println("表Staff是否存在:"+student);
        
        Boolean staff = admin.tableExists(TableName.valueOf("staff"));
        System.out.println("表Staff是否存在:"+staff);
        this.close(connection, admin);
        
    }
    
    // 创建表
    @Test
    public void createTable() throws IOException {
        // 创建表描述器
        HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf("country"));
        
        // 创建列描述器
        HColumnDescriptor hColumnDescriptor = new HColumnDescriptor("name");
        // 添加列族
        hTableDescriptor.addFamily(hColumnDescriptor);
        
        // 创建表操作
        admin.createTable(hTableDescriptor);
        
        System.out.println("表已经创建成功!");
        this.close(connection, admin);
    }
    
    // 删除表
    @Test
    public void deleteTable() throws IOException {
        
        // 使表不可用
        admin.disableTable(TableName.valueOf("country"));
        
        // 删除表
        admin.deleteTable(TableName.valueOf("country"));
        
        System.out.println("表已经删除成功!");
        this.close(connection, admin);
    }
    
    
    // 操作表中数据: 
    // 增/改数据
    @Test
    public void putData() throws IOException {
        // 获取table对象
        Table table = connection.getTable(TableName.valueOf("student"));
        
        // 创建put对象
        Put put = new Put(Bytes.toBytes("1010"));
        // 添加数据
        put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"), Bytes.toBytes("貂蝉"));
        
        // 执行添加操作
        table.put(put);
        
        System.out.println("数据添加成功!");
        this.close(connection, admin);
    }
    
    // 删除数据
    @Test
    public void deleteData() throws IOException {
        // 获取table对象
        Table table = connection.getTable(TableName.valueOf("student"));
        
        // 创建delete对象
        Delete delete = new Delete(Bytes.toBytes("1010"));
        // 第一种方式:不建议使用,只是删除最新版本
//      delete.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"));
        // 第二种方式:删除所有版本
        delete.addColumns(Bytes.toBytes("info"), Bytes.toBytes("name"));
        
        // 删除数据
        table.delete(delete);
        
        System.out.println("数据删除成功!");
        table.close();
        this.close(connection, admin);
    }
    
    // 查询数据
    // 全表扫描
    @Test
    public void scanTable() throws IOException {
        Table table = connection.getTable(TableName.valueOf("student"));
        // 构建扫描器
        Scan scan = new Scan();
        
        ResultScanner results = table.getScanner(scan);
        for(Result result : results) {
            Cell[] cells = result.rawCells();
            for (Cell cell : cells) {
                System.out.println("RK:" + Bytes.toString(CellUtil.cloneRow(cell)) +
                                   ",CF:" + Bytes.toString(CellUtil.cloneFamily(cell)) + 
                                   ",CN:" + Bytes.toString(CellUtil.cloneQualifier(cell)) + 
                                   ",VALUE:" + Bytes.toString(CellUtil.cloneValue(cell)));
            }
        }
        
        table.close();
        this.close(connection, admin);
    }

  // 获取指定列族:列的数据
    @Test
    public void scanColumnFamily() throws IOException {
        Table table = connection.getTable(TableName.valueOf("student"));
        // 创建get对象
        Get get = new Get(Bytes.toBytes("1001"));
        
        Result result = table.get(get);
        Cell[] cells = result.rawCells();
        for (Cell cell : cells) {
            System.out.println("RK:" + Bytes.toString(CellUtil.cloneRow(cell)) +
                               ",CF:" + Bytes.toString(CellUtil.cloneFamily(cell)) + 
                               ",CN:" + Bytes.toString(CellUtil.cloneQualifier(cell)) + 
                               ",VALUE:" + Bytes.toString(CellUtil.cloneValue(cell)));
        }
    }
}



参考资料:

转载于:https://www.cnblogs.com/linkworld/p/10963910.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值