《HBase原理与实践》学习笔记【1-8章 HBase基础知识及其工作原理】

CSDN目录显示不全,也可以点击我的博客查看更全的目录结构。

《HBase原理与实践》学习笔记

一、HBase概述

1.1 HBase数据模型

1.1.1 逻辑视图
  • table:表
  • row:行
  • column:列
  • timestamp:时间戳
  • cell:单元格
1.1.2 物理视图

HBase中的数据是按照列族存储的,即将数据按照列族分别存储在不同目录中。

1.2 HBase体系结构

avatar

1.2.1 Master

主要负责HBase系统的各种管理工作:

  • 处理用户的各种管理请求,包括建表、修改表、权限操作、切分表、合并数据等。
  • 管理集群中的RegionSerer,包括其中Region的负载均衡、迁移等。
  • 清理过期日志以及文件
1.2.2 RegionServer

主要用来相应用户IO请求,是HBase中最核心的模块:

  • WAL(HLog)

    1. 用于实现数据的高可靠性,HBase数据随机写入时,并非直接写入HFile数据文件,而是先写入缓存,再异步刷新落盘。为了防止缓存数据丢失,数据写入缓存之前需要首先顺序写入HLog。这样即使缓存数据丢失,也能够通过HLog日志恢复。
    2. 用于实现HBase集群间的主从复制,通过回放主集群推送过来的HLog日志实现主从复制。
  • BlockCache

    HBase中的读缓存。客户端从磁盘上熟读数据后通常会将数据缓存在系统内存中,后续再次访问相同的一行数据,可以直接从内存中获取,对于大量热点读的业务来说,可以很大提高性能。

    BlockCache缓存对象是一系类Block块,默认64K。利用了空间局部性和时间局部性原理,来实现。

  • Region

    数据表的一个分片,当数据表大小超过一定阈值就会“水平切分”,分裂为两个Region。Region是集群负载均衡的基本单位。通常一张表的Region会分布在整个集群的多台RegionServer上,一个RegionServer会管理多个Region。

    一个Region由一个或者多个Store构成。Store的个数取决于表中列族的个数,多少个列族就有多少个Store。(每个列族的数据都集中存放在一起形成一个存储单元Store)

    每个Store由一个MemStore和多个HFile组成。MemStore成为写缓存,用户写入数据时,会先写到MemStore,当MemStore写满之后(阈值默认为128M),系统会异步将数据flush成一个HFile文件。显然,随着数据不断写入HFile文件越来越多,当HFile文件数超过一定阈值的时候,会执行Compact操作,将小文件通过一定策略合并成一个大文件。

1.3 HBase系统特性

1.3.1 HBase的优点
  • 容量巨大:单表支持千亿行、百万列的数据规模。
  • 良好的可扩展性:集群扩展容易,主要是数据存储节点的扩展以及读写服务节点扩展。(添加RegionServer节点)
  • 稀疏性:允许大量列值为空,并不占用任何存储空间。
  • 高性能:主要擅长OLTP场景,数据写操作性能强劲,对于 随机单点读 以及 小范围扫描读 ,其性能也能得到保障。对于大范围的扫描读可以使用MR的API,以便实现更高效的并行扫描。
  • 多版本:时间戳,可以保留多个历史版本。
  • 支持过期:TTL过期特性,只要设置过期时间,就可以自动清理。
  • Hadoop原生支持
1.3.2 HBase的缺点
  • HBase本身不支持很复杂的聚合运算(如,Join、GroupBy等)。如果业务中需要使用聚合运算,可以在HBase之上架设Phoenix组件(小规模OLTP)或者Spark组件(大规模聚合的OLTP)。
  • HBase本身没有二级索引功能,不支持二级索引查找。好在针对HBase实现的第三方二级索引方案非常丰富,比如目前比较普遍的使用Phoenix提供的二级索引功能。
  • HBase原生不支持全局跨行事务,只支持单行事务模型。同样,可以使用Phoenix提供的全局事务模型组件来弥补HBase的这个缺陷。

二、基础数据结构与算法

2.1 跳跃表

跳跃表是一种能高效实现插入、删除、查找的内存数据结构,这些操作期望复杂度都是O(logN)。

