Hbase的预分区和协调处理器

Hbase的预分区和协调处理器

  • HBase的预分区
  • HBase的rowKey设计技巧:
  • HBase的协处理器
  • 附:与HUE的整合

HBase的预分区

预分区的作用:

  • 增加数据读写效率
  • 负载均衡,防止数据倾斜
  • 方便集群容灾调度region
  • 优化Map数量

如何预分区
每一个region维护着startRow与endRowKey,如果加入的数据符合某个region维护的rowKey范围,则该数据交给这个region维护。

设定预分区的方法
1、手动指定预分区
hbase(main):001:0> create ‘staff’,‘info’,‘partition1’,SPLITS => [‘1000’,‘2000’,‘3000’,‘4000’]
完成后如图:
Hbase的预分区和协调处理器_第1张图片

2、使用16进制算法生成预分区

hbase(main):003:0> create ‘staff2’,‘info’,‘partition2’,{NUMREGIONS => 15, SPLITALGO => ‘HexStringSplit’}

完成后如图:
Hbase的预分区和协调处理器_第2张图片

3、分区规则创建于文件中
创建splits.txt文件内容如下:

cd /export/servers/
vim splits.txt
aaaa
bbbb
cccc
dddd

然后执行:

hbase(main):004:0> create 'staff3','partition2',SPLITS_FILE => '/export/servers/splits.txt'

成功后如图:
Hbase的预分区和协调处理器_第3张图片

4、使用JavaAPI创建预分区
Java代码如下:


    @Test
    public void hbaseSplit() throws IOException {
     
        //获取连接
        Configuration configuration = HBaseConfiguration.create();
        configuration.set("hbase.zookeeper.quorum", "node01:2181,node02:2181,node03:2181");
        Connection connection = ConnectionFactory.createConnection(configuration);
        Admin admin = connection.getAdmin();
        //自定义算法,产生一系列Hash散列值存储在二维数组中
        byte[][] splitKeys = {
     {
     1,2,3,4,5},{
     'a','b','c','d','e'}};


        //通过HTableDescriptor来实现我们表的参数设置,包括表名,列族等等
        HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf("stuff4"));
        //添加列族
        hTableDescriptor.addFamily(new HColumnDescriptor("f1"));
        //添加列族
        hTableDescriptor.addFamily(new HColumnDescriptor("f2"));
        admin.createTable(hTableDescriptor,splitKeys);
        admin.close();

    }

完成后如下图:
Hbase的预分区和协调处理器_第4张图片

HBase的rowKey设计技巧:

HBase是三维有序存储的,通过rowkey(行键),column key(column family和qualifier)和TimeStamp(时间戳)这个三个维度可以对HBase中的数据进行快速定位。设计时应注意以下几个原则:

rowkey长度原则

  • rowkey是一个二进制码流,可以是任意字符串,最大长度64kb,实际应用中一般为10-100bytes,以byte[]形式保存,一般设计成定长。越短越好,不要超过16个字节,原因如下:

rowkey散列原则

  • 如果rowkey按照时间戳的方式递增,不要将时间放在二进制码的前面,建议将rowkey的高位作为散列字段,由程序随机生成,低位放时间字段,这样将提高数据均衡分布在每个RegionServer,以实现负载均衡的几率
    rowkey唯一原则
  • 必须在设计上保证其唯一性,rowkey是按照字典顺序排序存储的,因此,设计rowkey的时候,要充分利用这个排序的特点,将经常读取的数据存储到一块,将最近可能会被访问的数据放到一块。

热点的概念:

  • 热点发生在大量的client直接访问集群的一个或极少数个节点(访问可能是读,写或者其他操作)。大量访问会使热点region所在的单个机器超出自身承受能力,引起性能下降甚至region不可用,这也会影响同一个RegionServer上的其他region,由于主机无法服务其他region的请求。

加盐

  • 这里所说是在rowkey的前面增加随机数,具体就是给rowkey分配一个随机前缀以使得它和之前的rowkey的开头不同。

