写点什么

17 道题你能秒我?我 Hbase 八股文反手就甩你一脸

用户头像
王知无
关注
发布于: 4 小时前
17道题你能秒我?我Hbase八股文反手就甩你一脸

技术背景

起源于谷歌旧三篇论文中 bigtable。

设计目的

为了解决大数据环境中海量结构化数据的实时读写问题。为了弥补 hadoop 生态中没有实时存储的缺陷。

设计思想

分布式

技术本质

  • 概念:分布式列存储 nosql 数据库

  • 解释:

列存储:底层数据文件存储格式是列式存储

nosql:非关系型,可以存储结构化和半结构化数据

数据库:符合数据库的特征

核心特性

大表: 为存储海量数据而生,亿级别的行和百万级别的列

分布式:

1.分布式内存:为实现实时读写,将数据放在内存中

2.分布式外存:内存中放置不了的数据,刷写到 hdfs 上

多版本:一个列簇允许设置版本数,即允许一个数值存储多个版本,通过"ns:tb cf:c ts"唯一缺点一条数据

nosql:

1.RDBMS:关系型数据库,例如"mysql,oracle,postgresql,sqlserver"

2.nosql:非关系型数据库,例如"hbase,redis,mongodb"

随机实时读写

1.数据优先存储在内存中,命中率高数据

2.命中率中等的数据,存在缓存中

3.命中率低的数据,存在 hdfs 上

依赖于hdfs:将海量的数据存到hdfs上,即保证了数据了安全性,又保证了数据的持久化不支持join操作,只支持行级事务,复杂join操作需要集成hive只支持字节数组类型稀疏:对于空null的列,并不占用存储空间,因此表的设计可以非常稀疏
复制代码

集群角色

物理架构

client

种类:

  • bin/hbase shell:不支持 sql 语句,可以使用 help 'command',exit,

  • java api:

hue:hbase 实现了 ThriftServer 服务端,用于提供 hue 客户端连接,thriftserver 来实现整个过程的访问以及执行

sql on hbase:底层使用的 mapreduce 操作 hbase

zookeeper

概念:hbase 中的 zk 被称为真·主节点

职责:

  • 辅助集群的主节点选取,实现 HA 机制

  • 为集群的访问提供入口,存贮所有 Region 的寻址入口

  • 负责存储 hbase 中几乎所有的元数据,如节点信息,master 的主备节点,regionserver 的节点,表的状态

  • 负责实现系统容错,若发现 regionserver 注册节点消失,即认为此 regionserver 故障,需要通知 hmaster 启动恢复程序

  • 负责存储 meta 表的 region[rootregion]所在的 regionserver 地址

  • 负责 flush,splitWAL 的状态等

  • 存储 Hbase 的 schema,包括有哪些 table,每个 table 有哪些 column family

内容:

每一个节点都会在 zookeeper 上去注册

zookeeper 存储了 meta 表的 region 信息,客户端通过访问 zookeeper 才能请求集群


hdfs:

职责:存储 hfile,wal


Hmaster:

概念:辅助主节点

职责:

  • 负责管理所有从节点信息,

  • 负责 region 在 regionserver 上的分配,实现 regionserver 的负载均衡,

  • 负责 region 的数据迁移,例如分裂场景

  • 负责 meta 表以及元数据的修改,meta 表不等于元数据,可将 meta 表看做元数据的一部分,meta 表只是存储 region 的信息,而元数据包括 regionserver,region,表,namespace 等信息

  • 负责接收客户端的 DDL 请求,用于更改元数据,修改 zookeeper 中的存储

  • 通过 zookeeper 监听每个 regionserver 的状态,如果 regionserver 故障,就会启动恢复 regionserver 的进程

  • 发现失效的 region server 并重新分配其上的 region

  • HDFS 上的垃圾文件回收

  • 处理 schema 更新请求


RegionServer:

职责:

  • 负责接收并处理所有客户端的数据的读写请求

  • 负责管理该节点上所有的 region,处理对这些 region 的 IO 请求

  • 负责记录 WAL

  • 负责读缓存:memcache,占堆内存 40%,并刷新缓存到 HDFS

  • 执行压缩

  • 负责处理 Region 分片

补充:

  • regionserver 就是从节点,有多台

  • 一台 regionserver 中管理很多个不同的表分区【region】

  • meta 表中的数据也存在 regionserver 中


Hlog:

概念:预写日志,类似于 hdfs 上的 edits 文件,也类似于 mysql 中的 binlog 文件。

补充:

