HBase基础知识(个人总结)

    声明: 1. 本文为我的个人复习总结, 并那种从零基础开始普及知识 内容详细全面, 言辞官方的文章
              2. 由于是个人总结, 所以用最精简的话语来写文章
              3. 若有错误不当之处, 请指出

基础知识:

数据种类:

  1. 结构化数据 比如MySQL这种关心型数据库里的数据, 操控起来方便
  2. 半结构化数据 有特定语法格式的数据, 比如json
  3. 非结构化数据 视频,音频,文本 这种难以处理的数据

关系型数据库 & 非关系型(NoSQL)数据库:

  1. 数据类型不同: 关系型数据库的数据类型是二维表格, NoSQL数据库的数据类型没有确定形式, 很灵活, 有KV型, 列式, 文档型等等
  2. 关系型数据库支持SQL语法, 而NoSQL数据库不支持SQL语法

行式数据库 & 列式数据库

  1. 存储方式不同:

    比如有A列和B列, 数据有A1, A2, A3, B1, B2, B3

    行式存储为: [A1, B1, A2, B2, A3, B3]; 列式存储为: [A1, A2, A3, B1, B2, B3]

  2. 擅长领域不同: 行式数据库适用于查询, 列式数据库适用于聚合统计

    从存储方式上可以看出, 行式存储的某一行的不同列之间紧挨着, 适合查询一整行数据;

    ​ 列式存储的某一列的不同行之间紧挨着, 适合查询一整列的数据

    而大数据场景, 大多数时都是数据的统计。我们经常只是需要其中某一列进行聚合统计,而不关心其他列的数据

  3. 压缩效果不同, 列式存储压缩效果更好

OLTP & OLAP

OLTP: 联机事务处理, 一般是那种 后端的关系型数据库(存储数据少, 行式数据库MySQL等)

OLAP: 联机事务分析, 一般是那种 大数据的NoSQL数据库(存储数据多, 列式数据库如HBase/ClickHouse, Presto)

架构:

有RowKey, 列族, 列, Region, StoreFile(HFile), Cell, 命名空间, 表

增改为Put, 删除为Delete(本质也是Put), 关键字段timestap就代表着版本

结构图:

在这里插入图片描述

  • 一个Region是多行相邻数据, 按列族(对应StoreFile)存储,

自带的命名空间:

  1. hbase 存放的是HBase内置的表
  2. default 表是用户默认使用的命名空间
  • HBase定义表时只需要声明列族即可, 不需要声明具体的列, 字段可以动态、按需指定。因此适合应对字段变更的场景。

  • BlockCache是用来优化读操作的缓存, MemCache是为了优化写操作的缓冲(到刷写时机了批量写到磁盘)

WAL预写日志:

  1. HBase的WAL只是为了备份数据, flush和compact的时候并不用它(flush用的是内存数据, compact用的是HFile)

  2. Hadoop的EditLog除了是用来备份数据, 与FsImage合并时也要用到它

  • hbase truncate不要乱用, 它会同时删除元数据信息如分区键规则, 协处理器倒是不会删掉

LSM:

HBase和ClickHouse这种内存+磁盘的架构, 即用的是LSM结构(日志结构的合并树)

思想: 假定内存足够大,因此不需要每次有数据更新就必须将数据写入到磁盘中,而可以先将最新的数据驻留在内存中;

​ 等到积攒到足够多之后,再归并排序将数据合并追加到磁盘

与B+树相比:

  1. 牺牲读性能(读取时可能需要访问较多的磁盘文件)
  2. 提高写性能(刷写落盘前有一个内存缓冲区)

补偿读性能的优化:

  1. Bloom Filter 读HFile时使用布隆过滤器
  2. compact 小树合并为大树

架构角色:

  1. HMaster

    负责DDL操作: 对于表结构 create, delete, alter

    负责管理调度: 分配regions到每个RegionServer(并做负载均衡和故障转移)

    ​ 监控每个RegionServer的状态

  2. HRegion Server

    管理Region, WAL, 负责table数据的实际读写, 执行Flush 和 Compaction

  3. ZooKeeper

    • HBase通过ZooKeeper来做Master的高可用

    • 监控RegionServer

    • Client请求ZooKeeper meta表位于哪个RegionServer

  4. HDFS

