共计 4240 个字符,预计需要花费 11 分钟才能阅读完成。
HBase 架构
Region-Store-ColumnFmily
的关系
逻辑分层:<font color=red>HRegion 由一个或者多个 Store 组成 </font>
Table (HBase table)
Region (Regions for the table)
Store (Store per ColumnFamily for each Region for the table)
MemStore (MemStore for each Store for each Region for the table)
StoreFile (StoreFiles for each Store for each Region for the table)
Block (Blocks within a StoreFile within a Store for each Region for the table)
物理分层:<font color=red> 每个 store 保留一个 columns family</font>
一、写操作
1、Client
写入 ->
存入 MemStore
,始终到 MemStore 满 ->
Flush
成一个 StoreFile
2、StoreFile
文件数量增长到肯定阈值 ->
触发 Compact
合并操作 ->
多个 StoreFile 合并成一个 StoreFile,同时进行 版本合并和数据删除
3、当 StoreFiles Compact
后,逐步形成越来越大的 StoreFile
->
单个 StoreFile
大小超过肯定阈值后,触发 Split
操作,把以后 Region Split
成 2 个 Region
,原来的 Region
会下线,新 Split
出的 2 个 子Region
会被 HMaster
调配到相应的 HRegionServer
上(负载平衡),使得原先 1 个 Region
的压力得以分流到 2 个 Region
上
由此过程可知,HBase
只是减少数据,有所得更新和删除操作,都是在 Compact 阶段做的,所以,用户写操作只须要进入到内存即可立刻返回,从而保障 I / O 高性能。
二、读操作
client->zookeeper->.ROOT->.META->
用户数据表 zookeeper 记录了.ROOT 的门路信息(root 只有一个 region),.ROOT 里记录了.META 的 region 信息,(.META 可能有多个 region),.META 外面记录了 region 的信息。
在 HBase 中,所有的存储文件都被划分成了若干个小存储块(block
),这些小存储块在 get
或 scan
操作时会加载到内存中,他们相似于 RDBMS
中的存储单元页。这个参数的默认大小是 64K。通过以下形式设置:void setBlocksize(int s);
(留神:HBase 中 Hfile 的默认大小就是 64K 跟 HDFS 的块是 64M 没关系)
HBase
程序地读取 一个数据块到内存缓存中,其读取相邻的数据时就能够在内存中读取而不须要从磁盘中再次读取,无效地缩小了磁盘 I / O 的次数。
void setBlockCacheEnabled(boolean blockCacheEnable);
这个参数默认为 TRUE,这意味着每次读取的块都会缓存到内存中。
然而,如果用户程序读取某个特定的列族,最好将这个属性设置为 FALSE,从而禁止应用缓存快。
下面这样形容的起因:如果咱们拜访特定的列族,然而咱们还是启用了这个性能,这个时候咱们的机制会把咱们其它不须要的列族的数据也加载到了内存中,减少了咱们的累赘,咱们应用的条件是,咱们获取相邻数据。
三、优化
1、禁止主动刷写
咱们有少量数据要插入时,如果咱们没有禁止,Put
实例会被一一的传送到 region
服务器,如果用户禁止了主动刷写的性能,put
操作会在写缓冲区被填满时才会被送出。
2、应用扫描缓存
如果HBase
被用作一个 mapreduce
作业的输出源,请最好将作为 mapreduce
作业输出扫描器实例的缓存用 setCaching()
办法设置为比默认值 1 更大的数。应用默认值意味着 map
工作会在解决每条记录时都申请 region
服务器。不过,这个值要是 500 的话,则一次可传送 500 条数据到客户端进行解决,当然了这数据也是依据你的状况定的。这个是行级的。
3、限定扫描范畴
这个是很好了解的,比方咱们要解决大量行(特地是作为mapreduce
的输出源),其中用到 scan 的时候咱们有 Scan.addFamily()
的办法,这个时候咱们如果只是须要到这个列族中的几个列,那么咱们肯定要准确。因为过多的列会导致效率的损失。
4、敞开resultScanner
当然了这个不能进步咱们的效率,然而如果没关就会对效率有影响。
5、块缓存的用法
首先咱们的块缓存是通过Scan.setCacheBolcks()
的启动的,那些被频繁拜访的行咱们应该应用缓存块,然而 mapreduce
作业应用扫描大量的行,咱们就不该应用这个了。
6、优化获取 rowkey
的形式
当然用这个的前提是,咱们只须要表中的rowkey
时,能力用。
7、敞开 Put
上的 WAL
书上是这么说,然而我集体感觉这个性能还是不必的好,因为咱们敞开了这个性能,服务器就不会把put
写入到 WAL
,而是间接写到memstore
里,这样一旦服务器呈现故障,咱们的数据就失落了。
8、压缩
hbase 反对大量的算法,并且反对列族级别以上的压缩算法,除非有非凡起因,不然咱们应该尽量应用压缩,压缩通常会带来较好的 性能。通过一些测试,咱们举荐应用 SNAPPY 这种算法来进行咱们 hbase 的压缩
四、HLog
的性能
在分布式系统环境中,无奈防止零碎出错或者宕机,一旦 HRegionServer
意外退出,MemStore 中的内存数据就会失落 ,引入HLog
就是避免这种状况。
工作机制:每个 HRegionServer
中都会有一个 HLog
对象,HLog
是一个实现 Write Ahead Log
的类,每次用户操作写入 Memstore
的同时,也会写一份数据到 HLog
文件,HLog
文件 定期会滚动出新 ,并删除旧的文件(已长久化到 StoreFile
中的数据)。当 HRegionServer
意外终止后,HMaster
会通过 Zookeeper
感知,HMaster
首先解决遗留的 HLog
文件,将不同 region
的log
数据拆分,别离放到相应 region
目录下,而后再将生效的 region
(带有刚刚拆分的log
)重新分配,支付到这些region
的 HRegionServer
在 Load Region
的过程中,会发现有历史 HLog
须要解决,因而会 Replay HLog
中的数据到 MemStore
中,而后 flush
到StoreFiles
,实现数据恢复。
五、Hbase
存储架构及 Rowkey
设计的思考
Region
就是 StoreFiles
,StoreFiles
里由 HFile
形成,HFile
里由 hbase
的data
块形成,一个 data 块外面又有很多 keyvalue
对,每个 keyvalue
里存了咱们须要的值。
从上图能够发现 一张表 有两个 列族(红颜色的一个,黄色彩的一个)一个列族有两个列
从图中能够看出,这就是列式数据库的最大特点:同一个列族的数据在在一起的 ,咱们还发现如果是有 多个版本 。最初咱们还发现外面存了这样的值 r1: rowkey,cf1:column Family,c1:qualiter(列),t1:versionId(版本号),value 值
(最初一幅图阐明的是 value 值能够寄存的地位)。通过这样的认识,咱们发现如果咱们设计表的时候把这几个货色:r1: rowkey,cf1:column Family,c1:qualiter(列)
的 名字取短 一点是不是会 节俭存储空间!
倒数第二张图,字段筛选的效率从左到右显著降落 ,所以在keyvalue
的设计时用户能够思考把一些重要的筛选信息左移到适合的地位,从而在不扭转数 据量的状况下,进步查问性能。那么简略的说就是用户该当尽量把查问维度或信息存储在行健中,因为它筛选数据的效率最高。
失去下面的意识后,咱们应该还要会有这样的觉醒:
HBase
的数据会被 程序的存储到一个特定的范畴 (Region
依据 Rowkey
切分),因而会始终存到同一 Region
上,因为一个 Region
只能由一个 RegionServer
治理,这样咱们老是增加到同一个 Region
上,<font color=red>会造成读写热点 </font>,从而使集群性能降落。
解决办法:也是就是 Rowkey
的设计
Rowkey 散列
: 比方咱们 有 9 台服务器,那么咱们就回去以后工夫,而后 模 9 或者取反 ,加到Rowkey
前缀,这样就会被均匀的分到不同的 region 服务器上了,这样带来的益处是,因为相连的数据 都散布到不同的服务器上了,用户能够多线程并行的读取数据,这样查问的吞吐量会进步。
六、写缓存
小数据量的操作 :每 一个put
的操作实际上是 RPC
的操作,它将客户端的数据传送到服务器而后返回;
大数据量的操作 :如果有个应用程序须要每秒存储上千行数据到 HBase
表中,PUT
解决就不太适合了。HBase API
装备了一个客户端的 写缓冲区。
- 缓冲区 负责收集
put
操作,而后调用RPC
操作 一次性 将put list
送往服务器。默认状况下,客户端缓冲区是禁止的。能够通过主动刷写设置为FALSE
来激活缓冲区。
// 能够通过主动刷写设置为 FALSE 来激活缓冲区,禁止主动刷写
table.setAutoFlush(false);
// 这个办法是强制将数据写到服务器
void flushCommits () throws IOException
// 用户还能够依据上面的办法来配置客户端写缓冲区的大小,默认大小是 2MB
void setWritaeBufferSize(long writeBufferSize) throws IOException;
- 写缓冲区的大小,默认大小是 2MB,这个也是适中的,个别用户插入的数据不大,不过如果你插入的数据大的话,可能要思考增大这个值。从而容许客户端更高效地肯定数量的数据组成一组通 过一次
RPC
申请来执行。 - 给每个用户的
HTable
设置一个写缓冲区也是一件麻烦的事,为了防止麻烦,用户能够在Hbase-site.xml
中给用户设置一个较大的预设值。
<property>
<name>hbase.client.write.buffer</name>
<value>20971520</value>
</property>
关注我的公众号【宝哥大数据】,更多干货