HBase 协处理器 (一)

HBase 分布式 NoSQL 数据库详解 java// 创建表示例// 30天。 阅读详情

之前讨论了如何利用过滤器来降低从服务器端到客户端发送的数据量。利用 HBase 的协处理器特性,用户甚至可以将一部分计算移到数据所在的机器上。



3.1 协处理器简介 (Introduction to Coprocessors)


利用客户端 API, 配合特定的选择器机制,如果过滤器,或列族作用域,可以限制传输到客户端的数据。如果可以更进一步优化会更好,例如,数据的处理

直接放到服务器端执行,然后仅返回一个很小的处理结果集。把这种方法想象为一个小型的 MapReduce 框架,将工作分布到整个集群上。

协处理器可以使用户在每个 region server 上直接运行任意代码,更精确地说,它执行代码在 per-region 基础上(it executes the code on a per-region
basis), 类似于 trigger 的功能(trigger- like functionality), 就像 RDMS 世界里的存储过程。在客户端,不需要做特殊的操作,HBase 框架会透明地
处理分布式行为。

有一些隐式的事件用户可以监听(hook into),执行一些辅助的任务。如果这些还不够,可以扩展 PRC 协议来引入自己的调用,这些调用由客户端触发,并
在服务器端执行。

像过自定义滤器一样,需要创建特定的 Java 类实现特定的接口。一旦编译好了,需要以 JAR 文件的形式使这些类为服务器可用。region server 的服务器
进程能够实例化这些类,并在正确的环境中执行它们。和过滤器对比,协处理器也可以动态载入,这允许扩展一个运行中的 HBase 集群的功能。

有很多可以使用协处理器的场景,例如,使用钩子关联行修改操作来维护一个二级索引(secondary indexes), 或者实现某种引用完整性(referential
integrity)。过滤器可以被增强为有状态的,因而可以做一些跨行边界的决策。聚合函数,如 sum(), 或 avg(), 这些 RDBMS 和 SQL 中知名的函数,可以
移到服务器端来本地化地扫描数据,而只把数值结果返回给客户端。


    NOTE
    -------------------------------------------------------------------------------------------------------------------------------------
    另一个适合使用协处理器的场景是权限控制,authentication, authorization, and auditing 特性加入到 HBase 0.92,就是基于协处理器技术的。它
    们在系统启动时载入,并利用提供的与触发器类似的钩子函数来检查一个用户是否通过认证,以及授权访问存储在表中的特定的值。

协处理器框架已提供了一些类,用户可以通过继承这些类来扩展自己的功能。这些类主要分为两大类,endpoint 和 observer.


    ● Endpoint
    -------------------------------------------------------------------------------------------------------------------------------------
    除了事件处理,还可能需要添加对集群的自定义的操作。用户代码可以部署到存储数据的服务器上,例如执行服务器本地化计算。
    
    Endpoint 是对 RPC 协议的动态扩展,添加远程过程的回调(callable remote procedures)。把它们想象为 RDBMS 的存储过程(stored procedures)。
    它们可以配合 observer 实现来与服务器端状态进行直接的交互。
    
    ● Observer
    -------------------------------------------------------------------------------------------------------------------------------------
    这种类型的 coprocessor 与触发器(triggers)类似:当某一事件发生时,回调函数(这里被称为钩子,hooks)被执行。这包括用户生成的事件,也包括
    服务器内部自动生成的事件。
    

协处理器框架(coprocessor framework) 提供的接口如下:


    MasterObserver
    -------------------------------------------------------------------------------------------------------------------------------------
    可以被用作系统管理或 DDL 类型的操作,这是集群级的事件。


    RegionServerObserver
    -------------------------------------------------------------------------------------------------------------------------------------
    钩入到发送给 region server 的命令中,并覆盖到 region server 范围的事件中。


    RegionObserver
    -------------------------------------------------------------------------------------------------------------------------------------
    用于处理数据操作事件。它们关联的边界是 table 的分区(bound to the regions of a table)

    WALObserver
    -------------------------------------------------------------------------------------------------------------------------------------
    提供钩入 write-ahead log 处理,region server 范围。


    BulkLoadObserver
    -------------------------------------------------------------------------------------------------------------------------------------
    处理围绕 bulk loading API 的事件。在载入之前和之后触发。


    EndpointObserver
    -------------------------------------------------------------------------------------------------------------------------------------
    当 endpoint 被客户端调用时,这个 observer 提供一个回调方法。

这些 observer 提供了为集群服务器可能处理的每一种操作,定义好了事件回调。

所有这些接口都基于 Coprocessor 接口来获得共有的特性,然后实现它们自己的功能。

最后,协处理器可以被链接起来使用,类似于 Java Servlet API 的过滤器请求。



3.2 The Coprocessor Class Trinity
-----------------------------------------------------------------------------------------------------------------------------------------
所有用户协处理器类必须基于 Coprocessor 接口。它定义了一个协处理器的基本协议和框架本身管理的工具。该接口提供了两组类型,用于整个协处理框架:
PRIORITY 常量和 State 枚举。下表解释了优先级值:

    Priorities as defined by the Coprocessor.PRIORITY_<XYZ> constants
    +-------------------+---------------+----------------------------------------------------------------
    | Name                | Value            | Description
    +-------------------+---------------+----------------------------------------------------------------
    | PRIORITY_HIGHEST    | 0                | Highest priority, serves as an upper boundary.
    +-------------------+---------------+----------------------------------------------------------------
    | PRIORITY_SYSTEM    | 536870911        | High priority, used for system coprocessors (Integer.MAX_VALUE / 4).
    +-------------------+---------------+----------------------------------------------------------------
    | PRIORITY_USER        | 1073741823    | For all user coprocessors, which are executed subsequently (Integer.MAX_VALUE / 2).
    +-------------------+---------------+----------------------------------------------------------------
    | PRIORITY_LOWEST    | 2147483647    | Lowest possible priority, serves as a lower boundary (Integer.MAX_VALUE).
    +-------------------+---------------+----------------------------------------------------------------

协处理器的优先级定义了协处理器的执行顺序:system-level 实例在 user-level 协处理器执行之前调用。


    NOTE
    -------------------------------------------------------------------------------------------------------------------------------------
    在每一个优先级之内,还有一个序列号,用于跟踪协处理器载入的次序。序列号开始于 0,并且按 1 递增。
    
    这个数字本身没什么作用,但可以依靠框架来为协处理器排序,在每一个优先级之内,由序列号升序排序。这定义了它们的执行顺序。

协处理器在它们自己的生命周期内有框架管理,为此,Coprocessor 提供了如下两个方法调用:

    void start(CoprocessorEnvironment env) throws IOException
    void stop(CoprocessorEnvironment env) throws IOException

