1. 程式人生 > >使用HBase Coprocessor協處理器

使用HBase Coprocessor協處理器

原文:

HBase的Coprocessor是模仿谷歌BigTable的Coprocessor模型實現的。

Coprocessor提供了一種機制可以讓開發者直接在RegionServer上執行自定義程式碼來管理資料。

首先必須要指明使用Coprocessor還是存在一些風險的。Coprocessor是HBase的高階功能,本來是隻為HBase系統開發人員準備的。因為Coprocessor的程式碼直接在RegionServer上執行,並直接接觸資料,這樣就帶來了資料破壞的風險,比如“中間人攻擊(Man-in-the-MiddleAttack,簡稱“MITM攻擊”,見百度詞條

)”以及其他型別的惡意入侵。目前還沒有任何機制來遮蔽Coprocessor導致的資料破壞。此外,因為沒有資源隔離,一個即使不是惡意設計的但表現不佳的Coprocessor也會嚴重影響叢集的效能和穩定性。

通常我們訪問HBase的方式是使用scan或get獲取資料,使用Filter過濾掉不需要的部分,最後在獲取到的資料上進行業務運算。但是在資料量非常大的時候,比如一個有上億行及十萬個列的資料集,再按常用的方式移動獲取資料就會在網路層面遇到瓶頸。客戶端也需要有強大的計算能力以及足夠的記憶體來處理這麼多的資料。此外,這也會使客戶端的程式碼變得龐大而複雜。

這種場景正是Coprocessor可以發揮作用的地方。我們可以將業務運算程式碼封裝到Coprocessor中並在RegionServer上執行,即在資料實際儲存位置執行,最後將運算結果返回到客戶端。

如下的一些理論可以幫助我們理解Coprocessor是如何發揮作用的:

觸發器和儲存過程:一個Observer Coprocessor有些類似於關係型資料庫中的觸發器,通過它我們可以在一些事件(如Get或是Scan)發生前後執行特定的程式碼。Endpoint Coprocessor則類似於關係型資料庫中的儲存過程,因為它允許我們在RegionServer上直接對它儲存的資料進行運算,而非是在客戶端完成運算。

MapReduce:MapReduce的原則就是將運算移動到資料所處的節點。Coprocessor也是按照相同的原則去工作的。

AOP:如果熟悉AOP的概念的話,可以將Coprocessor的執行過程視為在傳遞請求的過程中對請求進行了攔截,並執行了一些自定義程式碼。

Coprocessor型別

Coprocessor可以分為兩大類:Observer Coprocessors(觀察者)和EndPoint Coprocessor(終端)。

Observer Coprocessors

Observer Coprocessor在一個特定的事件發生前或發生後觸發。在事件發生前觸發的Coprocessor需要重寫以pre作為字首的方法,比如prePut。在事件發生後觸發的Coprocessor使用方法以post作為字首,比如postPut。

Observer Coprocessor的使用場景如下:

  • 安全性:在執行Get或Put操作前,通過preGet或prePut方法檢查是否允許該操作;
  • 引用完整性約束:HBase並不直接支援關係型資料庫中的引用完整性約束概念,即通常所說的外來鍵。但是我們可以使用Coprocessor增強這種約束。比如根據業務需要,我們每次寫入user表的同時也要向user_daily_attendance表中插入一條相應的記錄,此時我們可以實現一個Coprocessor,在prePut方法中新增相應的程式碼實現這種業務需求。
  • 二級索引:可以使用Coprocessor來維持一個二級索引。這裡暫不展開,有時間會單獨說明。

根據作用的物件,Observer Coprocessor有如下幾種:RegionObserver、RegionServerObserver、MasterObserver和WalObserver。我們可以通過這些Observer來處理其觀察的物件的操作,比如可以通過RegionObserver處理Region相關的事件,如Get和Put操作。

Endpoint Coprocessor

Endpoint Coprocessor可以讓開發者在資料本地執行運算。一個典型的案例:一個table有幾百個Region,需要計算它的執行平均值或者總和。

Observer Coprocessor中程式碼的執行是相對透明的,而對於Endpoint Coprocessor,則需要顯式的呼叫Table, HTableInterface或者HTable中的CoprocessorService()方法才能使之執行。

從0.96版本開始,HBase開始使用Google的protobuff。這對Endpoint Coprocessor的開發多少有一些影響。Endpoint Coprocessor不應該使用HBase內部成員,儘量只使用公共的API,最理想的情況應該是隻依賴介面和資料結構。這樣可以使開發的Endpoint Coprocessor更加健壯,不會受到HBase核心演進的干擾。註釋為private或evolving的HBase內部API在刪除前不必遵守關於deprecate的語義版本規則或相關的一般java規則。而使用protobuff生成的檔案不會受到這些註釋的影響,因為這些檔案是用protoc工具自動生成的。在生成時這些檔案時,protoc不知道也不會考慮HBase是如何工作的。

裝載和解除安裝Coprocessor

要使用Coprocessor,就需要先完成對其的裝載。這可以靜態實現(通過HBase配置檔案),也可以動態完成(通過shell或Java API)。

靜態裝載和解除安裝Coprocessor

按以下如下步驟可以靜態裝載自定義的Coprocessor。需要注意的是,如果一個Coprocessor是靜態裝載的,要解除安裝它就需要重啟HBase。

