赞
踩
问题:
存储在HDFS上的一个大文件有100T,怎么在实时的要求下,快速找出对应的record
实时的增删改查 hbase 根据key 查找value 底层二进制编码 序列化和反序列化
主键 列簇1 列簇2 。。。
设计核心:跳表 + 布隆过滤器
HBase : 数据库 ,底层数据存储在HDFS
Hive只要支持 select 查询延迟很高 底层的执行引擎,其实就是一个分布式的计算引擎
hbase的最大特性就是解决根据key进行实时查询的需求,一般来说,不适合做关联查询
怎么解决大量数据集中的单条记录的实时增删改查?
1、第一,数据要排序, 二分查找
2、第二,因为数据集特别大,所以,需要分片。 分而治之
以上这两个特点结合起来,就是一个数据结构: 跳表
表的所有数据按照rowkey进行字典排序的。
如果按照rowkey进行查询,快速的定位到用户要查询的rowkey到底在最底层的那个小文件中,最后再去扫描这个小文件
配合使用布隆过滤器 怎么实现的?
提前在每一个小文件(region)设置好了一个布隆过滤器,那么根据布隆过滤器的特点。它能快速的判断,某个value是否在这个集合中。
优点:快速判断一个元素是否在这个集合(region)中
缺点:存在误判: 如果返回true,有可能是假的。 如果返回false,那么一定是不存在
布隆过滤器会占用额外的磁盘空间,底层数据文件,肯定不止1G
hbase的表结构:
1、表 和普通的mysql中的表的概念是一样的
2、rowkey 所有的数据,在进行查询的时候,一般来说,都是根据rowkey
但是也可以使用过滤器,去扫描整张表的数据
1、hbase的表数据的查询方式:
直接根据rowkey
根据rowkey的范围range
全表扫描
2、rowkey的长度限制问题
不能超过64KB, 最好在10-100byte之间 最好16,最好是8的倍数
3、列簇
一组key组成一个列簇: 具有相同IO特性
查询其中一个key1的时候一般来说,都会查询另外一个key2
所以说key1和key2具有相同的IO特性
经验推荐: 虽然说在部分场景中,有可能存储的数据,就具有多个不同的IO特性,应该要存储成为多个不同的列簇
但是根据经验来判断,最好使用一个列簇
4、列
真正的key-value中的key就是列
插入的key-value到底应该存储在哪个列簇中,是在插入的时候,一定要指定的
5、时间戳
作用:就相当于一个key_value中的value的多个版本的版本号
两种管理方式:
1、保存最近的最新的N个版本
2、保存一定时间范围内的所有数据, 如果某个版本数据超过时限要求,那么会被hbase的服务器自动删除的。
hbase的架构:
首先hbase集群有三种角色:
client
server : 主从架构
主节点:hmaster
从节点:hregionserver
hbase依赖于:
1、hdfs做数据存储
2、zookeeper做协调(解决SPOF, 存储寻址入口)
hmaster没有参与真正的数据的查询和插入的处理(主要用来管理hregionserver的状态,和所有的region的负载均衡)
单点故障的问题,但是不迫切
表示:hbase的主节点,可以在宕机了以后,整个hbase集群依然可以对外提供服务
当前hbase中的每个region都会增长。增长到10G的大小的时候就会进行分裂
分裂的标准:在hbase1.x以前,是256M
在hbase1.x开始,是10G
分裂出来的两个region一般来说,hregionserver会汇报给hmaster,hmaster一般来说,都会寻找
一个新的hregionserver来进行存储这分裂出来的两个region当中的一个
原始数据表raw:所有hbase表都会有多个region
.meta.:所有的这些region的映射信息都存储在第二级表中。映射信息过多,造成第二级表也会进行分裂,形成多个region
-root-:第二级表的多个region也被映射起来,存储在第一级表-root-中
最终的核心要点: -root-这个表中的数据量不管多大,都不会进行分裂
找到-root-这个表的那个唯一region在哪里,就能找到数据是哪些region
zookeeper给hbase存储寻址入口:
其实就是存储了-root-表的唯一region在哪个hregionserver中 但是会经常有迁移操作
hbase的寻址机制
region就是一张hbase表的逻辑抽象单位
一个region并不是一个单独的文件, 在HDFS上的目录树中体现为一个文件夹
regionserver:
1、一个regionserver中的所有region都是来自于一个表么? 不是的。
2、一个表的所有region都存储在一个表中么? 不是的。
所有表的所有region是进行负载均衡的处理之后存储在整个hbase集群
hbase的启动前提:
启动zk
启动hdfs
hdfs dfsadmin -safemode
hdfs haadmin -getServiceState nn1/nn2
HBase的shell操作:
1、进入客户端:hbase shell
2、查看当前hbase的shell命令有那些:help
3、通过查看帮助文档可以得知;
a、如果哪个命令不会使用: help "command"
b、如果不知道具体有那些组或者组中的命令的名称: help "command_group"
2、关于库
关于表(创建create,查看表列表list。查看表的详细信息desc,删除表drop,清空表truncate,修改表的定义alter)
关于数据的操作(增put,删delete,查get + scan, 改==变相的增加
drop == 清空数据truncate + 删除表定义
hbase的表一经创建之后。那么列簇的名字就不能更改了。
可以通过先删除列簇,然后添加回来,但是你必须要承受 损失这个列簇
修改:alter
get : rowkey
scan : 不用指定rowkey
hbase的java api操作:
HDFS当中的核心API :2 个
HBase当中的核心API :13个
HBaseConfiguration 配置信息
Connection
HBaseAdmin/Admin 管理员
HTable 整个表的抽象信息
HColumnDescriptor 列的描述信息
HTableDescriptor 列簇的描述信息
Put
Delete
Get
Scan
KeyValue
Cell
Result
ResultScanner
Filter
过滤器
分页操作
分享的面试的问题总结:
1、hbase的调优。 MR的调优, Hive的调优, Spark调优。
负载不均衡的问题/数据倾斜的问题
2、集群架构和节点数,数据量的问题
推导公式: 方便你们自己去模拟和构造数据量
30TB
每条记录的长度
总记录数
数据记录的总天数
3、数据仓库 Hive 数据仓库
hive的执行引擎:MR, Hive2推荐使用Spark
数据支撑:HDFS
也有可能来自于HBase Hive和HBase的整合
ZooKeeper
Hive的使用简单: 就是编写SQL
4、Spark中的一个面试题
跟kafka做整合的问题
Spark Streaming + kafka
消费数据有三种模式:
1、至少一次
2、最多一次
3、有且仅有一次 必须依赖 zookeeper
往hbase中插入数据的五种方式:
1、table.put(put)
2、table.put(puts)
3、MR
4、多线程多客户端并发写入
5、bulkload
其实是使用MR程序提前生成好HFile
最基本的数据插入:
1、首先往WAL Log中记录日志数据
2、把数据更新到内存
3、内存达到一定的阈值之后,就会flush数据到磁盘HFile
4、HfILE达到一定数量之后,就会进行合并。 StoreFile
hbase的底层原理:
1、hbase的各种核心概念(表)
key-value数据库(rowkey, hashmap)
一张四维表格
rowkey 行健(全局字典排序, 不能超过64KB, 最好10-100字节)
列簇 就是包含了一组具有相同IO特性的一组key
列 面向列,等同的任务是mysql表中的列
值 hbase表中的所有数据,都是按照字节数组存储
时间戳 控制hbase中的真正的key-valeu中的vlaue的版本的
get 'student','rk01','cf1:age',ts
2、hbase的组织架构
hbase的集群特点: 主从架构
1、hmaster 管理节点 主节点
2、hregionserver 工作节点 从节点
3、zookeeper 服务协调(选举master, 存储寻址入口:-root-这个表的那个唯一的region的唯一region在哪个regionserver)
4、hdfs 分布式的文件系统,用来给hbase做底层的数据存储支撑的。
/hbase126/data/default/user_info/846ce4c6701699c71bf4711a9a88e8d8/base_info/55378f109cbd4092bc59bd5b34c3afb7
55378f109cbd4092bc59bd5b34c3afb7: storefile hfile
5、mapreduce 非必须组件
6、client 给用户提供一个终端工具可以操作hbase(发送请求读写hbase库)
3、hbase的shell操作
hbase shell
help
help 'get' || help 'ddl'
4、api
con.getAdmin()
con.getTable()
Put Delete Get Scan
get : Result
Scan : ResultScanner
Cell 由 rowkey + cf + key + ts 唯一确定的一个格子 value KeyValue
分页过滤器
整合mapreduce : TableMapRedcueUtil (initTableMapperJob initTableReducerJob)
bulkload方式往hbase表中插入数据 (没有记录 HLog)
habse的底层原理:
在hbase的文件组织形式上,一定要记住:
一个集群会有多个regionserver
每一个regionserver就是用来去管理master分配给它的region
每一个regionserver中管理的所有的region是有可能来自于多个不同的table的
每一个regionserver中的所有region在进行数据插入的时候是会被记录日志的。
client:
存储了-root-这张表的那个唯一的region的所有数据会被缓存在当前这个resgionserver中的内存中
client会缓存第一次查询到的 -root- 这张表的那个唯一的region是存储在哪个regoinserver中的位置信息
client第一次请求,没有办法,只能通过请求zookeepr得到-root-的位置
client第N次请求的时候,直接从缓冲中保存的-root-的位置地址,直接请求即可
有可能会出现缓存失效, 再次重新请求zk即可
hbase的regionserver构造:
1、client发送的 put delete 其实在底层的数据文件中,都是 追加的形式
2、一个store就是就是一个region中的一个列簇
一个store由 一个memestore和多个storeFile(HFile)
为什么这么构造?
1、解决效率问题,如果都是在内存中进行查询和插入,效率高
2、解决安全问题,因为内存存在着掉电丢失数据的情况,数据存磁盘就不害怕数据的丢失
WAL
1、首先记录日志
2、然后更新请求数据到内存
3、当内存上涨到一定限制时,所以需要溢写数据到磁盘
4、溢出到磁盘的文件有可能会有很多,会进行合并
1、为了删除无效数据
2、为了保证全局有序
合并:
简单的说,就是把rowkey相同的所有KeyValue对象收集到一起,进行合并,按照key Type进行操作
首先判断是否有相同的key(行健,列簇,列,ts)对象,判断key type 同时也会判断事件戳
add delete ==== 最终抵消 delete add ===== 不会不出现
只有刚溢写出来的文件才会由 delete的keytype出现
hbase的数值组织形式:
1、表
2、region
3、store
4、hfile
5、data block ----> data
6、keyvalue
7、kv(rowkey, cf, qualifier, value, ts)
缓存淘汰算法:
FIFO
LRU least recently used
LFU : least frequently used
memcached redis
每一个列簇中的属性信息有很多。其中有一项叫做;
BloomFilter = Row
如果溢写出来一个HFile之后,触发了 compact 操作:
这个 compact 一定是 minor compact:
compact : 小合并 大合并
major_compact 和 minor_compact 的区别:
minor_compact 仅仅合并小文件(HFile) count(HFile) >= 3 就会触发 不会进行Put Delete数据的合并
清理的数据就是 设置了 TTL(time to live) 过期了的数据
major_compact 合并一个 region 内的所有文件
把所有的小文件都合并成一个大文件:StoreFile --- HDFS ---- HFile
小合并自动执行
大合并必须手动执行 -- 默认的配置是 --- 七天 ---- 一天
分裂 : 一个 region 一分为二
RS :
1、管理 master 分配给它的 region
2、管理 region的 分裂
3、管理 region 中的 storefile的合并
4、其实每一个regionserver都是一个 HDFS 客户端
RS 上线 和 下线
master:
1、管理所有的 regionserver
2、接收所有的regionserver的汇报,然后进行region的负载均衡
3、维护hbase的元数据信息(namespace, table,column family)
master可以宕机一段时间:
1、受影响: 所有 master该做的事都没有机器做,所以, 元数据的修改操作统统不能做
2、不受影响: 插入 和 查询不受影响。
master的上线 和 下线
压缩算法的比较
以下是Google几年前发布的一组测试数据(数据有些老了,有人近期做过测试的话希望能共享出来):
Algorithm % remaining Encoding Decoding
GZIP 13.4% 21 MB/s 118 MB/s
LZO 20.5% 135 MB/s 410 MB/s
Zippy/Snappy 22.2% 172 MB/s 409 MB/s
其中:
1)GZIP的压缩率最高,但是其实CPU密集型的,对CPU的消耗比其他算法要多,压缩和解压速度也慢;
2)LZO的压缩率居中,比GZIP要低一些,但是压缩和解压速度明显要比GZIP快很多,其中解压速度快的更多;
3)Zippy/Snappy的压缩率最低,而压缩和解压速度要稍微比LZO要快一些。
BigTable和HBase中压缩算法的选择
BigTable中采用的是Zippy算法,目标是达到尽可能快的压缩和解压速度,同时减少对CPU的消耗。
HBase中,在Snappy发布之前(Google 2011年对外发布Snappy),采用的LZO算法,目标和BigTable类似;在Snappy发布之后,建议采用Snappy算法(参考《HBase: The Definitive Guide》),具体可以根据实际情况对LZO和Snappy做过更详细的对比测试后再做选择。
实际项目中的实践经验
项目中使用clearspring公司开源的基数估计的概率算法:stream-lib,用于解决去重计算问题,如UV计算等,它的特点在于:
1)一个UV的计算,可以限制在一个固定大小的位图空间内完成(不同大小,对应不同的误差率),如8K,64K;
2)不同的位图可以进行合并操作,得到合并后的UV。
当系统中维护的位图越多的时候,不管是在内存中,还是在存储系统(MySQL、HBase等)中,都会占用相当大的存储空间。因此,需要考虑采取合适的算法来压缩位图。这里分为以下两类情况:
1)当位图在内存中时,此时压缩算法的选择,必须有尽可能快的压缩和解压速度,同时不能消耗过多CPU资源,因此,适合使用LZO或Snappy这样的压缩算法,做到快速的压缩和解压;
2)当位图存储到DB中时,更关注的是存储空间的节省,要有尽可能高的压缩率,因此,适合使用GZIP这样的压缩算法,同时在从内存Dump到DB的过程也可以减少网络IO的传输开销。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。