Hbase-Observer

  • HBase的協處理器涵蓋了兩種類似關係型數據庫中的應用場景:存儲過程和觸發器,所以協處理器也分爲兩種:用來實現存儲過程功能的終端 程序EndPoint和用來實現觸發器功能的觀察者Observers

Observer

  • 在hbase2.x的時候,按照之前的繼承BaseRegionObserver 是不起作用的,經過我的測試,這個類好像是被移除了,我使用的版本是2.1.1
  • 新的實現可以查看接口Coprocessor來查看,我們來看一下

    /**
     * Base interface for the 4 coprocessors - MasterCoprocessor, RegionCoprocessor,
     * RegionServerCoprocessor, and WALCoprocessor.
     * Do NOT implement this interface directly. Unless an implementation implements one (or more) of
     * the above mentioned 4 coprocessors, it'll fail to be loaded by any coprocessor host.
     *
     * Example:
     * Building a coprocessor to observe Master operations.
     * <pre>
     * class MyMasterCoprocessor implements MasterCoprocessor {
     *   &#64;Override
     *   public Optional&lt;MasterObserver> getMasterObserver() {
     *     return new MyMasterObserver();
     *   }
     * }
     * class MyMasterObserver implements MasterObserver {
     *   ....
     * }
     * </pre>
     * Building a Service which can be loaded by both Master and RegionServer
     * <pre>
     * class MyCoprocessorService implements MasterCoprocessor, RegionServerCoprocessor {
     *   &#64;Override
     *   public Optional&lt;Service> getServices() {
     *     return new ...;
     *   }
     * }
     */
  • 這是Coprocessor接口的介紹,非常清楚的介紹了協處理器的用法,那麼我就簡單的翻譯一下下,自己的英語很渣的

    有四個接口的父類是coprocessors,他們分別是MasterCoprocessor, RegionCoprocessor, RegionServerCoprocessor, WALCoprocessor.
    不要去直接實現coprocessors接口,除非你的實現類實現了上述4個Observer
    然後下面的就是一些具體的實現代碼
  • 經過之前的介紹,我們知道了Observer的作用就類似一個觸發器,當指定操作也就是你實現的方法對應的操作被執行的時候,你定義的Observer邏輯就會去在HBase上去跑,以實現一些控制
  • 當然上面的coprocessors的實現不知四個接口,還有一些其他實現類,比如AccessController,這個提供數據訪問和管理的基本授權檢查等操作,還有一些自己可以去查看一下
  • 多說無益,直接上 需求

     t1表中有f1列族
     向f1中插入name,然後自動計算出name的hash作爲此行的password列,不可單獨添加password
     可刪除name,順便一起刪除password,不可單獨刪除password
  • maven

    <dependencies>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-server</artifactId>
            <version>2.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>2.7.7</version>
        </dependency>
    </dependencies>
  • 直接上 代碼

    public class MyRegionCoprocessor implements RegionCoprocessor {
        @Override
        public Optional<RegionObserver> getRegionObserver() {
            return Optional.ofNullable(new MyRegionObserver());
        }
        private static class MyRegionObserver implements RegionObserver {
            private static final byte[] FAMILY = Bytes.toBytes("f1");
            private static final byte[] COL_NAME = Bytes.toBytes("name");
            private static final byte[] COL_PASSWORD = Bytes.toBytes("password");
            @Override
            public void prePut(ObserverContext<RegionCoprocessorEnvironment> c, Put put, WALEdit edit, Durability durability) throws IOException {
                //如果插入的是password列,那麼就報錯
                List<Cell> passwords = put.get(FAMILY, COL_PASSWORD);
                if (passwords.size() != 0 || !passwords.isEmpty()){
                    throw new IllegalArgumentIOException("Password insertion is not allowed !!");
                }
                //如果添加的是name,那麼就增加相對應的name的hash的password列
                List<Cell> names = put.get(FAMILY, COL_NAME);
                names.forEach(name -> {
                    int hash = Objects.hash(name);
                    put.addColumn(FAMILY,COL_PASSWORD,Bytes.toBytes(hash));
                });
            }
            @Override
            public void preDelete(ObserverContext<RegionCoprocessorEnvironment> c, Delete delete, WALEdit edit, Durability durability) throws IOException {
                //阻止刪除密碼,不可單獨刪除密碼
                List<Cell> passwords = delete.get(FAMILY, COL_PASSWORD);
                if (passwords.size() != 0 || !passwords.isEmpty()){
                    throw new IllegalArgumentIOException("Password insertion is not delete !!");
                }
                //到這就代表不是密碼了,獲取name,然後刪除對應的password
                List<Cell> names = delete.get(FAMILY, COL_NAME);
                names.forEach(name -> {
                    delete.addColumns(FAMILY,COL_PASSWORD);
                });
            }
        }
    }
  • 如果你對上面的Optional類感到陌生,你就記住他是用來判斷值是否是空的就可以,如果想進一步瞭解,你可以參考我的專輯Java8學習,希望能幫助到你
  • 上面的代碼邏輯還是比較清晰的,在外部類的重寫的方法getRegionObserver中返回了我們自己實現的Observer類,當然這個方法是不用必須重寫的,當我們需要實現自己的Observer的時候必須重寫getRegionObserver,而當我們實現自己的EndPoint的時候,就需要重寫getEndpointObserver方法了,還有一個在RegionCoprocessor中的方法是getBulkLoadObserver,從名字我們可以看到是批加載用的
  • 當我們實現好了自己的Observer的時候,我們就需要部署到HBase集羣中去看看效果,在網上我並沒有找到類似本地測試Observer的辦法,這可真是麻煩.
  • 開始部署,當然打成jar,我就不說了,打完後,部署到HBase的方式有兩種,一種是通過配置文件的方式去部署,一種是通過動態的方式去部署,前者稱爲靜態部署,後面即動態部署, 靜態部署 我將簡單介紹一下,如下,而自己使用的是動態部署的方法

    在hbase-site.xml中配置靜態部署
      <property>
          <name>hbase.coprocessor.region.classes</name>   #這是配置region的協處理器,對應的就是:hbase.coprocessor.master.classes
          <value>你的全類名</value>   #如果想同時配置多個協處理器,可以用逗號分隔多個協處理器的類名
      </property>
    相關的配置
      hbase.coprocessor.enabled:是否啓用協處理器機制,默認true,即開啓
      hbase.coprocessor.user.enabled:即是否允許用戶動態配置,如果爲false,就只能在xml中配置了
      hbase.coprocessor.wal.classes:即監控wal的
      hbase.coprocessor.abortonerror:即如果個別協處理器啓動失敗整個hbase是否啓動,默認是如果有的協處理器啓動失敗,那麼hbase就不起了
    需要注意的是
      1.配置順序決定了執行順序
      2. 所有協處理器是以系統級優先級加載的 (優先級一會兒會提到)
      3. 重啓集羣起作用
  • 動態配置

    • 首先你如果使用我上面的代碼測試,那麼請create 't1','f1'
    • 然後將你的jar上傳到集羣,然後上傳到hdfs,如果你使用我的代碼測試,請直接將jar上傳到hdfs:///hbase.jar
    • 然後disable 't1'
    • 然後使用特定命令在表上配置協處理器:alter 't1','coprocessor'=>'hdfs:///hbase.jar|qidai.MyRegionCoprocessor|1001|''
    • 再然後enabled 't1'
    • 然後desc 't1',你就會看到
    hbase(main):086:0> desc 't1'
    Table t1 is ENABLED
    #注意這裏代表已經配置上去了,如果沒有配置上的話,就是 : 緊接着COLUMN FAMILIES DESCRIPTION 字眼,並沒有下面的說明
    t1, {TABLE_ATTRIBUTES => {coprocessor$1 => 'hdfs://hbase.jar|qidai.MyRegionCoprocessor|1001|'}        
    COLUMN FAMILIES DESCRIPTION                                                       
    • 到了這一步其實就可以了,然後在t1表中盡情測試需求就好了,我測試的時候就很簡單的測試了一下,如果你使用我的代碼測試,如果有問題,請及時指正哈!!!如果你發現你的動態配置貌似沒起作用,那麼請重啓一下對應的RegionServer,我出現了這個問題,估計是我的筆記本內存上限了,沒反應過來??????
  • 到這就該 說說優先級 了,如上如果配置了處理器,多出來的那一行我們分析一下

    alter 't1','coprocessor'=>'hdfs:///hbase.jar|qidai.MyRegionCoprocessor|1001|'
    alter '表名','coprocessor'=>'hdfs地址|你的全類名|優先級|傳入給你實現類的參數'
    
    這裏的優先級是0是最高的,以整數來表示的,越小值越先被執行
  • 好了到這之後,大概的一些問題已經解決了,那麼怎麼將Observer給 卸載 呢 ?

    • 靜態部署的話,那麼刪除對應的xml內容,然後重啓HBase即可
    • 動態部署的話,我們可以先disable,然後使用alter 't1', METHOD => 'table_att_unset', NAME => 'coprocessor$1'來進行卸載,在最後面的coprocessor$1需要自己改一下,看看自己的處理器名是啥就寫啥,然後在enable就行了
  • 剩餘的EndPoint的使用這篇暫時不介紹, 不過遲早會補上的 , 因爲現在只對Avro瞭解一些, 而Protobuf 不太清楚, 恩..今天這篇涉及的只是Observer一些最基本的操作,是並沒有涉及什麼原理之類的, 所以在瞭解其原理之前這也是必備的知識, 如果本片文章對你有些許幫助那就點個贊吧哈哈
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章