读流程:

在这里插入图片描述

  1. Client先访问ZooKeeper,获取hbase:meta表位于哪个Region Server

  2. 访问对应的Region Server,获取hbase:meta表,

    根据namespace:table:rowkey,查询出目标数据位于哪个Region Server中的哪个Region

​ 并将该表的 Region信息&meta表的位置信息 缓存在客户端的meta cache

  1. 与目标Region Server进行通讯
  2. 先在MemStore中查询目标数据,
  3. 再去Block Cache中查询目标数据,如果找不到的话再去查询Store File(HFile)
  4. 将查询到的新的数据块(HFile的数据存储单元, 默认大小为64KB)缓存到Block Cache
  5. 返回这两次查到的 最新版本的数据

写流程:

在这里插入图片描述

1)Client先访问ZooKeeper,获取hbase:meta表位于哪个Region Server

2)访问对应的Region Server,获取hbase:meta表,

​ 根据namespace:table:rowkey, 查询出目标数据所在表位于哪个Region

​ 并将该表的 Region信息&meta表的位置信息 缓存在客户端的meta cache

3)与目标Region Server进行通讯

4)将数据顺序写入(追加)到HLog(WAL), 做备份

5)将数据写入对应的MemStore,数据会按RowKey在MemStore进行排序, 便于以后的查找缩小范围

6)Region Server向客户端发送ack

7)等达到MemStore的刷写时机后,将数据刷写到HFile

MemStore Flush刷写时机:

  1. 某个MemStore的大小达到了hbase.hregion.memstore.flush.size(默认128M)


    • 什么时候阻止继续往某个MemStore写数据?

      当MemStore的大小达到了hbase.hregion.memstore.flush.size(默认125M) * hbase.hregion.memstore.block.multiplier(默认4), 即500M时

  2. 某个RegionServer中所有MemStore的总大小达到

    堆内存大小 * hbase.regionserver.global.memstore.size(默认0.4)

    * hbase.regionserver.global.memstore.size.lower.limit(默认0.95), 即0.38倍堆大小时

    则按照所有MemStore由大到小的顺序依次进行刷写, 直到所有memstore的总大小减小到低于上述临界值

    这种情况下可见, HFile里的数据timestap未必是最小的, 那查数据时, 即便MemStore中找到了该数据也仍要去访问HFile文件(但会借助于布隆过滤器), 因为timestap大的才是最新数据


    • 什么时候阻止继续往所有MemStore写数据?

      当某个RegionServer中MemStore的总大小达到

      堆内存大小 * hbase.regionserver.global.memstore.size(默认值0.4), 即0.4倍堆大小时

  3. 到达自动刷写的时 hbase.regionserver.optionalcacheflushinterval(默认1小时)

  4. 当WAL文件的数量超过hbase.regionserver.max.logs,会按照timestap从小到大顺序依次进行刷写, 直到WAL文件数量减小到低于上述临界值(该属性名已废弃, 现无需手动设置,最大为32)

读写特点:

HBase的读写类似, 即便是写(增删改)数据也要先查找数据所在表位于哪个RegionServer中的哪个Region

而HDFS的写, 既然是写(增加)数据, 就不会提前位于DataNode中

StoreFile Compaction:

StoreFile底层是HFile

是为了减少HFile的个数,以及清理掉 过期和删除 的老数据

  1. Minor Compaction

    临近的若干个较小的HFile合并成一个较大的HFile, 并清理掉 过期和删除 的数据

  2. Major Compaction

    一个Store下的所有的HFile合并成一个大HFile, 并清理掉 过期和删除 的数据

Region Split:

起初表只有一个Region(如果不自己预分区的话),

为了更好的负载均衡 以及增加存储利用率,HMaster有可能会将某个Region转移给其他的Region Server

切分规则:

0.94版本之后, 2.0版本之前:

