Hbase面试+知识点总结2
Posted lucky_xian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hbase面试+知识点总结2相关的知识,希望对你有一定的参考价值。
Hbase知识点总结
- 1.Hbase和Hive的区别:
- 2.Hbase适用于怎样的场景:
- 3.描述Hbase中scan对象的setCache和setBatch方法的使用:
- 4.每天百亿数据存入Hbase,如何保证数据的存储正确和规定时间全部录入完毕,不残留数据:
- 5.Hbase是如何预建分区:
- 6.Hbase内部机制是什么:
- 7.MemStore的作用:
- 8.Hbase在进行模型设计时重点在什么地方,一张表中定义多少个Column Family最合适,为什么:
- 9.如何提高Hbase客户端的读写性能,请举例说明:
- 10.Hbase集群安装注意事项:
- 11.直接将时间戳作为行键,在写入单个Region的时候会发生热点问题,为什么呢:
- 12.请描述如何解决Hbase中region太小和Region太大带来的冲突:
- 13.Hbase客户端:
- 14.Hbase依赖服务:
- 15.Hbase基础结构与算法:
- 16.负载均衡实现:
- 17.Hbase复制:
- 18.备份与恢复-Snapshot:
- 19.HBase HBCK:
- 20.Hbase核心参数:
- 21.HBase读取性能优化:
- 22.HBase写入性能优化:
1.Hbase和Hive的区别:
- 整体理解:Hive相当于HDFS文件的视图,Hbase是建立了索引的Key-Value表。
- 表定义:Hive是逻辑表,它只存储元数据(元数据描述了如何把HDFS上的文件映射成关系型数据表),它完全依赖HDFS和MapReduce,它提供了一种平台使得其他组件可以使用sql操作HDFS上(结构化)的数据,这些SQL语句最后都会转换成MapReduce任务进行执行;HBase是基于HDFS的Nosql数据库,存储的数据是Key/Value类型,属于物理表,适合存储非结构化数据;
- 行列相关:Hive是通过MapReduce来处理数据,MapReduce是按照行来进行数据处理的,即每一行有多少列是确定的,列数据为null也需要占用空间来存储,Hbase是基于列模式的,结构松散,创建时不需要指定列,只需要指定列簇即可,且不存储null数据,因此用户可以给每一行数据定义不同的列;
- 实时性:Hive使用Hadoop系统来处理数据,Hadoop系统是批处理式系统,不能保证处理的低延时性,Hbase是近实时系统,支持实时查询(MemStore起作用);
- 更新支持:Hive不支持基于行的更新,它更多的被用到大量append-only数据集(如日志)的批任务处理(HDFS不支持更新,只支持追加的特性),HBase支持基于行的更新;
- 使用场景:Hive提供了完整的SQL实现,一般被用于离线数据的分析挖掘,Hbase不支持多级索引,有join操作的,表关系复杂的应用场景;
2.Hbase适用于怎样的场景:
- 半结构化或者非结构化数据:可以自由的定义每个数据的列;
- 对于数据结构字段不够确定或者杂乱无章很难按照一个概念去抽取的数据适合使用Hbase,Hbase支持列动态增加;
- 多版本存储:
- Hbase的cell有时间戳一项,可以记录数据的版本号,即一条数据的rowkey,列族,列以及Type都可以相同,只要它们的版本号不相同就可以被存储为两条数据,业务一般只会查询最新的值,如果想要查询历史数据只需要带上版本号一起查询即可;
- 超大容量:Hbase会自动水平切分扩展,和HDFS的无缝衔接保证了数据的可靠性以及海量分析的高性能;
- 关系型数据库处理超大容量数据:
- 1.先做读写分离,一个Master专门做写操作,多个Slave来负责读操作来分流
- 2.数据更大读写分离支撑不住,开始做分库,将关联不大的数据分开部署,这时候一些join操作就不能用了,需要借助中间层;
- 3.随着数据进一步增加,一个表的记录越来越多,查询变得很慢,就要分表;
- 关系型数据库处理超大容量数据:
- 数据十分稀疏:Hbase不存储列值为null的数据,此种情况使用Hbase可以节省大量空间。
- 关系型数据库有多少列是固定的,会存储null值浪费空间,而Hbase不会存储值为null的Culomn,这样既节省了时间又提高了读性能;
3.描述Hbase中scan对象的setCache和setBatch方法的使用:
- setCache:用于设置缓存,即设置一次RPC请求可以获取多少行数据(因为Hbase一次查询的数据量可能会非常大,全部返回给客户端可能会导致客户端OOM);
- setBatch:设置一次RPC请求的数据列数量;
- setMaxResultSize:设置每次RPC返回的数据量大小,不是数据条数,默认为2G;
4.每天百亿数据存入Hbase,如何保证数据的存储正确和规定时间全部录入完毕,不残留数据:
- 需求分析:
- 百亿数据:说明数据量非常大;
- 保证数据正确:要设计正确的数据结构保证正确性;
- 存入Hbase:和Hbase写入有关;
- 在规定的时间内完成:对存入速度有要求;
- 解决思路:
- 百亿数据一天写入,每秒写入100万条,Hbase正常的写入API无法支持,所以不考虑实时接入,采用批量导入,BulkLoad方式;
- 存入Hbase:不考虑JavaAPI,批量导入采用BulkLoad;
- 保证数据正确:需要考虑Rowkey设计,预建分区,列族设计等等;
- 速度要求:BulkLoad;
5.Hbase是如何预建分区:
- 预建分区的主要目的是在创建表的时候指定分区数,提前规划好表有多少个分区,以及每个分区的区间范围,这样在存储的时候,rowkey按照分区的区间存储,可以避免region热点问题;
6.Hbase内部机制是什么:
- 物理存储:Hbase的持久化数据是将数据存储在HDFS上的;
- 存储管理:一个表可以根据rowkey的range划分成很多的region,region由RegionServer管理,region内部还可以划分为store,store内部有memstore和Hfie;
- 版本管理:Hbase中数据的版本是不断追加新的版本,通过conpaction操作来做版本之间的合并,无用数据的处理,以及region的split;
- 集群管理:Zookeeper:负责集群中操作期间元数据的一致性,以及为客户端提供RegionServer地址,master主要负责集群表管理,包括表创建修改删除等,以及负载均衡之类,RegionServer管理Region,负责向客户端提供读写服务,并在内部完成region的compaction以及split;
7.MemStore的作用:
- 保证Hfile的数据有序:客户端的请求在到达RegionServer后,为了保证写入的rowkey的有序性,不能立刻将数据写入到hfile中,而是将其写入到内存中的memstore中,memstore内部采用跳跃表的形式,插入删除查询的复杂度都是logN,并能保证数据有序,当Memstore的数据大小超过阈值,就会启动flush将其写入到HDFS中,形成hfile文件,所以memstore将磁盘随机写变成了一次内存随机写+磁盘顺序写,充分提高了Hbase的写入性能;
- 保证数据不丢失:Memstore是存放在内存中,若果RegionServer宕机,就会导致Memstore中的数据全部丢失,为了避免这种情况,Hbase在写入到Memstore前会将数据顺序追加到HDFS的WAL文件中,当发生宕机故障时,Hbase会将其按照Region切分后进行数据回放,以此恢复数据;
8.Hbase在进行模型设计时重点在什么地方,一张表中定义多少个Column Family最合适,为什么:
- rowkey的设计:要保证唯一性,散列性(但是注意不要引发region热点问题),长度尽可能短,并在具体的业务场景下做不同的调整;
- 列族设计:多列族的优点是查询某一列族时不需要扫描全表,减少了读I/O,但是它在写入时,会导致同属于一个rowkey的多个store的memstore在进行flush操作时同时进行flush,增加IO开销;
9.如何提高Hbase客户端的读写性能,请举例说明:
- 开启bloom过滤器;
- Hbase对内存是有要求的(MemStore+BlockCache),如果在硬件允许的情况下,请尽量给他分配更多的内存;
- 增大RPC数量;
10.Hbase集群安装注意事项:
- Hbase是基于HDFS的数据库,所以在安装Hbase之前要先保证Hadoop完成安装;
- Hbase需要Zookeeper集群的安装;
- 注意Hbase和Hadoop之间的兼容性;
- 注意Hbase-env.sh和hbase-site.xml配置;
- 注意RegionServer配置文件的修改;
- 注意集群间各个节点的时间要同步;
11.直接将时间戳作为行键,在写入单个Region的时候会发生热点问题,为什么呢:
- region中的rowkey是有序存储,若时间比较集中,就会导致这段时间接入的数据全部接入到一个region中去导致region热点问题,指导region因为数据太多进行split操作,这种现象才会得到缓解,但是还是有一定程度上的region热点问题;
12.请描述如何解决Hbase中region太小和Region太大带来的冲突:
- region参数设置太大会发生多次compaction,将compaction操作是将小region数据读取得到一个大region,占用IO,region设置过小会导致region发生split,此时Region会短暂线下影响数据读写,并且在split会生成reference文件,一旦在compaction过程中检测到reference文件,就会发生Major compaction;
- 解决方案是根据实际情况确定region大小,如果平觉得key和value都很大的话,就将region大小设置的大一点,否则九江region设置的小一点,打的region有利于顺序读,小的region有利于随机读;
13.Hbase客户端:
- meta表:
- 表只有一个名为info的ColumnFamily;
- HBase保证hbase:meta表始终只有一个Region,这是为了确保meta表多次操作的原子性;
- hbase:meta的一个rowkey就对应一个Region,rowkey主要由TableName(业务表名)、StartRow(业务表Region区间的起始rowkey)、Timestamp(Region创建的时间戳)、EncodedName(上面3个字段的MD5 Hex值);
- 列:
- info:regioninfo:存储region的name,startTime,stopTime,EncodedName
- info:seqnumDuringOpen:主要存储Region打开时的sequenceId;
- info:server:对应的RegionServer;
- info:serverstartcode:RegionServer启动时的时间戳;
- hbase:meta热点问题:通过将元数据缓存在客户端解决。客户端发现元数据不对或者为空的时候,去hbase:mate表中同步;
- 参数:
- caching:每次loadCache操作最多放caching个result到cache队列中;
- batch:设置每次取多少列;
- allowPartial:用户能容忍拿到一行部分cell的result;
- maxResultSize:loadCache时单次RPC操作最多拿到maxResultSize字节的结果集
- RPC重试配置要点:
- 常见异常:
- 待访问Region所在的RegionServer发生宕机;
- 服务端负载较大,导致单次RPC响应超时;
- 访问meta表或者ZooKeeper异常
- 超时参数:
- hbase.rpc.timeout:表示单次RPC请求的超时时间;
- hbase.client.retries.number:表示调用API时最多容许发生多少次RPC重试操作;
- hbase.client.pause:表示连续两次RPC重试之间的休眠时间,重试休眠时间是按照随机退避算法计算,重试次数越多,则休眠的时间会越长。
- hbase.client.operation.timeout:表示单次API的超时时间
- 常见异常:
- CAS接口是Region级别串行执行的,吞吐受限:
- cas接口:
- checkAndPut;
- incrementColumnValue;
- 运行步骤:
- 服务端拿到Region的行锁(row lock),避免出现两个线程同时修改一行数据;
- 等待该Region内的所有写入事务都已经成功提交并在mvcc上可见;
- 通过Get操作拿到需要check的行数据,进行条件检查。若条件不符合,则终止CAS
- 将checkAndPut的put数据持久化;
- 释放第1)步拿到的行锁
- cas接口:
- Scan Filter设置:
- Pref ixFilter:Pref ixFilter是将rowkey前缀为指定字节串的数据都过滤出来并返回给用户;
- PageFilter:HBase里Filter状态全部都是Region内有效的,也就是说,Scan一旦从一个Region切换到另一个Region,之前那个Filter的内部状态就无效了,想实现分页功能,可以使用setLimit;
- SingleColumnPageFilter:将列簇为family、列为qualif ier、且值为value的cell返回给用户。
- 少量写和批量写:
- table.put(put):单行数据写入API,在服务端先写WAL,然后写MemStore,一旦MemStore写满就f lush到磁盘上,默认每次写入都需要执行一次RPC和磁盘持久化。因此,写入吞吐量受限于磁盘带宽、网络带宽以及flush的速度。但是,它能保证每次写入操作都持久化到磁盘,不会有任何数据丢失。最重要的是,它能保证put操作的原子性;
- table.put(List puts):在客户端缓存put,等凑足了一批put,就将这些数据打包成一次RPC发送到服务端,一次性写WAL,并写MemStore,,此方法省去了多次往返RPC以及多次刷盘的开销,吞吐量大大提升,不能保证这一批put的原子性,因为HBase并不提供跨Region的多行事务;
- bulk load:通过HBase提供的工具直接将待写入数据生成HFile,将这些HFile直接加载到对应的Region下的CF内;
- 业务发现请求延迟很高,但是HBase服务端延迟正常:
- HBase客户端所在进程Java GC;
- 业务进程所在机器的CPU或者网络负载较高;
- HBase客户端层面的bug;
14.Hbase依赖服务:
- ZooKeeper:
- 概述:
- 提供极低延迟、超高可用的内存KV数据库服务;
- 提供中心化的服务故障发现服务;
- ZooKeeper核心特性:
- 多类型节点:持久节点,临时节点,持久顺序节点,临时顺序节点
- Watcher机制:ZooKeeper实现的一种事件异步反馈机制
- watcher设置:ZooKeeper可以为所有的读操作设置watcher,这些读操作包括getChildren()、exists()以及getData();
- watcher触发反馈:ZooKeeper中客户端与服务器端之间的连接是长连接。watcher事件发生之后服务器端会发送一个信息给客户端,客户端会调用预先准备的处理逻辑进行应对;
- watcher特性:watcher事件是一次性的触发器;
- Session机制:客户端连接Zookeeper集群时会试遍所有的Zookeeper节点,直到连接成功;
- ZooKeeper典型使用场景:Master高可用管理、RegionServer宕机异常检测、分布式锁等等;
- 分布式锁:
- 客户端调用create()方法创建名为“ locknode/lock-”的临时节点;
- 客户端调用getChildren(“locknode”)方法来获取所有已经创建的子节点;
- 客户端获取到所有子节点path之后,如果发现自己在步骤1)中创建的节点序号最小,那么就认为这个客户端获得了锁;
- 如果在步骤3)中发现自己并非所有子节点中最小的,说明集群中其他进程获取到了这把锁。此时客户端需要找到最小子节点,然后对其调用exist()方法,同时注册事件监听;
- 一旦最小子节点对应的进程释放了分布式锁,对应的临时节点就会被移除,客户端因为注册了事件监听而收到相应的通知。这个时候客户端需要再次调用getChildren(“locknode”)方法来获取所有已经创建的子节点,然后进入步骤3。
- 分布式锁:
- 概述:
- ZooKeeper+Hbase:
- 子节点:
- meta-region-server:存储HBase集群hbase:meta元数据表所在的RegionServer访问地址;
- master/backup-masters:实现了Master的高可用功能;
- table:集群中所有表信息;
- region-in-transition:管理region迁移的元数据状态;
- table-lock:HBase系统使用ZooKeeper相关机制实现分布式锁,HBase中一张表的数据会以Region的形式存在于多个RegionServer上,因此对一张表的DDL操作(创建、删除、更新等操作)通常都是典型的分布式操作。每次执行DDL操作之前都需要首先获取相应表的表锁,防止多个DDL操作之间出现冲突;
- online-snapshot:在线snapshot操作的元数据管理;
- replication:Hbase复制功能;
- splitWAL/recovering-regions:实现HBase分布式故障恢复;
- rs:集群中所有运行的RegionServer;
- 子节点:
- HDFS:
- 概述:
- HBase项目本身并不负责文件层面的高可用和扩展性,它通过把数据存储在HDFS上来实现大容量文件存储和文件备份;
- HDFS架构:
- NameNode:本质上是一个独立的维护所有文件元数据的高可用KV数据库系统
- 线上需要部署2个NameNode :一个节点是Active状态并对外提供服务;另一个节点是StandBy状态,作为Active的备份;
- NameNode存储并管理HDFS的文件元数据,这些元数据主要包括文件属性(文件大小、文件拥有者、组以及各个用户的文件访问权限等)以及文件的多个数据块分布在哪些存储节点上,文件元数据是在不断更新的,为了保证每一次文件元数据都不丢失,NameNode采用写EditLog和FsImage的方式来保证元数据的高效持久化;
- DataNode:组成文件的所有Block都是存放在DataNode节点上;
- JournaNode:保证NameNode切换时的数据一致性,通过Paxos协议来保证数据一致性;
- NameNode:本质上是一个独立的维护所有文件元数据的高可用KV数据库系统
- HDFS文件写入:
- DFS Client在创建FSDataOutputStream时,把文件元数据发给NameNode,得到一个文件唯一标识的f ileId,并向用户返回一个OutputStream;
- 用户拿到OutputStream之后,开始写数据;
- 用户执行完写入操作后,需要关闭OutputStream;
- 概述:
- 文件读取:
- DFSClient请求NameNode,获取到对应read position的Block信息;
- DFSClient从Block对应的DataNode中选择一个合适的DataNode,对选中的DataNode创建一个BlockReader以进行数据读取;
- 用户执行完写入操作后,需要关闭OutputStream;
- HDFS在HBase系统中扮演的角色:HBase使用HDFS存储所有数据文件,从HDFS的视角看,HBase就是它的客户端
- HBase本身并不存储文件,它只规定文件格式以及文件内容,实际文件存储由HDFS实现;
- HBase不提供机制保证存储数据的高可靠,数据的高可靠性由HDFS的多副本机制保证;
- HBase-HDFS体系是典型的计算存储分离架构。计算资源和存储资源可以互相替换,也可以单独缩容或者扩展;
- HDFS+Hbase:
- HDFS上Hbase目录:
- hbase-snapshot:snapshot文件存储目录,存储snapshot元数据;
- .tmp:临时文件目录;
- MasterProcWALs:存储Master Procedure过程中的WAL文件;
- WALs:存储集群中所有RegionServer的HLog日志文件;
- data:存储集群中所有Region的HFile数据;
- oldWALs:WAL归档目录;
- HDFS上Hbase目录:
15.Hbase基础结构与算法:
- 概述:
- LSM树:列簇(Column Family)本质上就是一棵LSM树(Log-Structured Merge-Tree)。LSM树分为内存部分和磁盘部分。内存部分是一个维护有序数据集合的数据结构。。磁盘部分是由一个个独立的文件组成,每一个文件又是由一个个数据块组成。在磁盘中存储一些额外的二进制数据,用来判断对于给定的key是否有可能存储在这个数据块中,这个数据结构称为布隆过滤器(Bloom Filter);
- 跳跃表:
- 时间复杂度:跳跃表(SkipList)是一种能高效实现插入、删除、查找的内存数据结构,这些操作的期望复杂度都是O(logN);
- 定义:
- 跳跃表由多条分层的链表组成;
- 每条链表中的元素都是有序的;
- 每条链表都有两个元素:+∞(正无穷大)和- ∞(负无穷大),分别表示链表的头部和尾部;
- 从上到下,上层链表元素集合是下层链表元素集合的子集,即S1是S0的子集,S2是S1的子集;
- 跳跃表的高度定义为水平链表的层数。
- LSM树:
- 概念:一种磁盘数据的索引结构,将写入操作处理为一次顺序写,LSM树的索引一般由两部分组成,一部分是内存部分,一部分是磁盘部分。内存部分一般采用跳跃表来维护一个有序的KeyValue集合。磁盘部分一般由多个内部KeyValue有序的文件组成;
- 布隆过滤器:布隆过滤器串对任意给定元素w,给出的存在性结果为两种:1.w可能存在于集合A中;2.w肯定不在集合A中,当N取K*|A|/ln2时(其中|A|表示集合A元素个数),能保证最佳的误判率;
16.负载均衡实现:
- Region迁移:Region迁移操作分两个阶段:unassign阶段和assign阶
- unassign阶段:
- Master在内存中将region状态置为PENDING_CLOSE,然后生成M_ZK_REGION_CLOSING并更新到ZooKeeper组件;
- Master向RegionServer发送关闭region的命令;
- RegionServer收到命令后,在Zookeeper上注册ES_ZK_REGION_CLOSING事件;
- Master监听到该事件,将内存中该region的状态置为closing;
- RegionServer执行Region关闭操作,在此期间有flush或者compaction操作时,先等待操作执行完成;
- RegionServer完成关闭操作,注册RS_ZK_REGION_CLOSED到Zookeeper上;
- master检测到RS_ZK_REGION_CLOSED事件,将内存中该Region的状态置为closed;
- assign阶段:
- Master在内存中将region状态置为PENDING_OPEN,然后生成M_ZK_REGION_OFFLINE并更新到ZooKeeper组件;
- Master向RegionServer发送开启region的命令;
- RegionServer收到命令后,在Zookeeper上注册RS_ZK_REGION_OPENING事件;
- Master监听到该事件,将内存中该region的状态置为OPENING;
- RegionServer执行Region开启操作,初始化相应的服务;
- RegionServer完成关闭操作,注册RS_ZK_REGION_OPEND到Zookeeper上;
- master检测到RS_ZK_REGION_OPEND事件,将内存中该Region的状态置为opend;
- 组件职责:
- Master负责维护Region在整个操作过程中的状态变化,起到枢纽的作用;
- RegionServer负责接收Master的指令执行具体unassign/assign操作;
- ZooKeeper负责存储操作过程中的事件;
- unassign阶段:
- Region元数据管理:
-
meta表:只存储Region所在的RegionServer,并不存储迁移过程中的中间状态;
-
Master内存:存储整个集群所有的Region信息,根据这个信息可以得出此Region当前以什么状态在哪个RegionServer上。Master存储的Region状态变更都是由RegionServer通过ZooKeeper通知给Master的,所以Master上的Region状态变更总是滞后于真正的Region状态变更;
-
ZooKeeper:存储的是临时性的状态转移信息,作为Master和RegionServer之间反馈Region状态的通道。如果Master(或者相应RegionServer)在中间某个阶段发生异常,ZooKeeper上存储的状态可以在新Master启动之后作为依据继续进行迁移操作;
-
RIT:Region状态在三个地方并不能保持一致,这就会出现region-in-transition,Region在迁移的过程中必然会出现短暂的RIT状态,这种场景并不需要任何人工干预操作;
-
- Region合并:
- merge_region是一个异步操作,命令执行之后会立刻返回,用户需要一段时间之后手动检测合并是否成功。默认情况下merge_region命令只能合并相邻的两个Region,非相邻的Region无法执行合并操作
- 步骤:
- 1.客户端发送merge请求给Hbase集群;
- 2.Master将两个待合并的region移动到一个RegionServer上;
- 3.Master发送Merge请求给该RegionServer;
- 4.RegionServer启动一个本地事务执行merge操作;
- 5.将待合并的两个Region下线,进行合并;
- 6.将这两个Region从hbase:meta中删除,并将新生成的Region添加到hbase:meta中;
- 7.将新生成的Region上线
- Region分裂:
- Region分裂触发策略:
- ConstantSizeRegionSplitPolicy:一个Region中最大Store的大小超过设置阈值(hbase.hregion.max.f ilesize)之后会触发分裂;
- 缺点:分裂策略对于大表和小表没有明显的区分;
- IncreasingToUpperBoundRegionSplitPolicy:和ConstantSizeRegionSplitPolicy思路相同,一个Region中最大Store大小超过设置阈值就会触发分裂,阈值可变,调整后的阈值大小和Region所属表在当前RegionServer上的Region个数有关系;
- 缺点:在大集群场景下,很多小表就会产生大量小Region,分散在整个集群中;
- SteppingSplitPolicy:分裂阈值大小和待分裂Region所属表在当前RegionServer上的Region个数有关系,如果Region个数等于1,分裂阈值为f lush size * 2,否则为MaxRegionFileSize;
- ConstantSizeRegionSplitPolicy:一个Region中最大Store的大小超过设置阈值(hbase.hregion.max.f ilesize)之后会触发分裂;
- Region分裂准备工作——寻找分裂点:
- 分裂点:整个Region中最大Store中的最大文件中最中心的一个Block的首个rowkey。另外,HBase还规定,如果定位到的rowkey是整个文件的首个rowkey或者最后一个rowkey,则认为没有分裂点;
- **Region核心分裂流程 **:
- 概述:HBase将整个分裂过程包装成了一个事务,目的是保证分裂事务的原子性;
- prepare阶段:生成两个HRegionInfo对象,包含tableName、regionName、startkey、endkey等。同时会生成一个transaction journal,这个对象用来记录分裂的进展;
- execute阶段:
- RegionServer将ZooKeeper节点/region-in-transition中该Region的状态更改为SPLITING;
- Master通过watch节点/region-in-transition检测到Region状态改变,并修改内存中Region的状态;
- 在父存储目录下新建临时文件夹.split,保存split后的daughter region信;
- 关闭父Region;
- 在.split文件夹下新建两个子文件夹,称为daughter A、daughter B,并在文件夹中生成reference文件,分别指向父Region中对应文件,生成了如下reference文件日志;
- 父Region分裂为两个子Region后,将daughter A、daughter B拷贝到HBase根目录下,形成两个新的Region;
- 父Region通知修改hbase:meta表后下线,不再提供服务。下线后父Region在meta表中的信息并不会马上删除,而是将split列、off line列标注为true,并记录两个子Region;
- 开启daughter A、daughter B两个子Region。通知修改hbase:meta表,正式对外提供服务;
- rollback阶段:如果execute阶段出现异常,则执行rollback操作
- **Region分裂对其他模块的影响 **:
- Region分裂过程因为没有涉及数据的移动,所以分裂成本本身并不是很高,可以很快完成。分裂后子Region的文件实际没有任何用户数据,文件中存储的仅是一些元数据信息——分裂点rowkey;
- 文件查找:
- 根据reference文件名(父Region名+HFile文件名)定位到真实数据所在文件路径;
- 根据reference文件内容中记录的两个重要字段确定实际扫描范围,结合splitkey字段可以明确扫描范围为[splitkey, endkey);
- 父Region的数据迁移到子Region目录的时间:
- 移发生在子Region执行Major Compaction时。根据Compaction原理,从一系列小文件中依次由小到大读出所有数据并写入一个大文件,完成之后再将所有小文件删掉,因此Compaction本身就是一次数据迁移;
- 父Region被删除的时间:
- Master会启动一个线程定期遍历检查所有处于splitting状态的父Region,确定父Region是否可以被清理;
- 检测线程首先会在meta表中读出所有split列为true的Region,并加载出其分裂后生成的两个子Region;
- 检查两个子Region是否还存在引用文件,如果都不存在引用文件就可以认为该父Region对应的文件可以被删除。
- Region分裂触发策略:
- 负载均衡策略:
- SimpleLoadBalancer:保证每个RegionServer的Region个数基本相等;
- StochasticLoadBalancer:由多种独立负载加权计算的复合值,独立负载包括:
- Region负载;
- Region个数;
- 读写请求数;
- Region移动代价;
- Storef ile大小;
- MemStore大小;
- 数据本地化率;
17.Hbase复制:
- 负载场景及原理:
- 场景:Hbase集群上运行着业务A,业务A对Hbase集群的延迟和可用性都有很高的要求,此时业务B需要对Hbase集群上的TableX做分析操作,这种大表的scan是非常消耗资源的,容易影响上层业务性能,所以需要做一个Hbase集群备份,将TableX表的数据全量复制到集群B中,然后业务B在集群B中做分析;
- 步骤:(snapshot+Hlog)
- 1.先确认表TableX的多个Column Family都已经将REPLICATION_SCOPE设为1(允许复制);
- 2.在SSD集群上添加一条DISABLED复制链路,提前把主集群正在写入的HLog堵在复制队列中;
- 3.对TableX做一个Snapshot,将Snapshot拷贝到从集群中;
- 4.待Snapshot数据拷贝完成后,从Snapshot中恢复一个TableX表到离线集群;
- 5.打开步骤2中添加的Peer(Peer是指一条从主集群到备份集群的复制链路);
- 6.等待peer=100,所有堵住的HLog都被在线集群推送到离线集群,也就是两个集群的复制延迟等于0,就可以开始在离线集群上跑分析任务了;
- Peer作用:解决集群数据拷贝期间增量数据的不一致问题;
- 其他场景:
- 不同HBase集群间数据无缝迁移;
- 跨HBase集群的数据备份;
- HBase集群同步到异构的存储系统;
- 串行复制:
- 非串行复制导致的问题:复制在Region移动后无法保证串行性
- 原理:
- RegionA在RegionServer1上面,此时通过集群复制,会为RegionServer1生成一个HLog1,里面包含Region1的部分数据推送给从集群;
- RegionA迁移到RegionServer2上面,此时集群复制策略,RegionServer2也有一个HLog2,此时HLog2中同样含有RegionA的部分数据;
- 若RegionA在HLog1上的操作和在HLog上的操作严格串行执行,而在备份集群数据写入时,HLog2的诗句可能会先于HLog1完成,这就造成了数据的不一致性;
- 示例1:写入操作在源集群的执行顺序和Peer集群的执行顺序不一致
- RegionA在源数据集群写入顺序如下:
- 1)t1时间点执行:Put, K0, V0, t1。
- 2)t2时间点执行:Put, K0, V0, t2。
- 3)在t3时间点,Region-A从RegionServer0移到RegionServer1上。
- 4)t4时间点执行:Put, K0, V0, t5。
RegionServer可能并行地把同一个Region的数据往Peer推送,故Peer集群的写入顺序可能变成: - 1)t6时间点执行:Put, K0, V0, t1。
- 2)t7时间点执行:Put, K0, V0, t5。
- 3)t8时间点执行:Put, K0, V0, t2。
在Peer集群的[ t7, t8)时间区间内,用户可以读取到t1和t5这两个版本的Put,但这种状态在源集群是永远读取不到的,不能保证数据的一致性;
- 示例2:极端情况下,可能导致主集群数据和备集群数据不一致
- RegionA在源数据集群写入顺序如下:
- 结果:源集群上rowkey=K0的所有cell都被清除,但是到了Peer集群,用户还能读取到一个多余的Put;
- RegionA在源数据集群写入顺序如下:
- 串行复制的设计思路:
- 1.把Region的数据按照Region移动发生的时间点t0分成两段;
- 2.小于t0时间点的数据都在RegionServer0的HLog上,大于t0时间点的数据都在RegionServer1的HLog上;
- 3.让RegionServer0先推小于t0的数据,等RegionServer0把小于t0的数据全部推送到Peer集群之后,RegionServer1再开始推送大于t0的数据 ;
- 解决方案:
- 分布式栅栏;
- 非串行复制导致的问题:复制在Region移动后无法保证串行性
- 并行复制:
- 异步复制带来的问题:若主集群因意外或者Bug无法提供服务时,备份集群的数据是比主集群少的,不能满足某些一致性特别强的场景的需求;
- 设计思路:
- 1.RegionServer在收到写入请求之后,在主机和从机都写入一份HLog日志;
- 2.只有等主集群上的HLog和备集群上的RemoteWAL都写入成功且MemStore写入成功后,此次写入操作才成功;
- 3.主集群到备集群之间还会开启异步复制链路;
- 4.若主集群上的某个HLog通过异步复制完全推送到备份集群,那么这个HLog在备集群上对应的RemoteWAL则被清理,否则不可清理;
- 集群复制的几种状态:
- Active:这种状态的集群将在远程集群上写RemoteWAL日志,同时拒绝接收来自其他集群的复制数据(复制集群中的主集群处于此状态);
- Downgrade Active:这种状态的集群将跳过写RemoteWAL流程,同时拒绝接收来自其他集群的复制数据(复制集群中因备集群不可用会导致主机群成为这种状态);
- Standby:这种状态的集群不容许Peer内的表被客户端读写,它只接收来自其他集群的复制数据。同时确保不会将本集群中Peer内的表数据复制到其他集群上(复制集群中的从集群);
- None:没有开启同步复制;
- 集群复制状态比较:
- 建立同步复制:
- 在主集群和备份集群分别建立一个指向对方集群的同步复制Peer。这时,主集群和备份集群的状态默认为DA;
- 将备份集群的状态从DA切换成S;
- 将主集群状态从DA切换成A;
- 备集群故障处理流程:
- 先将主集群状态从A切换为DA。因为此时备份集群已经不可用(因为备集群的HLog日志已经写不进去了,为了业务不出错,此时需要切换主机群的状态);
- 在确保备份集群恢复后,可以直接把备份集群状态切换成S,在第1步到第2步之间的数据都会由异步复制同步到备份集群,第2步后的写入都是同步写入到备份集群;
- 把主集群状态从DA切换成A;
- 主集群故障处理流程:
- 先将备份集群状态从S切换成DA,切换成DA之后备份集群将不再接收来自主集群复制过来的数据;
- t4时间点,主集群已经恢复,虽然业务已经切换到原来的备集群上,但是原来的主集群还认为自己是A状态;
- 把原来的主集群切换成S状态;
- t6时间点,把备集群状态从DA切换成A,继续开启同步复制保持数据一致性;
- 同步复制和异步复制对比:
18.备份与恢复-Snapshot:
- Snapshot概述:
- Snapshot备份能实现什么功能:全量/增量备份和数据迁移;
- 在线Snapshot备份与恢复的用法:
- snapshot :为数据表建立快照:snapshot ‘sourceTable’,‘snatshopName’;
- restore_snapshot:用于恢复指定快照,恢复过程会替代原有数据,将表还原到快照点,快照点之后的所有更新将会丢失:restore_snapshot ‘snatshopName’;
- clone_snapshot,可以根据快照恢复出一个新表,恢复过程不涉及数据移动,可以在秒级完成:clone_snapshot ‘snatshopName’ tableName;
- ExportSnapshot:可以将A集群的快照数据迁移到B集群,ExportSnapshot是HDFS层面的操作,需使用MapReduce进行数据的并行迁移,因此需要在开启MapReduce的机器上进行迁移。Master和RegionServer并不参与这个过程,因此不会带来额外的内存开销以及GC开销.
- Snapshot创建:
- Snapshot技术基础原理:
- 一个Snapshot是全部文件系统或者某个目录在某一时刻的镜像;
- Snapshot机制并不会拷贝数据,可以理解为它是原数据的一份指针;
- HBase数据文件只能追加的机制。使实现某个表的Snapshot,只需为当前表的所有文件分别新建一个引用(指针)。对于其他新写入的数据,重新创建一个新文件写入即可;
- 步骤:1.将MemStore中的缓存数据f lush到文件中;2.为所有HFile文件分别新建引用指针,这些指针元数据就是Snapshot;
- 在线Snapshot的分布式架构——两阶段提交:
- HBase为指定表执行Snapshot操作,实际上真正执行Snapshot的是对应表的所有Region,需要一种机制来保证所有参与执行Snapshot的Region要么全部完成,要么都没有开始做,不能出现中间状态;
- 两阶段提交基本步骤:
- prepare阶段协调者会向所有参与者发送prepare命令;
- 所有参与者接收到命令,执行prepare操作确认可以执行成功。(核心工作都是在prepare操作中完成)
- 返回给协调者prepared应答;
- 协调者接收到所有参与者返回的prepared应答,在本地持久化committed状态。
- 持久化完成之后进入commit阶段,协调者会向所有参与者发送commit命令;
- 参与者接收到commit命令,执行commit操作并释放资源;
- 返回执行结果给协调者;
- 两阶段提交基本步骤:
- Snapshot两阶段提交实现:
- prepare阶段:
- Master在ZooKeeper创建一个节点,并在此节点上写入Snapshot相关信息;
- 所有RegionServer监测到这个节点,边理所有region执行snapShot命令;
- RegionServer执行完成之后会在zookeeper的指定节点上建立一个子节点,表示备份prepare已完成;
- HBase为指定表执行Snapshot操作,实际上真正执行Snapshot的是对应表的所有Region,需要一种机制来保证所有参与执行Snapshot的Region要么全部完成,要么都没有开始做,不能出现中间状态;
- commit阶段:
- 所有RegionServer建立完子节点后,Master就认为snapshot的prepare阶段已经完成,Master就会在zookeeper上创建一个节点,表示发送commit命令给所有的regionserver;
- 所有RegionServer监测到zookeeper上的代表commit的节点后,执行commit操作(将prepare阶段生成的结果从临时文件夹移动到最终文件夹即可);
- RegionServer在指定节点下建立子节点表示commit已经完成了;
- abort阶段:
- 一定时间内,Master没有在zookeeper上检测到所有的regionserver建立的表示commit的子节点,即认为创建快照失败,启动回滚;
- Master在zookeeper上新建节点表示需要所有RegionServer回滚;
- RegionServer监听到这个命令之后会清理Snapshot在临时文件夹中生成的结果;
- Snapshot核心实现:
- Region实现Snapshot:
- Master汇总所有Region Snapshot的结果:
- Master会在所有Region完成Snapshot之后执行一个汇总操作(consolidate),将所有regionsnapshot manifest汇总成一个单独manifest,路径为:/hbase/.hbase-snapshot/snapshotname/data.manifest;
- Snapshot技术基础原理:
- Snapshot概述:
- clone_snapshot步骤:
- 预检查。确认当前目标表没有执行snapshot以及restore等操作;
- 在tmp文件夹创建文件写入表schema信息;
- 根据snapshot manifest中的信息新建Region相关目录以及HFile文件;
- 将表目录从tmp文件夹下移到HBase Root Location;
- 修改hbase:meta表,将克隆表的Region信息添加到hbase:meta表;
- 将这些Region通过round-robin方式均匀分配到整个集群中,正式对外提供服务;
- clone_snapshot步骤:
19.HBase HBCK:
- 概述:
- HBaseFsck (HBCK)工具可以检测HBase集群中Region的一致性和完整性,同时可以对损坏的集群进行修复;
- HBase集群一致性状态:
- HBase Region一致性:集群中所有Region都被assign,而且deploy到唯一一台RegionServer上,并且该Region的状态在内存中、hbase:meta表中以及ZooKeeper这三个地方需要保持一致;
- HBase表完整性:对于集群中任意一张表,每个rowkey都仅能存在于一个Region区间;
- HBCK的集群一致性状态检测:
- 命令:hbase hbck;
- 命令执行完成后,会显示OK或者INCONSISTENCIES结果;
- 集群管理员通常需要执行多次hbck命令以防止部分Region出现临时性的非一致性状态;
- HBCK的局部低危修复:
- 集群修复的基本原则:首先修复低风险的Region一致性问题(以及部分表完整性问题),再谨慎修复部分高风险的表完整性问题(overlap问题)
- 低风险的Region一致性问题:仅仅涉及Master内存中Region状态、ZooKeeper临时节点中Region状态以及hbase:meta元数据表中Region状态的修改,并不实际修改任何HDFS文件。修复成功之后,Region的状态在.regioninfo文件、Master内存、ZooKeeper临时节点和hbase:meta元数据表中保持一致;
- 致性问题修复有两个基本选项:
- -f ixAssignments:修复assign相关问题,如没有assigned、assign不正确或者同时assign到多台RegionServer的问题Regions;
- -f ixMeta:修复.regioninfo文件和hbase:meta元数据表的不一致。修复原则是以HDFS文件为准;
- -f ixHdfsHoles:修复Hbase空洞,会在空洞形成的地方填充一个空Region;
20.Hbase核心参数:
- Region相关参数:
- hbase.hregion.max.filesize:默认为10G,region分裂阈值;
- BlockCache相关参数:
- BlockCache策略:推荐RegionServer内存在20G以内的就选择LRUBlockCache,大于20G的就选择BucketCache中的offheap模式;
- hfile.block.cache.size:默认为0.4,用来设置LRUBlockCache的内存大小,0.4表示JVM内存的40%;
- hbase.bucketcache.ioengine:BucketCache策略的模式选择,可选项包括heap、offheap以及f ile三种;
- hbase.bucketcache.size:堆外存大小,配置的大小主要依赖于物理内存大小;
- MemStore相关参数:
- hbase.hregion.memstore.flush.size:默认为128M(134217728),MemStore大于该阈值就会触发f lush;
- hbase.hregion.memstore.block.multiplier:region级别的memstore触发flush的阈值;
- hbase.regionserver.global.memstore.size:memstore占JVM内存的大小;
- hbase.regionserver.global.memstore.lower.limit:RegionServer级别总MemStore大小的低水位是hbase.regionserver.global.memstore.size的95%;
- hbase.regionserver.optionalcachef lushinterval:regionServer定时flush的时间间隔;
- Compaction相关参数:
- hbase.hstore.compactionThreshold:一个store中文件数阈值,超过这个阈值就会触发compaction;
- hbase.hstore.compaction.max:最多可以参与minor compaction的文件数;
- hbase.regionserver.thread.compaction.throttle:设置文件大小阈值,如果文件大小超过该值,则该文件不参与compaction操作;
- HLog相关参数:
- hbase.regionserver.maxlogs:Region f lush的触发条件之一,wal日志文件总数超过该阈值就会强制执行f lush操作;
- 其他重要参数:
- hbase.online.schema.update.enable:默认为true,表示更新表schema的时候不再需要先disable再enable,直接在线更新即可;
- hbase.snapshot.enabled :默认为true,表示是否开启snapshot功能;
- zookeeper.session.timeout :默认为180s,表示ZooKeeper客户端与服务器端session超时时间;
21.HBase读取性能优化:
- 1. 读请求是否均衡:
- 优化原理:避免造成region热点;
- 观察确认:观察所有RegionServer的读请求QPS曲线,确认是否存在读请求不均衡现象。
- 优化建议:Rowkey必须进行散列化处理,同时建表必须进行预分区处理
- 2.BlockCache设置是否合理
- 优化原理:BlockCache作为读缓存,对于读性能至关重要
- 观察确认:观察所有RegionServer的缓存未命中率、配置文件相关配置项以及GC日志,确认BlockCache是否可以优化。
- 优化建议:如果JVM内存配置量小于20G,BlockCache策略选择LRUBlockCache;否则选择BucketCache策略的offheap模式。
- 3.HFile文件是否太多
- 优化原理:HBase的类LSM树结构导致每个store包含多个HFile文件,文件越多,检索所需的IO次数越多,读取延迟也就越高
- 观察确认:观察RegionServer级别以及Region级别的HFile数,确认HFile文件是否过多。
- 优化建议:hbase.hstore.compactionThreshold设置不能太大,默认为3个。
- 4.Compaction是否消耗系统资源过多
- 优化原理:Compaction是将小文件合并为大文件,提高后续业务随机读性能,但是也会带来IO放大以及带宽消耗问题
- 观察确认:观察系统IO资源以及带宽资源使用情况,再观察Compaction队列长度,确认是否由于Compaction导致系统资源消耗过多。
- 优化建议:对于大Region读延迟敏感的业务(100G以上)通常不建议开启自动MajorCompaction,手动低峰期触发。小Region或者延迟不敏感的业务可以开启MajorCompaction,但建议限制流量;
- 5.数据本地率是不是很低
- 优化原理:如果数据本地率很低,数据读取时会产生大量网络IO请求,导致读延迟较高
- 观察确认:观察所有RegionServer的数据本地率
- 优化建议:尽量避免Region无故迁移。对于本地率较低的节点,可以在业务低峰期执行major_compact;
- 6.scan缓存是否设置合理
- 优化建议:大scan场景下将scan缓存从100增大到500或者1000,用以减少RPC次数;
- 7.get是否使用批量请求
- 优化建议:使用批量get进行读取请求。需要注意的是,对读取延迟非常敏感的业务,批量请求时每次批量数不能太大,最好进行测试;
- 8.请求是否可以显式指定列簇或者列
- 优化建议:大scan场景下将scan缓存从100增大到500或者1000,用以减少RPC次数;
- 9.scan缓存是否设置合理
- 优化建议:尽量指定列簇或者列进行精确查找;
- 10.离线批量读取请求是否设置禁止缓存
- 优化建议:离线批量读取请求设置禁用缓存;
- 11.布隆过滤器是否设置
- 优化建议:任何业务都应该设置布隆过滤器,通常设置为row,除非确认业务随机查询类型为row+column,则设置为rowcol;
22.HBase写入性能优化:
- 1.Region是否太少
- 优化建议:在Num (Region of Table) < Num (RegionServer)的场景下切分部分请求负载高的Region,并迁移到其他RegionServer;
- 2.写入请求是否均衡
- 优化建议:检查Rowkey设计以及预分区策略,保证写入请求均衡;
- 3.Utilize Flash storage for WAL
- 优化建议:该特性会将WAL文件写到SSD,注意Hbase版本和配置参数;
- 4.是否可以使用Bulkload方案写入
- 优化建议:Bulkload方案适合将已经存在于HDFS上的数据批量导入HBase集群,Bulkload方案可以更加高效、快速地导入数据,而且
以上是关于Hbase面试+知识点总结2的主要内容,如果未能解决你的问题,请参考以下文章
- 优化建议:Bulkload方案适合将已经存在于HDFS上的数据批量导入HBase集群,Bulkload方案可以更加高效、快速地导入数据,而且