每个 Region Server 维护一个 Hlog,而不是每个 Region 一个。这样不同 region(来自不同 table)的日志会混在一起,这样做的目的是不断追加单个文件相对于同时写多个文件而言,可以减少磁盘寻址次数,因此可以提高对 table 的写性能。带来的麻烦是,如果一台 region server 下线,为了恢复其上的 region,需要将 regionserver 上的 log 进行拆分,然后分发到其它 region server 上进行恢复,HLog 文件就是一个普通的 Hadoop Sequence File。


Region:

概念:

regionserver 中的数据存储单元,不是 region 级别的

补充:

  • 一张表将数据按照 rowkey 的范围来划分到多个 region 中,以此来散列表的数据,

  • 默认情况下创建的表只有一个 region

  • 同一张表的不同 region 的范围总和是从负无穷到正无穷

  • 一个 region 只会被一台 regionserver 管理

  • region 是整个 hbase 中最小的负载均衡单元,是实现分布式的基本

  • region 的分配不均衡会导致数据倾斜及热点问题

  • 用户读写时,会根据 rowkey 进行判断,从哪个分区读取,从哪个分区写入

  • 每一个分区是一个目录

  • store 个数/2 = region 个数


Store

意义:设计列簇时将具有相同 IO 属性的列放在同一个列簇里,因为底层存储是一个列簇存储独占一个 store;放在一个 storefile 中,可以提供快速的读写操作

概念:

region 是表的划分,store 是列簇的划分,机器内存 * 40% /128M=store 个数


MemStore

功能:

补充:

属于 Store 中的内存存储区域。每个 store 中都有一个 memstore,用于存储刚写入的数据。写内存,占堆内存的 40%,


StoreFile /HFile

功能:

解释:

1.memstore 满足条件会进行 flush,刷写出来的数据文件就是 storefile,存储在 hdfs 上被称为 hfile 2.一个 store 中会有多个 storefile 文件,但最终会优化合并成一个文件【二进制文件】 3.storefile 是 hfile 的封装,也可认为是同一个文件,不同的称呼

补充:

HFile 分为六个部分:

1.Data Block 段–保存表中的数据,这部分可以被压缩

2.Meta Block 段(可选的)–保存用户自定义的 kv 对,可以被压缩。

3.File Info 段–Hfile 的元信息,不被压缩,用户也可以在这一部分添加自己的元信息。

4.Data Block Index 段–Data Block 的索引。每条索引的 key 是被索引的 block 的第一条记录的 key。

5.Meta Block Index 段(可选的)–Meta Block 的索引。

6.Trailer–这一段是定长的。保存了每一段的偏移量

逻辑存储

NameSpace

名称空间,物理存在。默认创建时就已经存在两个名称空间 default 和 hbase。属于表的一部分,用于区分表的存储,每个表必定有自己是名称空间,若不指定,默认属于 default


Table

表,访问时通过 namespace:table_name 来访问这张表,不加默认访问是 default 下的表


Rowkey

行键,通过 rowkey 可以唯一指定一行的数据(注意不是一条),在创建表时就已经存在,不需要再次创建。

rowkey 的设计,影响了底层 region 的节点数据分配,会造成热点问题,影响读写性能。

rowkey 是整个 hbase 中的唯一索引,在 hbase 中不支持自定义索引,处理 rowkey 之外,没有别的索引,查找数据时,要么通过 rowkey 进行查找,要么全表扫描,区别于 mysql 中可以自定义索引。


ColumnFamily

列簇,列的分组,一个列簇下有多个列,每个列必然属于某个列簇,可通过列簇指定这一个列簇中所有列的版本号。一般将具有相同 io 属性的字段放入同一个列簇。创建表时必须指定至少一个列簇。一张表一般不建议超过两个列簇,一般在一到两个列簇,超过两个之后,hbase 的读写性能会降低。


Column

列,列标签,一个列簇下有多个列,一个列必属于某个列簇,两个列簇中的列个数不必相等。两个行同一列簇下运行有不同的列,即半结构化。通过 cf:c 唯一指定一列。


Value

值,每一列的值,hbase 底层没有数据类型,都是字节存储,允许存储多版本的值


Version

版本数,属于列簇的一个属性,默认版本为 1 个,可以配置多版本来存储多版本的数据 默认查询时,只显示每一列的最新的那个版本数据 如果每条存储数据超过版本数,旧的版本会被覆盖 设计多版本是为了存储,默认显示最新版本是为了读取


TimeStamp

时间戳,用来区分版本, version 版本数是一个设置,timestamp 是一个标识 默认值是数据插入的格林尼治时间 查询是需要指定时间戳才能唯一确定一条数据 每一列都有一个时间戳,同行同列簇同版本下的不同列的时间戳相同

列存储

概念:

区别于 rdbms 的行式存储格式,nosql 使用列式存储格式。

优点:

行式存储操作实时行级别的,列式存储操作是列级别的。所以粒度更细 行式存储一行中的列都是一样的(结构化),列式存储每一行中的列可以不一样(半结构化)。所以支持的数据格式更广泛,半结构化可以支持结构化数据,结构化数据不可以支持半结构化数据 性能更优化,读写速度更快

DDL

1. namespace    list_namespace    create_namespace    drop_namespace    describe_namespace    list_namespace_tables
2. ddl备注:只有管理员admin才能操作 list create:创建表时只需要给定表名和列簇名称,两种方式:配置列簇属性和不配置列簇属性 describe/desc drop:hbase中表是enable状态的话,不允许对表结构进行修改和删除,需要先disable禁用 disable enable
复制代码

DML

1.dml    put:hbase中没有更新和删除操作,所有的更新都是插入    scan:用于查询一行或多行,或全表扫描    get:用于查询某一行,就是某一个rowkey的数据    delete
复制代码

热点问题与数据倾斜


概念

热点问题:客户端的请求大量集中在某一个节点,导致该节点上的负载非常高,而其他节点负载过低的-


现象

数据倾斜:由于计算任务大量集中在某一个节点,导致该节点上的负载非常高,而其他节点负载过低的现象


区别

  • 热点问题:请求层面,热点问题可能会造成数据倾斜

  • 数据倾斜:计算层面,数据倾斜不一定由热点问题造成


原因

热点问题在很多场景中都会发生,在 hbase 中表现造成热点问题的原因是:

1.客户端大量请求的 rowkey 连续集中在某一个 region 上 2.表中只有一个分区,所有的请求都集中在这个 region 上


解决

1.需要设计好表的分区 region 范围,避免分区范围不均衡,通过分区范围解决

2.需要创建预分区,多分区,通过分区个数解决

预分区

背景:在创建表的时候,默认只有一个分区,此时容易操作服务端热点问题

概念:在创建表的时候,根据 rowkey 的分布来设计一张表刚开始就有多个分区,分区需要根据 rowkey 的前缀或者完整的 rowkey 来设计,因为 region 的分配就是根据 rowkey 来划分分区的


意义:

1.增加数据读写效率

2.负载均衡,防止数据倾斜

3.方便集群容灾调度 region

4.优化 Map 数量


方式:

1.指定分区范围 create 'ns1:t1', 'f1', SPLITS => ['10', '20', '30', '40']

2.适用于分区较多场景 指定规则文件 create 'ns1:t2', 'f1', SPLITS_FILE => '/export/datas/splits.txt'

3.通过 java API 来划分分区 admin.createTable(HtableDescriptor desc,byte splitKeys)


RowKey 的设计规则

原因:为什么 rowkey 设计至关重要?

  • 所有数据在存储时都是根据 rowkey 来读写对应分区的,即分区是根据 rowkey 来划分的。

  • rowkey 是 hbase 中的唯一索引。

  • rowkey 在查询时是前缀匹配的。

后果:rowkey 设计不好会产生什么后果?

  • 会造成热点问题

  • 会造成全表扫描


设计规则:

唯一原则:任何一个 rowkey,必须唯一标记一行,类似于主键的唯一性

散列原则:

构建 rowkey 的随机散列,不允许 rowkey 是连续的,避免热点问题。

若 rowkey 前缀是一个固定的字段,且会产生连续,如何解决呢?

  1. 编码,通过 md5/crc32 等方式来将固定字段进行编码然后作为 rowkey

  2. 反转,rowkey 是按照 ascii 码的字典顺序,固定字段反转之后,就不连续

  3. 随机数,将固定字段加随机数,不推荐,因为不便于维护

业务原则:根据业务维度来设计 rowkey,例如将经常作为查询条件的维度

组合原则:将各个业务维度组合来设计 rowkey

长度原则:一般 rowkey 的长度不要超过 100 个字节,可以使用十六进制或三十二进制压缩长度


JavaAPI

介绍:    1.hbase中 hbase shell 一般用来封装脚本,执行ddl操作,一般用来封装做ddl操作通过hbase shell  xxx.query指定,脚本操作结尾要加exit    2.javaapi则是实际使用场景,一般用来执行dml操作,和分布式框架使用,做中间件技术,提供程序访问hbase的接口
API方法: 1.HBaseConfiguration; 创建hbase的初始化对象 2.HBaseAdmin;hbase的管理员对象,需要进行ddl操作时需要的对象 1.tableExists 2.disableTable 3.deleteTable 4.deleteNamespace 5.listNamespaceDescriptors 3.HTableDescriptor;hbase的表描述对象 1.addFamily 2.createTable 3.getTableName 4.TableName;表名称对象 1.getNameAsString 5.HColumnDescriptor;hbase的列簇描述对象 1.setMaxVersions 2.setBlockCacheEnabled 3. 6.NamespaceDescriptor;hbase的名称空间描述对象 1.createNamespace 2.create 7.Get;get命令获取数据 8.Result;一个result代表一个rowkey的所有数据 1.rawCells 9.Cell;一个cell就是一列的数据 10.Table;表对象 1.get 2.put 3.delete 4.getScanner 11.Put; 1.addColumn 12.Delete; 1.addColumn 13.ResultScanner;result对象的集合
复制代码