这两方法在协处理器类开始和结束时被调用。提供的 CoprocessorEnvironment 实例用于跨协处理器实例的生命期保持状态。一个协处理器实例总是包含一个
提供的环境,该环境提供如下方法:

    String getHBaseVersion():返回 HBase 版本标识字符串,如 "1.0.0"
    int getVersion()        : 返回 Coprocessor 接口的版本号
    Coprocessor getInstance():返回载入的协处理器实例。
    int getPriority()        :提供协处理器的优先级
    int getLoadSequence()    :协处理器的顺序号。顺序号在该实例载入时设置,并且反应了其执行顺序。
    Configuration getConfiguration():提供访问当前的、服务器范围的配置
    
    HTableInterface getTable(TableName tableName)
    HTableInterface getTable(TableName tableName, ExecutorService service):对给定的表名称返回一个Table 实现。这使协处理器可以访问实际的表
    数据。第二个变体需要指定一个自定义的 ExecutorService 实例。

协处理器应只与提供给它的环境进行交互。这样做的好处是可以保证没有为恶意代码破坏数据的后门。


    NOTE
    -------------------------------------------------------------------------------------------------------------------------------------
    Coprocessor 实现应通过 getTable() 方法访问表,注意这个方法实对返回的 Table 实现添加了一定的安全措施。
    
    目前为止还没有阻止用户在协处理器代码中获取自己的 Table 实例的方法,这些问题可能会在今后的版本中检查出来,并且可能阻止这样做。

在协处理器实例的生命周期中,Coprocessor 接口的 start() 和 stop() 方法会被框架隐式调用。处理过程中的每一步都有一个定义好的状态,如下表所示:

    The states as defined by the Coprocessor.State enumeration
    +---------------+---------------------------------------------------------------------------------------------------+
    | Value            | Description                                                                                        |
    +---------------+---------------------------------------------------------------------------------------------------+
    | UNINSTALLED    | The coprocessor is in its initial state. It has no environment yet, nor is it initialized.        |
    +---------------+---------------------------------------------------------------------------------------------------+
    | INSTALLED        | The instance is installed into its environment                                                    |
    +---------------+---------------------------------------------------------------------------------------------------+
    | STARTING        | This state indicates that the coprocessor is about to be started, that is, its start() method        |
    |                | is about to be invoked.                                                                            |
    +---------------+---------------------------------------------------------------------------------------------------+
    | ACTIVE        | Once the start() call returns, the state is set to active.                                        |
    +---------------+---------------------------------------------------------------------------------------------------+
    | STOPPING        | The state set just before the stop() method is called.                                            |
    +---------------+---------------------------------------------------------------------------------------------------+
    | STOPPED        | Once stop() returns control to the framework, the state of the coprocessor is set to stopped.        |
    +---------------+---------------------------------------------------------------------------------------------------+

最后是 CoprocessorHost 类,它维护所有协处理器实例和它们专有的环境。它有一些专用子类,用于不同的使用环境,例如 master server, region server

三件套: Coprocessor, CoprocessorEnvironment, 和 CoprocessorHost 这三个类构成了实现 HBase 高级功能的类的基础,取决于它们被用到什么地方。
它们提供了对协处理器生命周期的支持,管理它们的状态,以及提供如期执行的环境。另外,这些类提供了一个抽象层,使开发者能够很容易地构建出自定义
的实现。


3.3 协处理器加载 (Coprocessor Loading)
-----------------------------------------------------------------------------------------------------------------------------------------
首先讨论如何部署协处理器。可以配置协处理器以静态方式加载,或者在集群运行时动态加载它们。静态加载方法通过配置文件和表模式(table schema),
动态载入只通过表模式加载协处理器。

也有集群范围的开关设置,用于禁止所有协处理器的载入,由如下两个配置属性控制:


    ● hbase.coprocessor.enabled
    -------------------------------------------------------------------------------------------------------------------------------------
    默认值为 true, 意思为加载系统级协处理器类和用户 table. 设置这个值为 false 停止服务器加载它们。可以在测试期间或集群应急处理时使用。


    ● hbase.coprocessor.user.enabled
    -------------------------------------------------------------------------------------------------------------------------------------
    默认为 true, 意思为在服务器启动或者一个 region 打开时,所有用户 table 协处理器都加载。设置这个属性为 false, 只是禁止载入用户 table
    协处理器。


3.3.1 从配置中加载 (Loading from Configuration)
-----------------------------------------------------------------------------------------------------------------------------------------
可以全局配置哪些协处理器在 HBase 启动时加载。这可以通过向 hbase-site.xml 配置文件中添加如下配置属性实现:

    <property>
        <name>hbase.coprocessor.master.classes</name>
        <value>coprocessor.MasterObserverExample</value>
    </property>
    <property>
        <name>hbase.coprocessor.regionserver.classes</name>
        <value>coprocessor.RegionServerObserverExample</value>
    </property>
    <property>
        <name>hbase.coprocessor.region.classes</name>
        <value>coprocessor.system.RegionObserverExample, coprocessor.AnotherCoprocessor</value>
    </property>
    <property>
        <name>hbase.coprocessor.user.region.classes</name>
        <value>coprocessor.user.RegionObserverExample</value>
    </property>
    <property>
        <name>hbase.coprocessor.wal.classes</name>
        <value>coprocessor.WALObserverExample, bar.foo.MyWALObserver</value>
    </property>

在每一个配置属性中类的顺序是很重要的,这个顺序决定了它们执行的顺序。所有这些协处理器都以系统优先级(system priority)载入。应将全局活动的
类配置到这里,这样它们就会被首先执行,并且有机会做一些权限方面的控制。安全性协处理器就是以这种方式加载的。


    NOTE
    -------------------------------------------------------------------------------------------------------------------------------------
    HBase 启动时,配置文件会首先被检验。虽然可以在其它地方定义系统级协处理器,在这里配置的会被首先执行。有时它们也被称为默认协处理器。

    只有五种可能配置之一被读取来匹配 CoprocessorHost 实现。例如,定义在 hbase.coprocessor.master.classes 中的协处理器被
    MasterCoprocessorHost 类加载。