哈希

  • 哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,
    反转

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

  • 时间戳反转
    一个常见的数据处理问题是快速获取数据的最近版本,使用反转的时间戳作为rowkey的一部分对这个问题十分有用,可以用 Long.Max_Value - timestamp 追加到key的末尾,例如 [key][reverse_timestamp] , [key] 的最新值可以通过scan [key]获得[key]的第一条记录,因为HBase中rowkey是有序的,第一条记录是最后录入的数据。

其他的优化
尽量减少行键和列族的大小在HBase中,value永远和它的key一起传输的。当具体的值在系统间传输时,它的rowkey,列名,时间戳也会一起传输。如果你的rowkey和列名很大,这个时候它们将会占用大量的存储空间。
列族尽可能越短越好,最好是一个字符。
冗长的属性名虽然可读性好,但是更短的属性名存储在HBase中会更好。

HBase的协处理器

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

协处理器有两种: observer 和 endpoint

(1) Observer 类似于传统数据库中的触发器,当发生某些事件的时候这类协处理器会被 Server 端调用。Observer Coprocessor 就是一些散布在 HBase Server 端代码中的 hook 钩子, 在固定的事件发生时被调用。比如: put 操作之前有钩子函数 prePut,该函数在 put 操作
执行前会被 Region Server 调用;在 put 操作之后则有 postPut 钩子函数。

以 HBase0.92 版本为例,它提供了三种观察者接口:
● RegionObserver:提供客户端的数据操纵事件钩子: Get、 Put、 Delete、 Scan 等。
● WALObserver:提供 WAL 相关操作钩子。
● MasterObserver:提供 DDL-类型的操作钩子。如创建、删除、修改数据表等。
到 0.96 版本又新增一个 RegionServerObserver
下图是以 RegionObserver 为例子讲解 Observer 这种协处理器的原理:

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

(3)总结
Observer 允许集群在正常的客户端操作过程中可以有不同的行为表现
Endpoint 允许扩展集群的能力,对客户端应用开放新的运算命令
observer 类似于 RDBMS 中的触发器,主要在服务端工作
endpoint 类似于 RDBMS 中的存储过程,主要在 client 端工作
observer 可以实现权限管理、优先级设置、监控、 ddl 控制、 二级索引等功能
endpoint 可以实现 min、 max、 avg、 sum、 distinct、 group by 等功能

协处理器加载方式
协处理器的加载方式有两种,我们称之为静态加载方式( Static Load) 和动态加载方式 ( Dynamic Load)。 静态加载的协处理器称之为 System Coprocessor,动态加载的协处理器称 之为 Table Coprocessor
1、静态加载
通过修改 hbase-site.xml 这个文件来实现, 启动全局 aggregation,能过操纵所有的表上 的数据。只需要添加如下代码:


hbase.coprocessor.user.region.classes
org.apache.hadoop.hbase.coprocessor.AggregateImplementation

为所有 table 加载了一个 cp class,可以用” ,”分割加载多个 class
2、动态加载
启用表 aggregation,只对特定的表生效。通过 HBase Shell 来实现。
disable 指定表。 hbase> disable ‘mytable’
添加 aggregation


hbase> alter 'mytable', METHOD => 'table_att','coprocessor'=>
'|org.apache.Hadoop.hbase.coprocessor.AggregateImplementation||'

重启指定表 hbase> enable ‘mytable’
4、协处理器卸载

5、协处理器Observer应用实战

通过协处理器Observer实现hbase当中一张表插入数据,然后通过协处理器,将数据复制一份保存到另外一张表当中去,但是只取当第一张表当中的部分列数据保存到第二张表当中去

第一步:HBase当中创建第一张表proc1

在HBase当中创建一张表,表名user2,并只有一个列族info
cd /export/servers/hbase-1.2.0-cdh5.14.0/
bin/hbase shell
hbase(main):053:0> create 'proc1','info'

第二步:Hbase当中创建第二张表proc2
创建第二张表user3,作为目标表,将第一张表当中插入数据的部分列,使用协处理器,复制到user3表当中来

hbase(main):054:0> create 'proc2','info'

第三步:开发HBase的协处理器
开发HBase的协处理器Copo

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.regionserver.wal.WALEdit;

import java.io.IOException;

public class MyProcessor extends BaseRegionObserver {
     