读取

1.驱动类,封装了mr程序中的参数集合,调用方法TableMapReduceUtil.inittablemapper(输入和map的参数);2.mapper类,需要继承TableMapper类,默认input输入的key和value为ImmutableBytesWritable和Result
实现: 底层通过tableinpputformat实现;sqoop底层通过dbinputformat实现
<解释> 因为mr读取hbase数据,只是做了数据的读取,并不做数据的聚合,所有不需要reduce
复制代码

写入

1.驱动类,封装了mr程序中的参数集合,调用方法TableMapReduceUtil.inittablereduce(reduce和输出的参数);2.reducer类,需要继承TableReducer类,默认output输出的value为put对象
实现: 底层通过TableOutputFormat实现;sqoop底层通过dboutputformat实现
<解释> 需要在reduce类中构建put对象,用于存储数据,所以需要reduce
复制代码

Filter 过滤器

背景知识:

  • 在 hbase 中,所有数据在存储时按照 rowkey 的 ASCII 码表字典顺序进行排序的

  • 在 hbase 中,rowkey 的查询都是前缀匹配

  • rowkey 是 hbase 中的唯一索引,所有数据的读写要么通过 rowkey 查询,要么就是全表扫描

  • hbase 底层没有数据类型,数据全部都是按照字节数组存储,

  • 按照 keyvalue 对格式存储每一列数据,key=ns+tb+cf+c+ts,value=value

  • 一般搭配 scan 来使用

 shell过滤器种类:    1. TimestampsFilter,时间戳过滤器    2. QualifierFilter,列名过滤器,需要指定比较参数和比较值 QualifierFilter (>=, 'binary:xyz')    3. ROWPREFIXFILTER,rowkey前缀过滤器
javaapi过滤器种类: 第一类:比较过滤器;通过比较的工具类,来实现过滤,返回符合的rowkey所有的数据 1.RowFilter 2.FamilyFilter 3.QualifierFilter 4.ValueFilter 第二类:专有过滤器;用的比较多,封装好的方法来实现 1.prexfixFilter:rowkey前缀过滤器 2.singleColumnValueFilter/singleColumnValueExcludeFilter:单列值过滤器 3.MultipleColumnPrefixFilter:多列过滤器 4.pageFilter:分页过滤器,一般在工作中,必须指定对应的起始位置,一般搭配startrow来使用 第三类:组合过滤器,就是各种过滤器组合在一起,FilterList

如何使用过滤器: 1.shell中使用"{列属性}"指定,例如: {COLUMNS => ''};{STARTROW => '闭区间',STOPROW => '开区间'} {ROWPREFIXFILTER => '',FILTER => ''}
复制代码

Hbase:ns/Hbase:meta

"hbase:namespace"表,这张表会记录 hbase 中所有 namespace 的信息,当用户进行请求时,会读取这张表的信息来判断用户访问的 namespace 是否存在


"hbase:meta"表,hbase 表中的元数据表,meta 表中记录了:


meta 表中的 rowkey 包含了 regioninfo 和 server 两个部分,其中包含 regioninfo 的 rowkey,记录了 region 的名称,startkey 和 stopkey。包含 server 的 rowkey 记录了这个 region 所在的 regionserver 的地址和端口。


meta 表记录了除了自己之外所有的在 hbase 中的表的 region 的名称;其中“region 名称”的构成:表名称+region 的起始范围+region 的时间+region 的唯一 id。


补充:


1.数据读写请求,客户端如何找到对应的 region 的 region 的?


A:zk 记录了 meta 表的"region 信息","region 信息"包括 region 的名称,startkey 和 stopkey,还包含了这个 region 所在的节点地址和端口,通过这些去对应 regionserver 上找到的 meta 表的数据,然后 meta 表中记录了除了自己之外的 hbase 中所有表的"region 信息",这些"region 信息"也包括 region 的名称,startkey 和 stopkey,还包含了这个 region 所在的节点地址和端口。然后通过这些信息再去找到对应 regionserver 上的 region

Hbase 的存储原理

