分享

Hbase学习之表设计大全

问题导读:

1.在建表中常使用的命令有哪些?
2.表设计中列簇设计和RowKey 设计是怎样的,他们追求的原则是什么?
3.如何防止数据热点?
4.协处理器observer 和 endpoint他们的原理及区别是什么?
5.协处理器的加载方式是怎样的?


1.建表高级属性

建表过程中常用的shell命令

1.1 BLOOMFILTER

默认是 NONE 是否使用布隆过虑及使用何种方式,布隆过滤可以每列族单独启用 使用HColumnDescriptor.setBloomFilterType(NONE|ROW|ROWCOL)对列族单独启用布隆 - Default = ROW 对行进行布隆过滤 - 对 ROW,行键的哈希在每次插入行时将被添加到布隆 - 对 ROWCOL,行键 + 列族 + 列族修饰的哈希将在每次插入行时添加到布隆

使用方法:
[mw_shl_code=bash,true]create 'table',{BLOOMFILTER =>'ROW'}[/mw_shl_code]
作用:用布隆过滤可以节省读磁盘过程,可以有助于降低读取延迟

1.2 VERSIONS

默认是1,这个参数的意思是数据保留1个版本,如果我们认为我们的数据没有这么大的必要保留这么多,随时都在更新,而老版本的数据对我们毫无价值,那将此参数设为1能节约2/3的空间。使用方法:
[mw_shl_code=bash,true]create 'table',{VERSIONS=>'2'}[/mw_shl_code]
附:MIN_VERSIONS => '0'是说在 compact 操作执行之后,至少要保留的版本

1.3 COMPRESSION

默认值是NONE即不使用压缩,这个参数意思是该列族是否采用压缩,采用什么压缩算法,方法:
[mw_shl_code=bash,true]create 'table',{NAME=>'info',COMPRESSION=>'SNAPPY'}[/mw_shl_code]
建议采用 SNAPPY 压缩算法,如果建表之初没有压缩,后来想要加入压缩算法,可以通过 alter 修改 schema

1.jpg

1.4 TTL

默认是2147483647 即:Integer.MAX_VALUE值大概是68年,这个参数是说明该列族数据的存活时间,单位是s。这个参数可以根据具体的需求对数据设定存活时间,超过存过时间的数据将在表中不再显示,待下次major·compact的时候再彻底删除数据

注意的是 TTL 设定之后MIN_VERSIONS=>'0'这样设置之后,TTL时间戳过期后,将全部彻底删除该 family下所有的数据,如果MIN_VERSIONS不等于0那将保留最新的 MIN_VERSIONS 个版本的数据,其它的全部删除,比如MIN_VERSIONS=>'1'届时将保留一个最新版本的数据,其它版本的数据将不再保存。

1.5 alter

使用方法:如修改压缩算法
[mw_shl_code=bash,true]disable 'table'
alter 'table',{NAME=>'info',COMPRESSION=>'snappy'}
enable 'table'[/mw_shl_code]
但是需要执行 major_compact 'table' 命令之后 才会做实际的操作。

1.6 describe/desc

这个命令查看了 create table 的各项参数或者是默认值。使用方式:
[mw_shl_code=bash,true]describe 'user_info'[/mw_shl_code]

1.7 disable_all/enable_all

disable_all 'toplist.*'disable_all支持正则表达式,并列出当前匹配的表的如下:
[mw_shl_code=bash,true]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)? 并给出确认提示[/mw_shl_code]

1.8 drop_all

这个命令和 disable_all 的使用方式是一样的

1.9 hbase 预分区

默认情况下,在创建HBase表的时候会自动创建一个region分区,当导入数据的时候, 所有的 HBase 客户端都向这一个region写数据,直到这个region足够大了才进行切分。一种可以加快批量写入速度的方法是通过预先创建一些空的regions,这样当数据写入 HBase时,会按照region分区情况,在集群内做数据的负载均衡。

1.9.1 命令方式

[mw_shl_code=bash,true]# 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' }[/mw_shl_code]

1.9.2 api 的方式

[mw_shl_code=bash,true]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[/mw_shl_code]
参数:
  test_table 是表名
  HexStringSplit 是split 方式
  -c 是分 10 个 region
  -f 是 family
可在 UI 上查看结果,如图:

2.jpg

这样就可以将表预先分为15个区,减少数据达到storefile大小的时候自动分区的时间 消耗,并且还有以一个优势,就是合理设计rowkey能让各个region的并发请求平均分配(趋于均匀)使IO效率达到最高,但是预分区需要将filesize设置一个较大的值,hbase.hregion.max.filesize 这个值默认是 10G也就是说单个region 默认大小是 10G.