    @Override
    public void prePut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, Durability durability) throws IOException {
     
        //获取连接
        Configuration configuration = HBaseConfiguration.create();
        configuration.set("hbase.zookeeper.quorum", "node01,node02,node03");
        Connection connection = ConnectionFactory.createConnection(configuration);
        Cell nameCell = put.get("info".getBytes(), "name".getBytes()).get(0);
        Put put1 = new Put(put.getRow());
        put1.add(nameCell);
        Table reverseuser = connection.getTable(TableName.valueOf("proc2"));
        reverseuser.put(put1);
        reverseuser.close();
    }
}

第四步:将项目打成jar包,并上传到HDFS上面
将我们的协处理器打成一个jar包,此处不需要用任何的打包插件即可,然后上传到hdfs

将打好的jar包上传到linux的/export/servers路径下

cd /export/servers
mv original-hbaseStudy-1.0-SNAPSHOT.jar  processor.jar
hdfs dfs -mkdir -p /processor
hdfs dfs -put processor.jar /processor

第五步:将打好的jar包挂载到proc1表当中去

hbase(main):056:0> describe 'proc1'
hbase(main):055:0> alter 'proc1',METHOD => 'table_att','Coprocessor'=>'hdfs://node01:8020/processor/processor.jar|cn.itcast.hbasemr.MyProcessor|1001|'
再次查看user2表,
hbase(main):043:0> describe 'user2'

可以查看到我们的卸载器已经加载了

第六步:proc1表当中添加数据

    @Test
    public void testPut() throws Exception{
     
        //获取连接
        Configuration configuration = HBaseConfiguration.create();
        configuration.set("hbase.zookeeper.quorum", "node01,node02");
        Connection connection = ConnectionFactory.createConnection(configuration);
        Table user5 = connection.getTable(TableName.valueOf("proc1"));
        Put put1 = new Put(Bytes.toBytes("hello_world"));
        put1.addColumn(Bytes.toBytes("info"),"name".getBytes(),"helloworld".getBytes());
        put1.addColumn(Bytes.toBytes("info"),"gender".getBytes(),"abc".getBytes());
        put1.addColumn(Bytes.toBytes("info"),"nationality".getBytes(),"test".getBytes());
        user5.put(put1);
        byte[] row = put1.getRow();
        System.out.println(Bytes.toString(row));
        user5.close();
    }

注意:如果需要卸载我们的协处理器,那么进入hbase的shell命令行,执行以下命令即可

disable 'proc1'
alter 'proc1',METHOD=>'table_att_unset',NAME=>'coprocessor$1'
enable 'proc1'

HBase当中的二级索引的基本介绍

由于HBase的查询比较弱,如果需要实现类似于 select name,salary,count(1),max(salary) from user group by name,salary order by salary 等这样的复杂性的统计需求,基本上不可能,或者说比较困难,所以我们在使用HBase的时候,一般都会借助二级索引的方案来进行实现

HBase的一级索引就是rowkey,我们只能通过rowkey进行检索。如果我们相对hbase里面列族的列列进行一些组合查询,就需要采用HBase的二级索引方案来进行多条件的查询。

  1. MapReduce方案
  2. ITHBASE(Indexed-Transanctional HBase)方案
  3. IHBASE(Index HBase)方案
  4. Hbase Coprocessor(协处理器)方案
  5. Solr+hbase方案
  6. CCIndex(complementalclustering index)方案

常见的二级索引我们一般可以借助各种其他的方式来实现,例如Phoenix或者solr或者ES等.

附:与HUE的整合

第一步:修改hue.ini

cd /export/servers/hue-3.9.0-cdh5.14.0/desktop/conf
vim hue.ini
[hbase]
  hbase_clusters=(Cluster|node01:9090)
  hbase_conf_dir=/export/servers/hbase-1.2.0-cdh5.14.0/conf

第二步:启动hbase的thrift server服务
第一台机器执行以下命令启动hbase的thriftserver

cd /export/servers/hbase-1.2.0-cdh5.14.0
bin/hbase-daemon.sh start thrift  

第三步:启动hue
第三台机器执行以下命令启动hue

cd /export/servers/hue-3.9.0-cdh5.14.0/
build/env/bin/supervisor

第四步:页面访问
http://node03:8888/hue/

你可能感兴趣的:(Hbase的预分区和协调处理器)