2.2 LSM树

LSM树(Log-Strucured Merge-Tree)本质上和B+树一样,是一种磁盘数据的索引结构。但和B+树不同的是,LSM树的索引对写入请求更友好。

LSM树的索引一般由两部分组成:

  • 内存部分:采用跳跃表来维护一个有序的KeyValue集合。
  • 磁盘部分:由多个内部KeyValue有序的文件组成。
2.2.1 KeyValue存储格式

一般来说,LSM中存储的是多个KeyValue组成的集合,每一个KeyValue一般都会用一个字节数组来表示。

HBase为例,其中,RowkeyFamilyQualifier(列族下的列)、TimestampType这5个字段组成KeyValue中的key部分(Key二进制内容,表示版本号64位long值,HBase中表现为timestamp,type三个必不可少)。Value部分直接存储这个KeyValue中Value的二进制内容。

其中type字段表示这个KeyValue操作的类型,这表明了LSM树内存储的不只是数据,而是每一次记录。

2.2.2 多路并归

类似归并排序算法一样,来合并多个有序文件成一个大文件。

2.2.3 LSM树的索引结构

分为内存部分和磁盘部分,本质是将写入操作全部转化成磁盘的顺序写入,极大地提高了写入操作的性能。但是对读取操作不友好,因为需要在读取的过程中,通过归并所有文件来读取所对应的KV,非常耗资源。因此HBase中设计了异步compaction来降低文件个数。

2.3布隆过滤器

场景

用来判断一个元素是否存在于一个集合中(当集合很大很大远远超出内存的时候)。

原理

布隆过滤器由一个长度为N的01数组组成。一开始全部初始化为0,然后对集合A中的每个元素进行K次Hash并对长度取模后获得K个下标索引,然后把这些下标对应的数组元素置为1。

现在需要判断w是否存在于集合A中,只要把w用上述方法一样K次Hash,每次的结果去数组里面查找,只要有一个值为0就说明这个元素不存在。如果全部为1,只能说明可能存在(假设x经过3次hash后,下标为1、2、6;y为3、4、5,这时候w的hash结果是1、2、3。虽然都是为1,但是属于2个元素)

N=K*|A|/ln2 ,使用这个公式可以保证最佳的误判率。N为数组长度,K为Hash次数,|A|为集合中元素个数。

HBase与布隆过滤器

在HBase 1.X中有3中类型:

  • NONE:不启用
  • ROW:按照rowkey来计算布隆过滤器的二进制串并存储。
  • ROWCOL:按照rowkey+family+qualifier这3个字段拼出byte[]来计算布隆过滤器值并存储。如果在查询的时候,get能指定这3个字段,那么布隆过滤器肯定能提高性能。但是如果缺少任何一个,则无法提升性能。

腾讯团队介绍了一种设计,他们游戏业务rowkey的设计:

rowkey=< userid>#< other-field>

即按照userid来做前缀扫描。(前缀固定,所以计算布隆过滤器的key值也就固定)

总结

布隆过滤器对Get和基于前缀扫描的Scan都非常友好。

三、HBase依赖服务

3.1 ZooKeeper

关于Zookeeper内容可以参考另一篇文章(ZooKeeper学习笔记)。现在来看一下HBase在ZK上创建的内容:

[zk: localhost:2181(CONNECTED) 1] ls /hbase
[meta-region-server, rs, splitWAL, backup-masters, flush-table-proc, master-maintenance, online-snapshot, switch, master, running, draining, namespace, hbaseid, table]
  • meta-region-server:存储HBase集群元数据hbase:meta元数据表所在的RegionServer访问地址。
  • master/backup-masters:主/备管理节点,防止单点故障。
  • table:集群中所有表信息。
  • splitWAL:分布式故障恢复。
  • rs:集群中所有运行的RegionServer。
  • 等等。。。

3.2 HDFS

HDFS读写流程,具体详情参考文章(Hadoop学习笔记(二)HDFS)。

HDFS在HBase中扮演的角色

  • HBase本身不存储文件,它只规定文件格式以及文件内容,实际文存储件由HDFS实现。
  • HBase不提供机制保证存储数据高可靠性,数据的高可靠性由HDFS多副本保证。