读写请求概述:

  • 客户端第一次请求时,本地没有记录 region 信息,先去请求 zk,获取 meta 表的 region 信息。

  • 然后再跟据 region 信息请求对应的 regionserver,获取 meta 表的数据,得到要查询表中 rowkey 对应的 region 信息。

  • 客户端再次跟据返回的表中 rowkey 对应的 region 信息去请求 regionserver 提交读写请求,并缓存本地请求的地址及 region 信息,供下次使用,直接请求 regionserver 获取表数据。

  • regionserver 跟据请求来操作 region,跟据列簇来判断读写哪个 store。


读请求:

请求会优先读取内存中数据,即 memstore,若数据没有在内存中,就读缓存,然后读 hdfs


写请求:

  • 请求会先写入内存 memstore 中,当 memstore 满足条件时,触发 flush 刷写,将 memstore 中的数据变成 storefile 文件

  • 通过 hbase 底层封装的 hdfs 客户端,将文件生成在以 hfile 的文件类型存储在 hdfs 上

Hbase 读写请求流程


写请求流程

  • 客户端提交一条写的命令,根据这个请求的 rowkey 来获取对应的 region 信息,来请求对应的 regionserver,以此来对 rowkey 进行操作

  • 将请求提交给对应的 regionserver,regionserver 根据请求写入的 region 的名称来操作

  • 根据请求中的列簇来判断要写入该 region 中的哪个 store

  • 将数据以 keyvalue 形式写入 memstore

  • memstore 达到一定条件以后,会触发 flush,内存中数据会写入 hdfs,

  • hdfs 中的 storefile 达到一定条件以后,会触发 compaction,将 storefile 文件归并排序进行合并

  • 当整个 region 的数据大小达到一定条件以后,会触发 split,一个 region 会分裂成两个 region,原来的 region 被销毁


读请求流程

  • 客户端请求 zk,从 zk 获取 meta 表的地址

  • 客户端读取 meta 表的数据,根据读命令中的表名来获取表所有的 reigon 信息,

  • 找到要读取的 region 以及对应的 regionserver 地址

  • 如果是 get 请求,指定了 rowkey,则返回这个 rowkey 对应的 region 信息

  • 如果是 scan 请求,则返回这张表对应的所有的 region 信息

  • 根据返回的 reigon 地址,请求对应的 regionserver,

  • regionserver 根据 region 名称来找到对应的 region,并进行读操作

  • 若请求中指定了列,则读取列簇对应的 store,若请求中没有指定列,则读取所有 store 的数据

  • 请求在读取 store 时,优先读取内存中的 store,即 memstore,若 memstore 中没有找到,若开启了缓存,则取 memcache 缓存中找,若没有开启缓存,则直接去 hdfs 上找 storefile,若 hdfs 上也没有,就是数据不存在,直接返回,若是 hdfs 上有,就将这条数据返回,若开启了缓存,还需要将数据添加到 memcache 中,方便下次使用

  • 查询内存: 有:返回 没有:缓存: 有:返回 没有:hdfs 有:返回并添加缓存 没有:返回


解释:

  1. 经实践分析,新写入的数据在请求访问是命中率最高,所以保存在内存中

  2. 根据 LRU 最近最少使用算法,将访问频率高的数据添加到缓存中,提高缓存访问的命中率

LSM-tree 模型

概念:Log-Struct-Merge 模型树,即 wal,flush,compaction,split 等过程;

功能:将随机无序的数据变成有序的数据,通过有序的算法来加快数据的读取,因为写入时需要进行排序,所有牺牲了一定的写入数据的效率,都用内存来实现数据的读写的存储


主要步骤:

  • 请求时现将数据保存到预写日志,然后写入内存

  • 在内存中对数据进行排序

  • 将内存中的数据写入文件,构成一个有序数据文件

  • 合并:将有序的多个数据文件进行合并生成一个新的有序的文件

  • 删除和更新:在模型设计中,本身并没有删除和更新,通过插入来模拟的,一般都是在文件合并时来进行实际的物理删除操作

WAL

  • 概念:预写日志, write-ahead-log

  • 职责:当产生写的请求后,写请求提交给 regionserver,regionserver 会将这个写的操作记录在 WAL 中,即 Hlog,然后再写入 memstore

  • 存储:将 WAL 存储在 hdfs 上,每台 regionserver 维护一份 WAL,

  • 场景:用于数据恢复,hfile 由 hdfs 恢复,memstore 由 WAL 恢复

补充:

  • oldwals:不再被需要的 Hlog 日志文件

Flush

  • 概念:刷写

  • 功能:数据在 memstore 中先做一次按 rowkey 的字典顺序排序,然后将 memstore 中的数据写入持久化到 hdfs 上,会生成一个有序的 storefile 文件

  • 场景:由于 memstore 是使用的内存,内存容量有限,为了提高新数据的命中率,需要将老的数据吸入 hdfs 进行安全存储