下表展示了每一种配置属性的应用:

    Possible configuration properties and where they are used
    +-------------------------------------------+-------------------------------+----------------------------------------------
    | Property                                    | Coprocessor Host                | Server Type
    +-------------------------------------------+-------------------------------+-----------------------------------------------
    | hbase.coprocessor.master.classes            | MasterCoprocessorHost            | Master Server
    +-------------------------------------------+-------------------------------+-----------------------------------------------
    | hbase.coprocessor.regionserver.classes    | RegionServerCoprocessorHost    | Region Server
    +-------------------------------------------+-------------------------------+-----------------------------------------------
    | hbase.coprocessor.region.classes            | RegionCoprocessorHost            | Region Server
    +-------------------------------------------+-------------------------------+-----------------------------------------------
    | hbase.coprocessor.user.region.classes        | RegionCoprocessorHost            | Region Server
    +-------------------------------------------+-------------------------------+-----------------------------------------------
    | hbase.coprocessor.wal.classes                | WALCoprocessorHost            | Region Server
    +-------------------------------------------+-------------------------------+-----------------------------------------------

为类载入 region 提供了两个不同的属性,原因如下:


    hbase.coprocessor.region.classes
    -------------------------------------------------------------------------------------------------------------------------------------
    所有列出的协处理器在系统级加载到 HBase 中的每个表上,包括特殊的目录表(catalog tables).


    hbase.coprocessor.user.region.classes
    -------------------------------------------------------------------------------------------------------------------------------------
    这个属性中列出的所有协处理器类也在系统级加载,但只对用户表(user tables), 不包括特定的目录表。
    
除此之外,定义在这两个属性里的协处理器,在一个 region 打开时加载。注意,用户不能指定载入的是哪个用户表或系统表,或者 region,换句话说,
它们为每个表或 region 载入。


3.3.2 从表描述符中加载 (Loading from Table Descriptor)
-----------------------------------------------------------------------------------------------------------------------------------------
另一个定义哪些协处理器加载的选项是表描述符(table descriptor). 因为这种配置是针对特定表的,因此加载的协处理器只针对这个表的 region, 并且只
被存储这些 region 的 region 服务器使用。换句话说,用户只能与 region 相关的协处理器上使用这种方法,不能用在 master 或 WAL 相关的协处理器上
使用。另一方面,由于它们是在某一个表的上下文(context)加载的,因此它们更具有针对性。需要使用下面两方法之一,将协处理器的定义添加到表描述符

    1. 使用通用的 HTableDescriptor.setValue() 方法
    2. 使用 HTableDescriptor.addCoprocessor() 方法

如果使用第一种方法,需要创建一个键,必须以 COPROCESSOR 开头,值必须遵循如下格式:

    [<path-to-jar>]|<classname>|[<priority>][|key1=value1,key2=value2,...]
    
下面是一个例子,定义了几个协处理器,第一个是系统级优先级,其它为用户级优先级:

'COPROCESSOR$1' => 'hdfs://localhost:8020/users/leon/test.jar|coprocessor.Test|2147483647'
'COPROCESSOR$2' => '/Users/laura/test2.jar|coprocessor.AnotherTest|1073741822'
'COPROCESSOR$3' => '/home/kg/advacl.jar|coprocessor.AdvancedAcl|1073741823|keytab=/etc/keytab'
'COPROCESSOR$99' => '|com.foo.BarCoprocessor|'

key 是一个组合,前缀为 COPROCESSOR, $ 符号作为分隔符,然后是一个次序号码,例如,COPROCESSOR$1。使用 $<number> 形式作为 key 的后缀,强制
定义的次序,从而定义了协处理器加载的次序。这在以相同的优先级加载多个协处理器时非常重要。

在使用 addCoprocessor() 方法向一个表描述符中添加协处理器时,方法会查找最高的已分配的数字,然后使用下一个没有使用的值。这个数值从 1 开始,
每次增加 1

value 由三到四部分组成,含义如下:

    path-to-jar
    -------------------------------------------------------------------------------------------------------------------------------------
    可选项。路径或者是一个完全限定的 HDFS 位置,或者是任何 Hadoop FileSystem 类支持的其它路径。例如上面第二、第三个协处理器,使用的是本地
    路径。如果为空,协处理器类必须可以通过已配置的类路径访问。
    
    如果指定了一个在 HDFS 中的路径,协处理器加载器支持会首先拷贝这个 JAR 文件到一个本地位置。文件会被放到更深的子目录 tmp 下,如 :
    
        /data/tmp/hbasehadoop/local/jars/tmp/
    
    JAR 文件的文件名也会改为一个内部唯一的名称,利用下面的模式:
        
        .<path-prefix>.<jar-filename>.<current-timestamp>.jar

    path-prefix 一般会使用一个随机的 UUID, 例如下面是一个完整的示例:

        $ $ ls -A /data/tmp/hbase-hadoop/local/jars/tmp/
        .c20a1e31-7715-4016-8fa7-b69f636cb07c.hbase-book-ch04.jar.1434434412813.jar

    本地文件会在服务器进程正常终止时删除。


    classname
    -------------------------------------------------------------------------------------------------------------------------------------
    必须项。类名定义实际的实现类。 JAR 文件可能含有很多协处理器类,针对表的属性,只可以指定有一个类。用标准的 Java 包名指定类名。
    
    
    priority
    -------------------------------------------------------------------------------------------------------------------------------------
    可选项。优先级必须是一个数字,在 Coprocessor.PRIORITY_LOWEST 边界范围之内,查看 Coprocessor.PRIORITY_<XYZ> 常量定义。如果没有指定,
    默认为 Coprocessor.PRIORITY_USER, 值为 1073741823


    key=value
    -------------------------------------------------------------------------------------------------------------------------------------
    可选项。key/value 参数,可以添加到由协处理器处理的配置中,可以通过调用 CoprocessorEnvironment.getConfiguration() 获取到。例如,start()
    方法中:
    
        private String keytab;
        
        @Override
        public void start(CoprocessorEnvironment env) throws IOException
        {
            this.keytab = env.getConfiguration().get("keytab");
        }
    
    上面的 getConfiguration() 调用返回当前服务器配置文件,合并了在协处理器声明中指定的一些可选参数。

示例: Load a coprocessor using the table descriptor

    public class LoadWithTableDescriptorExample {
        public static void main(String[] args) throws IOException {
        
            Configuration conf = HBaseConfiguration.create();
            Connection connection = ConnectionFactory.createConnection(conf);
        
            TableName tableName = TableName.valueOf("testtable");
            //Define a table descriptor.
            HTableDescriptor htd = new HTableDescriptor(tableName);
            htd.addFamily(new HColumnDescriptor("colfam1"));
            
            //Add the coprocessor definition to the descriptor, while omitting the path to the JAR file.
            htd.setValue("COPROCESSOR$1", "|" +
                RegionObserverExample.class.getCanonicalName() +
                "|" + Coprocessor.PRIORITY_USER);
            
            //Acquire an administrative API to the cluster and add the table.
            Admin admin = connection.getAdmin();
            admin.createTable(htd);
            
            //Verify if the definition has been applied as expected
            System.out.println(admin.getTableDescriptor(tableName));
            admin.close();
            
            connection.close();
        }
    }