但是如果MapReduce Input类型为TableInputFormat使用hbase作为输入的时候,每个 region 一个 map,如果数据小于10G那只会启用一个map造成很大的资源浪费, 这时候可以考虑适当调小该参数的值,或者采用预分配region的方式,并将检测如果达到 这个值,再手动分配 region。 回到顶部

2 表设计

2.1 列簇设计

追求的原则是:在合理范围内能尽量少的减少列簇就尽量减少列簇。

最优设计是:将所有相关性很强的key-value都放在同一个列簇下,这样既能做到查询效率最高,也能保持尽可能少的访问不同的磁盘文件。以用户信息为例,可以将必须的基本信息存放在一个列族,而一些附加的额外信息可以放在另一列族。

2.2 RowKey 设计

HBase 中,表会被划分为 1...n 个 Region,被托管在 RegionServer中。Region 二个重要的属性:StartKey与EndKey表示这个Region维护的rowKey范围,当我们要读/写数据时,如果rowKey落在某个start-endkey范围内,那么就会定位到目标 region 并且读/写到相关的数据

2.3 Rowkey 设计三原则

2.3.1 rowkey 长度原则

Rowkey 是一个二进制码流,Rowkey 的长度被很多开发者建议说设计在 10~100 个字节,不过建议是越短越好,不要超过 16 个字节。

原因如下:
  • 数据的持久化文件 HFile 中是按照 KeyValue存储的,如果Rowkey过长比如 100 个字 节,1000 万列数据光 Rowkey 就要占用100*1000万=10亿个字节,将近 1G 数据,这会极大影响 HFile 的存储效率;
  • MemStore 将缓存部分数据到内存,如果Rowkey字段过长内存的有效利用率会降低, 系统将无法缓存更多的数据,这会降低检索效率。因此Rowkey的字节长度越短越好。
  • 目前操作系统是都是 64 位系统,内存 8 字节对齐。控制在 16 个字节,8 字节的整数倍利用操作系统的最佳特性。

2.3.2 rowkey 散列原则

如果 Rowkey 是按时间戳的方式递增,不要将时间放在二进制码的前面,建议将 Rowkey 的高位作为散列字段,由程序循环生成,低位放时间字段,这样将提高数据均衡分布在每个 Regionserver实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息将产生所有新数据都在一个RegionServer上堆积的热点现象,这样在做数据检索的时候负载将会集中 在个别 RegionServer,降低查询效率。

2.3.3 rowkey 唯一原则

必须在设计上保证其唯一性。rowkey 是按照字典顺序排序存储的,因此,设计 rowkey 的时候,要充分利用这个排序的特点,将经常读取的数据存储到一块,将最近可能会被访问的数据放到一块。

2.4 数据热点

HBase 中的行是按照rowkey的字典顺序排序的,这种设计优化了scan操作,可以将相关的行以及会被一起读取的行存取在临近位置,便于scan。然而糟糕的rowkey 设计是热点的源头。热点发生在大量的client直接访问集群的一个或极少数个节点(访问可能是读,写或者其他操作)。大量访问会使热点region所在的单个机器超出自身承受能力,引起性能下降甚至region不可用,这也会影响同一个RegionServer上的其他 region,由于主机无法服务其他region的请求。设计良好的数据访问模式以使集群被充分,均衡的利用。为了避免写热点,设计rowkey使得不同行在同一个 region,但是在更多数据情况下,数据 应该被写入集群的多个 region,而不是一个。

2.5 防止数据热点的有效措施

2.5.1加盐

这里所说的加盐不是密码学中的加盐,而是在rowkey的前面增加随机数,具体就是给 rowkey 分配一个随机前缀以使得它和之前的rowkey的开头不同。分配的前缀种类数量应该 和你想使用数据分散到不同的 region 的数量一致。加盐之后的 rowkey 就会根据随机生成的 前缀分散到各个 region 上,以避免热点。

2.5.2 哈希

哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的rowkey,可以使用 get 操作准确获取 某一个行数据

2.5.3反转

第三种防止热点的方法是反转固定长度或者数字格式的 rowkey。这样可以使得 rowkey 中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的随机 rowkey,但是牺 牲了 rowkey 的有序性。

反转 rowkey 的例子以手机号为rowkey,可以将手机号反转后的字符串作为rowkey,这样的就避免了以手机号那样比较固定开头导致热点问题

2.5.4 时间戳反转

一个常见的数据处理问题是快速获取数据的最近版本,使用反转的时间戳作为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 - 结束时间]

3.协处理器—Coprocessor