Compaction

  • 概念:合并

  • 功能:将 hdfs 上的多个 storefile 文件进行合并,构建统一的有序文件

  • 场景:为提供文件的快速读取,将多个 storefile 文件合并成一个整体有序的 storefile 文件,因为读取多个数据源没有读取一个数据源快

  • 过程:

  • minor compaction:将hdfs上早些生成的一些文件进行合并 major compaction:将所有的文件进行合并,合并的过程中会将标记为删除或过期的数据真正的删除

Split

  • 概念:分裂.

  • 功能:若一个 region 分区的数据过多,会分裂成两个 region.

  • 场景:一个分区的数据过多时,就会容易造成服务端引起的热点问题,无法实现分布式高性能,此时由 regionserver 将这一个分区均分为两个分区,由 master 重新将两个分区分配到 不同的 regionserver 中,分配成功后旧的 region 下线.

数据加载

概念:将数据导入到 hbase 中,有两种实现方式。

  • 使用 put 对象

例如:hbase shell,java api,mr 程序封装。缺点:数据流经过 WAL,然后经过内存,最后再到 hdfs 上,当导入海量数据是,容易导致 region 和 hdfs 的 io 过高,增加服务端负载,影响其他应用。

  • Bulkload

原理:hbase底层存储是hdfs上的hfile文件,然后通过meta表关联数据,所以可以先本地将数据转换为hfile文件,然后上传到hdfs上去,同时补充上meta表数据。
场景:适用于导入大量数据的批量hbase场景,要求稳定性能
缺点:
数据第一次读取时都是在hdfs上的,没有存在memstore中,所以第一次会变慢,但是如果数据量特别大的时候,两种方式最终的数据第一次读取都是在hdfs上的,所以没差别数据直接从传到hdfs上的,没经过WAL,所以当出现数据丢失,没办法恢复数据,需要重新再转换一次
复制代码

实现:

应用程序实现:

  1. 负责将普通文件转换成为 hfile 文件

  2. 负责将转换好的 hfile 文件加载到 hbase 表中

hbase 自带实现:

1.ImportTSV,是 hbase-server.jar 包中自带的一个命令,可以实现使用 put 方式将数据导入 hbase 表中,也实现了将普通文件转换成一个 hfile 文件的两种方式

2.completebulkload,上面的 importtsv 命令将普通文件转换成一个 hfile 文件,但是并没有加载到 hbase 表中,completebulkload 负责将 hfile 文件加载到 hbase 表中

<命令>:     1. yarn jar /export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-server-1.2.0-cdh5.14.0.jar         importtsv  -Dimporttsv.columns=a,b,c <tablename> <inputdir> -Dimporttsv.separator=','          -Dimporttsv.bulk.output=/bulkload/output2     2. yarn jar export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-server-1.2.0-cdh5.14.0.jar           completebulkload /bulkload/output2  mrhbase
<解释>: -Dimporttsv.columns 指定文件中列映射的列簇及列 Dimporttsv.columns=HBASE_ROW_KEY,info:name,info:age,info:sex mrhbase /bulkload/input -Dimporttsv.separator 指定读取文件中的列分隔符,默认以制表符分隔 -Dimporttsv.bulk.output 指定生成的HFILE文件所在的hdfs的位置
复制代码

SQL on Hbase


背景:

hbase 是 nosql 数据库,有自己的 api 实现,不支持 sql 语言,不利于开发和数据分析人员,sql on hbase 解决了这一场景,在 hbase 上使用 sql/jdbc 操作


原理:

  • 基于 java api/mapreduce 实现

  • 基于 hbase shell 实现

  • 搭桥通过 hdfs 实现


实现:

hive 集成 hbase:

原理:通过 hive 中的 hql 语句,底层转换为 mapreduce 操作,在 mapreduce 操作的同时,也用 mapreduce 操作 hbase 表 实现:在 hive 中创建一张与 hbase 关联的表,操作 hive 中关联表,实际上是对 hbase 在操作

phoenix 第三方工具:

原理:基于 hbase 构建了二级索引,直接调用 hbase 的 api 实现,因此在于 hbase 集成度和性能是最优选

sqoop 第三方工具:

原理:底层也是使用 mapreduce 程序导入数据,从关系型数据库中导入到 hdfs,然后使用 importtsv 命令和 completebulkload 命令来完成从 hdfs 上的导入,sqoop 可以导入,但是不能导出,因为半结构化数据支持结构化数据存储,结构化数据不支持半结构化数据存储


补充:

  • 若 hbase 表已经存在,hive 中只能创建外部表,使用 key 来表示 rowkey

  • 若 hbase 表不存在,默认以 hive 表的第一列作为 hbase 的 rowkey

  • hbase 与 hive 关联,hive 中的关联表加载数据时不能使用 load 加载,因为 load 命令底层没有使用 mapreduce,因为 load 命令是使用 hdfs 的 put 命令,只能用 insert 命令

