- 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 { * @Override * public Optional<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 { * @Override * public Optional<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一些最基本的操作,是並沒有涉及什麼原理之類的, 所以在瞭解其原理之前這也是必備的知識, 如果本片文章對你有些許幫助那就點個贊吧哈哈