靜態裝載步驟如下:

1. 在hbase-site.xml中使用<property>標籤定義一個Coprocessor。<property>的子元素<name>的值只能從下面三個中選一個:

  • hbase.coprocessor.region.classes 對應 RegionObservers和Endpoints;
  • hbase.coprocessor.wal.classes 對應 WALObservers;
  • hbase.coprocessor.master.classes 對應MasterObservers。

而<value>標籤的內容則是自定義Coprocessor的全限定類名。

下面演示瞭如何裝載一個自定義Coprocessor(這裡是在SumEndPoint.java中實現的),需要在每個RegionServer的hbase-site.xml中建立如下的記錄:

1234<property><name>hbase.coprocessor.region.classes</name><value>org.myname.hbase.coprocessor.endpoint.SumEndPoint</value></property>

如果要裝載多個類,類名需要以逗號分隔。HBase會使用預設的類載入器載入配置中的這些類,因此需要將相應的jar檔案上傳到HBase服務端的類路徑下。

使用這種方式載入的Coprocessor將會作用在HBase所有表的全部Region上,因此這樣載入的Coprocessor又被稱為系統Coprocessor。在Coprocessor列表中第一個Coprocessor的優先順序值為Coprocessor.Priority.SYSTEM,其後的每個Coprocessor的值將會按序加一(這意味著優先順序會減降低,因為優先順序是按整數的自然順序降序排列的)。

當呼叫配置的Observer Coprocessor時,HBase將會按照優先順序順序依次呼叫它們的回撥方法。

2. 將程式碼放到HBase的類路徑下。一個簡單的方法是將封裝好的jar(包括程式碼和依賴)放到HBase安裝路徑下的/lib目錄中。

3. 重啟HBase。

靜態解除安裝的步驟如下:

1. 移除在hbase-site.xml中的配置。

2. 重啟HBase。

3. 這一步是可選的,將上傳到HBase類路徑下的jar包移除。

動態裝載Coprocessor

動態裝載Coprocessor的一個優勢就是不需要重啟HBase。不過動態裝載的Coprocessor只是針對某個表有效。因此,動態裝載的Coprocessor又被稱為表級Coprocessor。

此外,動態裝載Coprocessor是對錶的一次schema級別的調整,因此在動態裝載Coprocessor時,目標表需要離線。

動態裝載Coprocessor有兩種方式:通過HBase Shell和通過Java API。

在下面介紹關於動態裝載的部分,假設已經封裝好了一個coprocessor.jar的包,裡面包含實現程式碼及所有的依賴,並且已經將這個jar上傳到了HDFS中。

通過HBase Shell動態裝載和解除安裝

裝載步驟如下

1. 在HBase Shell中disable 掉目標表

hbase>disable'users'

2. 使用類似如下的命令載入Coprocessor

hbase alter'users',METHOD=>'table_att','Coprocessor'=>'hdfs://<namenode>:<port>/user/<hadoop-user>/coprocessor.jar|org.myname.hbase.Coprocessor.RegionObserverExample|1073741823|arg1=1,arg2=2'

簡單解釋下這個命令。這條命令在一個表的table_att中添加了一個新的屬性“Coprocessor”。使用的時候Coprocessor會嘗試從這個表的table_attr中讀取這個屬性的資訊。這個屬性的值用管道符“|”分成了四部分:

  • 檔案路徑:檔案路徑中需要包含Coprocessor的實現,並且對所有的RegionServer都是可達的。這個路徑可以是每個RegionServer的本地磁碟路徑,也可以是HDFS上的一個路徑。通常建議是將Coprocessor實現儲存到HDFS。HBASE-14548允許使用一個路徑中包含的所有的jar,或者是在路徑中使用萬用字元來指定某些jar,比如:hdfs://<namenode>:<port>/user/<hadoop-user>/ 或者 hdfs://<namenode>:<port>/user/<hadoop-user>/*.jar。需要注意的是如果是用路徑來指定要載入的Coprocessor,這個路徑下的所有jar檔案都會被載入,不過該路徑下的子目錄中的jar不會被載入。另外,如果要用路徑指定Coprocessor時,就不要再使用萬用字元了。這些特性在Java API中也得到了支援。
  • 類名:Coprocessor的全限定類名。
  • 優先順序:一個整數。HBase將會使用優先順序來決定在同一個位置配置的所有Observer Coprocessor的執行順序。這個位置可以留白,這樣HBase將會分配一個預設的優先順序。
  • 引數(可選的):這些值會被傳遞給要使用的Coprocessor實現。這個項是可選的。

3. enable這個表

hbase(main):003:0>enable'users'

4. 檢驗Coprocessor是否被載入

hbase(main):04:0>describe'users'

Coprocessor可以在TABLE_ATTRIBUTES中找到。

載入步驟就是這樣。

解除安裝步驟如下

1. disbale目標表

hbase>disable'users'

2. 使用alter命令移除掉Coprocessor

1hbase>alter'users',METHOD=>'table_att_unset',NAME=>'coprocessor$1'

3. enable目標表

1 hbase>enable'users'
使用Java API動態裝載和解除安裝

裝載方式如下

針對不同版本的HBase會有不同的JavaAPI。幸運的是有一個全版本的Java API。下面的程式碼演示了是如何使用Java API來裝載Coprocessor的:

TableName tableName=TableName.valueOf