​ 阈值为min(R^3 * initialSize,hbase.hregion.max.filesize"), 即min(R^3 * 256M, 10G)

​ R为当前Region Server中属于该表的Region个数

​ 示例:

第一次split:1^3 * 256 = 256MB

第二次split:2^3 * 256 = 2048MB

第三次split:3^3 * 256 = 6912MB

第四次split:4^3 * 256 = 16384M > 10GB,因此取较小的值10GB

后面每次split的size都是10GB了

2.0版本新策略:

  1. 如果当前RegionServer上该表只有1个Region,则按照2 * hbase.hregion.memstore.flush.size切分,

  2. 否则按照hbase.hregion.max.filesize切分。

预分区:

目的: 自定义分区后, 根据数据的RowKey可以迅速得知它属于哪一个Region

比如按 100,200,300分区键 去预分区, 则有(-∞, 100], (100,200], (200,300],(300,+∞) 这4个分区,

一条数据是拿Rowkey和分区键 按照字典序比较的

设定预分区的方法:

  1. 手动设定预分区

    create ‘staff1’,‘info’,‘partition1’,SPLITS => [‘100’,‘200’,‘300’]

  2. 生成16进制序列预分区(0-15, 16个分区键)

    create ‘staff2’,‘info’,‘partition2’,{NUMREGIONS => 15, SPLITALGO => ‘HexStringSplit’}

  3. 按照文件中设置的规则预分区(常用):

    vim splits.txt

    aaaa

    bbbb

    cccc

    dddd

    create ‘staff3’,‘partition3’,SPLITS_FILE => ‘splits.txt’

  4. 使用JavaAPI创建预分区

    //自定义算法,产生一系列Hash散列值存储在二维数组中, byte[]相当于String, bytre[][]相当于String[]
    byte[][] splitKeys = 某个散列值函数
    //创建HbaseAdmin实例
    HBaseAdmin hAdmin = new HBaseAdmin(HbaseConfiguration.create( ));
    //创建HTableDescriptor实例
    HTableDescriptor tableDesc = new HTableDescriptor(tableName);
    //通过HTableDescriptor实例和散列值二维数组创建带有预分区的Hbase表
    hAdmin.createTable(tableDesc, splitKeys);
    

RowKey设计:

目的: 让数据均匀的分布, 防止数据倾斜

_小于所有数字

| 是大于很多字符, 只小于}

设计原则:

  1. rowkey长度原则

  2. rowkey散列原则

  3. rowkey唯一原则

方案:

  1. 生成随机数、hash、加密

    例如原本rowKey为1001的,SHA1后变成:dd01903921ea24941c26a48f2cec24e0bb0e8cc7

  2. 日期时间反转(个位变化频率低, 高位变化频率低, 所以原数据分布有规律会数据密集, 而反转后就没规律了)

    20170524000001转成10000042507102

    20170524000002转成20000042507102

  3. 随机字符串拼接

    20170524000001_a12e

    20170524000001_93i7

高可用:

vim conf/backup-masters, 里面写上备机ip

内存优化:

不建议分配非常大的堆内存, 一般配16~36G

因为:

  1. 在(0.4-0.38)*堆大小 这段内存回收时, RegionServer是禁止写数据的, 堆内存过大会增大其值, 导致增加了禁止写数据的时间

  2. Linux系统运行和其他软件运行也需要内存, 不能全分给HBase了

