# 程序框架(Pv2): [HBASE-12439](https://issues.apache.org/jira/browse/HBASE-12439)
_ 程序 v2 ...旨在提供一種統一的方法來構建具有回滾/前滾能力的多步驟程序(例如創建/刪除表) - Pv2 的作者 Matteo Bertozzi。_
使用 Pv2,您可以構建和運行狀態機。它是由 Matteo 構建的,用于在過程失敗時使 HBase 中的分布式狀態轉換具有彈性。在 Pv2 之前,狀態轉換處理在代碼庫中傳播,實現因轉換類型和上下文而異。 Pv2 的靈感來自 Apache Accumulo 的 [FATE](https://accumulo.apache.org/1.8/accumulo_user_manual.html#_fault_tolerant_executor_fate) 。
早期的 Pv2 方面已經在 HBase 發布了很長一段時間,但隨著它涉及更多涉及的場景,它繼續發展。我們現在擁有的是強大但功能復雜,不完整,需要清理和加固。在本文檔中,我們對系統進行了概述,以便您可以使用它(并幫助其進行拋光)。
這個系統有一個尷尬的名字 Pv2,因為 HBase 已經有了快照中使用的過程的概念(參見 hbase-server _org.apache.hadoop.hbase.procedure_ 而不是 hbase-procedure _org .apache.hadoop.hbase.procedure2_ )。 Pv2 取代并取代程序。
## 180.程序
過程是對 HBase 實體進行的轉換。 HBase 實體的示例是區域和表格。過程由 ProcedureExecutor 實例運行。過程當前狀態保存在 ProcedureStore 中。 ProcedureExecutor 只有一個原始視圖,可以查看過程中發生的事情。從其 PoV,提交過程,然后 ProcedureExecutor 繼續調用 _#execute(Object)_,直到過程完成。在失敗或重啟的情況下,可以多次調用 Execute,因此每次運行時,過程代碼必須是冪等的,產生相同的結果。程序代碼也可以實現 _ 回滾 _,因此如果失敗則可以撤消步驟。調用 _execute()_ 可能會導致以下可能性之一:
* _execute()_ 返回
* _null_ :表示我們已經完成了。
* :表示還有更多這樣做,堅持當前程序狀態并重新 _ 執行()_。
* _ 子程序的數組 _:表示在我們繼續之前需要運行完成的一組程序(之后我們希望框架再次調用我們的執行)。
* _execute()_ 拋出異常
* _suspend_ :表示程序的執行被暫停,并且由于某些外部事件可以恢復。過程狀態是持久的。
* _yield_ :將程序添加回調度程序。過程狀態不會持久化。
* _ 中斷 _:目前與 _ 產量 _ 相同。
* 上面沒有列出任何 _ 異常 _:程序 _ 狀態 _ 變為 _FAILED_ (之后我們期望框架將嘗試回滾)。
ProcedureExecutor 將過程狀態的框架概念標記到過程本身;例如它將程序標記為提交時的初始化。它在執行時將狀態移動到 RUNNABLE。完成后,程序將標記為 FAILED 或 SUCCESS。以下是撰寫本文時所有州的清單:
* **_INITIALIZING_ **施工程序,尚未加入執行人
* **_RUNNABLE_ **程序添加到執行程序中,準備執行。
* **_WAITING_ **該程序正在等待兒童(子程序)完成
* **_WAITING _TIMEOUT_ **程序正在等待超時或外部事件
* **_ROLLEDBACK_ **程序失敗并被回滾。
* **_SUCCESS_ **程序執行成功完成。
* **_FAILED_ **程序執行失敗,可能需要回滾。
每次執行后,Procedure 狀態將持久保存到 ProcedureStore。在過程上調用掛鉤,以便它們可以保留自定義狀態。故障發生后,ProcedureExecutor 通過重放 ProcedureStore 的內容來重新補充其崩潰前狀態。這使得過程框架可以抵御過程失敗。
### 180.1。履行
在實施過程中,程序傾向于將變換劃分為更細粒度的任務,并且當這些工作項中的一些被移交給子程序時,批量作為處理 _ 步驟 _ in-Procedure;每次執行 execute 都用于執行一個步驟,然后 Procedure 放棄返回到框架。程序會自行跟蹤處理過程中的位置。
在執行過程中包含子任務或 _ 步驟 _ 的內容由程序作者決定,但通常它是一小部分工作,無法進一步分解并將處理向前移動到其最終狀態。由許多小步驟而不是幾個大步驟組成的程序允許程序框架提供關于我們在處理中的位置的洞察。它還允許框架在執行時更公平。如上所述,每個步驟可以被多次調用(失敗/重啟),因此步驟必須是冪等的。很容易混淆過程本身與框架本身保持一致的狀態。盡量保持它們的區別。
### 180.2。回滾
當過程或其中一個子過程失敗時,將調用回滾。回滾步驟應該清除 execute()步驟中創建的資源。如果失敗并重新啟動,可能會多次調用 rollback(),因此代碼必須是冪等的。
### 180.3。度量
有關于提交程序和完成時收集指標的鉤子。
* updateMetricsOnSubmit()
* updateMetricsOnFinish()
各個過程可以覆蓋這些方法以收集過程特定的度量標準這些方法的默認實現嘗試獲取一個實現接口 ProcedureMetrics 的對象,該接口封裝了以下一組通用度量:
* SubmittedCount(Counter):提交類型的過程實例總數。
* 時間(直方圖):過程實例的運行時直方圖。
* FailedCount(Counter):失敗的過程實例總數。
各個過程可以實現此對象并定義這些通用的度量標準集。
### 180.4。行李
程序可以攜帶行李。一個例子是 _ 步驟 _ 最后獲得的程序(參見上一節);程序持續存在標記它們當前的位置。其他示例可能是 Procedure 當前正在運行的 Region 或 Server 名稱。每次執行調用后,都會調用 Procedure#serializeStateData。程序可以堅持下去。
### 180.5。結果/狀態和查詢
(來自 Matteo 的 [ProcedureV2 和 Notification Bus](https://issues.apache.org/jira/secure/attachment/12693273/Procedurev2Notification-Bus.pdf) doc)在異步操作的情況下,必須保持結果,直到客戶端請求它為止。一旦我們收到結果的“獲取”,我們就可以安排刪除記錄。對于某些操作,結果可能是“不必要的”,尤其是在失敗的情況下(例如,如果創建表失敗,我們可以查詢操作結果,或者我們可以只執行列表來查看它是否已創建)所以在某些情況下我們可以超時后安排刪除。在客戶端,操作將返回“過程 ID”,此 ID 可用于等待過程完成并獲得結果/異常。
```
Admin.doOperation() { longprocId=master.doOperation(); master.waitCompletion(procId); } +
```
如果主機在執行操作時發生故障,備用主機將拾取半進行操作并完成它。客戶端不會注意到失敗。
## 181.子程序
子過程是 _ 過程 _ 實例,由過程實例(父過程)的 _#execute(Object)_ 方法創建和返回。由于子程序屬于 _ 程序 _,它們可以實例化自己的子程序。作為遞歸,過程堆棧由框架維護。該框架確保父過程不會繼續,直到過程堆棧中的所有子過程及其子過程成功完成。
## 182.程序執行人
_ProcedureExecutor_ 使用 _ProcedureStore_ 和 _ProcedureScheduler_ 并執行提交給它的程序。支持的一些基本操作是:
* _abort(procId)_:如果未完成,則中止指定的過程
* _ 提交(程序)_:提交執行程序
* _ 檢索:_ get 方法列表獲取 _ 程序 _ 實例和結果
* _ 注冊/取消注冊 _ 監聽器:用于監聽與程序相關的通知
當 _ProcedureExecutor_ 啟動時,它會在前一次運行的 _ProcedureStore_ 中加載過程實例。從最后存儲的狀態恢復所有未完成的過程。
## 183\. Nonces
您可以將 RPC 中的隨機數傳遞給執行程序提交的過程。然后將這個隨機數與 w 持續的過程序列化。如果崩潰,在重新加載時,如果客戶端嘗試第二次運行相同的程序(將被拒絕),則會將 nonce 放回到 pid 的 nonce 映射中。請參閱基本過程以及 nonce 是基本數據成員的方式。
## 184.等待/喚醒/暫停/收益
'suspend'意味著停止處理程序,因為在條件改變之前我們不能再進步;即我們發送 RPC 并需要等待響應。這種方法的工作方式是,一個過程在其內部引發一個暫停異常作為 GOTO 結束當前處理步驟。掛起還會將過程放回調度程序。有問題的是,即使在暫停時,我們也會對出路進行一些計算,因此可能需要時間退出(我們必須在 WAL 中更新狀態)。
RegionTransitionProcedure#reportTransition 在收到 RS 的報告時被調用。對于分配和取消分配,來自我們發送 RPC 的服務器的此事件響應喚醒暫停的分配/取消分配。
## 185.鎖定
過程鎖不是關于并發性的!它們是為了對 HBase 實體(例如表或區域)提供過程讀/寫訪問權限,這樣就可以阻止其他過程在當前過程運行時修改 HBase 實體狀態。
鎖定是可選的,直到過程實現者,但如果過程正在操作實體,則所有轉換都需要通過使用相同鎖定方案的過程完成,否則會造成嚴重破壞。
兩個 ProcedureExecutor Worker 線程實際上最終都會處理同一個 Procedure 實例。如果它發生了,那么線程就意味著運行一個過程的不同部分 - 那些沒有相互標記的變化(這在程序框架概念'暫停'方面變得很尷尬。更多內容見下文)。
可選地,可以在程序的有效期內保持鎖。例如,如果移動 Region,您可能希望擁有對 HBase Region 的獨占訪問權,直到 Region 完成(或失敗)。這與{@link #holdLock(Object)}一起使用。如果{@link #holdLock(Object)}返回 true,則過程執行程序將調用 acquireLock()一次,之后不調用{@link #releaseLock(Object)},直到過程完成(通常,它調用每個周圍的釋放/獲取)調用{@link #execute(Object)}。
鎖也可以過程的生命;即一旦一個分配程序開始,我們就不希望另一個程序干涉該分配的區域。持有程序生命周期鎖定的程序過程#holdLock 為 true。 AssignProcedure 執行此操作與拆分和移動一樣(如果在區域移動的中間,您不希望它拆分)。
鎖定可以終止程序。
一些鎖具有層次結構。例如,獲取區域鎖定還會對其包含的表和命名空間進行(讀取)鎖定,以防止另一個過程獲得對宿主表(或命名空間)的獨占鎖定。
## 186.程序類型
### 186.1。 StateMachineProcedure
可以將對 _#execute(Object)_ 方法的每次調用視為在狀態機中從一種狀態轉換到另一種狀態。抽象類 _StateMachineProcedure_ 是基礎 _ 過程 _ 類的包裝器,它提供了用于實現狀態機的構造作為 _ 過程 _。在每個狀態轉換之后,當前狀態被持久化,使得在崩潰/重啟的情況下,可以從崩潰/重啟之前的過程的先前狀態恢復狀態轉換。各個過程需要定義初始狀態和終止狀態和鉤子 _executeFromState()_ 和 _setNextState()_ 是為狀態轉換提供的。
### 186.2。 RemoteProcedureDispatcher
新的 RemoteProcedureDispatcher(+子類 RSProcedureDispatcher)原語負責運行基于過程的 Assignments 的“遠程”組件。該調度員了解“服務器”。它按時間/計數基于時間聚合分配,因此可以批量發送過程而不是每個 RPC 發送一個過程。過程狀態返回到 RegionServer 心跳報告在線/離線區域的背面(不再通過 ZK 通知)。響應將傳遞給 AMv2 以進行“處理”。它將檢查內存中的狀態。如果存在不匹配,則假設 RS 端出現問題,它會禁用 RegionServer。超時會觸發重試(尚未實施!)。過程機器使用實體 _ 鎖定 _ 確保任何一個區域/表上一次只能執行一個操作,并且智能關于什么是串行以及可以同時運行什么(鎖定是基于 zk 的 - 你放了一個 znode 在 zk 中表 - 但現在已經轉換為基于程序的項目的一部分)。
## 187.參考文獻
* Matteo 有一個關于程序框架看起來像什么的幻燈片,以及它最初解決的問題[附加到 Pv2 問題上。](https://issues.apache.org/jira/secure/attachment/12845124/ProcedureV2b.pdf)
* [Matteo](https://issues.apache.org/jira/secure/attachment/12693273/Procedurev2Notification-Bus.pdf) 關于問題以及 Pv2 如何使用路線圖(來自 Pv2 JIRA)的優秀文檔。我們應該回到路線圖來做通知總線,將日志分割轉換為 Pv2 等。
- HBase? 中文參考指南 3.0
- Preface
- Getting Started
- Apache HBase Configuration
- Upgrading
- The Apache HBase Shell
- Data Model
- HBase and Schema Design
- RegionServer Sizing Rules of Thumb
- HBase and MapReduce
- Securing Apache HBase
- Architecture
- In-memory Compaction
- Backup and Restore
- Synchronous Replication
- Apache HBase APIs
- Apache HBase External APIs
- Thrift API and Filter Language
- HBase and Spark
- Apache HBase Coprocessors
- Apache HBase Performance Tuning
- Troubleshooting and Debugging Apache HBase
- Apache HBase Case Studies
- Apache HBase Operational Management
- Building and Developing Apache HBase
- Unit Testing HBase Applications
- Protobuf in HBase
- Procedure Framework (Pv2): HBASE-12439
- AMv2 Description for Devs
- ZooKeeper
- Community
- Appendix