平台HBase学习总结
Posted PPV课数据科学社区
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了平台HBase学习总结相关的知识,希望对你有一定的参考价值。
图1 登录HBase官网的页面
图2 下载链接
1.解压安装包
执行“tar -zxvf hbase-1.0.1-bin.tar.gz”命令解压安装包,得到“hbase-1.0.1”。转到该目录下,可以看到有如下文件及目录:
要想让HBase成功运行,还需要在Linux机器上部署jdk,并设置java环境。为了支持最新的HBase版本,建议部署的jdk的版本在1.7.0以上。
将“jdk1.7.0-linux.tar.gz”上传到“/usr/java”目录下,运行“tar -zxvf jdk1.7.0-linux.tar.gz”命令,得到“/usr/java/jdk1.7.0”目录下的内容。
接下来需要在root用户(安装HBase的用户)下设置java环境。在root用户下执行“vi .bash_profile”命名,并将以下命令拷贝到该文件中:
转到“/root/zhouzx/hbase-1.0.1/bin”目录下,执行“sh start-hbase.sh”或“./start-hbase.sh”命令启动HBase。如果出现以下内容:
接着,执行“sh stop-hbase.sh”或“./stop-hbase.sh”命令停止HBase。如果出现以下内容:
第一,它是一种稀疏的、分布式的、持久化的、多维有序映射,它基于行键(row key)、列键(column key)和时间戳(timestamp)建立索引。
第二,它是一种键值(key value)存储,面向列族的数据库,有时也是一种存储多时间戳版本映射的数据库。
以上两种描述都是对的。但从根本上来说,HBase是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,是一个可以随机访问的存储和检索数据的平台。大家可以按照需要写入数据,然后再按照需要读取数据。
第一,它不介意数据类型,允许动态的、灵活的数据模型,并不限制存储的数据的种类。因此,它可以自如地存储结构化和半结构化的数据。
第二,它不用SQL语言,也不强调数据之间的关系。
第三,它不允许跨行的事务,可以在一行的某一列存储一个整数,而在另一行的同一列存储字符串。
第四,它被设计成在一个服务器集群上运行,而不是单台服务器。这意味着一种强大的、可扩展的数据的使用方式。
从HBase的特点可以看出,HBase的设计与目标都与传统的关系型数据库不同。
转到HBase解压包的“bin”目录下,使用命令“./hbase shell”或“sh hbase shell”命令即可启动HBase Shell。启动之后的信息如下:
表创建好之后,就需要写入一些数据。例如,我们想往表里写入“hello hbase”,那么我们就在“mytable”表的“first”行中的“cf:info”列对应的数据单元中插入“hello hbase”。命令执行如下:
HBase有两种方式读取数据:get和scan。get方式可以读取一行的数据信息,scan方式可以读取表中所有行的数据信息。
get命令执行如下:
要想删除一张表,需要先将其“disable”掉,然后再“drop”掉。命令执行如下:
(1)表(table):HBase用表来组织数据。表名是字符串(String),由可以在文件系统路径里使用的字符组成。
(2)行(row):在表里,数据按行存储。行由行键(rowkey)唯一标识。行键没有数据类型,总是视为字节数组byte 。
(3)列族(column family):行里的数据按照列族分组,列族也影响到HBase数据的物理存放,因此,它们必须事前定义并且不轻易修改。表中每行拥有相同列族,尽管行不需要在每个列族里存储数据。列族名字是字符串(String),由可以在文件系统路径里使用的字符组成。
(4)列限定符(column qualifier):列族里的数据通过列限定符或列来定位。列限定符不必事前定义,列限定符不必在不同行之间保持一致。就像行键一样,列限定符没有数据类型,总是视为字节数组byte 。
(5)单元(cell):行键、列族和列限定符一起确定一个单元。存储在单元里的数据称为单元值(value)。值也没有数据类型,总是视为字节数组byte 。
(6)时间版本(version):单元值有时间版本。时间版本用时间戳标识,是一个long。没有指定时间版本时,当前时间戳作为操作的基础。HBase保留单元值时间版本的数量基于列族进行配置,默认数量是3个。
HBase的每个数据值使用坐标来访问。一个值的完整坐标包括行键、列族、列限定符和时间版本。由于把所有坐标视为一个整体,因此HBase可以看作是一个键值(key-value)数据库。
(1)表名是“mytable”。
(2)行是“first”、“second”和“third”。
(3)列族是“cf”。
(4)列限定符是“info”、“name”和“nation”。
(5)单元值是“hello hbase”、“zhou”和“China”。
(6)时间戳是“1435548279711”、“1435548751549”和“1435548760826”。
在HBase中无论是增加新行还是修改已有的行,其内部流程都是相同的。默认情况下,执行写入时会写到两个地方:预写式日志(write-ahead log,WAL,也称HLog)和MemStore。HBase的默认方式是将写入动作记录在这两个地方,以保证数据持久化。只有当这两个地方的变化信息都写入并确认之后,才认为写动作完成。写入过程如图1所示。
图1 HBase同时向WAL和MemStore执行写入
MemStore是内存里的写入缓冲区,HBase中数据在永久写入磁盘之前在这里积累。当MemStore填满之后,其中的数据会刷写到硬盘,生成一个HFile。HFile是HBase使用的底层存储格式。HFile对应于列族,一个列族可以有多个HFile,但一个HFile不能存储多个列族的数据。在集群的每个节点上,每个列族有一个MemStore。MemStore生成HFile的过程如图2所示。
图2 MemStore生成HFile
如果HBase服务器宕机,没有从MemStore里刷写到HFile的数据将可以通过回放WAL来恢复。你不需要手工执行。HBase的内部机制中有恢复流程部分来处理。每台HBase服务器有一个WAL,这台服务器上的所有表(和它们的列族)共享这个WAL。
值得注意的是,不写入WAL会在RegionServer故障时增加丢失数据的风险。关闭WAL,出现故障时HBase可能无法恢复数据,没有刷写到硬盘的所有写入数据都会丢失。
如果想快速访问数据,通用的原则是数据保持有序并尽可能保存在内存里。HBase实现了这两个目标,大多数情况下读操作可以做到毫秒级。HBase读动作必须重新衔接持久化到硬盘上的HFile和内存中MemStore里的数据。HBase在读操作上使用了LRU(最近最少使用算法)缓存技术。这种缓存也叫做BlockCache,和MemStore在一个JVM堆里。BlockCache设计用来保存从HFile里读入内存的频繁访问的数据,避免硬盘读。每个列族都有自己的BlockCache。
掌握BlockCache是优化HBase性能的一个重要组成部分。BlockCache中的Block是HBase从硬盘完成一次读取的数据单位。HFile物理存放形式是一个Block的序列外加这些Block的索引。这意味着,从HBase里读取一个Block需要先在索引上查找一次该Block,然后从硬盘读出。Block是建立索引的最小数据单位,也是从硬盘读取的最小数据单位。Block大小按照列族设定,默认值是64KB。根据使用场景你可能会调大或者调小该值。Block变小会导致索引变大,进而消耗更多内存;Block变大意味着索引项变少,索引变小,因此节省内存。
从HBase中读出一行,首先会检查MemStore等待修改的队列,然后检查BlockCache看包含该行的Block是否最近被访问过,最后访问硬盘上的对应HFile。整个读入过程如图3所示。
图3 HBase读入过程
删除命令并不是立即删除内容,它只是给记录打上了删除的标记。就是说,针对那个内容的一条“墓碑”(tombstone)记录写入进来,作为删除的标记。墓碑记录用来标志删除的内容不能在get和scan命令中返回结果。因为HFile文件是不能改变的,直到执行一次大合并,这些墓碑记录才会被处理,被删除记录占用的空间才会被释放。
合并分为两种:大合并(major compaction)和小合并(minor compaction)。两种将会重整存储在HFile里的数据。小合并把多个小HFile合并生成一个大HFile。因为读出一条完整的行可能引用很多文件,限制HFile的数量对于读性能很重要。执行合并时,HBase读出已有的多个HFile的内容,把记录写入一个新文件。然后,把新文件设置为激活状态,删除构成这个新文件的所有老文件。HBase根据文件的号码和大小决定合并哪些文件。小合并设计出发点是轻微影响HBase的性能,所以涉及的HFile的数量有上限。这些都可以设置。小合并的示意如图4所示。
图4 小合并的示意图
图1 多个小一点的region组成一张表
图2 RegionServer和DataNode典型情况下并列配置在同一台主机上
图3 RegionServer托管region的示意图
HBase中有两个特殊的表,-ROOT-和.META.,用来查找各种表的region位置在哪里。-ROOT-和.META.也会切分成region,其中,-ROOT-永远不会切分超过一个region,.META.和其他表一样可以按需切分成许多region。
当客户端应用要访问某行时,它先找-ROOT-表,查找什么地方可以找到负责某行的region。-ROOT-指向.META.表的region去寻找答案。.META.表由入口地址组成,客户端应用使用这个入口地址判断哪一个RegionServer托管待查找的region。这个查找过程就像是一个3层分布式B+树(如图4所示),-ROOT-表是B+树的-ROOT-节点,.META. region是-ROOT-节点的叶子,用户表的region是.META. region的叶子。
图4 -ROOT-、.META.和用户表的B+树视图
图5 HBase中的表分布在各个RegionServer上
客户端与HBase系统的交互分几个步骤,ZooKeeper是入口点。整个交互过程如图6所示。
图6 客户端与HBase系统的交互过程
第一步:客户端询问ZooKeeper,-ROOT-在哪里?
第二步:ZooKeeper回复客户端,-ROOT-在RegionServer RS1上面。
第三步:客户端询问在RS1上的-ROOT-表,哪一个.META. region可以找到表T1里的行00007?
第四步:RS1上的-ROOT-表回复客户端,在RegionServer RS3上的.META. region M2可以找到。
第五步:客户端询问RS3上的.META. region M2,在哪一个region上可以找到表T1里的行00007以及哪一个RegionServer为它提供服务?
第六步:RS3上的.META. region M2回复客户端,数据在RegionServer RS3上面的region T1R3上。
第七步:客户端发消息给RS3上面的region T1R3,要求读取行00007。
第八步:RS3上面的region T1R3将数据返回给客户端。
(1)这个表应该有多少个列族?
(2)列族使用什么数据?
(3)每个列族应该有多少列?
(4)列名应该是什么?(尽管列名不必在建表时定义,但是读写数据时是需要知道的。)
(5)单元存放什么数据?
(6)每个单元存储多少个时间版本?
(7)行键结构是什么?应该包括什么信息?
1.问题建模
一个特定列族的所有数据在HDFS上会有一个物理存储。这个物理存储可能由多个HFile组成,理想情况下可以通过合并得到一个HFile。一个列族的所有列在硬盘上存放在一起,使用这个特性可以把不同访问模式的列放在不同列族,以便隔离它们。这也是HBase被称为面向列族的存储(column-family-oriented store)的原因。
在模式设计流程中尽早定义访问模式,以便通过它们检验你的设计决定。
为了定义访问模式,第一步最好定义想使用表来回答什么问题。
列限定符可以按数据处理,就像值。这和关系型系统不同,关系型系统的列名是固定的并且需要在建表时预先定义。
HBase没有跨行事务的概念,要避开在客户端代码里需要事务逻辑的设计,因为这会让你不得不维护复杂的客户端。
HBase的运算速度涉及很多考量因素。具体包括:
(1)表中KeyValue条目数量(包括put的结果和delete留下的墓碑标记)。
(2)HFile里数据块(HFile block)的数量。
(3)平均一个HFile里KeyValue条目的数量。
(4)每行里列的平均数量。
e代表任何指定时间在MemStore里的条目数量,因为MemStore是使用跳表(skip list)实现的,所以查找行的时间复杂度是O(log e)。
宽表(wide table)的一行包括很多列。高表(tall table)是一种新模式,HFile里的KeyValue对象存储列族名字,使用短的列族名字在减少硬盘和网络I/O方面很有帮助。
HBase语境中的热点指的是负载极度集中在一小部分region上。因为负载没有分散在整个集群上,这是不合理的。服务这些region的几台机器承担了绝大部分工作,将成为整体性能的瓶颈。
HBase表里只有键(KeyValue对象的Key部分,包括行键、列限定符和时间戳)可以建立索引。访问一个特定行的唯一办法是通过行键。
在列限定符和时间戳上建立索引,可以让你在一行上不用扫描前面所有的列而直接跳到正确的列。
从表中获取数据有两种方式,即get和scan。如果需要一行,可以使用get调用,这种情况下必须提供行键;如果想执行一次扫描(scan),如果知道起始和停止键,可以选择使用它们来限制扫描器对象扫描的行数。
根据指定的键的某个部分,可以限制读取硬盘的数据量或者网络传输的数据量。指定行键则只返回需要的行,但是服务器返回整行给客户端。指定列族让你进一步限制读取行的什么部分,因为如果行键跨多个列族,可以只读取HFile的一个子集。进一步指定列限定符和时间戳,可以让你减少返回客户端的列数,因此节省了网络I/O。
把数据放入单元值和把它放入列限定符或行键将占用相同的存储空间,但是把数据从单元移到行键将可能得到更好的性能。
一些基础知识:
(1) HBase表很灵活,可以用字符数组形式存储任何东西。
(2) 在同一列族里存储相似访问模式的所有数据。
(3) 索引建立在KeyValue对象的Key部分上,Key由行键、列限定符和时间戳按次序组成。
(4) 高表可能支持你把运算复杂度降到O(1),但是要在原子性上付出代价。
(5) 设计HBase模式时进行反规范化处理是一种可行的办法。
(6) 想想如何能够在单个API调用里而不是多个API调用里完成访问模式。HBase不支持跨行事务,要避免在客户端代码里维护这种复杂的逻辑。
(7) 散列支持定长键和更好的数据分布,但是失去了排序的好处。
(8) 列限定符可以用来存储数据,就像单元一样。
(9) 因为可以把数据放入列限定符,所以它的长度影响存储空间。当访问数据时,它也影响了硬盘和网络I/O的开销,所以尽量简练。
(10) 列族名字的长度影响了通过网络传回客户端的数据大小(在KeyValue对象里),所以尽量简练。
反规范化是一个相反概念。数据是重复的,存在多个地方。因为你不再需要开销很大的JOIN子句,这使得查询数据变得更容易、更快。
从性能观点看,规范化为写做优化,而反规范化为读做优化。
行键决定了访问HBase表时可以得到的性能。这个结论根植于两个事实:region基于行键为一个区间的行提供服务,并且负责区间内每一行;HFile在硬盘上存储有序的行。当region刷写留在内存里的行时生成了HFile。这些行已经排过序,也会有序地刷写到硬盘上。HBase表的有序特性和底层存储格式可以让你根据如何设计行键以及把什么放入列限定符来推理其性能表现。
关系型数据库可以在多个列上建立索引,但HBase只能在键上建立索引,访问数据的唯一办法是使用行键。如果不知道想访问的数据的行键,就必须扫描相当多的行。
1.为写优化
应该如何把数据分散在多个region上呢?
(1)散列
如果你愿意在行键里放弃时间戳信息,使用原始数据的散列值作为行键是一种可能的解决方案。
散列算法有一个非零碰撞概率。使用散列函数的方式也很重要。
(2)salting
在思考行键的构成时,salting是一种技巧。
尽量把较少的HFile数据块读入内存,来获得要寻找的数据集。因为数据存储在一起,每次读取HFile数据块时可以比数据分散存储时得到更多的信息。
这里行键的结构对于读性能很重要。
有效的行键设计不仅要考虑把什么放入行键中,而且要考虑它们在行键里的位置。
信息在行键里的位置和选择放入什么信息同等重要。
关系型数据库和HBase是不同的系统,它们拥有不同的设计特性,可以影响到应用系统的设计。
1.一些基本概念
关系型数据库建模包括3个主要概念:
a.实体(entity)—映射到表(table)。
b.属性(attribute)—映射到列(column)。
c.联系(relationship)—映射到外键(foreign-key)。
(1)实体
在关系型数据库和HBase中,实体的容器(container)是表,表中每行代表实体的一个实例。用户表中每行代表一个用户。
(2)属性
为了把属性映射到HBase,必须区分至少两种属性类型:
a.识别属性(identifying attribute):这种属性可以唯一地精确识别出实体的一个实例(也就是一行)。关系型表里,这种属性构成表的主键(primary key)。在HBase中,这种属性成为行键(rowkey)的一部分。
一个实体经常是由多个属性识别出来的,这一点正好映射到关系型数据库里的复合键(compound keys)概念。
b.非识别属性(non-identifying attribute):在HBase中,它们基本映射到列限定符。
(3)联系
逻辑关系模型使用两种主要联系:一对多和多对多。在关系型数据库中,把前者直接建模为外键(foreign key),把后者建模为连接表(junction table)。
HBase没有内建的联结(join)或约束(constrain),几乎不使用显示联系。
HBase的列(也叫做列限定符)不需要在设计时预先定义。它们可以是任何东西。HBase具有在一个父实体或主实体的行里嵌套另一个实体的能力,但这远远不是一个灵活的模式行(flexible schema row)。
如果你得到子实体的唯一方法是通过父实体,并且你希望在一个父实体的所有子实体上有事务级保护,这种技术是最正确的选择。
HFile数据块大小可以在列族层次设置。数据块索引存储每个HFile数据块的起始键。数据块大小配置会影响数据块索引的大小。数据块越小,索引越大,因而占用的内存空间越大。同时,因为加载进内存的数 据块更小,随机查找性能更好。
把数据放进读缓存,但工作负载却经常不能从中获得性能提升。
可以选择一些列族,赋予它们在数据块缓存里有更高的优先级(LRU缓存)。
布隆过滤器允许对存储在每个数据块的数据做一个反向测试。当某行被请求时,先检查布隆过滤器,看看该行是否不在这个数据块中。
HBase可以让你在数秒内在列族级设置一个TTL,早于指定TTL值的数据在下一次大合并时会被删除。如果你在同一单元上有多个时间版本,早于设定TTL的版本会被删除。
HFile可以被压缩并存放在HDFS上,HBase可以使用多种压缩编码,包括LZO、Snappy和GZIP。
注意,数据只在硬盘上是压缩的,在内存里或通过网络传输时是没有压缩的。
在默认情况下,HBase每个单元维护3个时间版本,这个属性是可以设置的。
同时也可以指定列族存储的最少时间版本数。
较为常用的过滤器包括:
1.行过滤器
这是一种预装的比较过滤器,支持基于行键过滤数据。
这是行过滤器的一种特例,它基于行键的前缀值进行过滤。
它是一种类似于行过滤器的比较过滤器,不同之处是它用来匹配列限定符而不是行键。它使用与行过滤器相同的比较运算符和比较器类型。
它提供了与行过滤器或限定符过滤器一样的功能,只是针对的是单元值。
它允许针对返回给客户端的时间版本进行更细粒度的控制。
组合使用多个过滤器经常是很有用的。
模式设计永远不会结束。
数据规模是第一本质性的因素。
每个维度都是一个提升性能的机会。
在关系型数据库中,模式迁移的管理是个头疼的问题,主要表现在两个方面:第一个是模式和应用的紧耦合关系,第二个是对数据库模式的变化的管理。
1.准备HBase Shell
启动命令:bin目录下执行./hbase shell或sh hbase shell。
2.使用UNIX Shell脚本创建表模式
REST服务作为一个独立的进程运行,它可以运行在任何能够与HBase通信的机器上。一个REST接口部署的网络拓扑如下图所示。
1.启动HBase REST服务
启动命名:./hbase rest start -p 9999
2.访问特定的表
如果不用Java,那么最常见的访问HBase的方法是通过Thrift。Thrift是一种语言和一套生成代码的工具。
asynchbase是另一种HBase客户端,也是用Java编写的。它是完全异步的,这意味着它不会阻塞调用应用的线程。
为了管理模式迁移,建议使用HBase Shell进行脚本编程。
除了JVM之外,还可以选择REST和Thrift。
作者 周兆熊
来源:http://www.daxixiong.com/?/article/20
本文由作者授权转发,转载请向作者获取授权
以上是关于平台HBase学习总结的主要内容,如果未能解决你的问题,请参考以下文章