参数优化

  1. ZooKeeper会话超时时间
    ZooKeeper.session.timeout 默认值为90000毫秒(90s)。当某个RegionServer挂掉了, 90s之后Master才能察觉到。

    可适当减小此值,以加快Master响应,可调整至600000毫秒。

  2. 设置RPC监听数量
    hbase.regionserver.handler.count 默认值为30

    可以根据客户端的请求数进行调整,读写请求较多时,增加此值。

  3. 手动控制Major Compaction的周期

    hbase.hregion.majorcompaction 默认值:604800000秒(7天)

    若关闭自动Major Compaction,可将其设为0

  4. 优化HFile大小
    hbase.hregion.max.filesize 默认值10737418240(10GB), 如果一个HFile(列族)的大小达到这个数值, 则这个Region就会被切分为两个Region

    如果要运行HBase的MR任务, 可以减小此值

    因为一个Region对应一个MapTask,如果单个Region过大,会导致MapTask执行时间过长。

  5. 优化HBase客户端缓存大小
    hbase.client.write.buffer 默认值2097152bytes(2M)

    增大该值可以减少RPC调用次数

  6. 指定scan.next扫描HBase所获取的行数
    hbase.client.scanner.caching

  7. BlockCache占用RegionServer堆内存的比例
    hfile.block.cache.size 默认0.4

    读请求比较多的情况下, 可适当调大

  8. MemStore占用RegionServer堆内存的比例
    hbase.regionserver.global.memstore.size 默认0.4

    写请求较多的情况下,可适当调大

  9. 优化数据的写入效率, 开启压缩

    mapreduce.map.output.compress 设为true

    mapreduce.map.output.compress.codec 指定压缩方式

Hive对比HBase:

速度上:

  • Hive 查询 和 增加数据 速度缓慢, 因为要走MR等引擎
  • HBase 查询 和 增加数据 快, 因为布隆过滤器 & BlockCache & 顺序写操作(按timestap判断是否为最新有效数据) 进行优化

增删改方面:

  • 只允许增加数据
  • 虽然也是只允许增加数据, 但是通过timestap字段, 可以实现增删改的功能

是否为数据库:

  • Hive本质上并不是数据库, 而是将MySQL表的元数据 和 HDFS文件进行映射, 形成了逻辑上的数据库
  • HBase是列式数据库

数据分析方面:

  • Hive擅长做数据分析

  • HBase不擅长做数据分析

    相同点:都依赖于HDFS进行存数据, 可以用SQL语句去查数据

Hive集成HBase:

目的: 建立Hive表关联HBase表,插入数据到Hive表的同时能够影响HBase表

注意: 不能将数据直接load进Hive(这只会校验存储格式, 合法的法直接剪切, 让HBase感知不到)

步骤: 创建表&关联 --> 创建临时表 --> load进临时表 --> insert into 原表 select 字段 from 临时表

在hive-site.xml里配置ZooKeeper

    <property>
        <name>hive.ZooKeeper.quorum</name>
        <value>hadoop102,hadoop103,hadoop104</value>
    </property>
    <property>
        <name>hive.ZooKeeper.client.port</name>
        <value>2181</value>
    </property>

建表时通过描述语句进行关联:

CREATE TABLE hive_hbase_emp_table(
empno int,
ename string,
job string,
)
-- 描述语句
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":id, info:ename, info:job")
TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");

Phoenix:

是HBase的SQL皮肤

坑: 注意大小写, 在引号内部才能保持原样, 否则就任务是大写

(一级)索引是对RowKey的索引

二级索引是对非RowKey字段的索引, 先找到这个普通字段数据对应的主键, 再通过主键去查找实际数据

全局 & 本地: (优缺点没搞懂)

  1. 全局二级索引(默认), 适用于读多写少, 索引 和 数据 不存储在一起

    优点: 读数据时 会优先选择索引表来查询

    缺点: 写操作时 要更新的索引可能位于不同机器, 加大了网络IO 和 磁盘寻址IO 的损耗, 更占用空间

  2. 本地二级索引, 适用于写多读少, 索引 和 数据 存放在同一个Region中(且是同一个),

    优点: 写操作时 要更新的索引位于同台机器, 减少了网络IO 和 磁盘寻址IO(实际数据在附近, 顺序寻址较快) 的额外开销, 更节省空间

    缺点: 无法提前确定数据在哪个Region上

面试题:

  • HBase的批量加载 底层是靠MapReduce实现的

  • 协处理器(CoProcessor)

    分为:

    1. Observer: 相当于MySQL的触发器, 监听到一个表变化后 便自动地去同步操作另一个表 (如 偶像表 和 粉丝表 需要同步变化)
    2. Endpoint: 类似于MySQL地存储过程, 一般用于分布式聚合计算

    建立二级索引, 需要同步索引表, 靠的就是Observer协处理器

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值