二级索引

  • 概念:基于 rowkey 再构建一个索引,称为二级索引。

  • 意义:rowkey 是唯一索引,而且 rowkey 是前缀匹配,若我们不知道前缀,但知道 rowkey 部分字段,只能全部扫描吗?二级索引就是解决了 rowkey 唯一索引这个问题。

  • 解决:构建二级索引。

  • 方式:

  • 创建索引表,将原表中的查询条件作为索引表的rowkey,将原表中的rowkey作为索引表中的value; 查询是若不指定原表的前缀,就先根据查询条件去查询索引表,找到原表的rowkey,再根据获得的rowkey去查原表

协处理器

  • 背景:构建二级索引,因为索引表和原表是两张不同的表,如何保证两张表的数据同步?

  • 同步方式:手动进行两次插入,在插入原表的同时,也插入索引表

  • 缺点:性能较差,操作繁琐,请求数加倍,对服务器负载过高

  • 构建协处理器,构建类似于 mysql 中的触发器

  • 依靠第三方工具,让他们来实现二级索引:例如:solr,ES 构建索引类型丰富,可以实现自动同步,Phoenix 用 sql 构建索引

  • 概念:Coprocessor,协助开发者构建自定义的二级索引

  • 本质:自定义实现 hbase 提供对应接口的一段程序


分类:

  1. observer:观察者的协处理器,类似于监听功能,类似于触发器,一般用于二级索引同步 功能:监听原表,只看客户端往原表中插入一条数据,协处理器自动往索引表中插入一条数据

  2. endpoint:终端者协处理器,类似于存储过程,或 java 中达到一个方法,一般用来做分布式聚合统计 功能:监听一张表,这张表的每个 region 都会计算自己的 rowkey 个数,当客户端调用时,就会返回每个 region 的个数

  3. 补充:如何快速统计一张表的 rowkey 个数

  4. 通过编写 mapreduce 方法,最慢的最蠢的方式

  5. 使用 hbase 自带的 count 命令

  6. 开发 endpoint 协处理,最快最有效的方式

Hbase 优化

概念:hbase 优化可通过以下几个方面,flush,compaction,split 和列簇属性来实现

Flush

  • 意义:用于将 memstore 中的数据写入 HDFS,变成 storefile 文件,空出内存,用于存储新数据

  • 自动触发规则:

默认单个memstore的存储达到128M,就会触发。
默认整个region的memstore的数据达到128M * 4,就会触发。
默认整个regionserver中的memstore的使用率达到堆内存的40%,就会触发。
复制代码

缺点:

自动触发,会导致磁盘 IO 的负载过高,会影响业务,一般会关闭自动触发,根据实际情况定期的在业务比较少的时候,手动触发

手动触发:

关闭自动触发:将所有自动触发的条件调高,定期的在没有达到自动触发的条件之前通过 flush 命令手动触发

总结:

将自动触发条件调高,以此来关闭自动触发 flush,并在业务量较少时通过手动触发 flush,以此来达到优化目的

Compaction

  • 意义:用于实现将多个 storefile 文件,合并成一个 storefile 文件,变成一个整体有序的文件,加快读的效率

自动触发规则:

minor compaction:轻量级的合并,合并部分storefile成一个文件,smart算法,将最早生成的三个文件合并,不定期执行,占用IO比较小major compaction:重量级的合并,合并所有的storefile文件成一个文件默认七天会触发一次compaction
复制代码
  • 缺点:

    自动触发,会导致磁盘IO的负载过高,会影响业务,一般会关闭自动触发,根据实际情况定期的在业务比较少的时候,手动触发 手动触发: 关闭自动触发,通过major_compact命令来进行手动指定表合并或列合并

  • 总结:

关闭自动触发 major compaction,并在业务量较少时通过手动触发 major_compact

Split

  • 意义:将一个 region 分裂成两个 region,分摊 region 的负载

  • 自动触发规则:

    0.94版本之前规则:如果整个region的某个store的大小达到10GB,就会触发 0.94版本之后Math.min(getDesiredMaxFileSize(),initialSize * tableRegionsCount * tableRegionsCount * tableRegionsCount); 即若region个数在0~100之间,min(10g,256M * region个数的三次方)

  • 缺点:

自动触发,会导致磁盘IO的负载过高,会影响业务,一般会关闭自动触发,根据实际情况定期的在业务比较少的时候,手动触发手动触发:关闭自动触发:hbase.client.keyvalue.maxsize=100GB,不可能达到这个值,根据集群region的数据量,来定期手动触发
复制代码
  • 总结:

关闭自动触发,并在业务量较少时通过手动触发 split