Hbase 作为列族数据库最经常被人诟病的特性包括:无法轻易建立“二级索引”,难以执 行求和、计数、排序等操作。比如,在旧版本的(0.92以前版本)Hbase中,统计数据表的总行数,需要使用Counter方法,执行一次MapReduce.Job才能得到。虽然 HBase 在数据存储层中集成了MapReduce,能够有效用于数据表的分布式计算。然而在很多情况下,做一些简单的相加或者聚合计算的时候,如果直接将计算过程放置在 server端,能够减少通讯开销,从而获得很好的性能提升。于是,HBase 在 0.92 之后引入了协处理器(coprocessors),实现一些激动人心的新特性:能够轻易建立二次索引、复杂过滤器(谓词下推)以及访问控制等。

3.1 协处理器分类

协处理器有两种:observer 和 endpoint

3.1.1 observer协处理器

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 这种协处理器的原理:

3.jpg

  • 客户端发出 put 请求
  • 该请求被分派给合适的 RegionServer 和 region
  • coprocessorHost 拦截该请求,然后在该表上登记的每个 RegionObserver 上调用 prePut()
  • 如果没有被 prePut()拦截,该请求继续送到 region,然后进行处理
  • region 产生的结果再次被 CoprocessorHost 拦截,调用 postPut()
  • 假如没有 postPut()拦截该响应,最终结果被返回给客户端

3.1.2 EndPoint协处理器

Endpoint 协处理器类似传统数据库中的存储过程,客户端可以调用这些Endpoint 协处 理器执行一段 Server端代码,并将Server端代码的结果返回给客户端进一步处理,最常见 的用法就是进行聚集操作。如果没有协处理器,当用户需要找出一张表中的最大数据,即max聚合操作,就必须进行全表扫描,在客户端代码内遍历扫描结果,并执行求最大值的操作。这样的方法无法利用底层集群的并发能力,而将所有计算都集中到Client端统一执行,势必效率低下。利用Coprocessor,用户可以将求最大值的代码部署到 HBase Server 端,HBase 将利用底层cluster 的多个节点并发执行求最大值的操作。即在每个Region范围内执行求最大值的代码,将每个Region的最大值在Region Server端计算出,仅仅将该max值返回给客 户端。在客户端进一步将多个Region的最大值进一步处理而找到其中的最大值。这样整体 的执行效率就会提高很多

下图是 EndPoint 的工作原理:

4.jpg

3.1.3 observer和endpoint处理器区别

Observer 允许集群在正常的客户端操作过程中可以有不同的行为表现

Endpoint 允许扩展集群的能力,对客户端应用开放新的运算命令

Observer 类似于 RDBMS 中的触发器,主要在服务端工作

Endpoint 类似于 RDBMS 中的存储过程,主要在服务端工作

Observer 可以实现权限管理、优先级设置、监控、ddl 控制、二级索引等功能

Endpoint 可以实现 min、max、avg、sum、distinct、group by 等功能

3.2 协处理加载方式

协处理器的加载方式有两种,我们称之为静态加载方式(Static Load)和动态加载方式 (Dynamic Load)。静态加载的协处理器称之为 System Coprocessor,动态加载的协处理器称之为 Table Coprocessor。

3.2.1 静态加载

通过修改 hbase-site.xml这个文件来实现,启动全局aggregation,能过操纵所有的表上 的数据。只需要添加如下代码:

[mw_shl_code=bash,true]<property>
<name>hbase.coprocessor.user.region.classes</name>
<value>org.apache.hadoop.hbase.coprocessor.AggregateImplementation</value>
</property>[/mw_shl_code]
为所有 table 加载了一个 cp class,可以用”,”分割加载多个 class

3.2.2 动态加载

启用表 aggregation,只对特定的表生效。通过 HBase Shell 来实现。
1. 停用表
[mw_shl_code=bash,true]disable 'guanzhu'[/mw_shl_code]
2.添加协处理器
[mw_shl_code=bash,true]alter 'guanzhu', METHOD => 'table_att', 'coprocessor' => 'hdfs://myha01/hbase/guanzhu.jar|com.study.hbase.cp.HbaseCoprocessorTest|1001|'[/mw_shl_code]
3.启用表
[mw_shl_code=bash,true]enable 'guanzhu'[/mw_shl_code]

3.2.3 协处理器卸载

同样是3步
[mw_shl_code=bash,true]
disable 'mytable'
alter 'mytable',METHOD=>'table_att_unset',NAME=>'coprocessor$1'
enable 'mytable'[/mw_shl_code]




最新经典文章,欢迎关注公众号




作者:Winston
原文:https://zhuanlan.zhihu.com/p/61573810




本帖被以下淘专辑推荐:

没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条