使用第二种方法, 描述符类提供的 addCoprocessor() method, 简化上述操作

    //Load a coprocessor using the table descriptor using provided method
    HTableDescriptor htd = new HTableDescriptor(tableName)
        .addFamily(new HColumnDescriptor("colfam1"))
        .addCoprocessor(RegionObserverExample.class.getCanonicalName(),
        null, Coprocessor.PRIORITY_USER, null);
        
    Admin admin = connection.getAdmin();
    admin.createTable(htd);

运行输出:
    'testtable', {TABLE_ATTRIBUTES => {METADATA => { \
    'COPROCESSOR$1' => '|coprocessor.RegionObserverExample|
    1073741823'}}, \
    {NAME => 'colfam1', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER
    => 'ROW', \
    REPLICATION_SCOPE => '0', VERSIONS => '1', COMPRESSION =>
    'NONE', \
    MIN_VERSIONS => '0', TTL => 'FOREVER', KEEP_DELETED_CELLS =>
    'FALSE', \
    BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE =>
    'true'}


3.3.3 从 HBase Shell 加载 (Loading from HBase Shell)
-----------------------------------------------------------------------------------------------------------------------------------------
如果要在 HBase 运行的时候加载协处理器,这里有一个选择可以动态加载必要的类和包含该类的 JAR 文件。这是通过使用表描述符和系统管理 API 提供的
 alter 调用实现的,并通过 HBase Shell 使用。其过程是更新 table schema, 然后重新载入到 table region. shell 在一次调用中完成此操作:
 
    hbase(main):001:0> alter 'testqauat:usertable', 'coprocessor' => 'file:///opt/hbase-book/hbase-bookch05-2.0.jar| \
    coprocessor.SequentialIdGeneratorObserver|'
    
    Updating all regions with the new schema...
    1/11 regions updated.
    6/11 regions updated.
    11/11 regions updated.
    Done.
    0 row(s) in 5.0540 seconds

    hbase(main):002:0> describe 'testqauat:usertable'
    
    Table testqauat:usertable is ENABLED
    testqauat:usertable, {TABLE_ATTRIBUTES => {coprocessor$1 => \
    'file:///opt/hbase-book/hbase-book-ch05-2.0.jar|coprocessor \
    .SequentialIdGeneratorObserver|'}
    COLUMN FAMILIES DESCRIPTION
    {NAME => 'cf1', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER =>
    'ROW', \
    REPLICATION_SCOPE => '0', COMPRESSION => 'NONE', VERSIONS =>
    '1', \
    TTL => 'FOREVER', MIN_VERSIONS => '0', KEEP_DELETED_CELLS =>
    'FALSE', \
    BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}
    1 row(s) in 0.0220 seconds

第二个命令使用 describe 来验证协处理器已设置,以及为它分配的 key, 这里为 coprocessor$1

一旦某个协处理器加载了,可以通过同样的形式将其移除,也就是,通过 HBase Shell 来更新 schema, 然后在所有的 region server 上重新载入受影响的
table regions, 通过一个命令调用:

    hbase(main):003:0> alter 'testqauat:usertable', METHOD =>'table_att_unset', NAME => 'coprocessor$1'
    Updating all regions with the new schema...
    2/11 regions updated.
    8/11 regions updated.
    11/11 regions updated.
    Done.
    0 row(s) in 4.2160 seconds    

    Table testqauat:usertable is ENABLED
    testqauat:usertable
    COLUMN FAMILIES DESCRIPTION
    {NAME => 'cf1', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', COMPRESSION => 'NONE', VERSIONS =>'1', \
    TTL => 'FOREVER', MIN_VERSIONS => '0', KEEP_DELETED_CELLS => 'FALSE', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}
    1 row(s) in 0.0180 seconds

移除一个协处理器,需要知道它在 table schema 中的 key



3.4 Endpoints
-----------------------------------------------------------------------------------------------------------------------------------------
我们需要这样的能力,将处理转移到服务器上,在服务器端进行聚合或者其它计算操作,然后只讲很小的计算结果返回给客户端。这就是 Endpoints 的功能
指示一个给定表的每个 region 所在的服务器载入代码,然后扫描该表,这会调用服务器端代码,扫描服务器上存在的数据。一旦计算完成,将结果返回给
客户端,每个 region 一个结果,在客户端收集这些结果并聚合为最终结果。



3.4.1 The Service Interface
-----------------------------------------------------------------------------------------------------------------------------------------
Endpoints 实现为客户端和服务器端之间的 RPC 协议的扩展。利用提供的协处理器服务 API, 载荷被序列化为 Protobuf message 在客户端和服务器端来回
传送。

为了给客户端提供一个 endpoint, 协处理器生成一个 Protobuf 实现来扩展 Service 类。该服务可以定义任何协处理器希望公开的方法。利用生成的类,
可以与协处理器实例进行通信,通过如下 Table 提供的方法调用:

    CoprocessorRpcChannel coprocessorService(byte[] row)

    <T extends Service, R> Map<byte[],R> coprocessorService(final Class<T> service, byte[] startKey, byte[] endKey,
    final Batch.Call<T,R> callable)    throws ServiceException, Throwable

    <T extends Service, R> void coprocessorService(final Class<T> service, byte[] startKey, byte[] endKey,
    final Batch.Call<T,R> callable,     final Batch.Callback<R> callback) throws ServiceException, Throwable

    <R extends Message> Map<byte[], R> batchCoprocessorService(Descriptors.MethodDescriptor methodDescriptor, Message request,
    byte[] startKey, byte[] endKey, R responsePrototype)throws ServiceException, Throwable

    <R extends Message> void batchCoprocessorService(Descriptors.MethodDescriptor methodDescriptor, Message request, byte[] startKey,
    byte[] endKey, R responsePrototype, Batch.Callback<R> callback) throws ServiceException, Throwable


Service 实例与一个 table 中单个的 region 关联,客户端 RPC 调用最终必须标识出在服务的方法调用时使用哪个 region. 很少在客户端代码中直接处理
region, 并且 region 的名称也会随时变化,因此协处理器 RPC 调用使用行键来标识在方法调用时使用的 region. 客户端可以针对如下情况调用 Service
方法:


    ● Single Region
    -------------------------------------------------------------------------------------------------------------------------------------
    通过单个 row key 调用 coprocessorService() 实现,返回一个 CoprocessorRpcChannel 类实例,该类直接扩展至 Protobuf。可用于调用任何
    endpoint 连接到包含特定行的 region.


    ● Ranges of Regions
    -------------------------------------------------------------------------------------------------------------------------------------
    通过使用起始行键和一个终止行键调用 coprocessorService()。表中包含在起始行键到终止行键范围内的所有 region 都将作为 endpoint 的目标。



    ● Batched Regions
    -------------------------------------------------------------------------------------------------------------------------------------
    如果调用 batchCoprocessorService(), 会块所有 region 并发执行, 但同一个 region server 调用会一起发送为一个调用,这会降低网络往返数量。

    

    NOTE
    -------------------------------------------------------------------------------------------------------------------------------------
    作为参数传递给 Table 方法的 row keys 不会传递给 Service 实现。它们只用于为 endpoint 的远程调用识别 region. 它们不必真实存在,仅仅用于
    通过起始键和结束键边界标识匹配 region

有些 table 方法调用 endpoint 使用了 Batch 类。该抽象类为 Service 调用多个 region 定义了两个接口:客户端实现 Batch.Call 来调用实际的 Service
实现的实例方法。一旦选定了 region, 该接口的 call 方法会被调用,将 Service 实现的实例作为参数传递进去。

客户端可以实现 Batch.Callback, 用于在每一个 region 调用执行完成时接收通知。实例的

    void update(byte[] region, byte[] row, R result)
    
方法会被调用,每个 region 通过

    R call(T instance)
    
返回的值。


3.4.2 实现 Endpoints (Implementing Endpoints)
-----------------------------------------------------------------------------------------------------------------------------------------
实现 endpoint 包括如下两个步骤:


    1. 定义 Protobuf 服务和生成类
    -------------------------------------------------------------------------------------------------------------------------------------
    这一步为 endpoint 设定通信细节:定义 RPC 服务,用于客户端和服务器端之间的方法和消息。利用 Protobuf compiler 的帮助,服务定义被编译成
    自定义的 Java 类。


    2. 扩展生成的,自定义的 Service 子类
    -------------------------------------------------------------------------------------------------------------------------------------
    需要提供 endpoint 实际的实现,扩展生成的、从 Service 继承的抽象类

下面定义一个 Protobuf 服务,名为 RowCountService, 带有客户端可调用的方法,用于在每一个它所运行的 region 上获取行的数量和 Cell 的数量。

    option java_package = "coprocessor.generated";
    option java_outer_classname = "RowCounterProtos";
    option java_generic_services = true;
    option java_generate_equals_and_hash = true;
    option optimize_for = SPEED;
    
    message CountRequest {
    }
    
    message CountResponse {
        required int64 count = 1 [default = 0];
    }
    
    service RowCountService {
        rpc getRowCount(CountRequest)
            returns (CountResponse);
        rpc getCellCount(CountRequest)
            returns (CountResponse);
    }

文件定义了输出的类名,代码生成时使用的包,等等。第一步的最后一件事是将定义文件编译为代码,利用 Protobuf 的 protoc 工具实现。

    $ protoc -Ich04/src/main/protobuf --java_out=ch04/src/main/java \
    ch04/src/main/protobuf/RowCountService.proto

会将生成的类文件放置到 source 目录。之后就可以使用这个生成的类型。因为生成的代码创建的是一个抽象类,因此第二步就是充实生成的代码。这
通过扩展生成的类。并与 Coprocessor 和 CoprocessorService 接口合并,这两个接口定义生命周期回调,以及标记该类为一个服务。下面示例展示了
上面定义的 row-counter 服务,利用提供的协处理器环境访问 region, 并最终通过 InternalScanner 实例访问数据。

示例: Example endpoint implementation, adding a row and cell count method.

public class RowCountEndpoint extends RowCounterProtos.RowCountService
implements Coprocessor, CoprocessorService {
    
    private RegionCoprocessorEnvironment env;
    @Override
    public void start(CoprocessorEnvironment env) throws IOException {
        if (env instanceof RegionCoprocessorEnvironment) {
            this.env = (RegionCoprocessorEnvironment) env;
        } else {
            throw new CoprocessorException("Must be loaded on a table region!");
        }
    }
    
    @Override
    public void stop(CoprocessorEnvironment env) throws IOException {
    // nothing to do when coprocessor is shutting down
    }
    
    @Override
    public Service getService() {
        return this;
    }
    
    @Override
    public void getRowCount(RpcController controller,
    RowCounterProtos.CountRequest request,
    RpcCallback<RowCounterProtos.CountResponse> done) {
    
        RowCounterProtos.CountResponse response = null;
    
        try {
            long count = getCount(new FirstKeyOnlyFilter(), false);
            response = RowCounterProtos.CountResponse.newBuilder()
            .setCount(count).build();
        } catch (IOException ioe) {
            ResponseConverter.setControllerException(controller, ioe);
        }
        done.run(response);
    }
    
    @Override
    public void getCellCount(RpcController controller, RowCounterProtos.CountRequest request,
    RpcCallback<RowCounterProtos.CountResponse> done) {
        RowCounterProtos.CountResponse response = null;
        try {
            long count = getCount(null, true);
            response = RowCounterProtos.CountResponse.newBuilder()
            .setCount(count).build();
        } catch (IOException ioe) {
            ResponseConverter.setControllerException(controller, ioe);
        }
        done.run(response);
    }
    /**
    * Helper method to count rows or cells.
    * *
    * @param filter The optional filter instance.
    * @param countCells Hand in <code>true</code> for cell counting.
    * @return The count as per the flags.
    * @throws IOException When something fails with the scan.
    */
    private long getCount(Filter filter, boolean countCells)
    throws IOException {
        long count = 0;
        Scan scan = new Scan();
        scan.setMaxVersions(1);
        if (filter != null) {
            scan.setFilter(filter);
        }
        
        try (
            InternalScanner scanner = env.getRegion().getScanner(scan);
        ) {
            List<Cell> results = new ArrayList<Cell>();
            boolean hasMore = false;
            byte[] lastRow = null;
            do {
                hasMore = scanner.next(results);
                for (Cell cell : results) {
                    if (!countCells) {
                        if (lastRow == null || !CellUtil.matchingRow(cell, lastRow))
                        {
                            lastRow = CellUtil.cloneRow(cell);
                            count++;
                        }
                        } else count++;
                }
                results.clear();
            } while (hasMore);
        }
        return count;
    }
}


    NOTE
    -------------------------------------------------------------------------------------------------------------------------------------
    需要向 hbase-site.xml 文件添加如下属性,使 region server 进程加载 endpoint 协处理器

        <property>
            <name>hbase.coprocessor.user.region.classes</name>
            <value>coprocessor.RowCountEndpoint</value>
        </property>
        
    调整之后,重启 HBase 以使配置生效。

下面示例展示客户端使用 Table 提供的方法调用执行已部署的协处理器 endpoint 功能。因为调用被分别发送到每个 region, 因此在最后需要一个总数计算

示例: Example using the custom row-count endpoint

public class EndpointExample {
    
    public static void main(String[] args) throws IOException {
        
        Configuration conf = HBaseConfiguration.create();
        TableName tableName = TableName.valueOf("testtable");
        Connection connection = ConnectionFactory.createConnection(conf);
        Table table = connection.getTable(tableName);
        
        try {
            final RowCounterProtos.CountRequest request = RowCounterProtos.CountRequest.getDefaultInstance();
            Map<byte[], Long> results = table.coprocessorService(RowCounterProtos.RowCountService.class, null, null,
            new Batch.Call<RowCounterProtos.RowCountService, Long>() {
            public Long call(RowCounterProtos.RowCountService counter)
            throws IOException {
                BlockingRpcCallback<RowCounterProtos.CountResponse> rpcCallback = new BlockingRpcCallback<RowCounterProtos.CountResponse>();
                counter.getRowCount(null, request, rpcCallback);
                RowCounterProtos.CountResponse response = rpcCallback.get();
                return response.hasCount() ? response.getCount() : 0;
                }
            }
            );
            
            long total = 0;
            for (Map.Entry<byte[], Long> entry : results.entrySet()) {
                total += entry.getValue().longValue();
                System.out.println("Region: " + Bytes.toString(entry.get‐
                Key()) +
                ", Count: " + entry.getValue());
            }
                System.out.println("Total Count: " + total);
            } catch (Throwable throwable) {
                throwable.printStackTrace();
        }
    }
}


输出:

Before endpoint call...
Cell: row1/colfam1:qual1/2/Put/vlen=4/seqid=0, Value: val2
Cell: row1/colfam2:qual1/2/Put/vlen=4/seqid=0, Value: val2
...
Cell: row5/colfam1:qual1/2/Put/vlen=4/seqid=0, Value: val2
Cell: row5/colfam2:qual1/2/Put/vlen=4/seqid=0, Value: val2
Region: testtable,,1427209872848.6eab8b854b5868ec...a66e83ea822c.,
Count: 2
Region: testtable,row3,1427209872848.3afd10e33044...8e071ce165ce.,
Count: 3
Total Count: 5

稍微修改一下用于批次调用:

示例: Example using the custom row-count endpoint in batch mode

final CountRequest request = CountRequest.getDefaultInstance();
Map<byte[], CountResponse> results = table.batchCoprocessorService(
RowCountService.getDescriptor().findMethodByName("getRowCount"),
request, HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW,
CountResponse.getDefaultInstance());

long total = 0;
for (Map.Entry<byte[], CountResponse> entry : results.entrySet()) {
    CountResponse response = entry.getValue();
    total += response.hasCount() ? response.getCount() : 0;
    System.out.println("Region: " + Bytes.toString(entry.get‐
    Key()) +
    ", Count: " + entry.getValue());
}
System.out.println("Total Count: " + total);

输出结果是一样的。



3.5 Observers
-----------------------------------------------------------------------------------------------------------------------------------------
endpoint 在某些方面能反应出数据库存储过程(stored procedures)的功能,而 observer 类似于触发器(trigger)。与 endpoint 不同的是,observer 不仅
可以运行于 region context, 它们可以运行于系统的不同部分,并与客户端触发的事件交互,也隐式地与服务器本身相互作用。

observer 的另一个不同之处是,observer 使用预先定义好的钩子钩入服务器进程,也就是说,用户不能添加自己的自定义钩子。它们也是只作用于服务器端,
与客户端没有连接。

由于可以加载多个 observer 到同一组 context 中,即:region, region server, master server, WAL, bulk loading, 以及 endpoint, 因此设置它们调用
次序非常重要。


3.6 The ObserverContext Class
-----------------------------------------------------------------------------------------------------------------------------------------
对于 Observer 提供的回调,所有调用都有一个特定的 context 作为第一个参数:ObserverContext 类的实例。它提供了访问当前环境,以及在回调完成后
协处理器框架要做的工作。

    NOTE
    -------------------------------------------------------------------------------------------------------------------------------------
    在执行链中所有的协处理器,observer context 实例都是同一个,只是为每一个协处理器通过 environment 进行了封装。
    

下面是其提供的方法:


    ● E getEnvironment()
    -------------------------------------------------------------------------------------------------------------------------------------
    返回当前协处理器环境的引用。返回的是匹配特定协处理器实现的参数化了的环境,如,一个 RegionObserver, 会表现为 RegionCoprocessorEnvironment
    接口实现的实例。

    ● void prepare(E env)
    -------------------------------------------------------------------------------------------------------------------------------------
    使用特定的环境(environment)准备 context. 仅由静态 createAndPrepare() 方法内部使用。


    ● void bypass()
    -------------------------------------------------------------------------------------------------------------------------------------
    用户代码调用这个方法,框架会使用用户提供的值,相对于通常调用方法返回的值。



    ● void complete()
    -------------------------------------------------------------------------------------------------------------------------------------
    指示框架可以跳过任何更进一步的处理,忽略执行链中剩余的协处理器。表明这个协处理器响应是最终的值。


    ● boolean shouldBypass()
    -------------------------------------------------------------------------------------------------------------------------------------
    用于框架内部以检查 bypass 标记。


    ● boolean shouldComplete()
    -------------------------------------------------------------------------------------------------------------------------------------
    用于框架内部以检查 complete 标记。

    
    ● static <T extends CoprocessorEnvironment> ObserverContext<T> createAndPrepare(T env, ObserverContext<T> context)
    -------------------------------------------------------------------------------------------------------------------------------------
    静态方法用于初始化一个 context, 当提供的 context 为 null 时,该方法会创建一个新的实例。


重要的 context 方法时 bypass() 和 complete(). 这两个方法给出了用户的协处理器实现控制框架后续行为的选择。complete()调用影响协处理器执行链,
而 bypass() 调用停止在服务器上,当前 observer 内更进一步的默认处理。例如,可以避免自动分区切分,如下:

    @Override
    public void preSplit(ObserverContext<RegionCoprocessorEnvironment>
    e) {
        e.bypass();
        e.complete();
    }

bypass 和 complete 有一些微妙的不同:它们用于不同的目的,因此用法上有不同的效果。

    Overview of bypass and complete, and their effects on coprocessors
    +-----------+-----------+---------------+-------------------+---------------+-------------------+
    | Bypass    | Complete    | Current-Pre    | Subsequent-Pre    | Current-Post    | Subsequent-Post    |
    +-----------+-----------+---------------+-------------------+---------------+-------------------+
    | ×            | ×            | no effect        | no effect            | no effect        | no effect            |
    +-----------+-----------+---------------+-------------------+---------------+-------------------+
    | √            | ×            | skip further    | no effect            | no effect        | no effect            |
    +-----------+-----------+---------------+-------------------+---------------+-------------------+
    | ×            | √            | no effect        | skip                | no effect        | skip                |
    +-----------+-----------+---------------+-------------------+---------------+-------------------+
    | √            | √            | skip further    | skip                | no effect        | skip                |

    +-----------+-----------+---------------+-------------------+---------------+-------------------+

 

 

系列目录:

    HBase 协处理器 (一)

    HBase 协处理器 (二)

 

参考:

    《HBase - The Definitive Guide - 2nd Edition》Early release —— 2015.7 Lars George

 

 

HBase Coprocessor:扩展HBase功能的利器 想象你经营着一家大型超市(HBase集群),货架(Region)上摆满了商品(数据),顾客(Client)来购物时,收银员(RegionServer)负责找商品、结账。但如果顾客问:“今天所有饮料的总销售额是多少?” 收银员需要跑遍所有饮料货架逐个统计,效率很低;计算逻辑只能在客户端执行,大量数据需要跨网络传输,处理效率低下。 阅读详情

相关推荐

手机移动端-纯js浏览器h5调用摄像头扫描识别解析 条形码+二维码

一、场景 h5原生js 浏览器端解决识别二维码条形码功能; 不借助Hbuilder.需要自己打包成APP,比如用Hbuilder打包,浏览器端项目h5无打包成app部署X不采用 不借助微信扫一扫,调用微信js-jdk有多麻烦,还要认证服务号,也不适用其它浏览器打开X不采用 二、思路 1.思路一:input(相机拍照)+条形码或二维码识别js支持库 通过h5-input[camera]调用相机进行拍照成图片,通过条形码等识别库解析出数据; <input @cha...

徐子厚的博客 3万+

Hbase使用Coprocessor构建二级索引

为什么需要二级索引 Hbase默认只支持对行键的索引,那么如果需要针对其它的列来进行查询,就只能全表扫描了。表如果较大的话,代价是不可接受的,所以要提出二级索引的方案。网上的实现方法很多,华为,360等公司都有自己的方案,其中华为的已经开源,但是貌似对源码改动较大,新手不容易接受,所以没有选择它们。而其它的像利用Phoenix,solr等外部框架构建索引对Hbase的学习并没有太大的帮助。综上所...

lzf的博客 908

camera 知识速查

本文总结了Camera开发中的常见问题排查方法和关键技术点。主要内容包括:I2C/MIPI不通的排查步骤、时序问题分析方法、Sensor/AF/Flash/PDAF的Bring Up流程、OTP调试方法、PDAF原理及调试、CTS/ITS问题解决思路、AE震荡解决方案、Systrace性能分析方法、Flicker产生原理、Tombstone问题定位等。还涉及V4L2框架解析、问题定位分层方法、Sensor Setting注意事项、时钟信号概念、第三方应用卡顿排查、大光圈概念、Monkey测试方法。

qq_41665131的博客 785

HBase隔离方案实战-rsgroup

本文参考: https://www.jianshu.com/p/04d56a2c8b5c  , 这篇文章写的很好, 就是命令没法用, 一度以为我们的集群不支持rsgroup, 无意中试出了帮助命令, 才发现, 命令不太对, 不知道是作者粗心还是每个版本的命令不一样, 这里做了一些修正, 我们的集群是CDH5.12.1, hbase是1.2.0   HBase适合用于海量数据的存储,横向扩展非常...

稼轩 6018

HighScore3.0实战指南:XRD物相分析从入门到精通(持续更新版)

本文提供HighScore3.0软件进行XRD物相分析的完整实战指南。从软件设置、数据导入、背景扣除、寻峰等预处理步骤,到核心的Search & Match物相搜索匹配、Rietveld精修定量,以及结果输出与常见问题排查,系统讲解了从入门到精通的全流程操作与核心技巧,帮助用户高效完成材料物相鉴定与分析工作。

weixin_29310605的博客 1046

110、3A 端到端调试:从 ISP register dump 到主观画质的完整调试流程

文章摘要 本文分享了ISP 3A(AE/AWB/AF)端到端调试的实战经验,通过具体案例解析常见问题排查方法。从硬件链路确认、寄存器dump分析、算法闭环验证到主观画质调优,提出了一套系统化调试流程。重点包括:如何通过示波器和寄存器抓包定位时序问题,AWB调试中black level校正的关键作用,AF闭环控制中hall传感器反馈的重要性,以及算法与硬件联调的"三板斧"方法论。作者强调3A调试本质是系统工程,需结合物理层信号测量、数据通路验证和算法状态跟踪,避免陷入局部优化陷阱。

sundong_81的博客 58

使用HBase Coprocessor协处理器

原文: http://www.zhyea.com/2017/04/13/using-hbase-coprocessor.html HBase的Coprocessor是模仿谷歌BigTable的Coprocessor模型实现的。 Coprocessor提供了一种机制可以让开发者直接在RegionServer上运行自定义代码来管理数据。 首先必须要指明使用Coprocess

9217

YOLOv8改进 | 独家创新篇 | 给YOLOv8增加辅助可逆分支结构(PGI,1:1改进)(全网独家创新,附视频讲解)

这张图(图3)展示了可编程梯度信息(PGI)及其相关网络架构和方法。这种网络结构主要用于改进特征融合,以提高目标检测的性能。然而,由于信息瓶颈的存在,网络中可能会丢失一些信息。这是一种旨在减少信息丢失的网络设计。它通过可逆的列结构来尝试维持信息流通不受损失,但如图中“Heavy Cost”所示,这种结构会增加计算成本。c) 深度监督:这种方法通过在网络的多个层次中插入额外的监督信号来提高学习的效率和最终模型的性能。图中显示了通过深度监督连接的各个层。

Snu77的博客 3745

HBase--Coprocessor协处理器

前面说过,Hbase做聚合,分组之类的运算很不方便,更不要说join之类的,更是麻烦。有没有好点的办法呢?这里介绍下HBase--Coprocessor。Hbase有两种类型的Coprocessor,为:Observer Coprocessors 和Endpoint Coprocessor,前者类似触发器,在特定的事件发生时候触发,后者类似存储过程,执行数据计算。观察者协处理器在  很多地方可能用

数据时代--收集,存储,处理,分析,挖掘,检索,展现 1810

Qt(C++)使用QChart动态显示3个设备的温度变化曲线

Qt的QChart是一个用于绘制图表和可视化数据的类。提供了一个灵活的、可扩展的、跨平台的图表绘制解决方案,可以用于各种应用程序,如数据分析、科学计算、金融交易等。

1917

DeepSeek网页版和DeepSeek Harness

DeepSeek网页版是开箱即用的对话工具,适合快速问答与日常任务;而DeepSeekHarness(dsh)是基于Node.js的开源智能体框架,支持文件操作、命令执行、多工具协同,实现“对话即执行”。二者定位不同:网页版为“大脑”,Harness为“躯体”。前者封闭易用,后者开放可扩展,具备可追溯的执行日志与插件化架构。未来,网页版将聚焦轻量化普及,Harness则致力于构建生态平台。对开发者而言,应将AI作为执行层,守住决策层,深耕垂直领域,并掌握AI工作流设计能力,以构建不可替代的技术优势。

几十年资深高级架构师,技术专家的技术笔记。专注C、Java、Python、微服务、云原生、AI工程化及高并发系统分布式架构实战,分享源码剖析、性能调优与架构治理经验。 930

【HBase】17-协处理器

1、协处理器简介 使用客户端API,配合筛选机制,例如,使用过滤器或限制列族的范围,都可以控制被返回到客户端的数据量。如果可以更进一步优化会更好,例如,数据的处理流程直接放到服务器端执行,然后仅返回一个小的处理结果集。这类似于一个小型的MapReduce框架,该框架将工作分发到整个集群。 协处理器允许用户在 region服务器上运行自己的代码,更准确地说是允许用户执行region级的操作,并且可...

通往神秘的道路的专栏 1927

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

HBase 协处理器实践(一)AggregationClient

HBase 协处理器实践(一)          对数据表中的数据进行求和。        1、添加coprocessor AggregateImplementation分为添加全局和为单表添加Aggregation。          a、 添加全局AggregateImplementation,方法:修改hbase-site.xml文件,在该文件中添加 hbase.copr

菜菜的博客 7060

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Hbase 协处理器(一)之RowCount代码

public class RowCountEndpoint extends ExampleProtos.RowCountService     implements Coprocessor, CoprocessorService {   private RegionCoprocessorEnvironment env;   public RowCountEndpoint() {

dhtx_wzgl的博客 1743

(九)HBase的协处理器

文章目录HBase的协处理器(一)协处理器起源(二)两种协处理器(三)协处理器加载方式(四)协处理器Observer实战1.HBase当中创建第一张表proc12.Hbase当中创建第二张表proc23.开发HBase的协处理器4.将项目打成jar包,并上传到HDFS上面5.将打好的jar包挂载到proc1表当中去6.向proc1表中添加数据7.卸载协处理器命令 HBase的协处理器 http:/...

DevinKim的博客 561

Hbase协处理器

cxy_19891109的博客 121

hbase 2.1.5利用协处理器同步新增数据到ES填坑记录

1.hbase-site.xml配置文件必须添加<property> <name>hbase.coprocessor.abortonerror</name> <value>false</value> </property>,防止因协处理器启动失败,导致regionServer挂掉,从而导致hbase崩溃。 2.一定要实现R...

lieying411 618

如何实现HBase的二级索引

方案二: 基于Phoenix实现, Phoenix是一款基于hbase的SQL客户端, 可以使用SQL的方式来操作hbase, 同时为了提升整体的查询性能, Phoenix中提供了各种索引(全局索引, 本地索引, 覆盖索引以及函数索引), 这些索引都是基于Hbase的协处理器(主要是ObServer协处理器)而实现的, 二级索引的查询方案, 也是Phoenix实现hbase二级索引的方式。

weixin_59295776的博客 633

HBase 协处理器统计行数

环境:cdh5.1.0 启用协处理器方法1. 启用协处理器 Aggregation(Enable Coprocessor Aggregation) 我们有两个方法:1.启动全局aggregation,能过操纵所有的表上的数据。通过修改hbase-site.xml这个文件来实现,只需要添加如下代码: <property> <name>hb...

weixin_30907523的博客 373

自定义 HBase-MapReduce

自定义 HBase-MapReduce1 hdfs -> table1) mapper2) reducer3) driver4) 打包上传并执行2 table -> table1) mapper2) reducer3) driver 1 hdfs -> table 需求: 从hdfs读取数据,插入到hbase的表中 1) mapper public class FruitMapper extends Mapper<LongWritable, Text,LongWritable, Te

