本文主要是介绍HBase第一天学习,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
HBase第一天学习
HBase的访问方式
进入退出:hbase shell exit
shell实现DDl操作
创建一个表:create 'member','member_id','address','info'
获得表的描述:list(查看所有的表) describe ‘member’(查看member表的详细信息)
'member_id',METHOD=>'delete'}"> 删除一个列簇:alter、disable、enable。 alter 'member',{NAME=>'member_id',METHOD=>'delete'}
drop一个表:create 'temp_table','member_id','address','info' disable 'temp_table'
查看表是否存在:exists ‘member’
查看文件的存储路径:hdfs dfs -ls /yjx/hbase/data/default/t1
shell实现DMl操作:put(插入数据):put'member','guojing','info:age','24'
删除id为temp的值'info:age'字段:delete 'member','temp','info:age'
将整张表清空;truncate 'member'
可以使用count命令计算表的行数量:count 'member'
Shell实现DQL操作
获取一个id的所有数据:get 'member','linghuchong'
获取一个id,一个列族的所有数据:get 'member','linghuchong','info'
获取一个id,一个列族中一个列的所有数据:get 'member','linghuchong','info:age'
全表扫描:scan 'member'
Shell实现Region管理
移动region:move 'encodeRegionName', 'ServerName'
开启/关闭redion:balance_switch true|false
手动spilt:spilt 'regionName','spiltKey'
压缩整个区域:major_compact 'r1'
在region中它说单列簇:major_compact 'r1','c1'
在表中压缩单列族:major_compact 't1','c1'
HBase架构模型
Client:客户端
负责将请求发送到数据库,客户端连接的方式有很多:hbase shell、类JDBC
发送的请求主要包括:
DDl:数据库定义语言(表的建立、删除、添加删除列簇,控制版本)
DMl:数据库操作语言(增删改)
DQL:数据库查询语言(查询--全表扫描--基于主键--基于过滤器)
client维护着一些cache来加快对hbase的访问,比如regione的位置信息
HBase有三个主要的组成部分:客户端库、主服务器和区域服务器
HMaster
HBase集群的主节点,HMaster也可以实现高可用(active-standby):通过zookeeper来维护祝福节点的切换
为Region server分配region并负责region server的负载均衡
zookeeper上面、表的数据-->HRegionServer上"> 管理用户对table的结构DDL(创建、删除、修改)操作:表的元数据信息-->zookeeper上面、表的数据-->HRegionServer上
当HRegionServer下线的时候,HMaster会将当前HRegionServer上的Region转移到其他的HRegionServer
zookeeper
保证在任何时候,集群都只有一个master
存储所有Region的寻址入口,存储所有的元数据信息
实时监控Region server的状态,将Region Server的上线和下线信息实时通知给Master
存储HBase的schema,包括有哪些table,每个table有哪些column family
HRegionServer
Region server是属于HBase具体数据的管理者
Region server 维护Master分配给他的region,处理对这些region的io请求
会实时的和HMaster保持心跳,汇报当前节点的信息
当接受到Hmaster命令创建表的时候,分配一个Region对应一张表
Region Server负责切分在运行过程中变得过大的Region
当客户端发送的DMl和DQL操作时,HRegionServer负责和客户端建立连接
当意外关闭的时候,当前节点的Region会被其他HRegionServer管理
HRegion
HRegion是HBase中分布式存储和负载均衡的最小单元,最小单元就表示不同的HRegion可以分布在不同的HRegion server上
HBase自动把表水平划分成多个区域(region),每个区域会保存一个表里面某段连续的数据
每个表一开始只有一个region,一个region只属于一张表,随着数据不断插入表,region不断增大
Region达到阈值10G的时候会被平分(逻辑上平分,尽量保证数据的完整性):hbase.hregion.max.filesize、切分后的其中一个Region转移到其他的HRegionServer上管理
当table中的行不断增多,就会有越来越多的region,这样一张完整的表就被保存在多个RegionServer
为了防止前期数据的处理都集中在一个HRegionServer,我们可以根据自己的业务进行预分区
Store
HRegion是表获取和分布的基本元素,由一个或者多个Store组成,每个store保存一个columns family
每个Store又由一个memStore和0个或者多个StoreFile组成
HFile是HBase在HDFS中存储数据的格式,它包含多层的索引,这样在Hbase检索数据的时候就不用完全加载整个文件了。
索引的大小(key的大小,数据量的大小影响block的大小,在大数据集群的情况下,blcok的大小设置为每个RegionServer 1G也是很常见的)
StoreFile
Data Block段-保存表中数据,这部分可以被压榨
Meta Blocks段(可选的)-保护用户自定义的kv对,可以被压缩
File info 段-Hfile的元信息,不被压缩,用户也可以在这一部分添加自己的元信息
Data Block Index段-Data Block的索引,每条索引的key是被索引的block的第一条记录的key
Meta Block index段(可选的)-Meta blcok的索引
Trailer-这一段是定长的
保存了每一段的偏移量,读取一个HFile时,会首先读取Trailer
Trailer保存了每个段的起始位置(段的Magic Number用来做安全check)
然后,DataBlock Index会被读取到内存中,当检索某个key时,不需要扫描整个HFile,而只
需从内存中找到key所在的block
通过一次磁盘io将整个 block读取到内存中,再找到需要的key。DataBlock Index采用LRU机
制淘汰。
MemStore
HFile中并没有任何Block,数据首先存在于MemStore中。Flush发生时,创建HFile Writer
当操作数据得时候,第一个空的Data Block初始化,初始化后的Data Block中为Header部分预留了空间
Header部分用来存放一个Data Block的元数据信息
位于MemStore中的KeyValues被一个个append到位于内存中的第一个Data Block中:
如果配置了Data Block Encoding,则会在Append KeyValue的时候进行同步编码,编码后的
数据不再是单纯的KeyValue模式。
Data Block Encoding是HBase为了降低KeyValue结构性膨胀而提供的内部编码机制。
Hlog
一个HRegionServer只有一个Log文档
WAL(Write After Log)做任何操作之前先写日志
HLog文件就是一个普通的Hadoop Sequence File,SequeceFile的Key是HLogKey对象,
HLogKey中记录了写入数据的归属信息,除了table和region名字外,同时还包括 sequence
number和timestamp
timestamp是” 写入时间”,
sequence number的起始值为0,或者是最近一次存入文件系统中sequence number。
SequeceFile的Value是HBase的KeyValue对象,即本次的操作。
日志直接存放到HDFS上
当memStore达到阈值的时候开始写出到文件之后,会在日志中对应的位置标识一个检查点
WAL记录所有的Hbase数据改变,如果一个RegionServer在MemStore进行FLush的时候挂掉了,
WAL可以保证数据的改变被应用到。如果写WAL失败了,那么修改数据的完整操作就是失败的。
通常情况,每个RegionServer只有一个WAL实例。在2.0之前,WAL的实现叫做HLog
WAL位于/hbase/WALs/目录下
MultiWAL: 如果每个RegionServer只有一个WAL,由于HDFS必须是连续的,导致必须写WAL
连续的,然后出现性能问题。MultiWAL可以让RegionServer同时写多个WAL并行的,通过
HDFS底层的多管道,最终提升总的吞吐量,但是不会提升单个Region的吞吐量。
WAL的配置:
<name>hbase.wal.provider</name> <value>multiwal</value> </property>">// 启用multiwal <property> <name>hbase.wal.provider</name> <value>multiwal</value> </property>
HBase读写流程
公共流程(三层索引)
HBase中单表的数据量通常可以达到TB级或PB级,但大多数情况下数据读取可以做到毫秒级。
HBase是如何做到的呢?要想实现表中数据的快速访问,通用的做法是数据保持有序并尽可能的将
数据保存在内存里。HBase也是这样实现的。
对于海量级的数据,首先要解决存储的问题。数据存储上,HBase将表切分成小一点的数据单位
region,托管到RegionServer上,和以前关系数据库分区表类似。但比关系数据库分区、分库易
用。这一点在数据访问上,HBase对用户是透明的。数据表切分成多个Region,用户在访问数据
时,如何找到该条数据对应的region呢?
HBase 0.96以前
有两个特殊的表,-Root-和.Meta. ,用来查找各种表的region位置在哪里。-Root-和.Meta.也像
HBase中其他表一样会切分成多个region。-Root-表比.Meta更特殊一些,永远不会切分超过一个
region。-ROOT-表的region位置信息存放在Zookeeper中,通过Zookeeper可以找到-ROOTregion托管的RegionServer。通过-ROOT-表就可以找到.META.表region位置。.META表中存放着
表切分region的信息。
当客户端访问一个表的时候,首先去询问Zookepper
Zookepper会告诉客户端-root-Region所在的RegionServer
公共表.meta.
是一张普通表,但是由HBase自己维护 它的机构和meta一模一样,但是它只维护meta表的切分信息
理论上-root-表不会被切分(数据量)
HBase 0.96以后
-ROOT-表被移除,直接将.Meta表region位置信息存放在Zookeeper中。Meta表更名为
hbase:meta,部分内容如下
查询流程
zookeeper-------->hbase:meta--------->用户表region">Client--------->zookeeper-------->hbase:meta--------->用户表region
读取数据流程
01Client访问zookeeper,获取hbase:meta所在RegionServer的节点信息
02Client访问hbase:meta所在的RegionServer,获取hbase:meta记录的元数据后先加载到内存
中,然后再从内存中根据需要查询的RowKey查询出RowKey所在的Region的相关信息(Region所 在RegionServer)
03Client访问RowKey所在Region对应的RegionServer,发起数据读取请求
04RegionServer构建RegionScanner(需要查询的RowKey分布在多少个Region中就需要构建多少
个RegionScanner),用于对该Region的数据检索
05RegionScanner构建StoreScanner(Region中有多少个Store就需要构建多少个StoreScanner,
Store的数量取决于Table的ColumnFamily的数量),用于对该列族的数据检索
06多个StoreScanner合并构建最小堆(已排序的完全二叉树)StoreHeap:PriorityQueue
07StoreScanner构建一个MemStoreScanner和一个或多个StoreFileScanner(数量取决于
StoreFile数量)
08过滤掉某些能够确定所要查询的RowKey一定不在StoreFile内的对应的StoreFileScanner或
MemStoreScanner
09经过筛选后留下的Scanner开始做读取数据的准备,将对应的StoreFile定位到满足的RowKey的
起始位置
10将所有的StoreFileScanner和MemStoreScanner合并构建最小堆
KeyValueHeap:PriorityQueue,排序的规则按照KeyValue从小到大排序
11从KeyValueHeap:PriorityQueue中经过一系列筛选后一行行的得到需要查询的KeyValue。
写入数据流程
首先客户端和RegionServer建立连接
然后将DML要做的操作写入到日志wal-log
然后将数据的修改更新到memstore中,然后本次操作结束
一个region由多个store组成,一个store对应一个CF(列族),store包括位于内存中的
memstore和位于磁盘的storefile,写操作先写入memstore.
当memstore数据写到阈值之后,创建一个新的memstore
旧的memstore写成一个独立的storefile,regionserver会启动flashcache进程写入storefile,每次
写入形成单独的一个storefile,存放到hdfs
当storefile文件的数量增长到一定阈值后,系统会进行合并(minor compaction、major
compaction)
在合并过程中会进行版本合并和删除工作,形成更大的storefile
当一个region所有storefile的大小和数量超过一定阈值后,会把当前的region分割为两个,并由
hmaster分配到相应的regionserver服务器,实现负载均衡
Store负责管理当前列族的数据
1memstore+nstorefile
当我们进行数据DML的时候,以插入数据为例
我们会将数据先存储到memStore中,当memStore达到阈值(128M)
首先创建一个新的memstore
然后会将memStore中的数据写成一个storefile,storefile会存储到hdfs上(hfile)
随着时间的推移:
HFile中会存放大量的失效数据(删除,修改)
会产生多个HFile
等达到阈值(时间、数量)会进行合并
多个HFile合并成一个大的HFile
合并会触发连锁反应,相邻的store也会进行合并
在Hbase中,表被分割成多个更小的块然后分散的存储在不同的服务器上,这些小块叫做
Regions,存放Regions的地方叫做RegionServer。Master进程负责处理不同的RegionServer之间
的Region的分发。在Hbase实现中HRegionServer和HRegion类代表RegionServer和Region。
HRegionServer除了包含一些HRegions之外,还处理两种类型的文件用于数据存储
HLog 预写日志文件,也叫做WAL(write-ahead log)
HFile 是HDFS中真实存在的数据存储文件
数据刷写(MemStore Flush)
触发时机
Region 中所有 MemStore 占用的内存超过相关阈值
hbase.hregion.memstore.flush.size 参数控制,默认为128MB
如果我们的数据增加得很快,
达到了 hbase.hregion.memstore.flush.size * hbase.hregion.memstore.block.multiplier
的大小,hbase.hregion.memstore.block.multiplier 默认值为4,
也就是128*4=512MB的时候,
那么除了触发 MemStore 刷写之外,HBase 还会在刷写的时候同时阻塞所有写入该 Store 的
写请求!
整个 RegionServer 的 MemStore 占用内存总和大于相关阈值
HBase 为 RegionServer 所有的 MemStore 分配了一定的写缓存(),大小等于
hbase_heapsize(RegionServer 占用的堆内存大小)*
hbase.regionserver.global.memstore.size(默认值是 0.4)。
如果整个 RegionServer 的 MemStore 占用内存总和大于阈值将会触发 MemStore 的刷写。
hbase.regionserver.global.memstore.size.lower.limit (默认值为 0.95)* MAX_SIZE
例如:HBase 堆内存总共是 32G ,MemStore 占用内存为:32 * 0.4 * 0.95 = 12.16G将触发
刷写
如果达到了 RegionServer 级别的 Flush,当前 RegionServer 的所有写操作将会被阻塞,这
个阻塞可能会持续到分钟级别
WAL数量大于相关阈值
数据到达 Region 的时候是先写入 WAL,然后再被写到 Memstore 。如
果 WAL 的数量越来越大,这就意味着 MemStore 中未持久化到磁盘的数据越来越多。
当 RS 挂掉的时候,恢复时间将会变得很长,所以有必要在 WAL 到达一定的数量时进行一次
刷写操作
定期自动刷写
hbase.regionserver.optionalcacheflushinterval
默认值 3600000(即 1 小时),HBase 定期 Flush 所有 MemStore 的时间间隔。
一般建议调大,比如 10 小时,因为很多场景下 1 小时 Flush 一次会产生很多小文件,一方
面导致 Flush 比较频繁,另一方面导致小文件很多,影响随机读性能
数据更新超过一定阈值
如果 HBase 的某个 Region 更新的很频繁,而且既没有达到自动刷写阀值,也没有达到内存
的使用限制,但是内存中的更新数量已经足够多,
比如超过 hbase.regionserver.flush.per.changes 参数配置,默认为30000000,那么也是会
触发刷写的。
手动触发刷写
Shell 中通过执行 flush 命令
特别注意:
以上所有条件触发的刷写操作最后都会检查对应的 HStore 包含的 StoreFiles 文件数是否超过
hbase.hstore.blockingStoreFiles 参数配置的个数,默认值是16。
如果满足这个条件,那么当前刷写会被推迟到hbase.hstore.blockingWaitTime 参数设置的时
间后再刷写。
在阻塞刷写的同时,HBase 还会请求 Compaction 或者Split 操作。
刷写策略
prepareFlush 阶段:
刷写的第一步是对 MemStore 做 snapshot,
为了防止刷写过程中更新的数据同时在 snapshot 和 MemStore 中而造成后续处理的困难,
所以在刷写期间需要持有 updateLock 。持有了 updateLock 之后,这将阻塞客户端的写操
作。
所以只在创建 snapshot 期间持有 updateLock,而且 snapshot 的创建非常快,所以此锁期间对客户的影响一般非常小。
对 MemStore 做 snapshot 是 internalPrepareFlushCache 里面进行的。
flushCache 阶段:
如果创建快照没问题,
那么返回的 result.result 将为 null。
这时候我们就可以进行下一步 internalFlushCacheAndCommit。
其实 internalFlushCacheAndCommit 里面包含两个步骤:flushCache 和 commit 阶段。
flushCache 阶段:
其实就是将 prepareFlush 阶段创建好的快照写到临时文件里面,
临时文件是存放在对应 Region 文件夹下面的 .tmp 目录里面。
commit 阶段:
将 flushCache 阶段生产的临时文件移到(rename)对应的列族目录下面,
并做一些清理工作,比如删除第一步生成的 snapshot。
数据合并
合并分类
HBase 根据合并规模将 Compaction 分为了两类:MinorCompaction 和 MajorCompaction
Minor Compaction
是指选取一些小的、相邻的StoreFile将他们合并成一个更大的StoreFile,在这个过程中不会
处理已经Deleted或Expired的Cell
但是会处理超过TTL的数据
一次Minor Compaction的结果是让小的storefile变的更少并且产生更大的StoreFile。
Major Compaction
是指将所有的StoreFile合并成一个StoreFile
清理三类无意义数据:被删除的数据、TTL过期数据、版本号超过设定版本号的数据。
一般情况下,Major Compaction时间会持续比较长,整个过程会消耗大量系统资源,对上层
业务有比较大的影响。因此线上业务都会将关闭自动触发Major Compaction功能,改为手动
在业务低峰期触发
合并时机
触发compaction的方式有三种:Memstore刷盘、后台线程周期性检查、手动触发
Memstore刷盘
memstore flush会产生HFile文件,文件越来越多就需要compact。
每次执行完Flush操作之后,都会对当前Store中的文件数进行判断,一旦文件数大于配置,就
会触发compaction。
compaction都是以Store为单位进行的,而在Flush触发条件下,整个Region的所有Store都
会执行compact
后台线程周期性检查
后台线程定期触发检查是否需要执行compaction,检查周期可配置。
hbase.server.thread.wakefrequency(默认10000毫秒)
*hbase.server.compactchecker.interval.multiplier(默认1000)
CompactionChecker大概是2hrs 46mins 40sec 执行一次
线程先检查文件数是否大于配置,一旦大于就会触发compaction。
如果不满足,它会接着检查是否满足major compaction条件,
如果当前store中hfile的最早更新时间早于某个值mcTime,
就会触发major compaction(默认7天触发一次,可配置手动触发)。
手动触发
一般来讲,手动触发compaction通常是为了执行major compaction,一般有这些情况需要手
动触发合并
是因为很多业务担心自动major compaction影响读写性能,因此会选择低峰期手动触
发;
也有可能是用户在执行完alter操作之后希望立刻生效,执行手动触发major
compaction; 是HBase管理员发现硬盘容量不够的情况下手动触发major compaction删除大量过期数
据;
合并策略
承载了大量IO请求但是文件很小的HFile,compaction本身不会消耗太多IO,而且合并完成之后对读的
性能会有显著提升。
线程池选择
HBase CompacSplitThread类内部对于Split、Compaction等操作专门维护了各自所使用的
线程池
和Compaction相关的是如下的longCompactions和shortCompactions
前者用来处理大规模compaction,后者处理小规模compaction
默认值为2 * maxFlilesToCompact * hbase.hregion.memstore.flush.size
如果flush size 大小是128M,该参数默认值就是2 * 10 * 128M = 2.5G
合并策略选择
1.HBase 主要有两种 minor 策略: RatioBasedCompactionPolicy (0.96.x之前)和
ExploringCompactionPolicy(当前默认)
2.RatioBasedCompactionPolicy(基于比列的合并策略) 从老到新逐一扫描HFile文件,满足以下条件之一停止扫描 当前文件大小<比当前文件新的所有文件大小总和*ratio(高峰期1.2,非高峰期5) 当前所剩候选文件数<=阈值(默认为3) 3.ExploringCompactionPolicy策略(默认策略) 基于Ratio策略,不同之处在于Ratio策略找到一个合适文件集合就停止扫描,而Exploring策略 会记录所有合适的文件集合,然后寻找最优解,待合并文件数最多或者待合并文件数相同的情况下 文件较小的进行合并 4.FIFO Compaction策略
收集过期文件并删除,对应业务的列簇必须设置有TTL
5.Tier-Based Compaction策略(分层策略) 针对数据热点情况设计的策略,根据候选文件的新老程度将其划分为不同的等级,每个等级都有对 应的Ratio,表示该等级文件比选择为参与Compation的概率
6.Stripe Compation策略(条纹策略) 将整个Store中的文件按照key划分为多个range,此处称为stripe,一个Stripe内部就类似于 一个小Region,可以执行Minon Compation和major Compation
执行文件合并
分别读出待合并hfile文件的KV,并顺序写到位于./tmp目录下的临时文件中
将临时文件移动到对应region的数据目录
将compaction的输入文件路径和输出文件路径封装为KV写入WAL日志,并打上compaction
标记,最后强制执行sync
将对应region数据目录下的compaction输入文件全部删除
数据切分(Region Spilt)
通过切分,一个region变为两个近似相同大小的子region,再通过balance机制均衡到不同 region
server上,使系统资源使用更加均衡。
切分原因
数据分布不均匀。
同一 region server 上数据文件越来越大,读请求也会越来越多。一旦所有的请求都落在同一
个 region server 上,尤其是很多热点数据,必然会导致很严重的性能问题。
compaction性能损耗严重。
compaction本质上是一个排序合并的操作,合并操作需要占用大量内存,因此文件越大,占
用内存越多
compaction有可能需要迁移远程数据到本地进行处理(balance之后的compaction就会存在
这样的场景),如果需要迁移的数据是大文件的话,带宽资源就会损耗严重。
资源耗费严重
HBase的数据写入量也是很惊人的,每天都可能有上亿条的数据写入
不做切分的话一个热点region的新增数据量就有可能几十G,用不了多长时间大量读请求就会
把单台region server的资源耗光。
触发时机
每次数据合并之后都会针对相应region生成一个requestSplit请求,requestSplit首先会执行
checkSplit,检测file size是否达到阈值,如果超过阈值,就进行切分。
检查阈值算法主要有两种:ConstantSizeRegionSplitPolicy( 0.94版本)和
IncreasingToUpperBoundRegionSplitPolicy(当前)
ConstantSizeRegionSplitPolicy :
系统会遍历region所有store的文件大小,如果有文件大小 > hbase.hregion.max.filesize(默 认10G),就会触发切分操作。
IncreasingToUpperBoundRegionSplitPolicy:
如果store大小大于一个变化的阀值就允许split。
默认只有1个region,那么逻辑这个region的store大小超过 1 * 1 * 1 * flushsize * 2 =
128M * 2 =256M 时,才会允许split
切分之后会有两个region,其中一个region中的某个store大小大于 2 * 2 * 2 * flushsize * 2
= 2048M 时,则允许split
后续超过hbase.hregion.max.filesize + hbase.hregion.max.filesize * 随机小数 *
hbase.hregion.max.filesize.jitter才允许split
基本也就固定了,如果粗劣的计算可以把这个hbase.hregion.max.filesize的大小作为最后的
阀值,默认是10G
切分流程
寻找切分点
将一个region切分为两个近似大小的子region,首先要确定切分点。切分操作是基于region执
行的,每个region有多个store(对应多个column famliy)。系统首先会遍历所有store,找
到其中最大的一个,再在这个store中找出最大的HFile,定位这个文件中心位置对应的
rowkey,作为region的切分点。
开启切分事务
切分线程会初始化一个SplitTransaction对象,从字面上就可以看出来split流程是一个类似‘事 务’的过程,整个过程分为三个阶段:prepare - execute - rollback
prepare阶段
在内存中初始化两个子region,具体是生成两个HRegionInfo对象,包含tableName、
regionName、startkey、endkey等。同时会生成一个transaction journal,这个对象
用来记录切分的进展
execute 阶段
region server 更改ZK节点 /region-in-transition 中该region的状态为SPLITING。
master检测到region状态改变。
region在存储目录下新建临时文件夹.split保存split后的daughter region信息。
parent region关闭数据写入并触发flush操作,将写入region的数据全部持久化到磁盘。
在.split文件夹下新建两个子文件夹,称之为daughter A、daughter B,并在文件夹中生
成引用文件,分别指向父region中对应文件。
将daughter A、daughter B拷贝到HBase根目录下,形成两个新的region。
parent region通知修改 hbase.meta 表后下线,不再提供服务。
开启daughter A、daughter B两个子region。
通知修改 hbase.meta 表,正式对外提供服务。 rollback阶段
如果execute阶段出现异常,则执行rollback操作。
为了实现回滚,整个切分过程被分为很多子阶段,回滚程序会根据当前进展到哪个子阶
段清理对应的垃圾数据。
这篇关于HBase第一天学习的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!