第六章目录
第六章HBASE
Hbase是一个分布式、大容量存储和快速响应的非关系数据库。
6.1 Hbase原理
6.1.1元表和根表
版本低于0.96的三层架构
元表的行键由表名、开始键和时间戳组成。如果开始键为空,则表示第一个区域。按开始键排序使行键能够表示没有结束键的范围。
该值是结束键、列族、列值、区域服务器的地址等。
由于数据量大,元表可能被多个RS分割存储,因此根表被设置为存储元表中的所有区域,以及这些区域所属的元表的位置。
因此,三层架构需要三次跳转才能获得HRegion,如果缓存失败,则需要六次。理论上,三层架构至少可以存储2ZB的数据。
0.96版或更高版本的双层架构
三层架构使hbase能够存储至少2ZB的数据。其实完全不需要这么多,所以删除根表,只使用元表定位。元表的一个区域可以定位高达16TB的行键范围。假设一个行键范围包含10条数据,那么它已经是160TB了。如果一个区域大于128M,会更多,所以根本不需要根表。
6.1.2写入数据
从客户端zk获取元表的位置,从对应的regionServer获取表,或者直接从缓存中读取表。
客户端从元表中获取要写入的数据存储的区域和它所在的区域服务器。
设置客户端的数据版本(默认当前时间),将日志数据写入regionServer的hlog,同时将数据写入regionServer的memstore。memstore溢出到磁盘。当溢出的小文件数量达到阈值时,它将被合并到storefileregion中。当音量达到阈值时,它将被分成两个区域,Hmaster将负责平衡负载。拆分规则是保留连续的行键,根据前缀判断。
写原子性
写操作必须确保在返回成功之前Hlog和memstore都被成功写入,并且读写行锁用于确保在行写期间其他读写请求将阻止等待。
6.1.3读取数据
从客户端zk获取元表的位置,从对应的regionServer获取表,或者直接从缓存中读取表。
从客户端元表中获取行键所在区域的位置。
首先从memstore读取,然后从blockcache读取,最后在hfile中查找。在查找hfile之前,使用Bloom过滤器过滤掉可能有该行关键字的hfile,从hfile读取的数据将被复制到blockcache。
6.1.4合并数据
最小紧凑
当文件数量达到一定阈值时,会触发min compact将多个storefile合并为一个,这是一个不删除数据的简单合并。
主要契约
默认情况下,每7天执行一次。多个storefile合并时,所有过期、超过版本号、标记为删除的数据都会被删除(一般应该在系统空闲时进行,因为需要大量的磁盘IO),通常会设置手动执行。
6.1.5删除数据
Hbase可以指定要删除的行键的列版本、列、列族和整行。
删除不是立即删除,而是插入一条新数据,并将该行标记为已删除。当执行major_compact时,数据会被一个一个遍历,被删除的数据会被真正删除。
6.1.6主机的功能
1.负责元表2的维护。将区域分配给hregionserver,并通过负载平衡重新分配区域3。当发现一个失败的regionserver 4时,在此节点上重新分发区域。处理模式更新请求。
6 . 1 . 7 hregionserver的作用
1.维护分配的区域并处理这些区域的io请求2。负责分割达到阈值3的区域。每个RegionServer都有自己的Hlog。
6.2 HBASE热点问题
6.2.1原则
hdfs中hbase的路径结构如下:命名空间/表名/区域名/列族名/文件名。
从这条路径中,我们可以看到每个表将被分成多个区域。事实上,这些区域将平均分布到多个节点。如果大量请求在某个时间点落在单个区域,会增加节点的负担,严重时甚至会造成崩溃。
Region根据rowkey将表划分为固定的大小,当范围内的数据达到阈值时会生成一个新的区域,所以hbase的热点问题也可以说是row key的热点问题。
6.2.2 解决方案
rowkey按照字典顺序从左到右逐字节排序,因此解决热点问题的方法就有三种:
加前缀:按照ASCII码一个前缀最多能有128种字节,可以根据业务需求限制随机范围,128种前缀对应128个节点随机分配,一般生产环境已经足够使用。
hash变换:将行键按照固定规则进行转换,同一个行键会被转换为同一个哈希值,这样做可以避开业务行键常见的前缀大量相同的问题。
行键反转:反转行键使变化幅度最大的业务键尾做键首,对行键连续性要求不高时可以使用(反转后行键整个都变了,失去有序性)。
6.3 Hbase 高可用(宕机恢复)
HMaster通过zk保持对外单服务,HReigionServer则通过Hlog保证以外宕机时内存数据丢失恢复。
HRegionServer意外宕机时,HMaster首先把原本分配给该节点的region(存储在hdfs上的文件都会有备份)分配给其它节点,然后尝试读取宕机节点的Hlog,将数据写入region。
读取日志进行恢复的机制随版本不断变化,一开始是性能最低的LogSplitting机制,后来采用Distributed Log Splitting机制,最后是Distributed Log Replay机制。
6.4 Hbase 优化
6.4.1 行键
唯一原则、长度原则、散列原则
长度尽量小,因为列式存储导致每行都必带行键,控制在byte的整数倍,因为是二进制存储
行键连续性:hbase按照字典顺序将连续的行键存储在一个region中,因此应该将经常同批访问的数据放到一起,将不同批访问的热点数据分开来存储。
6.4.2 列族
长度尽量小,最好单字节。因为列式存储必带列族名
数量尽量少,控制在2个以内。因为hbase按region拆表,而region按列族把列拆成多个store,当region整体达到阀值时会拆分region,因此当两个列族数据大小差距悬殊时会导致数据量很小的列族数据也被迫参与拆分,该列族数据分散太多。最终查询该列族数据时,不得不请求多个region。
6.4.3 协处理器 Coprocessor
hbase0.92版本之后支持协处理器,可以为表埋钩子代码,当条件符合时自动触发钩子,大幅降低用户端的维护难度。
如:可以利用协处理器建立hbase的二级索引
创建一个类继承观察者类,重写其中的preput方法,在插入数据到本表前会先执行该方法,自定义地将数据插入到索引表。
打包上传到hdfs上,用hbase shell命令加载该协处理器到表中。
6.4.4 预分区
提前划分region,避免单节点region一次性写入大量数据频繁分裂
6.4.5 其它优化
关闭自动刷写:HTable.setAutoFlushTo(false)
增加写入缓存:HTable.setWriteBufferSize(writeBufferSize)
不使用WAL:Put.setWriteToWAL(false)
压缩传输:hcd.setCompressionType(Algorithm.SNAPPY)
设置最大版本数:HColumnDescriptor.setMaxVersions(int maxVersions)
设置生命周期:HColumnDescriptor.setTimeToLive(int timeToLive)
6.4.6 phoenix
Phoenix是一个HBase的开源SQL引擎,它使开发者可以像访问普通数据库那样使用jdbc访问HBase
优缺点
优点
支持SQL查询hbase,自动转换SQL为最佳并行scan语句
将where子句交给过滤器处理,将聚合查询交给协处理器处理
支持直接创建二级索引来提升非主键的查询性能
跳过扫描过滤器来优化IN、Like、OR查询
优化写操作
缺点
不支持事务、不支持复杂查询
严格的版本限制,每个phoenix对应一个版本hbase
与hbase强相关,可能导致元数据被破坏
性能
使用where子句时,phoenix几乎是即时返回,普通的hive on hbase则需要等待一段时间;不使用where子句时,hive的延迟约是phoenix的3-40倍;进行聚合计算时,性能远超Impala(CDH提供的hdfs查询引擎),约为30-70倍。
6.5 Hbase和传统数据库的区别
hbase是海量数据的分布式存储,响应时间为秒级,列式存储,二进制行键。
hbase最大的优势就是存储TB级别的数据量时增删改查速度几乎不变,而传统数据库则会随着数据量增加,性能成倍地下降。
hbase只有string类型
hbase只支持增删改查,没有join和子查询
hbase元数据区分大小写