qq_51138261的博客 404

HBase协处理器问题

HBase协处理器问题

weixin_43540084的博客 562

Hbase--协处理器

协处理器1、协处理器:Coprocessor2、应用需求1:构建协处理器实现:当往proc1表中插入数据时,自动往proc2中插入一份相同的数据需求2:构建协处理器实现:当往proc3原表中插入数据时,自动往索引表proc4中插入原表的rowkey 1、协处理器:Coprocessor 本质:类似于Hive中的udf或者MySQL的触发器 本身Hbase没有提供这个功能 但是提供了 这个开发的接口 你可以自定义开发这个功能,集成在Hbase的服务端 分类 observer:观察者的协处理器,类似于

qq_46893497的博客 842

Hbase取数据问题Bug

问题描述: hbase表中有数据,而使用hbase的Client取数据的条数小于hbase实际的条数。并且在客户端是没有报错信息。 Bug1: 使用的是协处理器进行取数据的,说下协处理器的作用,在客户端对所取的数据进行处理后,再返回给客户端。这样可以减少数据的传输,提高查询速度。 客户端没有报错,找了下服务器端,报错信息如下: 2019-03-01 14:46:04,924 ERRO...

weixin_30765505的博客 253

Hbase二级索引,索引海量数据实现方案

方案1:使用开源的hbase-indexer,是借助于hbase的WAL实现,不会影响hbase性能            https://blog.csdn.net/xiahoujie_90/article/details/53400044方案2:基于ES自己实现,利用habse的协处理器实现,会影响hbase性能关键注意点:因为数据是存在Hbase中,ES充当的是索引角色,所以在创建ES的ma...

join_null的博客 3018

java.lang.RuntimeException: HRegionServer Aborted

我添加协处理后在hbase shell中执行scan操作时regionserver部分挂掉,查看日志。 java.lang.RuntimeException: HRegionServer Aborted at org.apache.hadoop.hbase.regionserver.HRegionServerCommandLine.start(HRegionServerCommandL at ...

weixin_38842096的博客 1259
上一篇: HBase 计数器 (Counters)
下一篇: HBase 协处理器 (二)
devalone
博客等级 码龄17年 108粉丝 80原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值