(这是我第一次写文章,不喜勿喷)
一,hbase的整体的介绍
1,hbase的安装
hbase的安装比较简单,网上的安装方法也比较多。这里就不说了
不过要注意hbase的版本,注意和hadoop或是spark的整和
2,hbase的简单实用
增删查操作,不支持改操作(put,get,delete)
crud操作也都可以还是用批处理,基于batch方法实现的
有行锁,到那时没有用到。想了解的可以直接百度。在所有的数据库(关系型和非关系型)中,有写的锁操作,但是没有读的锁操作
scan操作,这个可以详细看一下
还有hTable,bytes类的方法。可以不了解
3,hbase的高级特性
过滤器
比较过滤器(行过滤器,列族过滤器,列名过滤器,值过滤器,参考列过滤器)
专用过滤器(单列值过滤器,单列排除过滤器,前缀过滤器,分页过滤器,行健过滤器,首次行健过滤器,包含结束的过滤器,时间戳过滤器,列计数过滤器,列分页过滤器,列前缀过滤器,随机行过滤器)
附加过滤器(跳转过滤器,全匹配过滤器)
自定义过滤器(需要自己来实现,实现Filter接口或者是记成FilterBase类)。(自己没有用过,但是看过书,没记住)(自己没有用过,但是看过书,没记住)
计数器
单计数器(可以计算自增)
多计数器(increment方法)(有锁的情况下一样来计数)
协处理器
没有用过,不熟
4,hbase的管理功能
表数据写磁盘的读写机制,文件大小,memstore刷新(在hbase权威指南200页)
提供HbaseAdmin来建表,创建列族,检查表是否存在,修改表结构,列族结构,删除表等,还有集群的hbase的使用(region的所有情况:大小,索引,列族,文件数量等等)
5,可用客户端
rest,thrift,avro连接hbase,hive也可以连接hbase,使用shell直接连接客户端
6,与mr的集成
7,架构
存储的分类表,写路径(在hbase权威指南302页),读路径(在hbase权威指南325页)
WAL机制(在hbase权威指南316页)
region的查找(在hbase权威指南328页)
与zk的关系,与zk的一起使用
8,高级用法
行健(RowKey)的设计
辅助索引(自己没有用过,但是看过书,没记住)
搜索集成(自己没有用过,但是看过书,没记住)
9,集群监控
我现在使用的是cdh的监控
GangLia也可以监控整个集群
10,性能优化
垃圾回收优化
本地memstore分配缓冲区
压缩
对region的拆分和合并(region的热点),预拆分region
负载均衡
11,集群管理
增加,减少节点
数据的导入导出
二,hbase的主要难点,重点
1,WAL机制
HBase的Write Ahead Log (WAL)提供了一种高并发、持久化的日志保存与回放机制。每一个业务数据的写入操作(PUT / DELETE)执行前,都会记账在WAL中。
如果出现HBase服务器宕机,则可以从WAL中回放执行之前没有完成的操作。
1. 由于多个HBase客户端可以对某一台HBase Region Server发起并发的业务数据写入请求,因此WAL也要支持并发的多线程日志写入。——确保日志写入的线程安全、高并发。
2. 对于单个HBase客户端,它在WAL中的日志顺序,应该与这个客户端发起的业务数据写入请求的顺序一致。
(对于以上两点要求,大家很容易想到,用一个队列就搞定了。见下文的架构图。)
3. 为了保证高可靠,日志不仅要写入文件系统的内存缓存,而且应该尽快、强制刷到磁盘上(即WAL的Sync操作)。但是Sync太频繁,性能会变差。所以:
(1) Sync应当在多个后台线程中异步执行
(2) 频繁的多个Sync,可以合并为一次Sync——适当放松对可靠性的要求,提高性能。
2,读写数据的刷新
读请求过程
客户端通过zookeeper以及root表和meta表找到目标数据所在的regionserver
联系regionserver查询目标数据
regionserver定位到目标数据所在的region,发出查询请求
region先在memstore中查找,命中则返回
如果在memstore中找不到,则在storefile中扫描
写请求过程:
client向region server提交写请求
region server找到目标region
region检查数据是否与schema一致
如果客户端没有指定版本,则获取当前系统时间作为数据版本
将更新写入WAL log
将更新写入Memstore
判断Memstore的是否需要flush为StoreFile文件。
细节描述:
hbase使用MemStore和StoreFile存储对表的更新。
数据在更新时首先写入Log(WAL log)和内存(MemStore)中,MemStore中的数据是排序的,当MemStore累计到一定阈值时,就会创建一个新的MemStore,并且将老的MemStore添加到flush队列,由单独的线程flush到磁盘上,成为一个StoreFile。于此同时,系统会在zookeeper中记录一个redo point,表示这个时刻之前的变更已经持久化了。
当系统出现意外时,可能导致内存(MemStore)中的数据丢失,此时使用Log(WAL log)来恢复checkpoint之后的数据。
StoreFile是只读的,一旦创建后就不可以再修改。因此Hbase的更新其实是不断追加的操作。当一个Store中的StoreFile达到一定的阈值后,就会进行一次合并(minor_compact, major_compact),将对同一个key的修改合并到一起,形成一个大的StoreFile,当StoreFile的大小达到一定阈值后,又会对 StoreFile进行split,等分为两个StoreFile。
由于对表的更新是不断追加的,compact时,需要访问Store中全部的 StoreFile和MemStore,将他们按row key进行合并,由于StoreFile和MemStore都是经过排序的,并且StoreFile带有内存中索引,合并的过程还是比较快。
3,region的拆分,预分区
Region的大小是一个棘手的问题,需要考量如下几个因素。
Region是HBase中分布式存储和负载均衡的最小单元。不同Region分布到不同RegionServer上,但并不是存储的最小单元。
Region由一个或者多个Store组成,每个store保存一个columns family,每个Strore又由一个memStore和0至多个StoreFile 组成。memStore存储在内存中, StoreFile存储在HDFS上。
HBase通过将region切分在许多机器上实现分布式。也就是说,你如果有20GB的数据,只分了4个region, 你却有10台机器,有6台就浪费了。
region数目太多就会造成性能下降,现在比以前好多了。但是对于同样大小的数据,700个region比3000个要好。
region数目太少就会妨碍可扩展性,降低并行能力。有的时候导致压力不够分散。这就是为什么,你向一个10节点的HBase集群导入200MB的数据,大部分的节点是idle的。
RegionServer中1个region和10个region索引需要的内存量没有太多的差别。
Region的分割操作是不可见的,因为Master不会参与其中。RegionServer拆分region的步骤是,先将该region下线,然后拆分,将其子region加入到META元信息中,再将他们加入到原本的RegionServer中,最后汇报Master。
在HBase中,表会被划分为1...n个Region,被托管在RegionServer中。Region二个重要的属性:StartKey与EndKey表示这个Region维护的rowKey范围,当我们要读/写数据时,如果rowKey落在某个start-end key范围内,那么就会定位到目标region并且读/写到相关的数据。
1、由于业务数据一般都是从小到大增长的,根据上面hbase的region规则,就会出现“热点写”问题,随着系统的运营,数据总是会往最大的start-key所在的region里写,因为我们的rowkey总是会比之前的大,并且hbase的是按升序方式排序的。所以写操作总是被定位到无上界的那个region中。
2、其次,由于写热点,我们总是往最大start-key的region写记录,之前分裂出来的region不会再被写数据,有点被打进冷宫的赶脚,它们都处于半满状态,这样的分布也是不利的。
如果在写比较频率的场景下,数据增长快,split的次数也会增多,由于split是比较耗时耗资源的,所以我们并不希望这种事情经常发生。
看到这些缺点,我们知道,在集群的环境中,为了得到更好的并行性,我们希望有好的load blance,让每个节点提供的请求处理都是均等的。我们也希望,region不要经常split,因为split会使server有一段时间的停顿,如何能做到呢?
随机散列与预分区
随机散列与预分区:二者结合起来,是比较完美的,预分区一开始就预建好了一部分region,这些region都维护着自已的start-end keys,再配合上随机散列,写数据能均等地命中这些预建的region,就能解决上面的那些缺点,大大地提高了性能。
加盐,也就是说给rowkey加一个新的前缀,常见手段为rowkey值或者随机值 mod region数量(region数量固定不再autosplit),scan时需要从每个region中分别进行一次并归并,region按照前缀预分;
region的预分区之后,自己后面生成的rowkey还会和region分区的时候一模一样吗?还是只需要前缀一样就可以了。需要做一个测试
预分区的rowkey,只要在后面生成的rowkey规则和预分区设计的一样就可以了
如果我生成的 rowkey=0002rer4343343422,则当前这条数据就会保存到0001|~0002|这个region里
4,hbase的热点问题/数据倾斜问题
出现热点问题原因
1、hbase的中的数据是按照字典序排序的,当大量连续的rowkey集中写在个别的region,各个region之间数据分布不均衡;
2、创建表时没有提前预分区,创建的表默认只有一个region,大量的数据写入当前region;
3、创建表已经提前预分区,但是设计的rowkey没有规律可循,设计的rowkey应该由regionNo+messageId组成。
只有一个regionserver,然后所有的rowkey都往该region里面写数据。最后regionserver就会承受不了压力。就会出现单点故障,热点问题。
数据倾斜:Hbase可以被划分为多个Region,但是默认创建时只有一个Region分布在集群的一个节点上,数据一开始时都集中在这个Region,也就是集中在这一个节点上,就算region存储达到临界值时被划分,数据也是存储在少数节点上。这就是数据倾斜。
Hbase常见避免热点问题的方法(*****)
加盐
哈希
反转
时间戳反转
5,rowkey设计原则
rowkey唯一原则
必须在设计上保证其唯一性,rowkey是按照二进制字节数组排序存储的,因此,设计rowkey的时候,要充分利用这个排序的特点,将经常读取的数据存储到一块,将最近可能会被访问的数据放到一块。所以设计rwo key时尽量把体现业务特征的信息、业务上有唯一性的信息编进row key。
rowkey长度原则
rowkey是一个二进制码流,可以是任意字符串,最大长度 64kb ,实际应用中一般为10-100byte,以byte[] 形式保存,一般设计成定长。建议越短越好,不要超过16个字节,2个原因:
原因1:数据的持久化文件HFile中是按照(Key,Value)存储的,如果rowkey过长,例如超过100byte,那么1000万行的记录计算,仅row key就需占用100*1000万=10亿byte,近1Gb。这样会极大影响HFile的存储效率!
原因2:MemStore将缓存部分数据到内存,若 rowkey字段过长,内存的有效利用率就会降低,就不能缓存更多的数据,从而降低检索效率。
目前操作系统都是64位系统,内存8字节对齐,控制在16个字节,8字节的整数倍利用了操作系统的最佳特性。
rowkey散列原则
如果rowkey按照时间戳的方式递增,不要将时间放在二进制码的前面,建议将rowkey的高位作为散列字段,由程序随机生成,低位放时间字段,这样将提高数据均衡分布在每个RegionServer,以实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息,所有的数据都会集中在一个RegionServer上,这样在数据检索的时候负载会集中在个别的RegionServer上,造成热点问题,会降低查询效率。
hbase的RowKey的总结
1、尽量减少行和列的大小
2、列簇尽可能越短越好,最好是一个字符
3、冗长的属性名虽然可读性好,但是更短的属性存储在HBase中会更好
对于上面的内容有不同意见的可以下面评论或是加好友私聊
网友评论