列簇属性

  • BLOOMFILTER:布隆过滤器

用于在检索storefile文件时,根据索引判断该storefile文件中是否有想要的数据,若没有直接跳过。
级别:none 不开启。
row 判断是否有需要的rowkey,没有就跳过。
rowcol 判断是否有需要的rowkey和cf:c,没有就跳过。
复制代码
  • Versions:MaxVersions,最大版本数,该列族中的列最多允许存储多少个版本。

  • TTL:版本存活时间,从该版本的 timestamp 进行计算,一旦到达这个时间,就表示该数据过期,用户 hbase 自动清理数据。

  • MIN_VERSIONS:最小版本数,该列族中的数据当达到 TTL 时间以后,最小保留几个版本。

  • BLOCKCACHE:读缓存,是否将这个列簇的数据读到 memcache 缓存中,默认开启,建议将不经常读取的列簇关闭。

  • IN_MEMORY:代表 BLOCKCACHE 中的一种缓存的最高级别,默认是关闭的,IN_MEMORY 是最高级别的缓存,缓存会定期的进行 LRU 清理,缓存级别越低,优先会被清理,不要随便开启 IN_MEMORY,因为 meta 表就在 IN_MEMORY 级别的缓存中

  • BLOCKSIZE:storefile 文件块的大小,默认 64k,数据块越小,数据块越多,维护索引越多,内存占用越多,读快写慢,数据块越大,数据块越少,维护索引越少,内存占用越少,读慢写快

  • COMPRESSION:Hbase 中的压缩其实就是 hadoop 的压缩,本身就是压缩 storefile 的存储

Hbase 和 RDBMS 对比

Hbase

支持向外扩展使用API 和MapReduce 来访问HBase 表数据面向列,即每一列都是一个连续的单元数据总量不依赖具体某台机器,而取决于机器数量HBase 不支持ACID(Atomicity、Consistency、Isolation、Durability)适合结构化数据和非结构化数据一般都是分布式的HBase 不支持事务不支持Join
复制代码

rdbms

支持向上扩展使用SQL 查询面向行,即每一行都是一个连续单元数据总量依赖于服务器配置具有ACID 支持适合结构化数据传统关系型数据库一般都是中心化的支持事务支持Join
复制代码

Hbase 的增删改查

  • 功能:hbase 中实际没有更新和删除操作,hbase 中只有增加和查询操作;更新是将新数据插入内存,,删除是将数据逻辑删除,等后续合并时再做覆盖旧版本数据和物理删除数据

  • 意义:为了快速返回处理读写请求,数据只要写入就里面返回结果

  • get 与 scan 的区别:

get命令是hbase中最快的查询方式,因为指定了索引rowkey,但是只能查询一条数据。scan命令可以返回多条数据,一般结合过滤器使用。put和delete没有返回结果。
复制代码

hbase/hive/hdfs/rdbms 的区别


hbase

  • 概念:实时读写的数据库

  • 用途:存储数据

  • 场景:用于实现实现大量数据的实时读写文件,例如搜素引擎,一般用于高性能计算架构中,能存储半结构或结构化数据


hive

  • 概念:结构化数据仓库

  • 用途:存储数据

  • 场景:只能用于存储结构化数据,用来构建数据仓库的工具


hdfs

  • 概念:文件存储系统

  • 用途:存储数据

  • 场景:可以用于存储结构化,半结构化,非结构化的数据,适用于一次存入多次读取,例如网盘,用于做数据归档


rdbms

  • 概念:关系型数据库

  • 用途:存储数据


《硬刚Presto|Presto原理&调优&面试&实战全面升级版》

《硬刚Apache Iceberg | 技术调研&在各大公司的实践应用大总结》

《硬刚ClickHouse | 4万字长文ClickHouse基础&实践&调优全视角解析》

《硬刚数据仓库|SQL Boy的福音之数据仓库体系建模&实施&注意事项小总结》

《硬刚Hive | 4万字基础调优面试小总结》

标签体系下的用户画像建设小指南

《硬刚用户画像(二) | 基于大数据的用户画像构建小百科全书》


你好,我是王知无,一个大数据领域的硬核原创作者。

做过后端架构、数据中间件、数据平台 &架构、算法工程化。

专注大数据领域实时动态 &技术提升 &个人成长 &职场进阶,欢迎关注。


发布于: 4 小时前阅读数: 3
用户头像

王知无

关注

大数据成神之路作者,全网阅读超百万。 2019.01.20 加入

《大数据成神之路》作者,全网阅读超百万。公众号:《import_bigdata》,关注大数据领域最新动态。略微懂点大数据方面的知识。

评论

发布
暂无评论
17道题你能秒我?我Hbase八股文反手就甩你一脸