首页 > 大数据 > > HBase学习——3.HBase表设计
1.建表高级属性
建表过程中常用的shell命令
默认是 NONE 是否使用布隆过虑及使用何种方式,布隆过滤可以每列族单独启用 使用HColumnDescriptor.setBloomFilterType(NONE|ROW|ROWCOL)对列族单独启用布隆 - Default = ROW 对行进行布隆过滤 - 对 ROW,行键的哈希在每次插入行时将被添加到布隆 - 对 ROWCOL,行键 + 列族 + 列族修饰的哈希将在每次插入行时添加到布隆
使用方法:
create 'table',{BLOOMFILTER =>'ROW'}作用:用布隆过滤可以节省读磁盘过程,可以有助于降低读取延迟
默认是1,这个参数的意思是数据保留1个版本,如果我们认为我们的数据没有这么大的必要保留这么多,随时都在更新,而老版本的数据对我们毫无价值,那将此参数设为1能节约2/3的空间。使用方法:
create 'table',{VERSIONS=>'2'}
附:MIN_VERSIONS => '0'是说在 compact 操作执行之后,至少要保留的版本默认值是NONE即不使用压缩,这个参数意思是该列族是否采用压缩,采用什么压缩算法,方法:
create 'table',{NAME=>'info',COMPRESSION=>'SNAPPY'}建议采用 SNAPPY 压缩算法,如果建表之初没有压缩,后来想要加入压缩算法,可以通过 alter 修改 schema

默认是2147483647 即:Integer.MAX_VALUE值大概是68年,这个参数是说明该列族数据的存活时间,单位是s。这个参数可以根据具体的需求对数据设定存活时间,超过存过时间的数据将在表中不再显示,待下次major·compact的时候再彻底删除数据
注意的是 TTL 设定之后MIN_VERSIONS=>'0'这样设置之后,TTL时间戳过期后,将全部彻底删除该 family下所有的数据,如果MIN_VERSIONS不等于0那将保留最新的 MIN_VERSIONS 个版本的数据,其它的全部删除,比如MIN_VERSIONS=>'1'届时将保留一个最新版本的数据,其它版本的数据将不再保存。
使用方法:如修改压缩算法
disable 'table'
alter 'table',{NAME=>'info',COMPRESSION=>'snappy'}
enable 'table'但是需要执行 major_compact 'table' 命令之后 才会做实际的操作。
这个命令查看了 create table 的各项参数或者是默认值。使用方式:
describe 'user_info'disable_all 'toplist.*'disable_all支持正则表达式,并列出当前匹配的表的如下:
toplist_a_total_1001
toplist_a_total_1002
toplist_a_total_1008
toplist_a_total_1009
toplist_a_total_1019
toplist_a_total_1035
...
Disable the above 25 tables (y/n)? 并给出确认提示这个命令和 disable_all 的使用方式是一样的
默认情况下,在创建HBase表的时候会自动创建一个region分区,当导入数据的时候, 所有的 HBase 客户端都向这一个region写数据,直到这个region足够大了才进行切分。一种可以加快批量写入速度的方法是通过预先创建一些空的regions,这样当数据写入 HBase时,会按照region分区情况,在集群内做数据的负载均衡。
# create table with specific split points
hbase>create 'table1','f1',SPLITS => ['\x10\x00', '\x20\x00', '\x30\x00', '\x40\x00']
# create table with four regions based on random bytes keys
hbase>create 'table2','f1', { NUMREGIONS => 8 , SPLITALGO => 'UniformSplit' }
# create table with five regions based on hex keys
hbase>create 'table3','f1', { NUMREGIONS => 10, SPLITALGO => 'HexStringSplit' }hbase org.apache.hadoop.hbase.util.RegionSplitter test_table HexStringSplit -c 10 -f info
hbase org.apache.hadoop.hbase.util.RegionSplitter splitTable HexStringSplit -c 10 -f info
参数:
test_table 是表名
HexStringSplit 是split 方式
-c 是分 10 个 region
-f 是 family可在 UI 上查看结果,如图:

这样就可以将表预先分为15个区,减少数据达到storefile大小的时候自动分区的时间 消耗,并且还有以一个优势,就是合理设计rowkey能让各个region的并发请求平均分配(趋于均匀)使IO效率达到最高,但是预分区需要将filesize设置一个较大的值,hbase.hregion.max.filesize 这个值默认是 10G也就是说单个region 默认大小是 10G.
但是如果MapReduce Input类型为TableInputFormat使用hbase作为输入的时候,每个 region 一个 map,如果数据小于10G那只会启用一个map造成很大的资源浪费, 这时候可以考虑适当调小该参数的值,或者采用预分配region的方式,并将检测如果达到 这个值,再手动分配 region。 回到顶部
追求的原则是:在合理范围内能尽量少的减少列簇就尽量减少列簇。
最优设计是:将所有相关性很强的key-value都放在同一个列簇下,这样既能做到查询效率最高,也能保持尽可能少的访问不同的磁盘文件。以用户信息为例,可以将必须的基本信息存放在一个列族,而一些附加的额外信息可以放在另一列族。
HBase 中,表会被划分为 1...n 个 Region,被托管在 RegionServer中。Region 二个重要的属性:StartKey与EndKey表示这个Region维护的rowKey范围,当我们要读/写数据时,如果rowKey落在某个start-endkey范围内,那么就会定位到目标 region 并且读/写到相关的数据
Rowkey 是一个二进制码流,Rowkey 的长度被很多开发者建议说设计在 10~100 个字节,不过建议是越短越好,不要超过 16 个字节。
原因如下: - 1、数据的持久化文件 HFile 中是按照 KeyValue存储的,如果Rowkey过长比如 100 个字 节,1000 万列数据光 Rowkey 就要占用100*1000万=10亿个字节,将近 1G 数据,这会极大影响 HFile 的存储效率; - 2、MemStore 将缓存部分数据到内存,如果Rowkey字段过长内存的有效利用率会降低, 系统将无法缓存更多的数据,这会降低检索效率。因此Rowkey的字节长度越短越好。 - 3、目前操作系统是都是 64 位系统,内存 8 字节对齐。控制在 16 个字节,8 字节的整数倍利用操作系统的最佳特性。
如果 Rowkey 是按时间戳的方式递增,不要将时间放在二进制码的前面,建议将 Rowkey 的高位作为散列字段,由程序循环生成,低位放时间字段,这样将提高数据均衡分布在每个 Regionserver实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息将产生所有新数据都在一个RegionServer上堆积的热点现象,这样在做数据检索的时候负载将会集中 在个别 RegionServer,降低查询效率。
必须在设计上保证其唯一性。rowkey 是按照字典顺序排序存储的,因此,设计 rowkey 的时候,要充分利用这个排序的特点,将经常读取的数据存储到一块,将最近可能会被访问的数据放到一块。
HBase 中的行是按照rowkey的字典顺序排序的,这种设计优化了scan操作,可以将相关的行以及会被一起读取的行存取在临近位置,便于scan。然而糟糕的rowkey 设计是热点的源头。热点发生在大量的client直接访问集群的一个或极少数个节点(访问可能是读,写或者其他操作)。大量访问会使热点region所在的单个机器超出自身承受能力,引起性能下降甚至region不可用,这也会影响同一个RegionServer上的其他 region,由于主机无法服务其他region的请求。设计良好的数据访问模式以使集群被充分,均衡的利用。为了避免写热点,设计rowkey使得不同行在同一个 region,但是在更多数据情况下,数据 应该被写入集群的多个 region,而不是一个。
这里所说的加盐不是密码学中的加盐,而是在rowkey的前面增加随机数,具体就是给 rowkey 分配一个随机前缀以使得它和之前的rowkey的开头不同。分配的前缀种类数量应该 和你想使用数据分散到不同的 region 的数量一致。加盐之后的 rowkey 就会根据随机生成的 前缀分散到各个 region 上,以避免热点。
哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的rowkey,可以使用 get 操作准确获取 某一个行数据
第三种防止热点的方法是反转固定长度或者数字格式的 rowkey。这样可以使得 rowkey 中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的随机 rowkey,但是牺 牲了 rowkey 的有序性。
反转 rowkey 的例子以手机号为rowkey,可以将手机号反转后的字符串作为rowkey,这样的就避免了以手机号那样比较固定开头导致热点问题
一个常见的数据处理问题是快速获取数据的最近版本,使用反转的时间戳作为rowkey 的一部分对这个问题十分有用,可以用 Long.Max_Value - timestamp追加到 key 的末尾,例 如 [key][reverse_timestamp] , [key] 的最新值可以通过scan [key]获得[key]的第一条记录,因为HBase中rowkey是有序的,第一条记录是最后录入的数据。比如需要保存一个用户的操作记录,按照操作时间倒序排序,在设计rowkey 的时候,可以这样设计[userId反转][Long.Max_Value-timestamp],在查询用户的所有操作记录数据的时候,直接指定反转后的userId,startRow 是 [userId 反 转 ][000000000000],stopRow 是 [userId 反 转][Long.Max_Value - timestamp]
如果需要查询某段时间的操作记录,startRow 是[user 反转][Long.Max_Value - 起始时间], stopRow 是[userId 反转][Long.Max_Value - 结束时间]
Hbase 作为列族数据库最经常被人诟病的特性包括:无法轻易建立“二级索引”,难以执 行求和、计数、排序等操作。比如,在旧版本的(0.92以前版本)Hbase中,统计数据表的总行数,需要使用Counter方法,执行一次MapReduce.Job才能得到。虽然 HBase 在数据存储层中集成了MapReduce,能够有效用于数据表的分布式计算。然而在很多情况下,做一些简单的相加或者聚合计算的时候,如果直接将计算过程放置在 server端,能够减少通讯开销,从而获得很好的性能提升。于是,HBase 在 0.92 之后引入了协处理器(coprocessors),实现一些激动人心的新特性:能够轻易建立二次索引、复杂过滤器(谓词下推)以及访问控制等。
协处理器有两种:observer 和 endpoint
Observer类似于传统数据库中的触发器,当发生某些事件的时候这类协处理器会被Server端调用。Observer Coprocessor就是一些散布在HBaseServer端代码中的 hook钩子, 在固定的事件发生时被调用。比如:put操作之前有钩子函数prePut,该函数在 put 操作执 行前会被 Region Server 调用;在 put 操作之后则有 postPut 钩子函数.它提供了三种观察者接口: - RegionObserver:提供客户端的数据操纵事件钩子:Get、Put、Delete、Scan 等。 - WALObserver:提供 WAL 相关操作钩子。 - MasterObserver:提供 DDL-类型的操作钩子。如创建、删除、修改数据表等。 - 0.96 版本又新增一个 RegionServerObserver
以 RegionObserver 为例子讲解 Observer 这种协处理器的原理:

- 1、客户端发出 put 请求 - 2、该请求被分派给合适的 RegionServer 和 region - 3、coprocessorHost 拦截该请求,然后在该表上登记的每个 RegionObserver 上调用 prePut() - 4、如果没有被 prePut()拦截,该请求继续送到 region,然后进行处理 - 5、region 产生的结果再次被 CoprocessorHost 拦截,调用 postPut() - 6、假如没有 postPut()拦截该响应,最终结果被返回给客户端
Endpoint 协处理器类似传统数据库中的存储过程,客户端可以调用这些Endpoint 协处 理器执行一段 Server端代码,并将Server端代码的结果返回给客户端进一步处理,最常见 的用法就是进行聚集操作。如果没有协处理器,当用户需要找出一张表中的最大数据,即max聚合操作,就必须进行全表扫描,在客户端代码内遍历扫描结果,并执行求最大值的操作。这样的方法无法利用底层集群的并发能力,而将所有计算都集中到Client端统一执行,势必效率低下。利用Coprocessor,用户可以将求最大值的代码部署到 HBase Server 端,HBase 将利用底层cluster 的多个节点并发执行求最大值的操作。即在每个Region范围内执行求最大值的代码,将每个Region的最大值在Region Server端计算出,仅仅将该max值返回给客 户端。在客户端进一步将多个Region的最大值进一步处理而找到其中的最大值。这样整体 的执行效率就会提高很多
下图是 EndPoint 的工作原理:

Observer 允许集群在正常的客户端操作过程中可以有不同的行为表现
Endpoint 允许扩展集群的能力,对客户端应用开放新的运算命令
Observer 类似于 RDBMS 中的触发器,主要在服务端工作
Endpoint 类似于 RDBMS 中的存储过程,主要在服务端工作
Observer 可以实现权限管理、优先级设置、监控、ddl 控制、二级索引等功能
Endpoint 可以实现 min、max、avg、sum、distinct、group by 等功能
协处理器的加载方式有两种,我们称之为静态加载方式(Static Load)和动态加载方式 (Dynamic Load)。静态加载的协处理器称之为 System Coprocessor,动态加载的协处理器称之为 Table Coprocessor。
通过修改 hbase-site.xml这个文件来实现,启动全局aggregation,能过操纵所有的表上 的数据。只需要添加如下代码:
<property>
<name>hbase.coprocessor.user.region.classes</name>
<value>org.apache.hadoop.hbase.coprocessor.AggregateImplementation</value>
</property>为所有 table 加载了一个 cp class,可以用”,”分割加载多个 class
启用表 aggregation,只对特定的表生效。通过 HBase Shell 来实现。 1. 停用表
disable 'guanzhu'alter 'guanzhu', METHOD => 'table_att', 'coprocessor' => 'hdfs://myha01/hbase/guanzhu.jar|com.study.hbase.cp.HbaseCoprocessorTest|1001|'3.启用表
enable 'guanzhu'同样是3步
disable 'mytable'
alter 'mytable',METHOD=>'table_att_unset',NAME=>'coprocessor$1'
enable 'mytable'来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31537575/viewspace-3142664/ ,如需转载,请注明出处,否则将追究法律责任。