zoukankan      html  css  js  c++  java
  • 用Hbase协处理器Observer实现二次索引

    需求

    有一张uuid表,columnphone,要求在插入uuid数据的时候,会有一个通过phone指向uuid的索引表。本文通过Observer的的动态装载协处理方式实现

    实现

    HBase创建uuid表和phone表

    create 'phone','f1'
    create 'uuid','f1'

    maven依赖

    <dependencies>
            <dependency>
                <groupId>org.apache.hbase</groupId>
                <artifactId>hbase-server</artifactId>
                <version>1.3.1</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.hbase</groupId>
                <artifactId>hbase-client</artifactId>
                <version>1.3.1</version>
            </dependency>
        </dependencies>

    Java代码

    package com.me.hbase.Coprocessor;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.hbase.*;
    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 org.apache.hadoop.hbase.util.Bytes;
    
    import java.io.IOException;
    import java.util.List;
    
    public class TextObserver extends BaseRegionObserver {
        static Connection connection = null;
        static Table table = null;
    
        private static final String FROM_FAMAILLY_NAME = "f1";
        private static final String FROM_QUALIFIER_NAME = "phone";
    
        private static final String TO_TABLE_NAME = "phone";
        private static final String TO_FAMAILLY_NAME = "f1";
        private static final String TO_QUALIFIER_NAME = "uuid";
        static{
            Configuration conf = HBaseConfiguration.create();
            conf.set("hbase.zookeeper.quorum","slave2:2181");
            try {
                connection = ConnectionFactory.createConnection(conf);
                table = connection.getTable(TableName.valueOf(TO_TABLE_NAME));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public void prePut(final ObserverContext<RegionCoprocessorEnvironment> e, final Put put, final WALEdit edit, final Durability durability) throws IOException {
            try {
                //通过put对象获取插入数据的rowkey
                byte[] rowBytes = put.getRow();
                String rowkey = Bytes.toString(rowBytes);
    
                List<Cell> list = put.get(Bytes.toBytes(FROM_FAMAILLY_NAME), Bytes.toBytes(FROM_QUALIFIER_NAME));
                if (list == null || list.size() == 0) {
                    return;
                }
    
                Cell cell2 = list.get(0);
    
                //通过cell获取数据值
                String stringValue = Bytes.toString(CellUtil.cloneValue(cell2));
                //创建put对象,将二次索引插入进phone表
                Put put2 = new Put(stringValue.getBytes());
                put2.addColumn(Bytes.toBytes(TO_FAMAILLY_NAME), Bytes.toBytes(TO_QUALIFIER_NAME), rowkey.getBytes());
                table.put(put2);
                table.close();
            } catch (Exception e1) {
                return ;
            }
        }
    }

    java代码打包之后,放入HDFS

    hdfs dfs -put /jar包路径..../hbase_observer-1.0-SNAPSHOT.jar /observer.jar
    hdfs dfs -chmod 777 /observer.jar

    Hbase动态装载协处理器

    alter 'uuid', METHOD=> 'table_att', 'Coprocessor'=>'hdfs://master:9000/observer.jar|com.me.hbase.Coprocessor.TextObserver|1001'

    试验

    hbase执行如下命令

    //禁用
    disable 'uuid'
    //安装
    alter 'uuid', METHOD=> 'table_att', 'Coprocessor'=>'hdfs://master:9000/observer.jar|com.me.hbase.Coprocessor.TextObserver|1001'
    //启用
    enable 'uuid'
    //试验插入数据
    put 'uuid','uuid1','f1:phone','13811111111'
    

      

    'Coprocessor'=>'hdfs://master:9000/observer.jar|com.me.hbase.Coprocessor.TextObserver|1001'参数说明:

    • 一共四个参数,用|分割,最后一个params可省略
    • jar_file_path,Java代码打成的jar包存放的绝对路径,最好是HDFS路径
    • observer_class_path,observer类的包名加类名
    • priority,优先级,就用固定的1001即可
    • params,传递给observer的参数信息,相当于map,例如:id=123,name='hahaha',age=18

    安装注意:

    一定要把参数填对,路径填准确,不然会出现报如下错误:

    ERROR: org.apache.hadoop.hbase.DoNotRetryIOException: Class com.me.hbase.Coprocessor.TextObserver cannot be loaded Set hbase.table.sanity.checks to false at conf or table descriptor if you want to bypass sanity checks
    at org.apache.hadoop.hbase.master.HMaster.warnOrThrowExceptionForFailure(HMaster.java:1819)
    at org.apache.hadoop.hbase.master.HMaster.sanityCheckTableDescriptor(HMaster.java:1680)
    at org.apache.hadoop.hbase.master.HMaster.modifyTable(HMaster.java:2207)
    at org.apache.hadoop.hbase.master.MasterRpcServices.modifyTable(MasterRpcServices.java:1188)
    at org.apache.hadoop.hbase.protobuf.generated.MasterProtos$MasterService$2.callBlockingMethod(MasterProtos.java:58547)
    at org.apache.hadoop.hbase.ipc.RpcServer.call(RpcServer.java:2339)
    at org.apache.hadoop.hbase.ipc.CallRunner.run(CallRunner.java:123)
    at org.apache.hadoop.hbase.ipc.RpcExecutor$Handler.run(RpcExecutor.java:188)
    at org.apache.hadoop.hbase.ipc.RpcExecutor$Handler.run(RpcExecutor.java:168)

     

    测试结果:

     可以看到向uuid插入一条数据的时候,phone表自动会加一条指向uuid rowkey的数据

    卸载协处理器方式

    //禁用
    disable 'uuid'
    //卸载
    alter 'uuid',METHOD=>'table_att_unset',NAME=>'coprocessor$1'
    //启用
    enable 'uuid'

    扩展理论知识

    Hbase 协处理器分2种:

    1.Observer,类似于传统数据库的触发器。Observer会在固定的事件发生时被调用,比如:put操作之前有钩子函数 prePut,该函数在 put 操作
    执行前会被 Region Server 调用;在 put 操作之后则有 postPut 钩子函数

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

    协处理器详细理论:https://www.cnblogs.com/liuwei6/p/6837674.html

    HBase Observer协处理装载方式分2种:

    1.静态装载Coprocessor

    如果一个Coprocessor是静态装载的,要卸载它就需要重启HBase。

    2.动态装载Coprocessor

    动态装载Coprocessor的一个优势就是不需要重启HBase。不过动态装载的Coprocessor只是针对某个表有效。因此,动态装载的Coprocessor又被称为表级Coprocessor。

    详情参考:https://www.jianshu.com/p/d56584c45401

     

  • 相关阅读:
    C#中方法的分类、定义、调用(3)
    C#中的输入和输出与类和对象(2)
    .net中的数据类型与数据转换(1)
    android第二章控件2
    android第二章控件1
    安卓 第一章
    二进制文件的读写与小结
    字符流
    File类与字节流
    字节流
  • 原文地址:https://www.cnblogs.com/Alcesttt/p/13068932.html
Copyright © 2011-2022 走看看