3.3 HBase在HDFS中的文件布局

drwxr-xr-x   - hadoop supergroup          0 2020-05-29 02:05 /hbase/.hbck
drwxr-xr-x   - hadoop supergroup          0 2020-05-29 04:01 /hbase/.tmp
drwxr-xr-x   - hadoop supergroup          0 2020-06-18 21:15 /hbase/MasterProcWALs
drwxr-xr-x   - hadoop supergroup          0 2020-05-29 04:01 /hbase/WALs
drwxr-xr-x   - hadoop supergroup          0 2020-06-03 17:31 /hbase/archive
drwxr-xr-x   - hadoop supergroup          0 2020-05-29 02:05 /hbase/corrupt
drwxr-xr-x   - hadoop supergroup          0 2020-05-29 02:05 /hbase/data
-rw-r--r--   3 hadoop supergroup         42 2020-05-29 02:05 /hbase/hbase.id
-rw-r--r--   3 hadoop supergroup          7 2020-05-29 02:05 /hbase/hbase.version
drwxr-xr-x   - hadoop supergroup          0 2020-05-29 02:05 /hbase/mobdir
drwxr-xr-x   - hadoop supergroup          0 2020-06-18 21:15 /hbase/oldWALs
drwx--x--x   - hadoop supergroup          0 2020-05-29 02:05 /hbase/staging

四、HBase客户端

4.1 客户端与服务端交互流程

  1. 获取Configuration对象

    一般需要3个配置文件:hbase-size.xml、core-site.xml、hdfs-site.xml放到JVM可以加载到的地方

    Configuration conf = HBaseConfiguration.create();
    
  2. 通过Configuration初始化Connection

    Connection是HBase客户端一切操作的基础,维持了客户端到整个HBase集群的连接。

    例如,集群里有2个Master、5个RegionServer。那么Connection会维持一个到Active Master的TCP和5个到RegionServer的TCP。

    通常,一个进程只需要为一个独立的集群建立一个Connection即可,并不需要连接池

    Connection conn = ConnectionFactory.createConnection(conf);
    
  3. 通过Connection初始化Table

    Table是一个非常轻量级的对象,实现了用户访问表的所有API操作,如:Put、Get、Delete、Scan等。本质上,它使用的连接资源、配置信息、线程池、Meta缓存等,都来自Connection对象,因此由同一个Connection创建的多个Table,都可以共享上述这些资源。

    注意:branch-1以及之前版本,Table不是线程安全的类,不建议共享一个Table实例。但是,HBase2.0.0之后的版本,Table已经实现为线程安全类。可以通过同一个Connection为每个请求创建一个Table,但是要记得关闭Table对象。

    TableName tableName = TableName.valueOf("ns1:t1");
    Table table = conn.getTable(tableName);
    
  4. 通过Table执行Put和Scan操作

    put(这里注意到参数都是byte[]):

    // 通过bytes工具类创建字节数组(将字符串)
    byte[] rowId = Bytes.toBytes("row3");
    // 创建put对象
    Put put = new Put(rowId);
    byte[] f1 = Bytes.toBytes("f1");
    byte[] id = Bytes.toBytes("id");
    byte[] value = Bytes.toBytes(102);
    put.addColumn(f1, id, value);
    // 执行插入
    table.put(put);
    

    scan:

    Configuration conf = HBaseConfiguration.create();
    try (Connection connection = ConnectionFactory.createConnection(conf)) {
         
        try (Table table = connection.getTable(TableName.valueOf("ns1:t1"))) {
         
            // scan设置
            Scan scan = new Scan();
            
            try (ResultScanner scanner = table.getScanner(scan)) {
         
                // 每次scanner.next()返回一个结果
                for (Result result : scanner) {
         
                    // 这里可以看出每一个result中的cell都是相同的rowKey
                    final String rowKey = Bytes.toString(result.getRow());
                    System.out.println(rowKey);
                    // 1个result结果包含N个cells
                    for (Cell cell : result.listCells()) {
         
                        System.out.print("[" +
                                         Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()) + ":" +
                                         Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()) + "]" + "\t"
                                        );
                    }
                    System.out.println("------------------------------------------");
                
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值