# 架構
## 66\. 概述
### 66.1\. NoSQL?
HBase 是一種 "NoSQL" 數據庫。"NoSQL" 是一個通用術語,意味著數據庫不像 RDBMS 一樣支持 SQL 作為主要訪問語言,現有許多類型 NoSQL 數據庫:BerkeleyDB 是一種本地 NoSQL 數據庫,而 HBase 更適合稱為分布數據庫。從技術上講,HBase 實際上更像是“數據存儲”而不是“數據庫”,因為它缺少很多在 RDBMS 中能找到的功能,例如類型列,二級索引,觸發器和高級查詢語言等。
但是,HBase 具有許多支持線性和模塊化縮放的功能。 HBase 集群通過添加托管在商用服務器上的 RegionServer 進行擴展。舉個例子,如果一個集群從 10 個 RegionServer 擴展到 20 個,那么它的存儲和處理能力都會翻倍。 RDBMS 同樣可以很好地擴展,但會達到一個上限 - 特別是單個數據庫服務器的大小 - 并且為了獲得最佳性能,需要專門的硬件和存儲設備。 HBase 的特點是:
* 強一致讀/寫:HBase 不是”最終一致”的數據存儲。這使得它非常適合高速計數聚合等任務。
* 自動分片:HBase 表通過 region 分布在集群上,并且隨著數據的增長,region 會自動分割和重新分配。
* RegionServer 自動故障轉移
* 集成 Hadoop/HDFS:HBase 支持 HDFS 作為其分布式文件系統。
* MapReduce:HBase 可以作為 source 和 sink,通過 MapReduce 來支持大規模并行處理。
* Java 客戶端 API:HBase 支持易用的 Java API 以進行編程式訪問。
* Thrift/REST API:對于非 Java 前端訪問,HBase 還支持 Thrift 和 REST 方式。
* 塊緩存和布隆過濾器:HBase 支持塊緩存和布隆過濾器,以實現高容量查詢優化。
* 運維管理:HBase 提供內置網頁監控運維情況,并支持 JMX 指標。
### 66.2\. 什么時候應該使用 HBase?
HBase 并不適合解決所有問題。
第一,確認有足夠的數據。如果有上億或數十億行數據,那么 HBase 是一個好的選擇。如果只有幾千或幾百萬行數據,那么使用傳統的 RDBMS 或許是個更好的選擇,因為全部數據可能會被調度到單獨一個(或者兩個)節點上,集群的其他節點可能是空閑的。
第二,確認可以不用 RDBMS 提供的所有額外功能(例如,類型列,二級索引,事務,高級查詢語言等)。針對 RDBMS 構建的應用程序無法通過簡單地更改 JDBC Driver 就“移植”到 HBase。從 RDBMS 遷移到 HBase 需要完全重新設計而不是移植。
第三,確認有足夠的硬件設施。少于 5 個 DataNode 時,HDFS 甚至什么都做不了(由于諸如 HDFS 塊復制默認值為 3 之類的情況),再加上 NameNode。
HBase 可以在筆記本電腦上獨立運行 - 但是這只應該被當做開發配置
### 66.3\. HBase 和 Hadoop/HDFS 有什么不同?
[HDFS](https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html)是一個分布式文件系統,非常適合存儲大型文件。其文檔指出,它不是通用文件系統,并且不提供文件中的快速單個記錄查找。另一方面,HBase 建立在 HDFS 之上,為大型表提供快速記錄查找(和更新)。有時這可能是概念混淆的點。 HBase 內部將數據放在有索引的“StoreFiles”中,存儲在 HDFS 之上,以進行高速查找。有關 HBase 如何實現其目標的更多信息,請參見[數據模型](#datamodel)和本章的其余部分。
## 67\. 目錄表
目錄表 `hbase:meta` 作為 HBase 表存在,雖然它會從 HBase shell 的 `list` 命令中過濾掉,但實際上它也是一個表,像任何其他表一樣。
### 67.1\. hbase:meta
`hbase:meta` 表(以前稱為`.META.`)保存系統中所有 region 的列表,`hbase:meta` 被存儲在 ZooKeeper 中。
`hbase:meta` 表的結構如下:
Key
* Region key 的格式 (`[table],[region start key],[region id]`)
Values
* `info:regioninfo` (當前 region 的序列化實例 [HRegionInfo](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/HRegionInfo.html))
* `info:server` (包含當前 region 的 RegionServer 的 server:port)
* `info:serverstartcode` (包含此 region 的 RegionServer 進程的開始時間)
當一個表處于拆分過程中時,將創建額外兩個列,稱為 “info:splitA” 和 “info:splitB”。這些列代表兩個子 region。它們的值也是序列化后的 HRegionInfo 實例。region 分割完成后,最終將刪除此行。
> HRegionInfo 說明
>
> 空白 key 用于表示表的開始和結束。擁有空白開始 key 的 region 是表中的第一個 region。如果某個 region 同時包含空白開始 key 和空白結束 key,則它是表中唯一的 region
在(希望不太可能)需要編程處理目錄元數據的場景下,請參閱[RegionInfo.parseFrom](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/client/RegionInfo.html#parseFrom-byte:A-)實用程序。
### 67.2\. 啟動順序
首先,在 ZooKeeper 中查詢 `hbase:meta` 的位置信息。然后,使用服務器和啟動編碼更新 `hbase:meta` 的值
有關 region-RegionServer 分配的信息,參閱[Region-RegionServer Assignment](#regions.arch.assignment)。
## 68\. 客戶端
HBase 客戶端會查找為所關注的特定行范圍提供服務的 RegionServer。它通過查詢 `hbase:meta` 表來完成此操作。詳情參見[hbase:meta](#arch.catalog.meta)。在找到所需的 region 之后,客戶端聯系服務該 region 的 RegionServer 發出讀取或寫入請求,而不是通過 master。此信息被緩存在客戶端中,以便后續請求無需經過查找過程。如果 region 由主負載均衡器重新分配,或者因為 RegionServer 已經死亡,則客戶端將重新查詢目錄表以確定用戶 region 的新位置。
有關 Master 對 HBase Client 通信的影響的詳細信息,請參閱[Runtime Impact](#master.runtime)
管理功能是通過 [Admin](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Admin.html) 實例完成的
### 68.1\. 集群連接
HBase 1.0 中更改了 API。有關連接配置信息,請參閱[連接到 HBase 集群的客戶端配置和依賴關系](#client_dependencies)。
#### 68.1.1\. HBase 1.0.0 的 API
API 已被清理,使用者會通過接口而不是具體類型來工作。在 HBase 1.0 中,從 `ConnectionFactory` 中獲取一個 `Connection` 對象,然后根據需要從中獲取 `Table`,`Admin` 和 `RegionLocator` 的實例。完成后,關閉獲取的實例。最后,確保在退出之前清理 `Connection` 實例。`Connections` 是重量級對象,但是線程安全,因此可以在應用程序中創建并保持一個實例。`Table`,`Admin` 和 `RegionLocator` 實例是輕量級的。它們可以隨時創建,然后在使用后立即釋放掉。有關新 HBase 1.0 API 的使用示例,請參閱[Client Package Javadoc 說明](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/package-summary.html)。
#### 68.1.2\. HBase 1.0.0 之前的 API
1.0.0 之前,`HTable` 實例是與 HBase 集群進行交互的方式。 _[Table](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Table.html)實例不是線程安全的。在任何給定時間,只有一個線程可以使用 Table 的實例。創建 Table 實例時,建議使用相同的 [HBaseConfiguration](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/HBaseConfiguration)實例。確保將 ZooKeeper 和套接字實例共享到 RegionServers,通常也是你想要的。例如,推薦這種方式:
```
HBaseConfiguration conf = HBaseConfiguration.create();
HTable table1 = new HTable(conf, "myTable");
HTable table2 = new HTable(conf, "myTable");
```
而不是這種:
```
HBaseConfiguration conf1 = HBaseConfiguration.create();
HTable table1 = new HTable(conf1, "myTable");
HBaseConfiguration conf2 = HBaseConfiguration.create();
HTable table2 = new HTable(conf2, "myTable");
```
關于 HBase 客戶端如何處理連接的更多信息,請參閱 [ConnectionFactory](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/ConnectionFactory.html).
##### 連接池
For applications which require high-end multithreaded access (e.g., web-servers or application servers that may serve many application threads in a single JVM), you can pre-create a `Connection`, as shown in the following example:
對于需要高級多線程訪問的應用程序(例如,在單個 JVM 中為許多應用程序線程提供服務的 Web 服務器或應用服務器),你可以預先創建一個`Connection`,示例如下:
Example 22\. 預創建一個 `Connection`
```
// Create a connection to the cluster.
Configuration conf = HBaseConfiguration.create();
try (Connection connection = ConnectionFactory.createConnection(conf);
Table table = connection.getTable(TableName.valueOf(tablename))) {
// use table as needed, the table returned is lightweight
}
```
> `HTablePool` 已經廢棄
>
> 本指南的早期版本討論了 `HTablePool`,不過它在 HBase 0.94, 0.95 和 0.96 版本中被廢棄,并在 0.98.1 版本中被刪除,[HBASE-6580](https://issues.apache.org/jira/browse/HBASE-6580),而 `HConnection`,在 HBase 1.0 中被 `Connection` 代替。請改用[Connection](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Connection.html)。
### 68.2\. WriteBuffer 和批處理方法
在 HBase 1.0 和后續版本中,[HTable](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/client/HTable.html) 被廢棄,改用 [Table](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Table.html)。`Table` 并不使用自動刷新。如果需要緩沖寫入,使用 BufferedMutator 類。
在 HBase 2.0 及更高版本中,[HTable](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/client/HTable.html) 不使用 BufferedMutator 來執行 `Put` 操作。有關更多信息,請參閱[HBASE-18500](https://issues.apache.org/jira/browse/HBASE-18500)。
關于寫入持久性的更多信息,請參閱 [ACID semantics](/acid-semantics.html) 。
對于批量 `Put` 或 `Delete` 的細粒度控制,請參閱 Table 方法 [batch](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Table.html#batch-java.util.List-java.lang.Object:A-)。
### 68.3\. 異步客戶端
HBase 2.0 中引入了一種新 API,旨在提供異步訪問 HBase 的能力。
你可以從 `ConnectionFactory` 中獲取 `AsyncConnection`,然后從中獲取一個異步表實例來訪問 HBase。處理完成后,關閉 `AsyncConnection` 實例(通常在程序退出時)。
對于異步表,大多數方法與舊的 `Table` 接口具有相同的含義,返回值通常用 CompletableFuture 包裝。 因為這里沒有任何緩沖區,所以沒有異步表的 close 方法,你不需要關閉它。它是線程安全的。
對于 scan,有幾點不同:
* 仍然有一個 `getScanner` 方法返回一個 `ResultScanner`。可以以舊方式使用它,它的工作方式類似于舊的 `ClientAsyncPrefetchScanner`。
* 有一個 `scanAll` 方法,它會立即返回所有結果。它的目的是為通常希望立即獲得全部結果的小范圍掃描提供更簡單的方法。
* 觀察者模式。 有一個 scan 方法接受 `ScanResultConsumer` 作為參數。 它會將結果傳遞給消費者。
請注意,`AsyncTable` 接口是模板化的。模板參數指定掃描使用的 `ScanResultConsumerBase` 的類型,這意味著觀察者類型的 scan API 是不同的。scan 的消費者有兩種類型 - `ScanResultConsumer` 和 `AdvancedScanResultConsumer`。
`ScanResultConsumer` 需要一個單獨的線程池,用于執行注冊到返回 CompletableFuture 的回調方法。因為使用獨立的線程池可以釋放 RPC 線程,所以回調可以自由地執行任何操作。如果回調慢或不確定的時候,使用此配置。
`AdvancedScanResultConsumer` 在框架線程內執行回調。不允許在回調中進行耗時操作,否則它可能會阻塞框架線程并導致非常糟糕的性能問題。正如其名稱一樣,它專為希望編寫高性能代碼的高級用戶而設計。有關如何使用它編寫完全異步代碼,請參閱 `org.apache.hadoop.hbase.client.example.HttpProxyExample`。
### 68.4\. 異步管理
你可以從 `ConnectionFactory` 中獲取 `AsyncConnection`,然后從中獲取一個 `AsyncAdmin` 實例來訪問 HBase。請注意,有兩個 `getAdmin` 方法可以獲取 `AsyncAdmin` 實例。一種方法有一個額外的線程池參數,用于執行回調。它專為普通用戶設計。另一種方法不需要線程池,所有回調都在框架線程內執行,因此不允許在回調中進行耗時操作。它專為高級用戶設計。
默認的 `getAdmin` 方法將返回一個使用默認配置的 `AsyncAdmin` 實例。如果要自定義某些配置,可以使用 `getAdminBuilder` 方法獲取用于創建 `AsyncAdmin` 實例的 `AsyncAdminBuilder`。用戶可以自由設置他們關注的配置來創建一個新的 `AsyncAdmin` 實例。
對于 `AsyncAdmin` 接口,大多數方法與舊的 `Admin` 接口具有相同的含義,返回值通常被 CompletableFuture 包裝。
對于大多數管理操作,當返回的 CompletableFuture 完成時,也意味著管理操作已完成。但是對于壓縮操作,它只意味著壓縮請求被發送到 HBase 并且可能需要一些時間來完成壓縮操作。對于 `rollWALWriter` 方法,它只表示 rollWALWriter 請求被發送到 region server,可能需要一些時間來完成 `rollWALWriter` 操作。
對于 region 名稱,只接受 `byte[]` 類型的參數,它可以是完整的 region 名稱或編碼后的 region 名稱。對于服務器名稱,只接受 `ServerName` 類型的參數。 對于表名,只接受 `TableName` 類型的參數。 對于 `list*` 操作,如果想要進行正則表達式匹配,只接受 `Pattern` 類型的參數。
### 68.5\. 擴展客戶端
有關非 Java 客戶端和自定義協議的信息,請參閱[Apache HBase External APIs](#external_apis)
## 69.客戶請求過濾器
[獲取](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Get.html)和[掃描](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Scan.html)實例可以選擇配置應用于 RegionServer 的[過濾器](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/Filter.html)。
過濾器可能會造成混淆,因為有許多不同的類型,最好通過了解過濾器功能組來處理它們。
### 69.1。結構
結構過濾器包含其他過濾器
#### 69.1.1。 FilterList
[FilterList](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/FilterList.html) 表示在過濾器之間具有`FilterList.Operator.MUST_PASS_ALL`或`FilterList.Operator.MUST_PASS_ONE`關系的過濾器列表。以下示例顯示了兩個過濾器之間的“或”(在同一屬性上檢查“我的值”或“我的其他值”)。
```
FilterList list = new FilterList(FilterList.Operator.MUST_PASS_ONE);
SingleColumnValueFilter filter1 = new SingleColumnValueFilter(
cf,
column,
CompareOperator.EQUAL,
Bytes.toBytes("my value")
);
list.add(filter1);
SingleColumnValueFilter filter2 = new SingleColumnValueFilter(
cf,
column,
CompareOperator.EQUAL,
Bytes.toBytes("my other value")
);
list.add(filter2);
scan.setFilter(list);
```
### 69.2。列值
#### 69.2.1。 SingleColumnValueFilter
SingleColumnValueFilter(參見: [https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/SingleColumnValueFilter.html](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/SingleColumnValueFilter.html) )可用于測試等值的列值(`CompareOperaor.EQUAL` ),不等式(`CompareOperaor.NOT_EQUAL`)或范圍(例如,`CompareOperaor.GREATER`)。以下是測試列與 String 值“my value”的等效性的示例...
```
SingleColumnValueFilter filter = new SingleColumnValueFilter(
cf,
column,
CompareOperaor.EQUAL,
Bytes.toBytes("my value")
);
scan.setFilter(filter);
```
#### 69.2.2。 ColumnValueFilter
作為 SingleColumnValueFilter 的補充,在 HBase-2.0.0 版本中引入,ColumnValueFilter 僅獲取匹配的單元格,而 SingleColumnValueFilter 獲取匹配的單元格所屬的整個行(具有其他列和值)。 ColumnValueFilter 的構造函數的參數與 SingleColumnValueFilter 相同。
```
ColumnValueFilter filter = new ColumnValueFilter(
cf,
column,
CompareOperaor.EQUAL,
Bytes.toBytes("my value")
);
scan.setFilter(filter);
```
注意。對于簡單查詢,例如“等于系列:限定符:值”,我們強烈建議使用以下方法,而不是使用 SingleColumnValueFilter 或 ColumnValueFilter:
```
Scan scan = new Scan();
scan.addColumn(Bytes.toBytes("family"), Bytes.toBytes("qualifier"));
ValueFilter vf = new ValueFilter(CompareOperator.EQUAL,
new BinaryComparator(Bytes.toBytes("value")));
scan.setFilter(vf);
...
```
此掃描將限制到指定的列'family:qualifier',避免掃描不相關的族和列,具有更好的性能,`ValueFilter`是用于進行值過濾的條件。
但如果查詢比本書更復雜,那么請根據具體情況做出不錯的選擇。
### 69.3。列值比較器
Filter 包中有幾個 Comparator 類值得特別提及。這些比較器與其他濾波器一起使用,例如 [SingleColumnValueFilter](#client.filter.cv.scvf) 。
#### 69.3.1。 RegexStringComparator
[RegexStringComparator](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/RegexStringComparator.html) 支持用于值比較的正則表達式。
```
RegexStringComparator comp = new RegexStringComparator("my."); // any value that starts with 'my'
SingleColumnValueFilter filter = new SingleColumnValueFilter(
cf,
column,
CompareOperaor.EQUAL,
comp
);
scan.setFilter(filter);
```
有關 Java 中支持的[支持的 RegEx 模式,請參閱 Oracle JavaDoc。](http://download.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html)
#### 69.3.2。 SubstringComparator
[SubstringComparator](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/SubstringComparator.html) 可用于確定某個值是否存在給定的子字符串。比較不區分大小寫。
```
SubstringComparator comp = new SubstringComparator("y val"); // looking for 'my value'
SingleColumnValueFilter filter = new SingleColumnValueFilter(
cf,
column,
CompareOperaor.EQUAL,
comp
);
scan.setFilter(filter);
```
#### 69.3.3。 BinaryPrefixComparator
參見 [BinaryPrefixComparator](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/BinaryPrefixComparator.html) 。
#### 69.3.4。 BinaryComparator
參見 [BinaryComparator](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/BinaryComparator.html) 。
### 69.4。 KeyValue 元數據
由于 HBase 在內部將數據存儲為 KeyValue 對,因此 KeyValue 元數據過濾器會評估行的鍵的存在(即 ColumnFamily:Column 限定符),而不是上一節的值。
#### 69.4.1。 FamilyFilter
[FamilyFilter](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/FamilyFilter.html) 可用于過濾 ColumnFamily。在掃描中選擇 ColumnFamilies 通常比使用 Filter 執行它更好。
#### 69.4.2。 QualifierFilter
[QualifierFilter](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/QualifierFilter.html) 可用于根據列(又稱限定符)名稱進行過濾。
#### 69.4.3。 ColumnPrefixFilter
[ColumnPrefixFilter](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/ColumnPrefixFilter.html) 可用于根據 Column(又稱限定符)名稱的前導部分進行過濾。
ColumnPrefixFilter 向前搜索與每行中的前綴匹配的第一列以及每個涉及的列族。它可用于在非常寬的行中有效地獲取列的子集。
注意:可以在不同的列族中使用相同的列限定符。此過濾器返回所有匹配的列。
示例:查找以“abc”開頭的行和族中的所有列
```
Table t = ...;
byte[] row = ...;
byte[] family = ...;
byte[] prefix = Bytes.toBytes("abc");
Scan scan = new Scan(row, row); // (optional) limit to one row
scan.addFamily(family); // (optional) limit to one family
Filter f = new ColumnPrefixFilter(prefix);
scan.setFilter(f);
scan.setBatch(10); // set this if there could be many columns returned
ResultScanner rs = t.getScanner(scan);
for (Result r = rs.next(); r != null; r = rs.next()) {
for (KeyValue kv : r.raw()) {
// each kv represents a column
}
}
rs.close();
```
#### 69.4.4。 MultipleColumnPrefixFilter
[MultipleColumnPrefixFilter](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/MultipleColumnPrefixFilter.html) 的行為與 ColumnPrefixFilter 類似,但允許指定多個前綴。
與 ColumnPrefixFilter 一樣,MultipleColumnPrefixFilter 有效地向前搜索與最低前綴匹配的第一列,并且還在前綴之間尋找過去的列范圍。它可用于從非常寬的行中有效地獲得不連續的列集。
示例:查找以“abc”或“xyz”開頭的行和族中的所有列
```
Table t = ...;
byte[] row = ...;
byte[] family = ...;
byte[][] prefixes = new byte[][] {Bytes.toBytes("abc"), Bytes.toBytes("xyz")};
Scan scan = new Scan(row, row); // (optional) limit to one row
scan.addFamily(family); // (optional) limit to one family
Filter f = new MultipleColumnPrefixFilter(prefixes);
scan.setFilter(f);
scan.setBatch(10); // set this if there could be many columns returned
ResultScanner rs = t.getScanner(scan);
for (Result r = rs.next(); r != null; r = rs.next()) {
for (KeyValue kv : r.raw()) {
// each kv represents a column
}
}
rs.close();
```
#### 69.4.5。 ColumnRangeFilter
[ColumnRangeFilter](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/ColumnRangeFilter.html) 允許有效的行內掃描。
ColumnRangeFilter 可以提前查找每個相關列族的第一個匹配列。它可用于有效地獲得非常寬的行的“切片”。即你連續有一百萬列,但你只想查看列 bbbb-bbdd。
Note: The same column qualifier can be used in different column families. This filter returns all matching columns.
示例:在“bbbb”(包括)和“bbdd”(包括)之間查找行和族中的所有列
```
Table t = ...;
byte[] row = ...;
byte[] family = ...;
byte[] startColumn = Bytes.toBytes("bbbb");
byte[] endColumn = Bytes.toBytes("bbdd");
Scan scan = new Scan(row, row); // (optional) limit to one row
scan.addFamily(family); // (optional) limit to one family
Filter f = new ColumnRangeFilter(startColumn, true, endColumn, true);
scan.setFilter(f);
scan.setBatch(10); // set this if there could be many columns returned
ResultScanner rs = t.getScanner(scan);
for (Result r = rs.next(); r != null; r = rs.next()) {
for (KeyValue kv : r.raw()) {
// each kv represents a column
}
}
rs.close();
```
注意:在 HBase 0.92 中引入
### 69.5。 RowKey
#### 69.5.1。的 RowFilter
在掃描行選擇時使用 startRow / stopRow 方法通常更好一點,但也可以使用 [RowFilter](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/RowFilter.html) 。
### 69.6。效用
#### 69.6.1。 FirstKeyOnlyFilter
這主要用于 rowcount 作業。見 [FirstKeyOnlyFilter](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/FirstKeyOnlyFilter.html) 。
## 70.師父
`HMaster`是主服務器的實現。主服務器負責監視集群中的所有 RegionServer 實例,并且是所有元數據更改的接口。在分布式群集中,Master 通常在 [NameNode](#arch.hdfs.nn) 上運行。 J Mohamed Zahoor 在博客中發表了關于 Master Architecture 的更多細節, [HBase HMaster Architecture](http://blog.zahoor.in/2012/08/hbase-hmaster-architecture/) 。
### 70.1。啟動行為
如果在多主機環境中運行,則所有主機競爭以運行集群。如果活躍的 Master 在 ZooKeeper 中丟失了它的租約(或者 Master 關閉了),那么剩下的 Masters 會爭先恐后地接管 Master 角色。
### 70.2。運行時影響
一個常見的 dist-list 問題涉及當 Master 關閉時 HBase 集群會發生什么。由于 HBase 客戶端直接與 RegionServers 通信,因此群集仍然可以在“穩定狀態”下運行。此外,根據[目錄表](#arch.catalog),`hbase:meta`作為 HBase 表存在,并且不駐留在主服務器中。但是,Master 控制關鍵功能,例如 RegionServer 故障轉移和完成區域拆分。因此,雖然群集仍然可以在沒有 Master 的情況下短時間運行,但 Master 應該盡快重啟。
### 70.3。接口
`HMasterInterface`公開的方法主要是面向元數據的方法:
* 表(createTable,modifyTable,removeTable,enable,disable)
* ColumnFamily(addColumn,modifyColumn,removeColumn)
* 區域(移動,分配,取消分配)例如,當調用`Admin`方法`disableTable`時,它由主服務器提供服務。
### 70.4。流程
Master 運行幾個后臺線程:
#### 70.4.1。負載平衡器
定期地,當沒有轉換區域時,負載均衡器將運行并移動區域以平衡群集的負載。請參閱 [Balancer](#balancer_config) 以配置此屬性。
有關區域分配的更多信息,請參見 [Region-RegionServer Assignment](#regions.arch.assignment) 。
#### 70.4.2。 CatalogJanitor
定期檢查并清理`hbase:meta`表。有關元表的更多信息,請參見 [hbase:meta](#arch.catalog.meta) 。
### 70.5。 MasterProcWAL
HMaster 將管理操作及其運行狀態(例如崩潰的服務器,表創建和其他 DDL 的處理)記錄到其自己的 WAL 文件中。 WAL 存儲在 MasterProcWALs 目錄下。 Master WALs 與 RegionServer WALs 不同。保持 Master WAL 允許我們運行一個在 Master 故障中具有彈性的狀態機。例如,如果 HMaster 正在創建表遇到問題并且失敗,則下一個活動 HMaster 可以占用前一個停止的位置并執行操作。從 hbase-2.0.0 開始,引入了新的 AssignmentManager(AKA AMv2),HMaster 處理區域分配操作,服務器崩潰處理,平衡等,所有這些都通過 AMv2 持久化所有狀態并轉換為 MasterProcWAL 而不是流入 ZooKeeper,如我們在 hbase-1.x 中做。
如果您想了解有關新 AssignmentManager 的更多信息,請參閱 [AMv2 描述 Devs](#amv2) (和[程序框架(Pv2):](#pv2) [HBASE-12439](https://issues.apache.org/jira/browse/HBASE-12439) )。
#### 70.5.1。 MasterProcWAL 的配置
以下是影響 MasterProcWAL 操作的配置列表。您不必更改默認值。
**`hbase.procedure.store.wal.periodic.roll.msec`**
描述
生成新 WAL 的頻率
默認
`1h (3600000 in msec)`
**`hbase.procedure.store.wal.roll.threshold`**
Description
WAL 滾動前的大小閾值。每次 WAL 達到此大小或上述時間段,1 小時后,自上次滾動后經過,HMaster 將生成一個新的 WAL。
Default
`32MB (33554432 in byte)`
**`hbase.procedure.store.wal.warn.threshold`**
Description
如果 WAL 的數量超過此閾值,則在滾動時,以下消息應出現在具有 WARN 級別的 HMaster 日志中。
```
procedure WALs count=xx above the warning threshold 64\. check running procedures to see if something is stuck.
```
Default
`64`
**`hbase.procedure.store.wal.max.retries.before.roll`**
Description
將插槽(記錄)同步到其底層存儲(例如 HDFS)時的最大重試次數。每次嘗試,以下消息都應出現在 HMaster 日志中。
```
unable to sync slots, retry=xx
```
Default
`3`
**`hbase.procedure.store.wal.sync.failure.roll.max`**
Description
在上述 3 次重試之后,日志被滾動并且重試計數被重置為 0,其上開始一組新的重試。此配置控制同步失敗時日志滾動的最大嘗試次數。也就是說,HMaster 總共無法同步 9 次。一旦超過,HMaster 日志中就會出現以下日志。
```
Sync slots after log roll failed, abort.
```
Default
`3`
## 71\. RegionServer
`HRegionServer`是 RegionServer 實現。它負責服務和管理地區。在分布式群集中,RegionServer 在 [DataNode](#arch.hdfs.dn) 上運行。
### 71.1。接口
`HRegionRegionInterface`公開的方法包含面向數據和區域維護方法:
* 數據(獲取,放置,刪除,下一步等)
* Region(splitRegion,compactRegion 等)例如,當在表上調用`Admin`方法`majorCompact`時,客戶端實際上迭代指定表的所有區域并直接請求對每個區域進行主要壓縮。
### 71.2。流程
RegionServer 運行各種后臺線程:
#### 71.2.1。 CompactSplitThread
檢查拆分并處理輕微壓縮。
#### 71.2.2。 MajorCompactionChecker
檢查主要的壓縮。
#### 71.2.3。 MemStoreFlusher
定期刷新 MemStore 到 StoreFiles 中的內存中寫入。
#### 71.2.4。 LogRoller
定期檢查 RegionServer 的 WAL。
### 71.3。協處理器
協處理器的添加量為 0.92。有一個徹底的[博客概述 CoProcessors](https://blogs.apache.org/hbase/entry/coprocessor_introduction) 發布。文檔最終會轉到此參考指南,但博客是目前最新的信息。
### 71.4。塊緩存
HBase 提供兩種不同的 BlockCache 實現來緩存從 HDFS 讀取的數據:默認的堆上`LruBlockCache`和`BucketCache`,它(通常)是堆外的。本節討論每個實現的優缺點,如何選擇適當的選項以及每個實現的配置選項。
> 阻止緩存報告:U
>
> 有關緩存部署的詳細信息,請參閱 RegionServer UI。請參閱配置,大小,當前使用情況,緩存時間,甚至是塊計數和類型的詳細信息。
#### 71.4.1。緩存選擇
`LruBlockCache`是原始實現,完全在 Java 堆中。 `BucketCache`是可選的,主要用于將塊緩存數據保留在堆外,盡管`BucketCache`也可以是文件支持的緩存。
啟用 BucketCache 時,您將啟用雙層緩存系統。我們曾經將這些層描述為“L1”和“L2”,但是從 hbase-2.0.0 開始就棄用了這個術語。 “L1”緩存將 LruBlockCache 的實例和“L2”引用到堆外 BucketCache。相反,當啟用 BucketCache 時,所有 DATA 塊都保存在 BucketCache 層中,元塊(INDEX 和 BLOOM 塊)在`LruBlockCache`中堆棧。這兩個層次的管理以及決定塊如何在它們之間移動的策略由`CombinedBlockCache`完成。
#### 71.4.2。常規緩存配置
除了緩存實現本身,您還可以設置一些常規配置選項來控制緩存的執行方式。參見 [CacheConfig](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/io/hfile/CacheConfig.html) 。設置任何這些選項后,重新啟動或滾動重新啟動群集以使配置生效。檢查日志是否有錯誤或意外行為。
另見 [Blockcache 的預取選項](#blockcache.prefetch),它討論了 [HBASE-9857](https://issues.apache.org/jira/browse/HBASE-9857) 中引入的新選項。
#### 71.4.3。 LruBlockCache 設計
LruBlockCache 是??一個 LRU 緩存,包含三個級別的塊優先級,以允許掃描阻力和內存中的 ColumnFamilies:
* 單一訪問優先級:第一次從 HDFS 加載塊時,它通常具有此優先級,并且它將成為驅逐期間要考慮的第一組的一部分。優點是掃描塊比使用更多的塊更容易被驅逐。
* 多訪問優先級:如果再次訪問先前優先級組中的塊,則會升級到此優先級。因此,它是在驅逐期間考慮的第二組的一部分。
* 內存中訪問優先級:如果塊的族已配置為“內存中”,則它將成為此優先級的一部分,而不考慮它的訪問次數。目錄表配置如下。該組是在驅逐期間考慮的最后一組。
要將列族標記為內存,請調用
```
HColumnDescriptor.setInMemory(true);
```
如果從 java 創建表,或在 shell 中創建或更改表時設置`IN_MEMORY ? true`:例如
```
hbase(main):003:0> create 't', {NAME => 'f', IN_MEMORY => 'true'}
```
有關更多信息,請參閱 LruBlockCache 源
#### 71.4.4。 LruBlockCache 用法
默認情況下,為所有用戶表啟用塊緩存,這意味著任何讀取操作都將加載 LRU 緩存。這可能適用于大量用例,但通常需要進一步調整才能獲得更好的性能。一個重要的概念是[工作集大小](http://en.wikipedia.org/wiki/Working_set_size)或 WSS,它是:“計算問題答案所需的內存量”。對于網站,這將是在短時間內回答查詢所需的數據。
計算 HBase 中用于緩存的內存量的方法是:
```
number of region servers * heap size * hfile.block.cache.size * 0.99
```
塊緩存的默認值為 0.4,表示可用堆的 40%。最后一個值(99%)是 LRU 高速緩存中的默認可接受加載因子,在此之后啟動逐出。它包含在這個等式中的原因是,說可以使用 100%的可用內存是不現實的,因為這會使進程從加載新塊的點開始阻塞。這里有些例子:
* 堆大小設置為 1 GB 的一個區域服務器和默認的塊高速緩存大小將具有 405 MB 的塊高速緩存可用。
* 堆大小設置為 8 GB 的 20 個區域服務器和默認的塊高速緩存大小將具有 63.3 的塊高速緩存。
* 堆大小設置為 24 GB 且塊緩存大小為 0.5 的 100 個區域服務器將具有大約 1.16 TB 的塊緩存。
您的數據不是塊緩存的唯一駐留者。以下是您可能需要考慮的其他因素:
目錄表
`hbase:meta`表被強制進入塊緩存并具有內存中的優先級,這意味著它們更難被驅逐。
> hbase:元表可以占用幾 MB,具體取決于區域的數量。
HFiles 指數
_HFile_ 是 HBase 用于在 HDFS 中存儲數據的文件格式。它包含一個多層索引,允許 HBase 在不必讀取整個文件的情況下查找數據。這些索引的大小是塊大小(默認為 64KB),鍵大小和存儲數據量的一個因素。對于大數據集,每個區域服務器的數字大約為 1GB 并不罕見,盡管并非所有數據都在緩存中,因為 LRU 將驅逐未使用的索引。
按鍵
存儲的值只是圖片的一半,因為每個值都與其鍵(行鍵,族限定符和時間戳)一起存儲。請參閱[嘗試最小化行和列大小](#keysize)。
布隆過濾器
就像 HFile 索引一樣,這些數據結構(啟用時)存儲在 LRU 中。
目前,測量 HFile 索引和布隆過濾器大小的推薦方法是查看區域服務器 Web UI 并檢查相關指標。對于密鑰,可以使用 HFile 命令行工具進行采樣,并查找平均密鑰大小度量。從 HBase 0.98.3 開始,您可以在 UI 中的特殊“塊緩存”部分中查看有關 BlockCache 統計信息和指標的詳細信息。
當 WSS 不適合內存時,使用塊緩存通常是不好的。例如,當您在所有區域服務器的塊緩存中提供 40GB 可用時,您需要處理 1TB 數據。其中一個原因是驅逐產生的流失將不必要地引發更多的垃圾收集。以下是兩個用例:
* 完全隨機的讀取模式:這種情況下,您幾乎不會在很短的時間內兩次訪問同一行,這樣命中緩存塊的幾率就接近于 0.在這樣的表上設置塊緩存是浪費內存和 CPU 周期,更多,以便它將產生更多垃圾由 JVM 提取。有關監視 GC 的更多信息,請參閱 [JVM 垃圾收集日志](#trouble.log.gc)。
* 映射表:在輸入中占用表的典型 MapReduce 作業中,每行只讀一次,因此不需要將它們放入塊緩存中。 Scan 對象可以選擇通過 setCaching 方法將其關閉(將其設置為 false)。如果您需要快速隨機讀取訪問,您仍然可以在此表上保持塊緩存。一個例子是計算提供實時流量的表中的行數,緩存該表的每個塊會產生大量流失,并且肯定會驅逐當前正在使用的數據。
##### 僅緩存 META 塊(fscache 中的 DATA 塊)
一個有趣的設置是我們只緩存 META 塊,我們在每次訪問時讀取 DATA 塊。如果 DATA 塊適合 fscache,當訪問在非常大的數據集中完全隨機時,這種替代方案可能有意義。要啟用此設置,請更改表和每個列族集`BLOCKCACHE ? 'false'`。您只為此列系列“禁用”BlockCache。您永遠不能禁用 META 塊的緩存。由于 [HBASE-4683 始終緩存索引和布隆塊](https://issues.apache.org/jira/browse/HBASE-4683),即使禁用了 BlockCache,我們也會緩存 META 塊。
#### 71.4.5。堆外塊緩存
##### 如何啟用 BucketCache
BucketCache 的常規部署是通過一個管理類來設置兩個緩存層:LruBlockCache 實現的堆內緩存和 BucketCache 實現的第二個緩存。默認情況下,管理類是 [CombinedBlockCache](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/io/hfile/CombinedBlockCache.html) 。上一個鏈接描述了 CombinedBlockCache 實現的緩存“策略”。簡而言之,它的工作原理是將元塊 - INDEX 和 BLOOM 保留在堆上 LruBlockCache 層 - 而 DATA 塊保存在 BucketCache 層中。
Pre-hbase-2.0.0 版本
與 pre-hbase-2.0.0 中的 BucketCache 相比,與本機堆上 LruBlockCache 相比,獲取總是會更慢。但是,隨著時間的推移,延遲往往不那么不穩定,因為使用 BucketCache 時垃圾收集較少,因為它管理的是 BlockCache 分配,而不是 GC。如果 BucketCache 以堆外模式部署,則該內存根本不由 GC 管理。這就是為什么你在 2.0.0 之前使用 BucketCache,所以你的延遲不那么不穩定,以緩解 GC 和堆碎片,因此你可以安全地使用更多的內存。有關運行堆上和堆外測試的比較,請參閱 Nick Dimiduk 的 [BlockCache 101](http://www.n10k.com/blog/blockcache-101/) 。另請參閱[比較 BlockCache Deploys](https://people.apache.org/~stack/bc/) ,它會發現如果您的數據集適合您的 LruBlockCache 部署,請使用它,否則如果您遇到緩存流失(或者您希望緩存存在于 java GC 的變幻莫測之外),請使用 BucketCache 。
在 2.0.0 之前的版本中,可以配置 BucketCache,以便它接收 LruBlockCache 驅逐的`victim`。所有數據和索引塊首先緩存在 L1 中。當從 L1 發生逐出時,塊(或`victims`)將移動到 L2。通過`(HColumnDescriptor.setCacheDataInL1(true)`或在 shell 中設置`cacheDataInL1`,創建或修改列族設置`CACHE_DATA_IN_L1`為真:例如
```
hbase(main):003:0> create 't', {NAME => 't', CONFIGURATION => {CACHE_DATA_IN_L1 => 'true'}}
```
hbase-2.0.0 +版本
HBASE-11425 更改了 HBase 讀取路徑,因此它可以將讀取數據保留在堆外,從而避免將緩存數據復制到 Java 堆上。參見 [Offheap 讀取路徑](#regionserver.offheap.readpath)。在 hbase-2.0.0 中,堆外延遲接近堆棧緩存延遲,具有不會激發 GC 的額外好處。
從 HBase 2.0.0 開始,L1 和 L2 的概念已被棄用。當 BucketCache 打開時,DATA 塊將始終轉到 BucketCache,INDEX / BLOOM 塊轉到堆 LRUBlockCache。 `cacheDataInL1`支持已被刪除。
BucketCache Block Cache 可以部署 _ 堆外 _,_ 文件 _ 或 _mmaped_ 文件模式。
您可以通過`hbase.bucketcache.ioengine`設置進行設置。將其設置為`offheap`將使 BucketCache 在堆外進行分配,并且`file:PATH_TO_FILE`的 ioengine 設置將指示 BucketCache 使用文件緩存(特別是如果您有一些快速 I / O 連接到盒子,如 SSD) )。從 2.0.0 開始,可以有多個文件支持 BucketCache。當 Cache 大小要求很高時,這非常有用。對于多個后備文件,請將 ioengine 配置為`files:PATH_TO_FILE1,PATH_TO_FILE2,PATH_TO_FILE3`。 BucketCache 也可以配置為使用 mmapped 文件。為此,將 ioengine 配置為`mmap:PATH_TO_FILE`。
可以部署分層設置,我們繞過 CombinedBlockCache 策略并讓 BucketCache 作為 L1 LruBlockCache 的嚴格 L2 緩存。對于這樣的設置,將`hbase.bucketcache.combinedcache.enabled`設置為`false`。在這種模式下,在從 L1 驅逐時,塊轉到 L2。緩存塊時,它首先在 L1 中緩存。當我們去尋找一個緩存的塊時,我們首先查看 L1,如果沒有找到,則搜索 L2。我們稱這種部署格式為 _Raw L1 + L2_ 。注意:此 L1 + L2 模式已從 2.0.0 中刪除。使用 BucketCache 時,它將嚴格地是 DATA 緩存,LruBlockCache 將緩存 INDEX / META 塊。
其他 BucketCache 配置包括:指定一個位置以在重新啟動時保持緩存,使用多少線程來編寫緩存等。有關配置選項和說明,請參閱 [CacheConfig.html](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/io/hfile/CacheConfig.html) 類。
要檢查它是否已啟用,請查找描述緩存設置的日志行;它將詳細介紹如何部署 BucketCache。另請參閱 UI。它將詳細介紹緩存分層及其配置。
###### BucketCache 示例配置
此示例提供了 4 GB 堆外 BucketCache 的配置,其中包含 1 GB 的堆棧緩存。
配置在 RegionServer 上執行。
設置`hbase.bucketcache.ioengine`和`hbase.bucketcache.size`> 0 啟用`CombinedBlockCache`。讓我們假設 RegionServer 已設置為以 5G 堆運行:即`HBASE_HEAPSIZE=5g`。
1. 首先,編輯 RegionServer 的 _hbase-env.sh_ 并將`HBASE_OFFHEAPSIZE`設置為大于所需的堆外大小的值,在本例中為 4 GB(表示為 4G)。我們將它設置為 5G。對于我們的堆外緩存,這將是 4G,對于堆外存儲器的任何其他用途都是 1G(除了 BlockCache 之外還有其他堆外存儲器用戶;例如 RegionServer 中的 DFSClient 可以利用堆外存儲器)。參見 HBase 中的[直接內存使用情況。](#direct.memory)
```
HBASE_OFFHEAPSIZE=5G
```
2. 接下來,將以下配置添加到 RegionServer 的 _hbase-site.xml_ 。
```
<property>
<name>hbase.bucketcache.ioengine</name>
<value>offheap</value>
</property>
<property>
<name>hfile.block.cache.size</name>
<value>0.2</value>
</property>
<property>
<name>hbase.bucketcache.size</name>
<value>4196</value>
</property>
```
3. 重新啟動或滾動重新啟動群集,并檢查日志中是否存在任何問題。
在上面,我們將 BucketCache 設置為 4G。我們配置堆上 LruBlockCache 有 20%(0.2)的 RegionServer 的堆大小(0.2 * 5G = 1G)。換句話說,您可以像平常一樣配置 L1 LruBlockCache(就好像沒有 L2 緩存一樣)。
[HBASE-10641](https://issues.apache.org/jira/browse/HBASE-10641) 引入了為 BucketCache 的桶配置多種大小的能力,HBase 0.98 及更高版本。要配置多個存儲桶大小,請將新屬性`hbase.bucketcache.bucket.sizes`配置為以逗號分隔的塊大小列表,從最小到最大排序,不帶空格。目標是根據您的數據訪問模式優化存儲桶大小。以下示例配置大小為 4096 和 8192 的存儲桶。
```
<property>
<name>hbase.bucketcache.bucket.sizes</name>
<value>4096,8192</value>
</property>
```
> HBase 中的直接內存使用
>
> 默認的最大直接內存因 JVM 而異。傳統上它是 64M 或與分配的堆大小(-Xmx)或根本沒有限制(顯然是 JDK7)的某種關系。 HBase 服務器使用直接內存,特別是短路讀取(參見[利用本地數據](#perf.hdfs.configs.localread)),托管 DFSClient 將分配直接內存緩沖區。 DFSClient 使用多少不容易量化;它是打開的 HFiles * `hbase.dfs.client.read.shortcircuit.buffer.size`的數量,其中`hbase.dfs.client.read.shortcircuit.buffer.size`在 HBase 中設置為 128k - 參見 _hbase-default.xml_ 默認配置。如果你進行堆外塊緩存,你將使用直接內存。 RPCServer 使用 ByteBuffer 池。從 2.0.0 開始,這些緩沖區是堆外 ByteBuffers。啟動 JVM,確保 _conf / hbase-env.sh_ 中的`-XX:MaxDirectMemorySize`設置考慮了堆外 BlockCache(`hbase.bucketcache.size`),DFSClient 使用情況,RPC 端 ByteBufferPool 最大值。這必須比關閉堆 BlockCache 大小和最大 ByteBufferPool 大小的總和高一點。為最大直接內存大小分配額外的 1-2 GB 已經在測試中起作用。直接內存是 Java 進程堆的一部分,它與-Xmx 分配的對象堆是分開的。 `MaxDirectMemorySize`分配的值不得超過物理 RAM,并且由于其他內存要求和系統限制,可能會小于總可用 RAM。
>
> 您可以通過查看 _Server Metrics:Memory_ 選項卡,查看 RegionServer 配置使用的內存量和堆外/直接內存量以及它在任何時候使用了多少內存。 UI。它也可以通過 JMX 獲得。特別是服務器當前使用的直接內存可以在`java.nio.type=BufferPool,name=direct` bean 上找到。在 Java 中使用堆外內存時,Terracotta 有一個[良好的寫入](http://terracotta.org/documentation/4.0/bigmemorygo/configuration/storage-options)。它適用于他們的產品 BigMemory,但是很多問題一般都適用于任何脫機的嘗試。看看這個。
>
> hbase.bucketcache.percentage.in.combinedcache
>
> 這是刪除了之前的 HBase 1.0 配置,因為它令人困惑。它是一個浮點數,你可以設置為 0.0 到 1.0 之間的某個值。它的默認值是 0.9。如果部署使用 CombinedBlockCache,則 LruBlockCache L1 大小計算為`(1 - hbase.bucketcache.percentage.in.combinedcache) * size-of-bucketcache`,BucketCache 大小為`hbase.bucketcache.percentage.in.combinedcache * size-of-bucket-cache`。其中 bucket-cache-cache 本身的大小是配置的值`hbase.bucketcache.size`如果它被指定為兆字節 OR `hbase.bucketcache.size` * `-XX:MaxDirectMemorySize`,如果`hbase.bucketcache.size`在 0 和 1.0 之間。
>
> 在 1.0 中,它應該更直接。使用`hfile.block.cache.size setting`(不是最佳名稱)將 Onheap LruBlockCache 大小設置為 java 堆的一小部分,并將 BucketCache 設置為絕對兆字節。
#### 71.4.6。壓縮的 BlockCache
[HBASE-11331](https://issues.apache.org/jira/browse/HBASE-11331) 引入了懶惰的 BlockCache 解壓縮,更簡單地稱為壓縮的 BlockCache。當啟用壓縮的 BlockCache 時,數據和編碼數據塊以其磁盤格式緩存在 BlockCache 中,而不是在緩存之前進行解壓縮和解密。
對于托管更多數據而不能容納緩存的 RegionServer,通過 SNAPPY 壓縮啟用此功能已顯示吞吐量增加 50%,平均延遲提高 30%,同時將垃圾收集增加 80%并增加總體 CPU 負載 2%。有關如何衡量和實現性能的更多詳細信息,請參閱 HBASE-11331。對于托管可以輕松適應緩存的數據的 RegionServer,或者如果您的工作負載對額外的 CPU 或垃圾收集負載敏感,您可能會獲得較少的好處。
默認情況下禁用壓縮的 BlockCache。要啟用它,請在所有 RegionServers 上的 _hbase-site.xml_ 中將`hbase.block.data.cachecompressed`設置為`true`。
### 71.5。 RegionServer Offheap 讀/寫路徑
#### 71.5.1。 Offheap 讀取路徑
在 hbase-2.0.0 中, [HBASE-11425](https://issues.apache.org/jira/browse/HBASE-11425) 改變了 HBase 讀取路徑,因此它可以將讀取數據保留在堆外,從而避免將緩存數據復制到 Java 堆上。由于產生的垃圾較少而且清除較少,因此可以減少 GC 暫停。堆外讀取路徑的性能與堆上 LRU 緩存的性能類似/更好。此功能自 HBase 2.0.0 起可用。如果 BucketCache 處于`file`模式,則與本機堆上 LruBlockCache 相比,獲取總是會更慢。有關更多詳細信息和測試結果,請參閱下面的博客[關閉 Apache HBase 中的讀取路徑:第 2 部分](https://blogs.apache.org/hbase/entry/offheaping_the_read_path_in)和[生產中的 Offheap 讀取路徑 - 阿里巴巴故事](https://blogs.apache.org/hbase/entry/offheap-read-path-in-production)
對于端到端的非堆積讀取路徑,首先應該有一個堆外支持的[堆外塊緩存](#offheap.blockcache)(BC)。在 _hbase-site.xml_ 中將'hbase.bucketcache.ioengine'配置為堆外。同時使用`hbase.bucketcache.size`配置指定 BC 的總容量。請記住在 _hbase-env.sh_ 中調整'HBASE_OFFHEAPSIZE'的值。這就是我們如何為 RegionServer java 進程指定最大可能的堆外內存分配。這應該比堆外 BC 大小更大。請記住,`hbase.bucketcache.ioengine`沒有默認值,這意味著 BC 默認關閉(參見 [HBase 中的直接內存使用情況](#direct.memory))。
接下來要調整的是 RPC 服務器端的 ByteBuffer 池。此池中的緩沖區將用于累積單元字節并創建結果單元塊以發送回客戶端。 `hbase.ipc.server.reservoir.enabled`可用于打開或關閉此池。默認情況下,此池為 ON 且可用。 HBase 將創建關閉堆 ByteBuffers 并將它們池化。如果您希望在讀取路徑中進行端到端的堆疊,請確保不要將其關閉。如果關閉此池,服務器將在堆上創建臨時緩沖區以累積單元字節并生成結果單元塊。這可能會影響高度讀取加載的服務器上的 GC。用戶可以根據池中緩沖區的數量以及每個 ByteBuffer 的大小來調整此池。使用 config `hbase.ipc.server.reservoir.initial.buffer.size`調整每個緩沖區大小。默認值為 64 KB。
當讀取模式是隨機行讀取負載并且每個行的大小與此 64 KB 相比較小時,請嘗試減少此行。當結果大小大于一個 ByteBuffer 大小時,服務器將嘗試獲取多個緩沖區并從中生成結果單元塊。當池緩沖區用完時,服務器將最終創建臨時堆棧緩沖區。
可以使用 config'hbase.ipc.server.reservoir.initial.max'調整池中 ByteBuffers 的最大數量。其值默認為 64 *區域服務器處理程序配置(請參閱 config'hbase.regionserver.handler.count')。數學是這樣的,默認情況下我們認為每個讀取結果的結果單元塊大小為 2 MB,每個處理程序將處理讀取。對于 2 MB 大小,我們需要 32 個大小為 64 KB 的緩沖區(請參閱池中的默認緩沖區大小)。所以每個處理程序 32 ByteBuffers(BB)。我們將此大小的兩倍分配為最大 BBs 計數,以便一個處理程序可以創建響應并將其交給 RPC Responder 線程,然后處理創建新響應單元塊的新請求(使用池化緩沖區)。即使響應者無法立即發回第一個 TCP 回復,我們的計數應該允許我們在池中仍然有足夠的緩沖區而不必在堆上創建臨時緩沖區。同樣,對于較小尺寸的隨機行讀取,請調整此最大計數。有懶惰創建的緩沖區,計數是要合并的最大計數。
如果在堆外端到端讀取路徑之后仍然看到 GC 問題,請在相應的緩沖池中查找問題。使用 INFO 級別檢查以下 RegionServer 日志:
```
Pool already reached its max capacity : XXX and no free buffers now. Consider increasing the value for 'hbase.ipc.server.reservoir.initial.max' ?
```
_hbase-env.sh_ 中 _HBASE _OFFHEAPSIZE_ 的設置也應考慮 RPC 端的堆緩沖池。我們需要將 RegionServer 的最大堆大小配置為略高于此最大池大小和關閉堆高速緩存大小的總和。 TCP 層還需要為 TCP 通信創建直接字節緩沖區。此外,DFS 客戶端將需要一些堆外工作來完成其工作,尤其是在配置了短路讀取的情況下。為最大直接內存大小分配額外的 1 - 2 GB 已經在測試中起作用。
如果您正在使用協處理器并在讀取結果中引用單元格,請不要將這些單元格的引用存儲在 CP 掛鉤方法的范圍之外。有時,CP 需要存儲有關單元格的信息(如其行鍵),以便在下一個 CP 鉤子調用等中進行考慮。對于這種情況,請根據用例克隆整個 Cell 的必需字段。 [參見 CellUtil#cloneXXX(Cell)API]
#### 71.5.2。 Offheap 寫路徑
去做
### 71.6。 RegionServer 拆分實現
由于寫請求由區域服務器處理,它們會累積在稱為 _memstore_ 的內存存儲系統中。 memstore 填充后,其內容將作為附加存儲文件寫入磁盤。此事件稱為 _memstore flush_ 。隨著存儲文件的累積,RegionServer 將[將](#compaction)壓縮為更少,更大的文件。每次刷新或壓縮完成后,存儲在該區域中的數據量已更改。 RegionServer 查詢區域拆分策略,以確定該區域是否已經變得太大,或者是否應該針對另一個特定于策略的原因進行拆分。如果策略建議,則會將區域拆分請求排入隊列。
從邏輯上講,分割區域的過程很簡單。我們在區域的鍵空間中找到一個合適的點,我們應該將區域分成兩半,然后將區域的數據分成兩個新的區域。然而,該過程的細節并不簡單。當發生拆分時,新創建的 _ 子區域 _ 不會立即將所有數據重寫為新文件。相反,他們創建類似于符號鏈接文件的小文件,名為[參考文件](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/io/Reference.html),它根據分割點指向父商店文件的頂部或底部。參考文件的使用方式與常規數據文件類似,但只考慮了一半的記錄。如果不再有對父區域的不可變數據文件的引用,則只能拆分該區域。這些參考文件通過壓縮逐漸清理,以便該區域將停止引用其父文件,并可以進一步拆分。
雖然拆分區域是 RegionServer 做出的本地決策,但拆分過程本身必須與許多參與者協調。 RegionServer 在拆分之前和之后通知 Master,更新`.META.`表,以便客戶端可以發現新的子區域,并重新排列 HDFS 中的目錄結構和數據文件。拆分是一個多任務流程。要在發生錯誤時啟用回滾,RegionServer 會保留有關執行狀態的內存日記。 RegionServer 執行拆分所采取的步驟在 [RegionServer 拆分流程](#regionserver_split_process_image)中說明。每個步驟都標有其步驟編號。 RegionServers 或 Master 的操作顯示為紅色,而客戶端的操作顯示為綠色。
圖 1\. RegionServer 拆分流程
1. RegionServer 在本地決定拆分區域,并準備拆分。 **分拆交易已經開始。** 作為第一步,RegionServer 獲取表上的共享讀鎖,以防止在拆分過程中修改模式。然后它在`/hbase/region-in-transition/region-name`下的 zookeeper 中創建一個 znode,并將 znode 的狀態設置為`SPLITTING`。
2. Master 了解這個 znode,因為它有一個父`region-in-transition` znode 的觀察者。
3. RegionServer 在 HDFS 的父級`region`目錄下創建一個名為`.splits`的子目錄。
4. RegionServer 關閉父區域,并在其本地數據結構中將該區域標記為脫機。 **分裂區域現在離線。** 此時,來到父區域的客戶端請求將拋出`NotServingRegionException`。客戶端將重試一些退避。關閉區域被刷新。
5. RegionServer 在`.splits`目錄下為子區域 A 和 B 創建區域目錄,并創建必要的數據結構。然后它會分割存儲文件,因為它會在父區域中為每個存儲文件創建兩個參考文件。這些參考文件將指向父區域的文件。
6. RegionServer 在 HDFS 中創建實際的區域目錄,并移動每個子項的參考文件。
7. RegionServer 將`Put`請求發送到`.META.`表,在`.META.`表中將父級設置為脫機,并添加有關子區域的信息。此時,`.META.`中的女兒不會有個別條目。客戶將看到父區域在掃描`.META.`時被拆分,但在`.META.`出現之前不會知道這些女兒。另外,如果這`Put`到`.META`。成功后,父母將被有效分割。如果 RegionServer 在此 RPC 成功之前失敗,則 Master 和下一個打開該區域的 Region Server 將清除有關區域拆分的臟狀態。但是,`.META.`更新后,區域拆分將由 Master 進行前滾。
8. RegionServer 并行打開女兒 A 和 B.
9. RegionServer 將女兒 A 和 B 添加到`.META.`,以及它托管區域的信息。 **分裂地區(帶有父母參考的孩子)現在在線。** 在此之后,客戶可以發現新區域并向他們發出請求。客戶端在本地緩存`.META.`條目,但是當它們向 RegionServer 或`.META.`發出請求時,它們的緩存將無效,并且它們將從`.META.`中了解新區域。
10. RegionServer 將 ZooKeeper 中的 znode `/hbase/region-in-transition/region-name`更新為狀態`SPLIT`,以便主人可以了解它。如有必要,平衡器可以自由地將子區域重新分配給其他區域服務器。 **分裂交易現已完成。**
11. 拆分后,`.META.`和 HDFS 仍將包含對父區域的引用。當子區域中的壓縮重寫數據文件時,將刪除這些引用。主服務器中的垃圾收集任務會定期檢查子區域是否仍然引用父區域的文件。如果不是,則將刪除父區域。
### 71.7。寫前方日志(WAL)
#### 71.7.1。目的
_ 預寫日志(WAL)_ 將對 HBase 中數據的所有更改記錄到基于文件的存儲。在正常操作下,不需要 WAL,因為數據更改從 MemStore 移動到 StoreFiles。但是,如果 RegionApp 在刷新 MemStore 之前崩潰或變得不可用,則 WAL 會確保可以重播對數據的更改。如果寫入 WAL 失敗,則修改數據的整個操作將失敗。
HBase 使用 [WAL](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/wal/WAL.html) 接口的實現。通常,每個 RegionServer 只有一個 WAL 實例。一個例外是攜帶 _hbase:meta_ 的 RegionServer; _meta_ 表獲得了自己的專用 WAL。 RegionServer 記錄其 WAL 的刪除和刪除,然后為受影響的[商店](#store)記錄這些突變 [MemStore](#store.memstore) 。
> HLo
>
> 在 2.0 之前,HBase 中 WALs 的接口被命名為`HLog`。在 0.94 中,HLog 是 WAL 實現的名稱。您可能會在針對這些舊版本的文檔中找到對 HLog 的引用。
WAL 駐留在 _/ hbase / WALs /_ 目錄中的 HDFS 中,每個區域都有子目錄。
有關預寫日志概念的更多一般信息,請參閱 Wikipedia [Write-Ahead Log](http://en.wikipedia.org/wiki/Write-ahead_logging) 文章。
#### 71.7.2。 WAL 提供商
在 HBase 中,有許多 WAL 元素(或“提供者”)。每個都有一個簡短的名稱標簽(不幸的是,它并不總是描述性的)。您在 _hbase-site.xml_ 中設置提供程序,將 WAL 提供者短名稱作為 _hbase.wal.provider_ 屬性的值設置(設置 _hbase 的提供程序: meta_ 使用 _hbase.wal.meta _ 提供程序 _ 屬性,否則它使用由 _hbase.wal.provider_ 配置的相同提供程序。
* _asyncfs_ :**默認**。自 hbase-2.0.0 以來的新版本(HBASE-15536??,HBASE-14790)。這個 _AsyncFSWAL_ 提供程序,它在 RegionServer 日志中標識自身,是基于一個新的非阻塞 dfsclient 實現。它目前駐留在 hbase 代碼庫中,但目的是將其移回 HDFS 本身。 WALs 編輯被并發(“扇出”)樣式寫入每個 DataNode 上的每個 WAL 塊復制品,而不是像默認客戶端那樣在鏈式管道中。延遲應該更好。有關實施的更多詳細信息,請參閱第 14 頁第 14 頁的小米的 [Apache HBase 改進和實踐。](https://www.slideshare.net/HBaseCon/apache-hbase-improvements-and-practices-at-xiaomi)
* _filesystem_ :這是 hbase-1.x 版本中的默認值。它建立在阻塞 _DFSClient_ 的基礎上,并在經典 _DFSCLient_ 管道模式下寫入副本。在日志中,它標識為 _FSHLog_ 或 _FSHLogProvider_ 。
* _multiwal_ :此提供程序由 _asyncfs_ 或 _ 文件系統 _ 的多個實例組成。有關 _multiwal_ 的更多信息,請參閱下一節。
在 RegionServer 日志中查找如下所示的行,以查看適當的提供程序(下面顯示了默認的 AsyncFSWALProvider):
```
2018-04-02 13:22:37,983 INFO [regionserver/ve0528:16020] wal.WALFactory: Instantiating WALProvider of type class org.apache.hadoop.hbase.wal.AsyncFSWALProvider
```
> 由于 _AsyncFSWAL_ 侵入了 DFSClient 實現的內部,因此即使對于簡單的補丁版本,也可以通過升級 hadoop 依賴關系來輕松破解它。因此,如果您沒有明確指定 wal 提供程序,我們將首先嘗試使用 _asyncfs_ ,如果失敗,我們將回退使用 _ 文件系統 _。請注意,這可能并不總是有效,因此如果由于啟動 _AsyncFSWAL_ 的問題仍然無法啟動 HBase,請在配置文件中明確指定 _ 文件系統 _。
>
> 已經在 hadoop-3.x 中添加了 EC 支持,并且它與 WAL 不兼容,因為 EC 輸出流不支持 hflush / hsync。為了在 EC 目錄中創建非 EC 文件,我們需要為 _FileSystem_ 使用新的基于構建器的創建 API,但它僅在 hadoop-2.9 +中引入,對于 HBase 我們仍然需要支持 hadoop-2.7.x。因此,在我們找到處理它的方法之前,請不要為 WAL 目錄啟用 EC。
#### 71.7.3。 MultiWAL
對于每個 RegionServer 一個 WAL,RegionServer 必須串行寫入 WAL,因為 HDFS 文件必須是順序的。這導致 WAL 成為性能瓶頸。
HBase 1.0 在 [HBASE-5699](https://issues.apache.org/jira/browse/HBASE-5699) 中引入了對 MultiWal 的支持。 MultiWAL 允許 RegionServer 通過在底層 HDFS 實例中使用多個管道來并行寫入多個 WAL 流,這會增加寫入期間的總吞吐量。這種并行化是通過按區域劃分傳入編輯來完成的。因此,當前的實現無助于增加單個區域的吞吐量。
使用原始 WAL 實現的 RegionServers 和使用 MultiWAL 實現的 RegionServers 都可以處理任一組 WAL 的恢復,因此通過滾動重啟可以實現零停機配置更新。
配置 MultiWAL
要為 RegionServer 配置 MultiWAL,請通過粘貼以下 XML 將屬性`hbase.wal.provider`的值設置為`multiwal`:
```
<property>
<name>hbase.wal.provider</name>
<value>multiwal</value>
</property>
```
重新啟動 RegionServer 以使更改生效。
要為 RegionServer 禁用 MultiWAL,請取消設置該屬性并重新啟動 RegionServer。
#### 71.7.4。 WAL 法拉盛
TODO(描述)。
#### 71.7.5。 WAL 分裂
RegionServer 服務于許多地區。區域服務器中的所有區域共享相同的活動 WAL 文件。 WAL 文件中的每個編輯都包含有關它所屬的區域的信息。打開某個區域時,需要重播屬于該區域的 WAL 文件中的編輯。因此,WAL 文件中的編輯必須按區域分組,以便可以重放特定的集合以重新生成特定區域中的數據。按區域對 WAL 編輯進行分組的過程稱為 _ 日志分割 _。如果區域服務器出現故障,這是恢復數據的關鍵過程。
日志拆分由集群啟動期間的 HMaster 完成,或者由區域服務器關閉時由 ServerShutdownHandler 完成。為了保證一致性,受影響的區域在數據恢復之前不可用。在給定區域再次可用之前,需要恢復和重放所有 WAL 編輯。因此,在進程完成之前,受日志拆分影響的區域將不可用。
過程:Log Step,Step by Step
1. 重命名 _/ hbase / WALs / <host>,<port>, <startcode></startcode> </port></host>_ 目錄。
重命名目錄很重要,因為即使 HMaster 認為它已關閉,RegionServer 仍可能正在啟動并接受請求。如果 RegionServer 沒有立即響應并且沒有對其 ZooKeeper 會話進行心跳,則 HMaster 可能會將其解釋為 RegionServer 故障。重命名 logs 目錄可確保仍然無法寫入仍由活動但繁忙的 RegionServer 使用的現有有效 WAL 文件。
新目錄根據以下模式命名:
```
/hbase/WALs/<host>,<port>,<startcode>-splitting
```
此類重命名目錄的示例可能如下所示:
```
/hbase/WALs/srv.example.com,60020,1254173957298-splitting
```
2. 每個日志文件被拆分,一次一個。
日志分割器一次讀取一個編輯條目的日志文件,并將每個編輯條目放入與編輯區域對應的緩沖區中。同時,拆分器啟動了幾個寫入程序線程。 Writer 線程獲取相應的緩沖區并將緩沖區中的編輯條目寫入臨時恢復的編輯文件。臨時編輯文件使用以下命名模式存儲到磁盤:
```
/hbase/<table_name>/<region_id>/recovered.edits/.temp
```
此文件用于存儲此區域的 WAL 日志中的所有編輯。日志分割完成后, _.temp_ 文件將重命名為寫入該文件的第一個日志的序列 ID。
要確定是否已編寫所有編輯,將序列 ID 與寫入 HFile 的最后一次編輯的序列進行比較。如果最后一次編輯的序列大于或等于文件名中包含的序列 ID,則很明顯編輯文件中的所有寫入都已完成。
3. 日志拆分完成后,每個受影響的區域都將分配給 RegionServer。
打開該區域時,將檢查 _restored.edits_ 文件夾中是否有恢復的編輯文件。如果存在任何此類文件,則通過閱讀編輯并將其保存到 MemStore 來重放它們。重放所有編輯文件后,MemStore 的內容將寫入磁盤(HFile)并刪除編輯文件。
##### 日志拆分過程中的錯誤處理
如果將`hbase.hlog.split.skip.errors`選項設置為`true`,則會將錯誤視為:
* 將記錄拆分期間遇到的任何錯誤。
* 有問題的 WAL 日志將被移動到 hbase `rootdir`下的 _.corrupt_ 目錄中,
* WALL 的處理將繼續進行
如果`hbase.hlog.split.skip.errors`選項設置為`false`(默認值),則會傳播該異常并將拆分記錄為失敗。請參閱 [HBASE-2958 當 hbase.hlog.split.skip.errors 設置為 false 時,我們無法進行拆分,但這就是](https://issues.apache.org/jira/browse/HBASE-2958)。如果設置了這個標志,我們需要做的不僅僅是失敗拆分。
###### 拆分崩潰的 RegionServer 的 WAL 時如何處理 EOFExceptions
如果在分割日志時發生 EOFException,即使`hbase.hlog.split.skip.errors`設置為`false`,分割仍會繼續。在讀取要拆分的文件集中的最后一個日志時可能會出現 EOFException,因為 RegionServer 可能正在崩潰時寫入記錄。有關背景信息,請參閱 [HBASE-2643 圖如何處理 eof 拆分日志](https://issues.apache.org/jira/browse/HBASE-2643)
##### 日志拆分期間的性能改進
WAL 日志拆分和恢復可能是資源密集型的,需要很長時間,具體取決于崩潰中涉及的 RegionServers 的數量和區域的大小。 [啟用或禁用分布式日志拆分](#distributed.log.splitting)是為了提高日志拆分期間的性能而開發的。
啟用或禁用分布式日志拆分
默認情況下啟用分布式日志處理,因為 HBase 為 0.92。該設置由`hbase.master.distributed.log.splitting`屬性控制,可以設置為`true`或`false`,但默認為`true`。
分布式日志拆分,一步一步
配置分布式日志分割后,HMaster 控制該過程。 HMaster 在日志分割過程中注冊每個 RegionServer,分割日志的實際工作由 RegionServers 完成。如[分布式日志分割,逐步](#log.splitting.step.by.step)中所述的日志分割的一般過程仍然適用于此處。
1. 如果啟用了分布式日志處理,則 HMaster 會在啟動集群時創建 _ 拆分日志管理器 _ 實例。
1. 拆分日志管理器管理需要掃描和拆分的所有日志文件。
2. 拆分日志管理器將所有日志放入 ZooKeeper splitWAL 節點( _/ hbase / splitWAL_ )作為任務。
3. 您可以通過發出以下`zkCli`命令來查看 splitWAL 的內容。顯示示例輸出。
```
ls /hbase/splitWAL
[hdfs%3A%2F%2Fhost2.sample.com%3A56020%2Fhbase%2FWALs%2Fhost8.sample.com%2C57020%2C1340474893275-splitting%2Fhost8.sample.com%253A57020.1340474893900,
hdfs%3A%2F%2Fhost2.sample.com%3A56020%2Fhbase%2FWALs%2Fhost3.sample.com%2C57020%2C1340474893299-splitting%2Fhost3.sample.com%253A57020.1340474893931,
hdfs%3A%2F%2Fhost2.sample.com%3A56020%2Fhbase%2FWALs%2Fhost4.sample.com%2C57020%2C1340474893287-splitting%2Fhost4.sample.com%253A57020.1340474893946]
```
輸出包含一些非 ASCII 字符。解碼后,它看起來更簡單:
```
[hdfs://host2.sample.com:56020/hbase/WALs
/host8.sample.com,57020,1340474893275-splitting
/host8.sample.com%3A57020.1340474893900,
hdfs://host2.sample.com:56020/hbase/WALs
/host3.sample.com,57020,1340474893299-splitting
/host3.sample.com%3A57020.1340474893931,
hdfs://host2.sample.com:56020/hbase/WALs
/host4.sample.com,57020,1340474893287-splitting
/host4.sample.com%3A57020.1340474893946]
```
該列表表示要掃描和拆分的 WAL 文件名,這是日志拆分任務的列表。
2. 拆分日志管理器監視日志拆分任務和工作人員。
拆分日志管理器負責以下正在進行的任務:
* 一旦拆分日志管理器將所有任務發布到 splitWAL znode,它就會監視這些任務節點并等待它們被處理。
* 檢查是否有任何死亡分裂日志工作者排隊。如果它找到無響應的工作人員聲稱的任務,它將重新提交這些任務。如果重新提交由于某些 ZooKeeper 異常而失敗,則死亡工作者將再次排隊等待重試。
* 檢查是否有任何未分配的任務。如果找到任何,它將創建一個短暫的重新掃描節點,以便通知每個拆分日志工作者通過`nodeChildrenChanged` ZooKeeper 事件重新掃描未分配的任務。
* 檢查已分配但已過期的任務。如果找到任何一個,它們將再次移回`TASK_UNASSIGNED`狀態,以便可以重試它們。這些任務可能會分配給慢速工作人員,或者可能已經完成。這不是問題,因為日志拆分任務具有冪等性。換句話說,可以多次處理相同的日志分割任務而不會引起任何問題。
* 拆分日志管理器不斷監視 HBase 拆分日志 znodes。如果更改了任何拆分日志任務節點數據,則拆分日志管理器將檢索節點數據。節點數據包含任務的當前狀態。您可以使用`zkCli` `get`命令檢索任務的當前狀態。在下面的示例輸出中,輸出的第一行顯示該任務當前未分配。
```
get /hbase/splitWAL/hdfs%3A%2F%2Fhost2.sample.com%3A56020%2Fhbase%2FWALs%2Fhost6.sample.com%2C57020%2C1340474893287-splitting%2Fhost6.sample.com%253A57020.1340474893945
unassigned host2.sample.com:57000
cZxid = 0×7115
ctime = Sat Jun 23 11:13:40 PDT 2012
...
```
根據更改數據的任務的狀態,拆分日志管理器執行以下操作之一:
* 如果未分配,則重新提交任務
* 如果已分配任務,請心跳任務
* 如果任務被重新簽名則重新提交或失敗(請參閱[任務失敗的原因](#distributed.log.replay.failure.reasons))
* 如果任務完成但有錯誤,請重新提交或失敗(請參閱[任務失敗的原因](#distributed.log.replay.failure.reasons))
* 如果由于錯誤而無法完成任務,請重新提交或失敗(請參閱[任務失敗的原因](#distributed.log.replay.failure.reasons))
* 如果任務成功完成或失敗,請刪除該任務
> 任務失敗的原因
>
> * 該任務已被刪除。
>
>
> * 節點不再存在。
>
>
> * 日志狀態管理器無法將任務狀態移動到`TASK_UNASSIGNED`。
>
>
> * 重新提交的次數超過重新提交閾值。
3. 每個 RegionServer 的拆分日志工作程序都執行日志分割任務。
每個 RegionServer 都運行一個名為 _ 拆分日志工作程序 _ 的守護程序線程,該程序負責拆分日志。守護程序線程在 RegionServer 啟動時啟動,并注冊自己以監視 HBase znode。如果任何 splitWAL znode 子代更改,它會通知睡眠工作線程喚醒并獲取更多任務。如果更改了工作人員當前任務的節點數據,則工作人員會檢查該任務是否已由另一個工作人員執行。如果是這樣,工作線程將停止當前任務的工作。
工作人員不斷監視 splitWAL znode。當出現新任務時,拆分日志工作程序將檢索任務路徑并檢查每個任務路徑,直到找到無人認領的任務,并嘗試聲明該任務。如果聲明成功,它會嘗試執行任務并根據拆分結果更新任務的`state`屬性。此時,拆分日志工作程序將掃描另一個無人認領的任務。
拆分日志工作者如何處理任務
* 它查詢任務狀態,僅在任務處于`TASK_UNASSIGNED`狀態時才執行操作。
* 如果任務處于`TASK_UNASSIGNED`狀態,則工作程序會嘗試將狀態設置為`TASK_OWNED`。如果它未能設置狀態,另一個工人將嘗試抓住它。如果任務仍未分配,拆分日志管理器還將要求所有工作人員稍后重新掃描。
* 如果工作者成功獲得任務的所有權,它會再次嘗試獲取任務狀態,以確保它真正異步獲取它。在此期間,它啟動一個拆分任務執行器來完成實際工作:
* 獲取 HBase 根文件夾,在根目錄下創建臨時文件夾,并將日志文件拆分為臨時文件夾。
* 如果拆分成功,則任務執行程序將任務設置為狀態`TASK_DONE`。
* 如果 worker 捕獲到意外的 IOException,則該任務將設置為 state `TASK_ERR`。
* 如果工作人員正在關閉,請將任務設置為`TASK_RESIGNED`狀態。
* 如果任務由另一個工作人員執行,則只需記錄它。
4. 拆分日志管理器監視未完成的任務。
當所有任務成功完成時,拆分日志管理器將返回。如果所有任務都在某些失敗的情況下完成,則拆分日志管理器會拋出異常,以便可以重試日志拆分。由于異步實現,在極少數情況下,拆分日志管理器會丟失一些已完成的任務。因此,它會定期檢查其任務圖或 ZooKeeper 中剩余的未完成任務。如果沒有找到,它會拋出異常,以便可以立即重試日志拆分,而不是掛在那里等待不會發生的事情。
#### 71.7.6。 WAL 壓縮
可以使用 LRU Dictionary 壓縮來壓縮 WAL 的內容。這可用于加速 WAL 復制到不同的數據節點。字典最多可以存儲 2 個 <sup>15</sup> 元素;在超過此數量后開始驅逐。
要啟用 WAL 壓縮,請將`hbase.regionserver.wal.enablecompression`屬性設置為`true`。此屬性的默認值為`false`。默認情況下,啟用 WAL 壓縮時會打開 WAL 標記壓縮。您可以通過將`hbase.regionserver.wal.tags.enablecompression`屬性設置為“false”來關閉 WAL 標記壓縮。
WAL 壓縮的一個可能的缺點是,如果在寫入中間終止,則我們會丟失 WAL 中最后一個塊的更多數據。如果最后一個塊中的條目添加了新的字典條目但由于突然終止而導致修改的字典仍然存在,則讀取該最后一個塊可能無法解析最后寫入的條目。
#### 71.7.7。耐久力
可以在每個突變或表格上設置 _ 耐久性 _。選項包括:
* _SKIP _WAL_ :不要將變形寫入 WAL(參見下一節,[禁用 WAL](#wal.disable) )。
* _ASYNC _WAL_ :異步寫入 WAL;不要讓客戶等待他們寫入文件系統的同步,而是立即返回。編輯變得可見。同時,在后臺,Mutation 將在稍后的某個時間刷新到 WAL。此選項目前可能會丟失數據。見 HBASE-16689。
* _SYNC _WAL_ :**默認**。在我們將成功返回給客戶端之前,每個編輯都會同步到 HDFS。
* _FSYNC _WAL_ :在我們將成功返回給客戶端之前,每個編輯都與 HDFS 和文件系統進行 fsync。
不要將 Mutation 或 Table 上的 _ASYNC _WAL_ 選項與 _AsyncFSWAL_ 編寫器混淆;不幸的是,它們是不同的選擇
#### 71.7.8。禁用 WAL
可以禁用 WAL,以在某些特定情況下提高性能。但是,禁用 WAL 會使您的數據面臨風險。推薦這種情況的唯一情況是在批量加載期間。這是因為,如果出現問題,可以重新運行批量加載而不會有數據丟失的風險。
通過調用 HBase 客戶端字段`Mutation.writeToWAL(false)`禁用 WAL。使用`Mutation.setDurability(Durability.SKIP_WAL)`和 Mutation.getDurability()方法設置并獲取字段的值。沒有辦法只為特定的表禁用 WAL。
> 如果禁用 WAL 而不是批量加載,則數據存在風險。
## 72.地區
區域是表的可用性和分布的基本元素,并且由每列存儲族組成。對象的層次結構如下:
```
Table (HBase table)
Region (Regions for the table)
Store (Store per ColumnFamily for each Region for the table)
MemStore (MemStore for each Store for each Region for the table)
StoreFile (StoreFiles for each Store for each Region for the table)
Block (Blocks within a StoreFile within a Store for each Region for the table)
```
有關寫入 HDFS 時 HBase 文件的描述,請參閱[瀏覽 HBFS 對象的 HDFS](#trouble.namenode.hbase.objects) 。
### 72.1。區域數量的考慮因素
通常,HBase 被設計為每個服務器運行一小部分(20-200)個相對較大(5-20??Gb)的區域。對此的考慮如下:
#### 72.1.1。我為什么要保持我的地區數量低?
通常,您希望保留您的區域在 HBase 上的數量較少,原因有很多。通常每個 RegionServer 大約 100 個區域產生了最好的結果。以下是保持區域數量低的一些原因:
1. MSLAB(MemStore 本地分配緩沖區)每個 MemStore 需要 2MB(每個區域每個系列 2MB)。每個擁有 2 個系列的 1000 個區域使用了 3.9GB 的堆,并且它甚至還沒有存儲數據。注意:2MB 值是可配置的。
2. 如果以相同的速率填充所有區域,則全局內存使用會使得當您有太多區域而這會產生壓縮時會強制進行微小的刷新。幾十次重寫相同的數據是你想要的最后一件事。一個例子是平均填充 1000 個區域(有一個系列),讓我們考慮全局 MemStore 使用 5GB 的下限(區域服務器將有一個大堆)。一旦達到 5GB,它將強制刷新最大區域,此時它們幾乎都應該有大約 5MB 的數據,因此它將刷新該數量。稍后插入 5MB,它將刷新另一個區域,現在將有超過 5MB 的數據,依此類推。這是目前區域數量的主要限制因素;參見[每個 RS 的區域數 - 上限](#ops.capacity.regions.count)詳細公式。
3. 主人對大量地區過敏,并且需要花費大量時間分配它們并分批移動它們。原因是它對 ZK 的使用很重,而且目前它并不是非常同步(真的可以改進 - 并且已經在 0.96 HBase 中得到了改進)。
4. 在舊版本的 HBase(pre-HFile v2,0.90 和之前版本)中,少數 RS 上的大量區域可能導致存儲文件索引上升,增加堆使用量并可能在 RS 上產生內存壓力或 OOME
另一個問題是 MapReduce 作業的區域數量的影響;每個 HBase 區域通常有一個映射器。因此,每個 RS 僅托管 5 個區域可能不足以為 MapReduce 作業獲取足夠數量的任務,而 1000 個區域將生成太多任務。
有關配置指南,請參閱[確定區域計數和大小](#ops.capacity.regions)。
### 72.2。 Region-RegionServer 分配
本節介紹如何將區域分配給 RegionServers。
#### 72.2.1。啟動
當 HBase 啟動時,區域分配如下(短版本):
1. Master 在啟動時調用`AssignmentManager`。
2. `AssignmentManager`查看`hbase:meta`中的現有區域分配。
3. 如果區域分配仍然有效(即,如果 RegionServer 仍在線),則保留分配。
4. 如果賦值無效,則調用`LoadBalancerFactory`來分配區域。負載均衡器(HBase 1.0 中默認為`StochasticLoadBalancer`)將區域分配給 RegionServer。
5. 在 RegionServer 打開區域時,使用 RegionServer 分配(如果需要)和 RegionServer 啟動代碼(RegionServer 進程的開始時間)更新`hbase:meta`。
#### 72.2.2。故障轉移
RegionServer 失敗時:
1. 由于 RegionServer 已關閉,這些區域立即變為不可用。
2. Master 將檢測到 RegionServer 失敗。
3. 區域分配將被視為無效,并將像啟動順序一樣重新分配。
4. 機上查詢會重新嘗試,而不會丟失。
5. 操作在以下時間內切換到新的 RegionServer:
```
ZooKeeper session timeout + split time + assignment/replay time
```
#### 72.2.3。區域負載平衡
可以通過 [LoadBalancer](#master.processes.loadbalancer) 周期性地移動區域。
#### 72.2.4。地區國家轉型
HBase 維護每個區域的狀態,并在`hbase:meta`中保持狀態。 `hbase:meta`區域本身的狀態在 ZooKeeper 中持久存在。您可以在 Master Web UI 中查看轉換中的區域的狀態。以下是可能的區域狀態列表。
可能的地區國家
* `OFFLINE`:該區域處于脫機狀態且未打開
* `OPENING`:該地區正處于開放狀態
* `OPEN`:區域已打開且 RegionServer 已通知主服務器
* `FAILED_OPEN`:RegionServer 無法打開該區域
* `CLOSING`:該地區正處于關閉狀態
* `CLOSED`:RegionServer 已關閉該區域并通知主站
* `FAILED_CLOSE`:RegionServer 無法關閉該區域
* `SPLITTING`:RegionServer 通知主站區域正在拆分
* `SPLIT`:RegionServer 通知主站區域已完成拆分
* `SPLITTING_NEW`:正在通過正在進行的拆分創建此區域
* `MERGING`:RegionServer 通知主服務器該區域正在與另一個區域合并
* `MERGED`:RegionServer 通知主服務器該區域已合并
* `MERGING_NEW`:該區域由兩個區域的合并創建
圖 2\. Region State TransitionsGraph Legend
* 布朗:離線狀態,一種特殊狀態,可以是瞬態的(在打開之前關閉之后),終端(禁用表的區域)或初始(新創建的表的區域)
* Palegreen:在線狀態,區域可以提供請求
* Lightblue:瞬態
* 紅色:失敗狀態需要 OPS 注意
* 黃金:區域的終端狀態分裂/合并
* 灰色:通過拆分/合并創建的區域的初始狀態
過渡狀態描述
1. 主設備將區域從`OFFLINE`移動到`OPENING`狀態,并嘗試將區域分配給 RegionServer。 RegionServer 可能已收到或未收到開放區域請求。主服務器重試將開放區域請求發送到 RegionServer,直到 RPC 通過或主服務器用完為止。 RegionServer 收到開放區域請求后,RegionServer 開始打開該區域。
2. 如果主服務器沒有重試,則主服務器會阻止 RegionServer 通過將區域移動到`CLOSING`狀態并嘗試關閉它來打開該區域,即使 RegionServer 開始打開該區域也是如此。
3. 在 RegionServer 打開區域后,它會繼續嘗試通知主服務器,直到主服務器將區域移動到`OPEN`狀態并通知 RegionServer。該地區現已開放。
4. 如果 RegionServer 無法打開該區域,則會通知主服務器。主服務器將區域移動到`CLOSED`狀態并嘗試在不同的 RegionServer 上打開該區域。
5. 如果主服務器無法在某個區域中的任何區域上打開該區域,則會將該區域移動到`FAILED_OPEN`狀態,并且在操作員從 HBase shell 進行干預或服務器已停止之前不會采取進一步操作。
6. 主設備將區域從`OPEN`移動到`CLOSING`狀態。持有該區域的 RegionServer 可能已收到或未收到近區域請求。主服務器重試向服務器發送關閉請求,直到 RPC 通過或主服務器用完為止。
7. 如果 RegionServer 未聯機或拋出`NotServingRegionException`,則主服務器將該區域移至`OFFLINE`狀態并將其重新分配給其他 RegionServer。
8. 如果 RegionServer 處于聯機狀態,但在主計算機用完重試后無法訪問,則主服務器會將該區域移至`FAILED_CLOSE`狀態,并且在操作員從 HBase shell 進行干預或服務器已停止之前不會采取進一步操作。
9. 如果 RegionServer 獲取關閉區域請求,它將關閉該區域并通知主服務器。主設備將區域移動到`CLOSED`狀態,并將其重新分配給不同的 RegionServer。
10. 在分配區域之前,如果區域處于`CLOSED`狀態,則主區域會自動將區域移動到`OFFLINE`狀態。
11. 當 RegionServer 即將拆分區域時,它會通知主服務器。主設備將要分割的區域從`OPEN`狀態移動到`SPLITTING`狀態,并將要創建的兩個新區域添加到 RegionServer。這兩個區域最初處于`SPLITTING_NEW`狀態。
12. 通知主服務器后,RegionServer 開始拆分該區域。一旦超過不返回點,RegionServer 就會再次通知主站,以便主站可以更新`hbase:meta`表。但是,在服務器通知拆分完成之前,主服務器不會更新區域狀態。如果分割成功,則分割區域從`SPLITTING`移動到`SPLIT`狀態,并且兩個新區域從`SPLITTING_NEW`移動到`OPEN`狀態。
13. 如果分割失敗,則分割區域從`SPLITTING`移回`OPEN`狀態,并且創建的兩個新區域從`SPLITTING_NEW`移動到`OFFLINE`狀態。
14. 當 RegionServer 即將合并兩個區域時,它會首先通知主服務器。主設備將要合并的兩個區域從`OPEN`合并到`MERGING`狀態,并將保存合并區域區域內容的新區域添加到 RegionServer。新區域最初處于`MERGING_NEW`狀態。
15. 通知主服務器后,RegionServer 開始合并這兩個區域。一旦超過不返回點,RegionServer 就會再次通知主服務器,以便主服務器可以更新 META。但是,在 RegionServer 通知合并已完成之前,主服務器不會更新區域狀態。如果合并成功,則兩個合并區域從`MERGING`移動到`MERGED`狀態,并且新區域從`MERGING_NEW`移動到`OPEN`狀態。
16. 如果合并失敗,則兩個合并區域從`MERGING`移回到`OPEN`狀態,并且為保持合并區域的內容而創建的新區域從`MERGING_NEW`移動到`OFFLINE`狀態。
17. 對于`FAILED_OPEN`或`FAILED_CLOSE`狀態的區域,當操作員通過 HBase Shell 重新分配它們時,主設備會嘗試再次關閉它們。
### 72.3。 Region-RegionServer 的位置
隨著時間的推移,Region-RegionServer 的位置是通過 HDFS 塊復制實現的。在選擇寫入副本的位置時,HDFS 客戶端默認執行以下操作:
1. 第一個副本寫入本地節點
2. 第二個副本寫入另一個機架上的隨機節點
3. 第三個副本與第二個副本寫在同一個機架上,但是在隨機選擇的不同節點上
4. 后續副本將寫入群集上的隨機節點。請參閱此頁面上的 _ 副本放置:第一個嬰兒步驟 _: [HDFS 架構](https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html)
因此,HBase 最終在沖洗或壓實之后實現區域的局部性。在 RegionServer 故障轉移情況下,可以為 RegionServer 分配具有非本地 StoreFiles 的區域(因為沒有任何副本是本地的),但是當在該區域中寫入新數據,或者壓縮表并重寫 StoreFiles 時,它們將成為 RegionServer 的“本地”。
有關詳細信息,請參閱此頁面上的 _ 副本放置:第一個嬰兒步驟 _: [HDFS 架構](https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html)以及 Lars George 關于 [HBase 和 HDFS 位置](http://www.larsgeorge.com/2010/05/hbase-file-locality-in-hdfs.html)的博客。
### 72.4。地區分裂
區域在達到配置的閾值時分割。下面我們簡單地討論這個話題。有關更長時間的展示,請參閱我們的 Enis Soztutar 的 [Apache HBase 區域拆分和合并](http://hortonworks.com/blog/apache-hbase-region-splitting-and-merging/)。
Splits 在 RegionServer 上獨立運行;即師父不參加。 RegionServer 拆分一個區域,對拆分區域進行離線,然后將子區域添加到`hbase:meta`,打開父級托管 RegionServer 上的女兒,然后將拆分報告給 Master。請參閱 [Managed Splitting](#disable.splitting) ,了解如何手動管理拆分(以及為什么要這樣做)。
#### 72.4.1。自定義拆分策略
您可以使用自定義 [RegionSplitPolicy](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/regionserver/RegionSplitPolicy.html) (HBase 0.94+)覆蓋默認拆分策略。通常,自定義拆分策略應該擴展 HBase 的默認拆分策略: [IncreaseToUpperBoundRegionSplitPolicy](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/regionserver/IncreasingToUpperBoundRegionSplitPolicy.html) 。
策略可以通過 HBase 配置或基于每個表進行全局設置。
在 _hbase-site.xml_ 中全局配置拆分策略
```
<property>
<name>hbase.regionserver.region.split.policy</name>
<value>org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy</value>
</property>
```
使用 Java API 在表上配置拆分策略
```
HTableDescriptor tableDesc = new HTableDescriptor("test");
tableDesc.setValue(HTableDescriptor.SPLIT_POLICY, ConstantSizeRegionSplitPolicy.class.getName());
tableDesc.addFamily(new HColumnDescriptor(Bytes.toBytes("cf1")));
admin.createTable(tableDesc);
----
```
使用 HBase Shell 在表上配置拆分策略
```
hbase> create 'test', {METADATA => {'SPLIT_POLICY' => 'org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy'}},{NAME => 'cf1'}
```
可以通過使用的 HBaseConfiguration 或基于每個表來全局設置策略:
```
HTableDescriptor myHtd = ...;
myHtd.setValue(HTableDescriptor.SPLIT_POLICY, MyCustomSplitPolicy.class.getName());
```
> `DisabledRegionSplitPolicy`策略阻止手動區域拆分。
### 72.5。手動區域拆分
可以在創建表(預分割)時或在稍后的時間手動拆分表作為管理操作。出于以下一個或多個原因,您可以選擇拆分您的區域。可能還有其他正當理由,但手動拆分表的需要也可能表明您的架構設計存在問題。
手動拆分表的原因
* 您的數據按時間序列或其他類似算法排序,該算法在表格末尾對新數據進行排序。這意味著持有最后一個區域的 Region Server 始終處于負載狀態,而其他 Region Servers 處于空閑狀態或大部分處于空閑狀態。另請參見[單調遞增行鍵/時間序列數據](#timeseries)。
* 您在桌子的一個區域中開發了一個意外的熱點。例如,跟蹤網絡搜索的應用程序可能會因為有關該名人的新聞而對名人進行大量搜索而被淹沒。有關此特定方案的更多討論,請參見 [perf.one.region](#perf.one.region) 。
* 在群集中 RegionServers 數量大幅增加之后,可以快速分散負載。
* 在大容量負載之前,這可能會導致跨區域的異常和不均勻負載。
有關完全手動管理拆分的危險和可能的好處的討論,請參閱[管理拆分](#disable.splitting)。
> The `DisabledRegionSplitPolicy` policy blocks manual region splitting.
#### 72.5.1。確定分裂點
手動拆分表的目的是為了在單獨使用良好的 rowkey 設計無法實現的情況下,提高平衡群集負載的幾率。牢記這一點,您劃分區域的方式非常依賴于數據的特征。您可能已經知道拆分桌子的最佳方法。如果沒有,你拆分表的方式取決于你的鍵是什么樣的。
字母數字 Rowkeys
如果您的 rowkeys 以字母或數字開頭,則可以在字母或數字邊界處拆分表格。例如,以下命令創建一個表,其中區域在每個元音處分開,因此第一個區域具有 A-D,第二個區域具有 E-H,第三個區域具有 I-N,第四個區域具有 O-V,第五個區域具有 U-Z。
使用自定義算法
RegionSplitter 工具隨 HBase 一起提供,并使用 _SplitAlgorithm_ 為您確定分割點。作為參數,您可以為其提供算法,所需的區域數和列族。它包括三種分割算法。第一種是`[HexStringSplit](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/util/RegionSplitter.HexStringSplit.html)`算法,它假設行鍵是十六進制字符串。第二個是`[DecimalStringSplit](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/util/RegionSplitter.DecimalStringSplit.html)`算法,它假定行鍵是 00000000 到 99999999 范圍內的十進制字符串。第三個`[UniformSplit](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/util/RegionSplitter.UniformSplit.html)`假設行鍵是隨機字節數組。你可能需要開發自己的`[SplitAlgorithm](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/util/RegionSplitter.SplitAlgorithm.html)`,使用提供的那些作為模型。
### 72.6。在線區域合并
Master 和 RegionServer 都參與在線區域合并事件。客戶端將合并 RPC 發送到主服務器,然后主服務器將這些區域一起移動到負載較重的區域所在的 RegionServer。最后,主服務器將合并請求發送到此 RegionServer,然后運行合并。與區域拆分過程類似,區域合并在 RegionServer 上作為本地事務運行。它勾勒出區域,然后合并文件系統上的兩個區域,從`hbase:meta`原子刪除合并區域并將合并區域添加到`hbase:meta`,打開 RegionServer 上的合并區域并將合并報告給主區域。
HBase shell 中區域合并的示例
```
$ hbase> merge_region 'ENCODED_REGIONNAME', 'ENCODED_REGIONNAME'
$ hbase> merge_region 'ENCODED_REGIONNAME', 'ENCODED_REGIONNAME', true
```
這是一個異步操作,調用立即返回而不等待合并完成。將`true`作為可選的第三個參數傳遞將強制合并。通常只能合并相鄰區域。 `force`參數會覆蓋此行為,僅供專家使用。
### 72.7。商店
商店擁有一個 MemStore 和 0 個或更多 StoreFiles(HFiles)。商店對應于給定區域的表的列族。
#### 72.7.1。那種 MEMSTORE
MemStore 保存對 Store 的內存修改。修改是 Cells / KeyValues。請求刷新時,當前的 MemStore 將移動到快照并被清除。 HBase 繼續提供來自新 MemStore 和后備快照的編輯,直到刷新器報告刷新成功。此時,快照將被丟棄。請注意,當刷新發生時,屬于同一區域的 MemStore 都將被刷新。
#### 72.7.2。 MemStore Flush
可以在下面列出的任何條件下觸發 MemStore 刷新。最小沖洗單位是每個區域,而不是單個 MemStore 級別。
1. 當 MemStore 達到`hbase.hregion.memstore.flush.size`指定的大小時,屬于其區域的所有 MemStore 都將刷新到磁盤。
2. 當整個 MemStore 使用率達到`hbase.regionserver.global.memstore.upperLimit`指定的值時,來自不同區域的 MemStores 將刷新到磁盤,以減少 RegionServer 中的 MemStore 總體使用量。
刷新順序基于區域的 MemStore 用法的降序。
區域將刷新其 MemStore,直到整個 MemStore 使用率降至或略低于`hbase.regionserver.global.memstore.lowerLimit`。
3. 當給定區域服務器的 WAL 中的 WAL 日志條目數達到`hbase.regionserver.max.logs`中指定的值時,來自不同區域的 MemStores 將刷新到磁盤以減少 WAL 中的日志數。
沖洗訂單基于時間。
具有最早 MemStores 的區域首先被刷新,直到 WAL 計數降至`hbase.regionserver.max.logs`以下。
#### 72.7.3。掃描
* 當客戶端對表發出掃描時,HBase 會生成`RegionScanner`對象,每個區域一個,以提供掃描請求。
* `RegionScanner`對象包含`StoreScanner`對象列表,每列一個對象。
* 每個`StoreScanner`對象還包含`StoreFileScanner`對象的列表,對應于相應列族的每個 StoreFile 和 HFile,以及 MemStore 的`KeyValueScanner`對象列表。
* 這兩個列表合并為一個,按照升序排序,列表末尾的 MemStore 掃描對象。
* 構造`StoreFileScanner`對象時,它與`MultiVersionConcurrencyControl`讀取點相關聯,該讀取點是當前`memstoreTS`,過濾掉讀取點之外的任何新更新。
#### 72.7.4。 StoreFile(HFile)
StoreFiles 是您的數據所在的位置。
##### HFile 格式
_HFile_ 文件格式基于[BigTable [2006](http://research.google.com/archive/bigtable.html) ]論文和 Hadoop 的 [TFile](https://hadoop.apache.org/common/docs/current/api/org/apache/hadoop/io/file/tfile/TFile.html) 中描述的 SSTable 文件(單元測??試套件和壓縮線束是直接取自 TFile)。 Schubert Zhang 關于 [HFile 的博文:存儲分類鍵值對的塊索引文件格式](http://cloudepr.blogspot.com/2009/09/hfile-block-indexed-file-format-to.html)對 HBase 的 HFile 進行了全面介紹。 Matteo Bertozzi 也提出了一個有用的描述, [HBase I / O:HFile](http://th30z.blogspot.com/2011/02/hbase-io-hfile.html?spref=tw) 。
有關更多信息,請參閱 HFile 源代碼。另請參閱帶有內聯塊(版本 2)的 [HBase 文件格式,以獲取有關 0.92 中包含的 HFile v2 格式的信息。](#hfilev2)
##### HFile 工具
要查看 HFile 內容的文本化版本,您可以使用`hbase hfile`工具。鍵入以下內容以查看用法:
```
$ ${HBASE_HOME}/bin/hbase hfile
```
例如,要查看文件 _hdfs://10.81.47.41:8020 / hbase / default / TEST / 1418428042 / DSMP / 4759508618286845475_ 的內容,請鍵入以下內容:
```
$ ${HBASE_HOME}/bin/hbase hfile -v -f hdfs://10.81.47.41:8020/hbase/default/TEST/1418428042/DSMP/4759508618286845475
```
如果你不使用選項-v 來查看 HFile 的摘要。有關`hfile`工具的其他信息,請參閱用法。
> 在此工具的輸出中,您可能會在“Mid-key”/“firstKey”/“lastKey”等位置看到某些鍵的“seqid = 0”。這些是'KeyOnlyKeyValue'類型實例 - 意味著它們的 seqid 是無關緊要的&amp;我們只需要這些鍵值實例的鍵。
##### HDFS 上的 StoreFile 目錄結構
有關目錄結構的 HDFS 上 StoreFiles 的詳細信息,請參閱[瀏覽 HBase 對象的 HDFS](#trouble.namenode.hbase.objects) 。
#### 72.7.5。塊
StoreFiles 由塊組成。 blocksize 是基于每個 ColumnFamily 配置的。
壓縮發生在 StoreFiles 中的塊級別。有關壓縮的更多信息,請參見 HBase 中的[壓縮和數據塊編碼。](#compression)
有關塊的更多信息,請參閱 HFileBlock 源代碼。
#### 72.7.6。核心價值
KeyValue 類是 HBase 中數據存儲的核心。 KeyValue 包裝一個字節數組,并將偏移量和長度轉換為傳遞的數組,該數組指定將內容解釋為 KeyValue 的位置。
字節數組中的 KeyValue 格式為:
* keylength
* valuelength
* 鍵
* 值
密鑰進一步分解為:
* rowlength
* 行(即 rowkey)
* columnfamilylength
* 的 ColumnFamily
* 列限定符
* 時間戳
* keytype(例如,Put,Delete,DeleteColumn,DeleteFamily)
KeyValue 實例是 _ 而不是 _ 跨塊分割。例如,如果存在 8 MB KeyValue,即使塊大小為 64kb,此 KeyValue 也將作為相干塊讀入。有關更多信息,請參閱 KeyValue 源代碼。
##### 例
為了強調上述幾點,請檢查同一行的兩個不同列的兩個 Puts 會發生什么:
* 放#1:`rowkey=row1, cf:attr1=value1`
* 放#2:`rowkey=row1, cf:attr2=value2`
即使這些是同一行,也會為每列創建一個 KeyValue:
Put#1 的關鍵部分:
* `rowlength -----------→ 4`
* `row -----------------→ row1`
* `columnfamilylength --→ 2`
* `columnfamily --------→ cf`
* `columnqualifier -----→ attr1`
* `timestamp -----------→ server time of Put`
* `keytype -------------→ Put`
Put#2 的關鍵部分:
* `rowlength -----------→ 4`
* `row -----------------→ row1`
* `columnfamilylength --→ 2`
* `columnfamily --------→ cf`
* `columnqualifier -----→ attr2`
* `timestamp -----------→ server time of Put`
* `keytype -------------→ Put`
了解 rowkey,ColumnFamily 和 column(aka columnqualifier)嵌入在 KeyValue 實例中至關重要。這些標識符越長,KeyValue 就越大。
#### 72.7.7。壓實
模棱兩可的術語
* _StoreFile_ 是 HFile 的外觀。在壓縮方面,StoreFile 的使用似乎在過去一直盛行。
* _ 商店 _ 與列族相同。商店文件與商店或 ColumnFamily 相關。
* 如果您想了解更多關于 StoreFiles 與 HFiles 和 Stores 與 ColumnFamilies 的信息,請參閱 [HBASE-11316](https://issues.apache.org/jira/browse/HBASE-11316) 。
當 MemStore 達到給定大小(`hbase.hregion.memstore.flush.size`)時,它會將其內容刷新到 StoreFile。商店中的 StoreFiles 數量會隨著時間的推移而增加。 _ 壓縮 _ 是一種通過將它們合并在一起來減少 Store 中 StoreFiles 數量的操作,以提高讀取操作的性能。壓縮可能需要大量資源,并且可能會因許多因素而有助于或阻礙性能。
壓縮分為兩類:次要和主要。次要和主要壓縮在以下方面有所不同。
_ 次要壓縮 _ 通常選擇少量小的相鄰 StoreFiles 并將它們重寫為單個 StoreFile。由于潛在的副作用,次要壓縮不會刪除(過濾掉)刪除或過期版本。有關如何處理與壓縮相關的刪除和版本的信息,請參閱[壓縮和刪除](#compaction.and.deletes)和[壓縮和版本](#compaction.and.versions)。對于給定的商店,次要壓縮的最終結果是更少,更大的 StoreFiles。
_ 主要壓縮 _ 的最終結果是每個商店的單個 StoreFile。主要壓縮也處理刪除標記和最大版本。有關如何處理與壓縮相關的刪除和版本的信息,請參閱[壓縮和刪除](#compaction.and.deletes)和[壓縮和版本](#compaction.and.versions)。
壓縮和刪除
在 HBase 中發生顯式刪除時,實際上不會刪除數據。而是編寫 _ 墓碑 _ 標記。邏輯刪除標記可防止數據與查詢一起返回。在主要壓縮過程中,實際上會刪除數據,并從 StoreFile 中刪除邏輯刪除標記。如果由于 TTL 過期而發生刪除,則不會創建邏輯刪除。相反,過期的數據被過濾掉,不會寫回到壓縮的 StoreFile。
壓縮和版本
創建列族時,可以通過指定`HColumnDescriptor.setMaxVersions(int versions)`指定要保留的最大版本數。默認值為`3`。如果存在的版本超過指定的最大值,則會過濾掉多余的版本,而不會將其寫回到壓縮的 StoreFile。
> 主要壓縮可能會影響查詢結果
>
> 在某些情況下,如果明確刪除較新版本,則可能會無意中復活舊版本。請參閱[主要壓縮更改查詢結果](#major.compactions.change.query.results)以獲得更深入的解釋。這種情況只有在壓縮完成之前才有可能。
從理論上講,主要壓縮可以提高性能。但是,在高負載系統中,主要壓縮可能需要不適當數量的資源并對性能產生負面影響。在默認配置中,主要壓縮會自動安排在 7 天內運行一次。這有時不適合生產中的系統。您可以手動管理主要壓縮。參見[管理的壓縮](#managed.compactions)。
壓縮不執行區域合并。有關區域合并的更多信息,請參見 [Merge](#ops.regionmgt.merge) 。
壓實開關
我們可以在區域服務器上打開和關閉壓縮。關閉壓縮也會中斷任何當前正在進行的壓縮。它可以使用 hbase shell 中的“compaction_switch”命令動態完成。如果從命令行完成,則在重新啟動服務器時此設置將丟失。要在區域服務器之間保留更改,請修改 hbase-site.xml 中的配置 hbase.regionserver .compaction.enabled 并重新啟動 HBase。
##### 壓縮策略 - HBase 0.96.x 及更新版本
壓縮大型 StoreFiles 或一次使用太多 StoreFiles 會導致比集群能夠處理的 IO 負載更多,而不會導致性能問題。 HBase 選擇哪個 StoreFiles 包含在壓縮中的方法(以及壓縮是次要壓縮還是主要壓縮)稱為 _ 壓縮策略 _。
在 HBase 0.96.x 之前,只有一個壓縮策略。原始壓縮策略仍可作為`RatioBasedCompactionPolicy`使用。新的壓縮默認策略稱為`ExploringCompactionPolicy`,隨后被移植到 HBase 0.94 和 HBase 0.95,并且是 HBase 0.96 及更新版本的默認值。它在 [HBASE-7842](https://issues.apache.org/jira/browse/HBASE-7842) 中實施。簡而言之,`ExploringCompactionPolicy`嘗試選擇盡可能最好的 StoreFiles 集合,以最少的工作量壓縮,而`RatioBasedCompactionPolicy`選擇符合條件的第一個集合。
無論使用何種壓縮策略,文件選擇都由幾個可配置參數控制,并以多步驟方式發生。這些參數將在上下文中進行解釋,然后將在表格中給出,該表格顯示了它們的描述,默認值以及更改它們的含義。
###### 被卡住
當 MemStore 變得太大時,它需要將其內容刷新到 StoreFile。但是,Stores 配置了 StoreFiles 數字`hbase.hstore.blockingStoreFiles`的綁定,如果超過,則 MemStore 刷新必須等到 StoreFile 計數減少一個或多個壓縮。如果 MemStore 太大而且 StoreFiles 的數量也太高,則該算法被稱為“卡住”。默認情況下,我們將等待`hbase.hstore.blockingWaitTime`毫秒的壓縮。如果這段時間到期,即使我們超過`hbase.hstore.blockingStoreFiles`計數,我們也會沖洗。
提高`hbase.hstore.blockingStoreFiles`計數將允許刷新,但具有許多 StoreFiles 的 Store 可能具有更高的讀取延遲。試著想一想為什么 Compactions 沒跟上。這是一種引發這種情況的寫入突發還是經常出現,并且群集的寫入量不足?
###### ExploringCompactionPolicy 算法
在選擇壓縮最有益的集合之前,ExploringCompactionPolicy 算法會考慮每個可能的相鄰 StoreFiles 集合。
ExploringCompactionPolicy 工作得特別好的一種情況是,當您批量加載數據時,批量加載會創建比 StoreFiles 更大的 StoreFiles,而 StoreFiles 的數據保存的數據早于批量加載數據。這可以“欺騙”HBase 在每次需要壓縮時選擇執行主要壓縮,并導致大量額外開銷。使用 ExploringCompactionPolicy,主要壓縮發生的頻率要低得多,因為較小的壓縮效率更高。
通常,ExploringCompactionPolicy 是大多數情況下的正確選擇,因此是默認的壓縮策略。您還可以使用 ExploringCompactionPolicy 和 [Experimental:Stripe Compactions](#ops.stripe) 。
可以在 hbase-server / src / main / java / org / apache / hadoop / hbase / regionserver / compactions / ExploringCompactionPolicy.java 中檢查此策略的邏輯。以下是 ExploringCompactionPolicy 邏輯的演練。
1. 列出商店中所有現有的 StoreFiles。算法的其余部分過濾此列表以提出將被選擇用于壓縮的 HFile 子集。
2. 如果這是用戶請求的壓縮,則嘗試執行請求的壓縮類型,而不管通常選擇什么。請注意,即使用戶請求主要壓縮,也可能無法執行主要壓縮。這可能是因為并非列族中的所有 StoreFiles 都可用于壓縮,或者因為列族中的存儲太多。
3. 某些 StoreFiles 會自動排除在考慮之外。這些包括:
* 大于`hbase.hstore.compaction.max.size`的 StoreFiles
* 由明確排除壓縮的批量加載操作創建的 StoreFiles。您可以決定從壓縮中排除因批量加載而產生的 StoreFiles。為此,請在批量裝入操作期間指定`hbase.mapreduce.hfileoutputformat.compaction.exclude`參數。
4. 迭代步驟 1 中的列表,并列出所有可能的 StoreFiles 集合以壓縮在一起。潛在集合是列表中的`hbase.hstore.compaction.min`連續 StoreFiles 的分組。對于每個集合,執行一些完整性檢查并確定這是否是可以完成的最佳壓縮:
* 如果此集合中的 StoreFiles 數量(不是 StoreFiles 的大小)小于`hbase.hstore.compaction.min`或大于`hbase.hstore.compaction.max`,請將其考慮在內。
* 將這組 StoreFiles 的大小與目前在列表中找到的最小可能壓縮的大小進行比較。如果這組 StoreFiles 的大小代表可以完成的最小壓縮,則存儲它以用作后退,如果算法被“卡住”并且否則將不選擇 StoreFiles。見[被困](#compaction.being.stuck)。
* 對這組 StoreFiles 中的每個 StoreFile 進行基于大小的健全性檢查。
* 如果此 StoreFile 的大小大于`hbase.hstore.compaction.max.size`,請將其考慮在內。
* 如果大小大于或等于`hbase.hstore.compaction.min.size`,則根據基于文件的比率進行健全性檢查,以查看它是否太大而無法考慮。
如果符合以下條件,則完整性檢查成功:
* 此集中只有一個 StoreFile,或
* 對于每個 StoreFile,其大小乘以`hbase.hstore.compaction.ratio`(如果配置非高峰時間,則為`hbase.hstore.compaction.ratio.offpeak`,并且在非高峰時段)小于該集合中其他 HFile 的大小總和。
5. 如果仍在考慮這組 StoreFiles,請將其與先前選擇的最佳壓縮進行比較。如果它更好,用這個替換先前選擇的最佳壓縮。
6. 當處理完整個潛在壓縮列表后,執行找到的最佳壓縮。如果沒有選擇 StoreFiles 進行壓縮,但有多個 StoreFiles,則假設算法被卡住(參見[被困](#compaction.being.stuck)),如果是,請執行步驟 3 中找到的最小壓縮。
###### RatioBasedCompactionPolicy 算法
RatioBasedCompactionPolicy 是 HBase 0.96 之前唯一的壓縮策略,盡管 ExploringCompactionPolicy 現已被反向移植到 HBase 0.94 和 0.95。要使用 RatioBasedCompactionPolicy 而不是 ExploringCompactionPolicy,請在 _hbase-site.xml_ 文件中將`hbase.hstore.defaultengine.compactionpolicy.class`設置為`RatioBasedCompactionPolicy`。要切換回 ExploringCompactionPolicy,請從 _hbase-site.xml_ 中刪除該設置。
以下部分將引導您完成用于在 RatioBasedCompactionPolicy 中選擇 StoreFiles 進行壓縮的算法。
1. 第一階段是創建所有壓縮候選者的列表。將創建一個列表,該列表不包含在壓縮隊列中的所有 StoreFiles,以及比當前正在壓縮的最新文件更新的所有 StoreFiles。 StoreFiles 列表按序列 ID 排序。將 Put 添加到預寫日志(WAL)時生成序列 ID,并將其存儲在 HFile 的元數據中。
2. 檢查算法是否卡住(參見[被困](#compaction.being.stuck),如果是,則強制進行主要壓縮。這是 [ExploringCompactionPolicy 算法](#exploringcompaction.policy)通常比選擇的更好的關鍵區域。 RatioBasedCompactionPolicy。
3. 如果壓縮是用戶請求的,請嘗試執行請求的壓縮類型。請注意,如果所有 HFile 都不可用于壓縮或存在太多 StoreFiles(超過`hbase.hstore.compaction.max`),則可能無法進行主要壓縮。
4. Some StoreFiles are automatically excluded from consideration. These include:
* StoreFiles that are larger than `hbase.hstore.compaction.max.size`
* StoreFiles that were created by a bulk-load operation which explicitly excluded compaction. You may decide to exclude StoreFiles resulting from bulk loads, from compaction. To do this, specify the `hbase.mapreduce.hfileoutputformat.compaction.exclude` parameter during the bulk load operation.
5. 主要壓縮中允許的最大 StoreFiles 數由`hbase.hstore.compaction.max`參數控制。如果列表包含的數量超過此數量的 StoreFiles,則即使進行了主要壓縮,也會執行次要壓縮。但是,即使存在多個`hbase.hstore.compaction.max` StoreFiles 要壓縮,仍會發生用戶請求的主要壓縮。
6. 如果列表包含少于`hbase.hstore.compaction.min` StoreFiles 以進行壓縮,則會中止輕微壓縮。請注意,可以在單個 HFile 上執行主要壓縮。它的功能是刪除刪除和過期版本,并重置 StoreFile 上的位置。
7. `hbase.hstore.compaction.ratio`參數的值乘以小于給定文件的 StoreFiles 的總和,以確定是否在次要壓縮期間選擇了 StoreFile 進行壓縮。例如,如果 hbase.hstore.compaction.ratio 為 1.2,則 FileX 為 5MB,FileY 為 2MB,FileZ 為 3MB:
```
5 <= 1.2 x (2 + 3) or 5 <= 6
```
在這種情況下,FileX 有資格進行輕微壓縮。如果 FileX 為 7MB,則不符合輕微壓縮的條件。這個比例有利于較小的 StoreFile。如果還配置了`hbase.offpeak.start.hour`和`hbase.offpeak.end.hour`,則可以使用參數`hbase.hstore.compaction.ratio.offpeak`配置在非高峰時段使用的不同比率。
8. 如果最后一次主要的壓縮是很久以前并且要壓縮多個 StoreFile,則會運行一個主要的壓縮,即使它本來是次要的。默認情況下,主要壓縮之間的最長時間為 7 天,加上或減去 4.8 小時,并在這些參數中隨機確定。在 HBase 0.96 之前,主要壓實期為 24 小時。請參閱下表中的`hbase.hregion.majorcompaction`以調整或禁用基于時間的主要壓縮。
###### 壓縮算法使用的參數
該表包含壓縮的主要配置參數。這份清單并非詳盡無遺。要從默認值中調整這些參數,請編輯 _hbase-default.xml_ 文件。有關所有可用配置參數的完整列表,請參閱 [config.files](#config.files)
`hbase.hstore.compaction.min`
在壓縮之前必須符合壓縮條件的最小 StoreFiles 數量才能運行。調整`hbase.hstore.compaction.min`的目的是避免使用太多的小型 StoreFiles 來壓縮。將此值設置為 2 會在每次在 Store 中存在兩個 StoreFiles 時導致輕微壓縮,這可能不合適。如果將此值設置得太高,則需要相應調整所有其他值。對于大多數情況,默認值是合適的。在以前版本的 HBase 中,參數`hbase.hstore.compaction.min`被稱為`hbase.hstore.compactionThreshold`。
**默認**:3
`hbase.hstore.compaction.max`
無論符合條件的 StoreFiles 的數量,將為單個次要壓縮選擇的 StoreFiles 的最大數量。實際上,`hbase.hstore.compaction.max`的值控制單個壓縮完成所需的時間長度。將其設置得更大意味著更多 StoreFiles 包含在壓縮中。對于大多數情況,默認值是合適的。
**默認**:10
`hbase.hstore.compaction.min.size`
小于此大小的 StoreFile 將始終符合輕微壓縮的條件。通過`hbase.hstore.compaction.ratio`評估此大小或更大的 StoreFiles 以確定它們是否符合條件。由于此限制表示所有小于此值的 StoreFiles 的“自動包含”限制,因此可能需要在寫入 1-2 MB 范圍內的許多文件的寫入繁重環境中減少此值,因為每個 StoreFile 都將成為目標壓縮和生成的 StoreFiles 可能仍然在最小尺寸,需要進一步壓縮。如果降低此參數,則會更快地觸發比率檢查。這解決了早期版本的 HBase 中出現的一些問題,但在大多數情況下不再需要更改此參數。
**默認值**:128 MB
`hbase.hstore.compaction.max.size`
大于此大小的 StoreFile 將被排除在壓縮之外。提高`hbase.hstore.compaction.max.size`的效果更少,更大的 StoreFiles 不會經常被壓縮。如果您覺得壓縮過于頻繁而沒有太多好處,您可以嘗試提高此值。
**默認**:`Long.MAX_VALUE`
`hbase.hstore.compaction.ratio`
對于輕微壓縮,此比率用于確定大于`hbase.hstore.compaction.min.size`的給定 StoreFile 是否有資格進行壓縮。它的作用是限制大型 StoreFile 的壓縮。 `hbase.hstore.compaction.ratio`的值表示為浮點小數。
* 較大的比例(例如 10)將生成單個巨型 StoreFile。相反,值為.25,將產生類似于 BigTable 壓縮算法的行為,產生四個 StoreFiles。
* 建議使用介于 1.0 和 1.4 之間的中等值。調整此值時,您將平衡寫入成本與讀取成本。提高值(類似于 1.4)會產生更多的寫入成本,因為您將壓縮更大的 StoreFiles。但是,在讀取過程中,HBase 需要通過更少的 StoreFiles 來完成讀取。如果你不能利用[布隆過濾器](#blooms),請考慮這種方法。
* 或者,您可以將此值降低到 1.0 以降低寫入的后臺成本,并用于限制讀取期間觸摸的 StoreFiles 的數量。對于大多數情況,默認值是合適的。
**默認**:`1.2F`
`hbase.hstore.compaction.ratio.offpeak`
非高峰時段使用的壓實比例,如果還配置了非高峰時段(見下文)。表示為浮點小數。這允許在設定的時間段內更具侵略性(或者如果將其設置為低于`hbase.hstore.compaction.ratio`則更不具侵略性)壓實。如果禁用非高峰時忽略(默認)。這與`hbase.hstore.compaction.ratio`的作用相同。
**默認**:`5.0F`
`hbase.offpeak.start.hour`
非高峰時段的開始,表示為 0 到 23 之間的整數,包括 0 和 23。設置為-1 可禁用非高峰。
**默認**:`-1`(禁用)
`hbase.offpeak.end.hour`
非高峰時段結束,表示為 0 到 23 之間的整數,包括 0 和 23。設置為-1 可禁用非高峰。
**Default**: `-1` (disabled)
`hbase.regionserver.thread.compaction.throttle`
壓縮有兩種不同的線程池,一種用于大型壓縮,另一種用于小型壓縮。這有助于快速壓縮精益表(例如`hbase:meta`)。如果壓縮大于此閾值,則會進入大型壓縮池。在大多數情況下,默認值是合適的。
**默認**:`2 x hbase.hstore.compaction.max x hbase.hregion.memstore.flush.size`(默認為`128`)
`hbase.hregion.majorcompaction`
主要壓縮之間的時間,以毫秒表示。設置為 0 可禁用基于時間的自動主要壓縮。用戶請求的和基于大小的主要壓縮仍將運行。該值乘以`hbase.hregion.majorcompaction.jitter`,以使壓縮在給定的時間窗口內以稍微隨機的時間開始。
**默認**:7 天(`604800000`毫秒)
`hbase.hregion.majorcompaction.jitter`
應用于 hbase.hregion.majorcompaction 的乘數,以使壓縮在`hbase.hregion.majorcompaction`的任一側發生給定的時間。數字越小,壓縮越接近`hbase.hregion.majorcompaction`間隔。表示為浮點小數。
**默認**:`.50F`
##### 壓縮文件選擇
> 遺產信息
>
> 此部分由于歷史原因而保留,并且指的是在 HBase 0.96.x 之前壓縮的方式。如果啟用 [RatioBasedCompactionPolicy 算法](#compaction.ratiobasedcompactionpolicy.algorithm),您仍然可以使用此行為。有關壓縮在 HBase 0.96.x 及更高版本中的工作方式的信息,請參閱[壓縮](#compaction)。
要了解 StoreFile 選擇的核心算法,Store 源代碼中有一些 ASCII 技術將作為有用的參考。
它已復制如下:
```
/* normal skew:
*
* older ----> newer
* _
* | | _
* | | | | _
* --|-|- |-|- |-|---_-------_------- minCompactSize
* | | | | | | | | _ | |
* | | | | | | | | | | | |
* | | | | | | | | | | | |
*/
```
重要的旋鈕:
* `hbase.hstore.compaction.ratio`壓縮文件選擇算法中使用的比率(默認值為 1.2f)。
* `hbase.hstore.compaction.min`(在 HBase v 0.90 中稱為`hbase.hstore.compactionThreshold`)(文件)要為壓縮發生選擇的每個商店的最小 StoreFiles 數(默認值為 2)。
* `hbase.hstore.compaction.max`(files)每次輕微壓縮時壓縮的最大 StoreFiles 數(默認值為 10)。
* `hbase.hstore.compaction.min.size`(字節)任何小于此設置的 StoreFile 都會自動成為壓縮的候選對象。默認為`hbase.hregion.memstore.flush.size`(128 mb)。
* `hbase.hstore.compaction.max.size`(。92)(字節)任何大于此設置的 StoreFile 都會自動從壓縮中排除(默認為 Long.MAX_VALUE)。
次要壓縮 StoreFile 選擇邏輯是基于大小的,并在`file ? sum(smaller_files) * hbase.hstore.compaction.ratio`時選擇要壓縮的文件。
###### 次要壓縮文件選擇 - 示例#1(基本示例)
此示例反映了單元測試`TestCompactSelection`中的示例。
* `hbase.hstore.compaction.ratio` = 1.0f
* `hbase.hstore.compaction.min` = 3(檔案)
* `hbase.hstore.compaction.max` = 5(文件)
* `hbase.hstore.compaction.min.size` = 10(字節)
* `hbase.hstore.compaction.max.size` = 1000(字節)
存在以下 StoreFiles:每個 100,50,33,12 和 12 個字節(從最舊到最新)。使用上述參數,將為輕微壓縮選擇的文件為 23,12 和 12。
為什么?
* 100→否,因為總和(50,23,12,12)* 1.0 = 97。
* 50→否,因為總和(23,12,12)* 1.0 = 47。
* 23→是,因為總和(12,12)* 1.0 = 24。
* 12→是,因為已包含上一個文件,因為這不超過最大文件限制 5
* 12→是,因為已包含上一個文件,因為這不超過最大文件限制 5。
###### 次要壓縮文件選擇 - 示例#2(沒有足夠的文件壓縮)
This example mirrors an example from the unit test `TestCompactSelection`.
* `hbase.hstore.compaction.ratio` = 1.0f
* `hbase.hstore.compaction.min` = 3 (files)
* `hbase.hstore.compaction.max` = 5 (files)
* `hbase.hstore.compaction.min.size` = 10 (bytes)
* `hbase.hstore.compaction.max.size` = 1000 (bytes)
存在以下 StoreFiles:每個 100,25,12 和 12 個字節(從最舊到最新)。使用上述參數,將不會啟動壓縮。
Why?
* 100→否,因為總和(25,12,12)* 1.0 = 47
* 25→否,因為總和(12,12)* 1.0 = 24
* 12→No.候選因為 sum(12)* 1.0 = 12,只有 2 個文件要壓縮,小于 3 的閾值
* 12→No.候選,因為以前的 StoreFile 是,但沒有足夠的文件來壓縮
###### 次要壓縮文件選擇 - 示例#3(將文件限制為緊湊)
This example mirrors an example from the unit test `TestCompactSelection`.
* `hbase.hstore.compaction.ratio` = 1.0f
* `hbase.hstore.compaction.min` = 3 (files)
* `hbase.hstore.compaction.max` = 5 (files)
* `hbase.hstore.compaction.min.size` = 10 (bytes)
* `hbase.hstore.compaction.max.size` = 1000 (bytes)
存在以下 StoreFiles:每個 7,6,5,4,3,2 和 1 個字節(從最舊到最新)。使用上述參數,為輕微壓縮選擇的文件是 7,6,5,4,3。
Why?
* 7→是,因為總和(6,5,4,3,2,1)* 1.0 = 21.此外,7 小于最小尺寸
* 6→是,因為總和(5,4,3,2,1)* 1.0 = 15.此外,6 小于最小尺寸。
* 5→是,因為總和(4,3,2,1)* 1.0 = 10.此外,5 小于最小尺寸。
* 4→是,因為總和(3,2,1)* 1.0 = 6.此外,4 小于最小尺寸。
* 3→是,因為 sum(2,1)* 1.0 = 3.此外,3 小于最小尺寸。
* 2→編號候選,因為選擇了先前的文件,并且 2 小于最小尺寸,但已達到要壓縮的最大文件數。
* 1→編號候選,因為選擇了上一個文件,1 小于最小尺寸,但已達到要壓縮的最大文件數。
> 密鑰配置選項的影響此信息現在包含在壓縮算法使用的[參數的配置參數表中。](#compaction.parameters)
##### 日期分層壓縮
日期分層壓縮是一種日期感知的存儲文件壓縮策略,有利于時間序列數據的時間范圍掃描。
##### 何時使用日期分層壓縮
考慮使用 Date Tiered Compaction 進行有限時間范圍的讀取,尤其是對最近數據的掃描
不要用它
* 隨機獲得沒有有限的時間范圍
* 經常刪除和更新
* 頻繁的亂序數據會寫入創建長尾的情況,尤其是具有未來時間戳的寫入
* 頻繁的批量加載,時間范圍很重疊
績效改進
性能測試表明,時間范圍掃描的性能在有限的時間范圍內有很大改善,特別是對最近數據的掃描。
###### 啟用日期分層壓縮
您可以通過將`hbase.hstore.engine.class`設置為`org.apache.hadoop.hbase.regionserver.DateTieredStoreEngine`來為表或列族啟用日期分層壓縮。
如果使用所有默認設置,您還需要將`hbase.hstore.blockingStoreFiles`設置為高數字,例如 60,而不是默認值 12)。如果更改參數,則使用 1.5~2 x 預計文件計數,預計文件計數=每層的窗口 x 層數+傳入窗口最小值+早于最大年齡的文件
您還需要將`hbase.hstore.compaction.max`設置為與`hbase.hstore.blockingStoreFiles`相同的值以取消阻止主要壓縮。
過程:啟用日期分層壓縮
1. 在 HBase shell 中運行以下命令之一。將表名`orders_table`替換為表的名稱。
```
alter 'orders_table', CONFIGURATION => {'hbase.hstore.engine.class' => 'org.apache.hadoop.hbase.regionserver.DateTieredStoreEngine', 'hbase.hstore.blockingStoreFiles' => '60', 'hbase.hstore.compaction.min'=>'2', 'hbase.hstore.compaction.max'=>'60'}
alter 'orders_table', {NAME => 'blobs_cf', CONFIGURATION => {'hbase.hstore.engine.class' => 'org.apache.hadoop.hbase.regionserver.DateTieredStoreEngine', 'hbase.hstore.blockingStoreFiles' => '60', 'hbase.hstore.compaction.min'=>'2', 'hbase.hstore.compaction.max'=>'60'}}
create 'orders_table', 'blobs_cf', CONFIGURATION => {'hbase.hstore.engine.class' => 'org.apache.hadoop.hbase.regionserver.DateTieredStoreEngine', 'hbase.hstore.blockingStoreFiles' => '60', 'hbase.hstore.compaction.min'=>'2', 'hbase.hstore.compaction.max'=>'60'}
```
2. 如果需要,配置其他選項。有關詳細信息,請參閱[配置日期分層壓縮](#ops.date.tiered.config)。
過程:禁用日期分層壓縮
1. 將`hbase.hstore.engine.class`選項設置為 nil 或`org.apache.hadoop.hbase.regionserver.DefaultStoreEngine`。任一選項都具有相同的效果。確保將您更改的其他選項也設置為原始設置。
```
alter 'orders_table', CONFIGURATION => {'hbase.hstore.engine.class' => 'org.apache.hadoop.hbase.regionserver.DefaultStoreEngine', 'hbase.hstore.blockingStoreFiles' => '12', 'hbase.hstore.compaction.min'=>'6', 'hbase.hstore.compaction.max'=>'12'}}
```
當您以任一方式更改商店引擎時,可能會在大多數區域執行主要壓縮。在新表上沒有必要這樣做。
###### 配置日期分層壓縮
應在表或列族級別配置日期分層壓縮的每個設置。如果使用 HBase shell,則常規命令模式如下:
```
alter 'orders_table', CONFIGURATION => {'key' => 'value', ..., 'key' => 'value'}}
```
層參數
您可以通過更改以下參數的設置來配置日期層:
| 設置 | 筆記 |
| --- | --- |
| `hbase.hstore.compaction.date.tiered.max.storefile.age.millis` |
max-timestamp 小于此值的文件將不再被壓縮。默認值為 Long.MAX_VALUE。
| | `hbase.hstore.compaction.date.tiered.base.window.millis` |
基本窗口大小(以毫秒為單位)。默認為 6 小時。
| | `hbase.hstore.compaction.date.tiered.windows.per.tier` |
每層的窗口數。默認為 4。
| | `hbase.hstore.compaction.date.tiered.incoming.window.min` |
在傳入窗口中壓縮的最小文件數。將其設置為窗口中預期的文件數,以避免浪費壓縮。默認為 6。
| | `hbase.hstore.compaction.date.tiered.window.policy.class` |
在同一時間窗口內選擇存儲文件的策略。它不適用于傳入窗口。在探索壓縮時默認。這是為了避免浪費的壓實。
|
壓縮 Throttler
通過分層壓縮,群集中的所有服務器將同時將窗口提升到更高層,因此建議使用壓縮節流:將`hbase.regionserver.throughput.controller`設置為`org.apache.hadoop.hbase.regionserver.compactions.PressureAwareCompactionThroughputController`。
> 有關日期分層壓縮的更多信息,請參閱 [https://docs.google.com/document/d/1_AmlNb2N8Us1xICsTeGDLKIqL6T-oHoRLZ323MG_uy8](https://docs.google.com/document/d/1_AmlNb2N8Us1xICsTeGDLKIqL6T-oHoRLZ323MG_uy8) 中的設計規范
##### 實驗:條紋壓縮
條帶壓縮是 HBase 0.98 中添加的一個實驗性功能,旨在改善大區域或非均勻分布的行鍵的壓縮。為了實現更小和/或更細粒度的壓縮,區域內的 StoreFiles 分別維護該區域的若干行鍵子范圍或“條帶”。條帶對 HBase 的其余部分是透明的,因此對 HFiles 或數據的其他操作無需修改即可工作。
條帶壓縮會更改 HFile 布局,從而在區域內創建子區域。這些子區域更容易壓縮,并且應該導致更少的主要壓縮。這種方法減輕了較大區域的一些挑戰。
條帶壓縮與 [Compaction](#compaction) 完全兼容,并與 ExploringCompactionPolicy 或 RatioBasedCompactionPolicy 結合使用。它可以為現有表啟用,如果稍后禁用,表將繼續正常運行。
##### 何時使用條紋壓縮
如果您具有以下任一條件,請考慮使用條帶壓縮:
* 大區域。您可以獲得較小區域的積極影響,而無需 MemStore 和區域管理開銷的額外開銷。
* 非統一鍵,例如鍵中的時間維度。只有接收新密鑰的條紋才需要壓縮。如果有的話,舊數據不會經常壓縮
Performance Improvements
性能測試表明,讀取性能有所提高,讀寫性能的可變性大大降低。在大的非均勻行鍵區域上可以看到整體的長期性能改進,例如以散列為前綴的時間戳鍵。在已經很大的桌子上,這些性能提升是最顯著的。性能改進可能會擴展到區域分割。
###### 啟用條帶壓縮
您可以通過將`hbase.hstore.engine.class`設置為`org.apache.hadoop.hbase.regionserver.StripeStoreEngine`來為表或列族啟用條帶壓縮。您還需要將`hbase.hstore.blockingStoreFiles`設置為高數字,例如 100(而不是默認值 10)。
過程:啟用條帶壓縮
1. Run one of following commands in the HBase shell. Replace the table name `orders_table` with the name of your table.
```
alter 'orders_table', CONFIGURATION => {'hbase.hstore.engine.class' => 'org.apache.hadoop.hbase.regionserver.StripeStoreEngine', 'hbase.hstore.blockingStoreFiles' => '100'}
alter 'orders_table', {NAME => 'blobs_cf', CONFIGURATION => {'hbase.hstore.engine.class' => 'org.apache.hadoop.hbase.regionserver.StripeStoreEngine', 'hbase.hstore.blockingStoreFiles' => '100'}}
create 'orders_table', 'blobs_cf', CONFIGURATION => {'hbase.hstore.engine.class' => 'org.apache.hadoop.hbase.regionserver.StripeStoreEngine', 'hbase.hstore.blockingStoreFiles' => '100'}
```
2. 如果需要,配置其他選項。有關詳細信息,請參閱[配置條帶壓縮](#ops.stripe.config)。
3. 啟用表格。
過程:禁用條帶壓縮
1. 將`hbase.hstore.engine.class`選項設置為 nil 或`org.apache.hadoop.hbase.regionserver.DefaultStoreEngine`。任一選項都具有相同的效果。
```
alter 'orders_table', CONFIGURATION => {'hbase.hstore.engine.class' => 'rg.apache.hadoop.hbase.regionserver.DefaultStoreEngine'}
```
2. Enable the table.
在以任一方式更改存儲引擎后啟用大表時,可能會在大多數區域上執行主要壓縮。在新表上沒有必要這樣做。
###### 配置條帶壓縮
應該在表或列族級別配置條帶壓縮的每個設置。如果使用 HBase shell,則常規命令模式如下:
```
alter 'orders_table', CONFIGURATION => {'key' => 'value', ..., 'key' => 'value'}}
```
區域和條帶大小
您可以根據區域大小調整配置條帶大小。默認情況下,新區域將以一個條帶開頭。在條帶變得太大(16 x MemStore 刷新大小)之后的下一次壓縮中,它被分成兩個條帶。隨著區域的增長,條紋分裂繼續,直到該區域足夠大以分裂。
您可以為自己的數據改進此模式。一個好的規則是瞄準至少 1 GB 的條帶大小,以及用于統一行鍵的大約 8-12 個條帶。例如,如果您的區域為 30 GB,則 12 x 2.5 GB 條紋可能是一個很好的起點。
| Setting | Notes |
| --- | --- |
| `hbase.store.stripe.initialStripeCount` |
啟用條帶壓縮時要創建的條帶數。您可以按如下方式使用它:
* 對于相對統一的行鍵,如果您知道上面的條紋的近似目標數,則可以通過從幾個條紋(2,5,10 ......)開始來避免一些分裂開銷。如果早期數據不代表整體行密鑰分配,則效率不高。
* 對于包含大量數據的現有表,此設置將有效地預分割條帶。
* 對于諸如散列前綴順序密鑰之類的密鑰,每個區域具有多個散列前綴,預分割可能是有意義的。
| | `hbase.store.stripe.sizeToSplit` |
條帶在分割之前增長的最大大小。根據上述尺寸考慮,將此項與`hbase.store.stripe.splitPartCount`結合使用可控制目標條帶尺寸(`sizeToSplit = splitPartsCount * target stripe size`)。
| | `hbase.store.stripe.splitPartCount` |
分割條帶時要創建的新條帶數。默認值為 2,適用于大多數情況。對于非統一行鍵,您可以嘗試將數字增加到 3 或 4,以將到達的更新隔離到區域的較窄切片中,而無需額外的拆分。
|
MemStore 大小設置
默認情況下,刷新根據現有條帶邊界和要刷新的行鍵從一個 MemStore 創建多個文件。這種方法可以最大限度地減少寫入放大,但如果 MemStore 很小且有很多條紋,則可能不合需要,因為文件太小。
在這種情況下,您可以將`hbase.store.stripe.compaction.flushToL0`設置為`true`。這將導致 MemStore 刷新創建單個文件。當至少`hbase.store.stripe.compaction.minFilesL0`這樣的文件(默認為 4)累積時,它們將被壓縮成條帶文件。
正常壓實配置和條帶壓縮
適用于正常壓縮的所有設置(參見壓縮算法使用的[參數)適用于條帶壓縮。最小和最大文件數例外,默認設置為較高值,因為條帶中的文件較小。要控制這些條紋壓縮,請使用`hbase.store.stripe.compaction.minFiles`和`hbase.store.stripe.compaction.maxFiles`,而不是`hbase.hstore.compaction.min`和`hbase.hstore.compaction.max`。](#compaction.parameters)
## 73.批量裝載
### 73.1。概觀
HBase 包括幾種將數據加載到表中的方法。最直接的方法是使用 MapReduce 作業中的`TableOutputFormat`類,或使用普通的客戶端 API;然而,這些并不總是最有效的方法。
批量加載功能使用 MapReduce 作業以 HBase 的內部數據格式輸出表數據,然后直接將生成的 StoreFiles 加載到正在運行的集群中。與僅使用 HBase API 相比,使用批量加載將使用更少的 CPU 和網絡資源。
### 73.2。批量加載架構
HBase 批量加載過程包括兩個主要步驟。
#### 73.2.1。通過 MapReduce 作業準備數據
批量加載的第一步是使用`HFileOutputFormat2`從 MapReduce 作業生成 HBase 數據文件(StoreFiles)。此輸出格式以 HBase 的內部存儲格式寫出數據,以便以后可以非常有效地將它們加載到集群中。
為了有效地工作,必須配置`HFileOutputFormat2`使得每個輸出 HFile 適合單個區域。為此,將輸出將批量加載到 HBase 中的作業使用 Hadoop 的`TotalOrderPartitioner`類將映射輸出劃分為密鑰空間的不相交范圍,對應于表中區域的鍵范圍。
`HFileOutputFormat2`包括便利功能`configureIncrementalLoad()`,它根據表格的當前區域邊界自動設置`TotalOrderPartitioner`。
#### 73.2.2。完成數據加載
準備好數據導入后,使用帶有“importtsv.bulk.output”選項的`importtsv`工具或使用`HFileOutputFormat`的其他 MapReduce 作業,`completebulkload`工具用于將數據導入正在運行的集群。此命令行工具遍歷準備好的數據文件,并且每個文件確定文件所屬的區域。然后它會聯系相應的 RegionServer,它采用 HFile,將其移入其存儲目錄并使數據可供客戶端使用。
如果在批量裝載準備過程中或在準備和完成步驟之間區域邊界已更改,則`completebulkload`實用程序將自動將數據文件拆分為與新邊界對應的部分。此過程效率不高,因此用戶應注意盡量減少準備批量加載和將其導入群集之間的延遲,尤其是在其他客戶端通過其他方式同時加載數據時。
```
$ hadoop jar hbase-server-VERSION.jar completebulkload [-c /path/to/hbase/config/hbase-site.xml] /user/todd/myoutput mytable
```
`-c config-file`選項可用于指定包含相應 hbase 參數的文件(例如,hbase-site.xml)(如果 CLASSPATH 上尚未提供)(此外,CLASSPATH 必須包含具有 zookeeper 配置文件的目錄,如果 zookeeper 不是由 HBase 管理的)。
> 如果 HBase 中尚不存在目標表,則此工具將自動創建表。
### 73.3。也可以看看
有關引用的實用程序的更多信息,請參閱 [ImportTsv](#importtsv) 和 [CompleteBulkLoad](#completebulkload) 。
請參閱[操作方法:使用 HBase 批量加載,以及為什么](http://blog.cloudera.com/blog/2013/09/how-to-use-hbase-bulk-loading-and-why/)獲取最新博客的當前批量加載狀態。
### 73.4。高級用法
盡管`importtsv`工具在許多情況下很有用,但高級用戶可能希望以編程方式生成數據,或從其他格式導入數據。要開始這樣做,請深入研究`ImportTsv.java`并檢查 JavaDoc for HFileOutputFormat。
批量加載的導入步驟也可以通過編程方式完成。有關更多信息,請參見`LoadIncrementalHFiles`類。
### 73.5。批量加載復制
HBASE-13153 為批量加載的 HFile 增加了復制支持,自 HBase 1.3 / 2.0 起可用。通過將`hbase.replication.bulkload.enabled`設置為`true`(默認為`false`)啟用此功能。您還需要將源群集配置文件復制到目標群集。
還需要其他配置:
1. `hbase.replication.source.fs.conf.provider`
這定義了在目標集群中加載源集群文件系統客戶端配置的類。應為目標群集中的所有 RS 配置此項。默認值為`org.apache.hadoop.hbase.replication.regionserver.DefaultSourceFSConfigurationProvider`。
2. `hbase.replication.conf.dir`
這表示將源群集的文件系統客戶端配置復制到目標群集的基本目錄。應為目標群集中的所有 RS 配置此項。默認值為`$HBASE_CONF_DIR`。
3. `hbase.replication.cluster.id`
群集中需要此配置,其中啟用了批量加載數據的復制。源群集由目標群集使用此 ID 唯一標識。應為所有 RS 的源群集配置文件中的所有 RS 配置此項。
例如:如果將源群集 FS 客戶端配置復制到目錄`/home/user/dc1/`下的目標群集,則`hbase.replication.cluster.id`應配置為`dc1`,`hbase.replication.conf.dir`應配置為`/home/user`。
> `DefaultSourceFSConfigurationProvider`僅支持`xml`類型文件。它僅加載源群集 FS 客戶端配置一次,因此如果更新源群集 FS 客戶端配置文件,則必須重新啟動每個對等群集 RS 以重新加載配置。
## 74\. HDFS
由于 HBase 在 HDFS 上運行(并且每個 StoreFile 都作為 HDFS 上的文件寫入),因此了解 HDFS 架構非常重要,尤其是在存儲文件,處理故障轉移和復制塊方面。
有關更多信息,請參閱 [HDFS 架構](https://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html)上的 Hadoop 文檔。
### 74.1。的 NameNode
NameNode 負責維護文件系統元數據。有關更多信息,請參閱上面的 HDFS 架構鏈接。
### 74.2。數據管理部
DataNode 負責存儲 HDFS 塊。有關更多信息,請參閱上面的 HDFS 架構鏈接。
## 75.時間線一致的高可用讀數
> 當前 [Assignment Manager V2](#amv2) 與區域副本不兼容,因此可能會破壞此功能。請謹慎使用。
### 75.1。介紹
從結構上看,HBase 從一開始就始終具有強大的一致性保證。所有讀取和寫入都通過單個區域服務器進行路由,這可確保所有寫入按順序發生,并且所有讀取都會查看最新提交的數據。
但是,由于將讀取單一歸位到單個位置,如果服務器變得不可用,則區域服務器中托管的表的區域將在一段時間內不可用。區域恢復過程分為三個階段 - 檢測,分配和恢復。其中,檢測通常是最長的,目前大約 20-30 秒,具體取決于 ZooKeeper 會話超時。在此期間和恢復完成之前,客戶端將無法讀取區域數據。
但是,對于某些用例,要么數據可能是只讀的,要么對某些陳舊數據進行讀取是可以接受的。通過時間線一致的高可用讀取,HBase 可用于這類延遲敏感的用例,其中應用程序可能期望在讀取完成時具有時間限制。
為了實現讀取的高可用性,HBase 提供了一種稱為 _ 區域復制 _ 的功能。在此模型中,對于表的每個區域,將有多個副本在不同的 RegionServers 中打開。默認情況下,區域復制設置為 1,因此只部署了一個區域副本,并且不會對原始模型進行任何更改。如果區域復制設置為 2 或更多,則主服務器將分配表的區域的副本。負載均衡器可確保區域副本不在同一區域服務器中共存,也可在同一機架中共存(如果可能)。
單個區域的所有副本將具有從 0 開始的唯一 replica_id。具有 replica_id == 0 的區域副本被稱為主要區域,而其他區域 _ 次要區域 _ 或次要區域。只有主服務器可以接受來自客戶端的寫入,主服務器將始終包含最新的更改。由于所有寫入仍然必須通過主區域,因此寫入不是高度可用的(這意味著如果區域變得不可用,它們可能會阻塞一段時間)。
### 75.2。時間線一致性
通過此功能,HBase 引入了一致性定義,可以根據讀取操作(獲取或掃描)提供該定義。
```
public enum Consistency {
STRONG,
TIMELINE
}
```
`Consistency.STRONG`是 HBase 提供的默認一致性模型。如果表具有 region replication = 1,或者在具有區域副本的表中但讀取是使用此一致性完成的,則讀取始終由主要區域執行,因此不會對先前的行為進行任何更改,并且客戶端始終觀察最新數據。
如果使用`Consistency.TIMELINE`執行讀取,則首先將讀取的 RPC 發送到主區域服務器。在短暫的間隔(`hbase.client.primaryCallTimeout.get`,默認為 10 毫秒)之后,如果主服務器沒有響應,也將發送輔助區域副本的并行 RPC。在此之后,從最先完成的 RPC 返回結果。如果響應從主要區域副本返回,我們始終可以知道數據是最新的。為此,添加了 Result.isStale()API 來檢查陳舊性。如果結果來自輔助區域,則 Result.isStale()將設置為 true。然后,用戶可以檢查該字段以可能推斷數據。
在語義方面,HBase 實現的 TIMELINE 一致性與這些方面的純粹最終一致性不同:
* 單個歸屬和有序更新:區域復制與否,在寫入端,仍然只有 1 個可以接受寫入的已定義副本(主要)。此副本負責對編輯進行排序并防止沖突。這可以保證不同副本不會同時提交兩個不同的寫入,并且數據會發散。有了這個,就沒有必要進行讀取修復或最后時間戳獲勝的沖突解決方案。
* 輔助節點也按主節點提交的順序應用編輯。這樣,輔助節點將包含任何時間點的原色數據的快照。這類似于 RDBMS 復制,甚至是 HBase 自己的多數據中心復制,但是在單個集群中。
* 在讀取端,客戶端可以檢測讀取是來自最新數據還是過時數據。此外,客戶端可以在每個操作的基礎上發出具有不同一致性要求的讀取,以確保其自身的語義保證。
* 客戶端仍然可以觀察無序編輯,如果它首先觀察來自一個輔助副本的讀取,然后是另一個輔助副本,則可以及時返回。區域副本或基于事務 ID 的保證沒有粘性。如果需要,可以稍后實施。
圖 3.時間軸一致性
為了更好地理解 TIMELINE 語義,讓我們看一下上圖。假設有兩個客戶端,第一個客戶端首先寫入 x = 1,然后 x = 2,x = 3。如上所述,所有寫入都由主要區域副本處理。寫入保存在寫入日志(WAL)中,并異步復制到其他副本。在上圖中,請注意 replica_id = 1 接收到 2 次更新,其數據顯示 x = 2,而 replica_id = 2 僅接收單次更新,其數據顯示 x = 1。
如果 client1 以 STRONG 一致性讀取,它將僅與 replica_id = 0 對話,因此保證觀察到 x = 3 的最新值。如果客戶端發出 TIMELINE 一致性讀取,則 RPC 將轉到所有副本(在主超時之后),并且將返回第一個響應的結果。因此,客戶端可以看到 1,2 或 3 作為 x 的值。假設主要區域已失敗,并且日志復制無法繼續一段時間。如果客戶端使用 TIMELINE 一致性進行多次讀取,則可以先觀察 x = 2,然后 x = 1,依此類推。
### 75.3。權衡
為讀取可用性托管次要區域需要進行一些權衡,應根據用例仔細評估。以下是優點和缺點。
好處
* 只讀表的高可用性
* 過時讀取的高可用性
* 能夠進行非常低延遲的讀取,具有非常高的百分位數(99.9%+)延遲讀取的延遲
缺點
* 具有區域復制的表的雙/三 MemStore 使用(取決于區域復制計數)&gt; 1
* 增加塊緩存使用率
* 日志復制的額外網絡流量
* 副本的額外備份 RPC
為了從多個副本服務區域數據,HBase 在區域服務器中以輔助模式打開區域。以輔助模式打開的區域將與主要區域副本共享相同的數據文件,但是每個輔助區域副本將具有其自己的 MemStore 以保留未刷新的數據(僅主要區域可以執行刷新)。同樣為了提供來自次要區域的讀取,數據文件塊也可以高速緩存在用于次要區域的塊高速緩存中。
### 75.4。代碼在哪里?
此功能分兩個階段提供,第 1 階段和第 2 階段。第一階段及時完成 HBase-1.0.0 版本。這意味著使用 HBase-1.0.x,您可以使用為階段 1 標記的所有功能。階段 2 在 HBase-1.1.0 中提交,這意味著 1.1.0 之后的所有 HBase 版本都應包含階段 2 項。
### 75.5。傳播對區域副本的寫入
如上所述,寫入僅轉到主要區域副本。為了將寫入從主要區域副本傳播到輔助副本,有兩種不同的機制。對于只讀表,您不需要使用以下任何方法。禁用和啟用表應使所有區域副本中的數據可用。對于可變表,您必須僅使用以下機制之一:storefile refresher 或 async wal replication。推薦后者。
#### 75.5.1。 StoreFile 復習
第一種機制是存儲文件刷新,它在 HBase-1.0 +中引入。存儲文件刷新是每個區域服務器的一個線程,它定期運行,并對輔助區域副本的主區域的存儲文件執行刷新操作。如果啟用,則刷新器將確保輔助區域副本及時查看來自主區域的新刷新,壓縮或批量加載文件。但是,這意味著只能從輔助區域副本中讀回刷新的數據,并且在刷新運行之后,使輔助數據庫滯后于主數據庫更長時間。
要打開此功能,應將`hbase.regionserver.storefile.refresh.period`配置為非零值。請參閱下面的配置部分
#### 75.5.2。 Asnyc WAL 復制
第二種寫入傳播的機制是通過“異步 WAL 復制”功能完成的,僅在 HBase-1.1 +中可用。這類似于 HBase 的多數據中心復制,但是來自區域的數據被復制到輔助區域。每個輔助副本始終以與主區域提交它們相同的順序接收和觀察寫入。從某種意義上說,這種設計可以被認為是“群集內復制”,而不是復制到不同的數據中心,數據會轉到次要區域,以保持次要區域的內存狀態為最新狀態。數據文件在主區域和其他副本之間共享,因此不會產生額外的存儲開銷。但是,輔助區域將在其存儲庫中具有最近的非刷新數據,這會增加內存開銷。主要區域也將 flush,compaction 和 bulk load 事件寫入其 WAL,這些事件也通過 wal 復制到輔助節點進行復制。當他們觀察到 flush / compaction 或 bulk load 事件時,輔助區域會重放事件以獲取新文件并刪除舊文件。
以與主數據庫相同的順序提交寫入可確保輔助數據不會偏離主要區域數據,但由于日志復制是異步的,因此數據在輔助區域中可能仍然是陳舊的。由于此功能可用作復制端點,因此預計性能和延遲特性與群集間復制類似。
默認情況下,異步 WAL 復制禁用。您可以通過將`hbase.region.replica.replication.enabled`設置為`true`來啟用此功能。當您使用區域復制&gt;創建表時,Asyn WAL 復制功能將添加名為`region_replica_replication`的新復制對等體作為復制對等體。 1 是第一次。啟用后,如果要禁用此功能,則需要執行兩項操作:_ 在`hbase-site.xml`中將配置屬性`hbase.region.replica.replication.enabled`設置為 false(請參閱下面的配置部分)_ 禁用名為`region_replica_replication`的復制對等體在使用 hbase shell 或`Admin`類的集群中:
```
hbase> disable_peer 'region_replica_replication'
```
### 75.6。存儲文件 TTL
在上面提到的兩種寫傳播方法中,主存儲文件將在輔助節點中獨立于主區域打開。因此,對于主要壓縮的文件,輔助節點可能仍然會引用這些文件進行讀取。這兩個功能都使用 HFileLinks 來引用文件,但是沒有保護(尚未)保證文件不會過早刪除。因此,作為保護,您應該將配置屬性`hbase.master.hfilecleaner.ttl`設置為更大的值,例如 1 小時,以保證您不會收到轉發到副本的請求的 IOExceptions。
### 75.7。 META 表區域的區域復制
目前,沒有為 META 表的 WAL 執行異步 WAL 復制。元表的輔助副本仍然會從持久存儲文件中刷新自己。因此,需要將`hbase.regionserver.meta.storefile.refresh.period`設置為某個非零值以刷新元存儲文件。請注意,此配置的配置與`hbase.regionserver.storefile.refresh.period`不同。
### 75.8。記憶核算
輔助區域副本引用主要區域副本的數據文件,但它們有自己的存儲庫(在 HBase-1.1 +中)并且也使用塊緩存。但是,一個區別是次要區域副本在其存儲器存在壓力時無法刷新數據。它們只能在主區域執行刷新時釋放 memstore 內存,并且此刷新將復制到輔助節點。由于在某些區域中托管主副本的區域服務器和其他區域的輔助副本,因此輔助副本可能會導致額外刷新到同一主機中的主區域。在極端情況下,沒有內存可用于添加來自主要來自 wal 復制的新寫入。為了解除阻塞這種情況(并且由于輔助服務器不能自行刷新),允許輔助服務器通過執行文件系統列表操作來執行“存儲文件刷新”,以從主服務器獲取新文件,并可能刪除其 memstore。僅當最大輔助區域副本的 memstore 大小至少比主副本的最大 memstore 大`hbase.region.replica.storefile.refresh.memstore.multiplier`(默認值為 4)時,才會執行此刷新。需要注意的是,如果執行此操作,則輔助節點可以觀察跨列族的部分行更新(因為列族是獨立刷新的)。默認情況下應該不經常執行此操作。如果需要,可以將此值設置為較大的數值以禁用此功能,但請注意,它可能會導致復制永久阻止。
### 75.9。輔助副本故障轉移
當輔助區域副本首次聯機或故障轉移時,它可能已從其 memstore 中進行了一些編輯。由于輔助副本的恢復處理方式不同,因此輔助副本必須確保它在分配后開始提供請求之前不會及時返回。為此,輔助節點等待直到它觀察到從主節點復制的完全刷新周期(開始刷新,提交刷新)或“區域打開事件”。在此情況發生之前,輔助區域副本將通過拋出 IOException 來拒絕所有讀取請求,并顯示消息“區域的讀取被禁用”。但是,其他副本可能仍然可以讀取,因此不會對具有 TIMELINE 一致性的 rpc 造成任何影響。為了促進更快的恢復,輔助區域將在打開時觸發主要的刷新請求。如果需要,配置屬性`hbase.region.replica.wait.for.primary.flush`(默認啟用)可用于禁用此功能。
### 75.10。配置屬性
要使用高可用性讀取,應在`hbase-site.xml`文件中設置以下屬性。沒有用于啟用或禁用區域副本的特定配置。相反,您可以在創建表時或使用 alter table 更改每個表的區域副本數量以增加或減少。以下配置用于使用異步 wal 復制和使用 3 的元副本。
#### 75.10.1。服務器端屬性
```
<property>
<name>hbase.regionserver.storefile.refresh.period</name>
<value>0</value>
<description>
The period (in milliseconds) for refreshing the store files for the secondary regions. 0 means this feature is disabled. Secondary regions sees new files (from flushes and compactions) from primary once the secondary region refreshes the list of files in the region (there is no notification mechanism). But too frequent refreshes might cause extra Namenode pressure. If the files cannot be refreshed for longer than HFile TTL (hbase.master.hfilecleaner.ttl) the requests are rejected. Configuring HFile TTL to a larger value is also recommended with this setting.
</description>
</property>
<property>
<name>hbase.regionserver.meta.storefile.refresh.period</name>
<value>300000</value>
<description>
The period (in milliseconds) for refreshing the store files for the hbase:meta tables secondary regions. 0 means this feature is disabled. Secondary regions sees new files (from flushes and compactions) from primary once the secondary region refreshes the list of files in the region (there is no notification mechanism). But too frequent refreshes might cause extra Namenode pressure. If the files cannot be refreshed for longer than HFile TTL (hbase.master.hfilecleaner.ttl) the requests are rejected. Configuring HFile TTL to a larger value is also recommended with this setting. This should be a non-zero number if meta replicas are enabled (via hbase.meta.replica.count set to greater than 1).
</description>
</property>
<property>
<name>hbase.region.replica.replication.enabled</name>
<value>true</value>
<description>
Whether asynchronous WAL replication to the secondary region replicas is enabled or not. If this is enabled, a replication peer named "region_replica_replication" will be created which will tail the logs and replicate the mutations to region replicas for tables that have region replication > 1\. If this is enabled once, disabling this replication also requires disabling the replication peer using shell or Admin java class. Replication to secondary region replicas works over standard inter-cluster replication.
</description>
</property>
<property>
<name>hbase.region.replica.replication.memstore.enabled</name>
<value>true</value>
<description>
If you set this to `false`, replicas do not receive memstore updates from
the primary RegionServer. If you set this to `true`, you can still disable
memstore replication on a per-table basis, by setting the table's
`REGION_MEMSTORE_REPLICATION` configuration property to `false`. If
memstore replication is disabled, the secondaries will only receive
updates for events like flushes and bulkloads, and will not have access to
data which the primary has not yet flushed. This preserves the guarantee
of row-level consistency, even when the read requests `Consistency.TIMELINE`.
</description>
</property>
<property>
<name>hbase.master.hfilecleaner.ttl</name>
<value>3600000</value>
<description>
The period (in milliseconds) to keep store files in the archive folder before deleting them from the file system.</description>
</property>
<property>
<name>hbase.meta.replica.count</name>
<value>3</value>
<description>
Region replication count for the meta regions. Defaults to 1.
</description>
</property>
<property>
<name>hbase.region.replica.storefile.refresh.memstore.multiplier</name>
<value>4</value>
<description>
The multiplier for a “store file refresh” operation for the secondary region replica. If a region server has memory pressure, the secondary region will refresh it’s store files if the memstore size of the biggest secondary replica is bigger this many times than the memstore size of the biggest primary replica. Set this to a very big value to disable this feature (not recommended).
</description>
</property>
<property>
<name>hbase.region.replica.wait.for.primary.flush</name>
<value>true</value>
<description>
Whether to wait for observing a full flush cycle from the primary before start serving data in a secondary. Disabling this might cause the secondary region replicas to go back in time for reads between region movements.
</description>
</property>
```
還要記住的一點是,區域副本放置策略僅由作為默認平衡器的`StochasticLoadBalancer`強制執行。如果在 hbase-site.xml(`hbase.master.loadbalancer.class`中)使用自定義負載均衡器屬性,則區域的副本最終可能會托管在同一服務器中。
#### 75.10.2。客戶端屬性
確保為將使用區域副本的所有客戶端(和服務器)設置以下內容。
```
<property>
<name>hbase.ipc.client.specificThreadForWriting</name>
<value>true</value>
<description>
Whether to enable interruption of RPC threads at the client side. This is required for region replicas with fallback RPC’s to secondary regions.
</description>
</property>
<property>
<name>hbase.client.primaryCallTimeout.get</name>
<value>10000</value>
<description>
The timeout (in microseconds), before secondary fallback RPC’s are submitted for get requests with Consistency.TIMELINE to the secondary replicas of the regions. Defaults to 10ms. Setting this lower will increase the number of RPC’s, but will lower the p99 latencies.
</description>
</property>
<property>
<name>hbase.client.primaryCallTimeout.multiget</name>
<value>10000</value>
<description>
The timeout (in microseconds), before secondary fallback RPC’s are submitted for multi-get requests (Table.get(List<Get>)) with Consistency.TIMELINE to the secondary replicas of the regions. Defaults to 10ms. Setting this lower will increase the number of RPC’s, but will lower the p99 latencies.
</description>
</property>
<property>
<name>hbase.client.replicaCallTimeout.scan</name>
<value>1000000</value>
<description>
The timeout (in microseconds), before secondary fallback RPC’s are submitted for scan requests with Consistency.TIMELINE to the secondary replicas of the regions. Defaults to 1 sec. Setting this lower will increase the number of RPC’s, but will lower the p99 latencies.
</description>
</property>
<property>
<name>hbase.meta.replicas.use</name>
<value>true</value>
<description>
Whether to use meta table replicas or not. Default is false.
</description>
</property>
```
注意 HBase-1.0.x 用戶應該使用`hbase.ipc.client.allowsInterrupt`而不是`hbase.ipc.client.specificThreadForWriting`。
### 75.11。用戶界面
在主用戶界面中,表的區域副本也與主要區域一起顯示。您可以注意到區域的副本將共享相同的開始和結束鍵以及相同的區域名稱前綴。唯一的區別是附加的 replica_id(編碼為十六進制),區域編碼的名稱將不同。您還可以在 UI 中看到顯式顯示的副本 ID。
### 75.12。創建具有區域復制的表
區域復制是每個表的屬性。默認情況下,所有表都有`REGION_REPLICATION = 1`,這意味著每個區域只有一個副本。您可以通過在表描述符中提供`REGION_REPLICATION`屬性來設置和更改表的每個區域的副本數。
#### 75.12.1。貝殼
```
create 't1', 'f1', {REGION_REPLICATION => 2}
describe 't1'
for i in 1..100
put 't1', "r#{i}", 'f1:c1', i
end
flush 't1'
```
#### 75.12.2。 Java 的
```
HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(“test_table”));
htd.setRegionReplication(2);
...
admin.createTable(htd);
```
您還可以使用`setRegionReplication()`和 alter table 來增加,減少表的區域復制。
### 75.13。閱讀 API 和用法
#### 75.13.1。貝殼
您可以使用 Consistency.TIMELINE 語義在 shell 中進行讀取,如下所示
```
hbase(main):001:0> get 't1','r6', {CONSISTENCY => "TIMELINE"}
```
您可以模擬暫停或變為不可用的區域服務器,并從輔助副本執行讀取操作:
```
$ kill -STOP <pid or primary region server>
hbase(main):001:0> get 't1','r6', {CONSISTENCY => "TIMELINE"}
```
使用掃描也是類似的
```
hbase> scan 't1', {CONSISTENCY => 'TIMELINE'}
```
#### 75.13.2。 Java 的
您可以按如下方式設置獲取和掃描的一致性并執行請求。
```
Get get = new Get(row);
get.setConsistency(Consistency.TIMELINE);
...
Result result = table.get(get);
```
您還可以傳遞多個獲取:
```
Get get1 = new Get(row);
get1.setConsistency(Consistency.TIMELINE);
...
ArrayList<Get> gets = new ArrayList<Get>();
gets.add(get1);
...
Result[] results = table.get(gets);
```
和掃描:
```
Scan scan = new Scan();
scan.setConsistency(Consistency.TIMELINE);
...
ResultScanner scanner = table.getScanner(scan);
```
您可以通過調用`Result.isStale()`方法檢查結果是否來自主區域:
```
Result result = table.get(get);
if (result.isStale()) {
...
}
```
### 75.14。資源
1. 有關設計和實施的更多信息,請參閱 jira 問題: [HBASE-10070](https://issues.apache.org/jira/browse/HBASE-10070)
2. HBaseCon 2014 講話: [HBase 使用時間軸一致區域副本讀取高可用性](https://hbase.apache.org/www.hbasecon.com/#2014-PresentationsRecordings)還包含一些細節和[幻燈片](http://www.slideshare.net/enissoz/hbase-high-availability-for-reads-with-time)。
## 76.存儲中型物體(MOB)
數據有多種尺寸,保存 HBase 中的所有數據(包括圖像和文檔等二進制數據)是理想的選擇。雖然 HBase 在技術上可以處理大小超過 100 KB 的單元格的二進制對象,但 HBase 的正常讀取和寫入路徑針對小于 100KB 的值進行了優化。當 HBase 處理超過此閾值的大量對象(此處稱為中等對象或 MOB)時,由于分割和壓縮引起的寫入放大,性能會降低。使用 MOB 時,理想情況下,您的對象將介于 100KB 和 10MB 之間(參見 [FAQ](#faq) )。 HBase ****FIX_VERSION_NUMBER** **增加了對更好地管理大量 MOB 的支持,同時保持了性能,一致性和低運營開銷。 MOB 支持由 [HBASE-11339](https://issues.apache.org/jira/browse/HBASE-11339) 完成的工作提供。要利用 MOB,您需要使用 [HFile 版本 3](#hfilev3) 。 (可選)為每個 RegionServer 配置 MOB 文件讀取器的緩存設置(請參閱[配置 MOB 緩存](#mob.cache.configure)),然后配置特定列以保存 MOB 數據。客戶端代碼無需更改即可利用 HBase MOB 支持。該功能對客戶端是透明的。
MOB 壓縮
在 MemStore 刷新后,MOB 數據被刷新到 MOB 文件中。一段時間后會有很多 MOB 文件。為了減少 MOB 文件數量,有一個周期性任務可以將小型 MOB 文件壓縮成大型 MOB 文件(MOB 壓縮)。
### 76.1。為 MOB 配置列
您可以在表創建或更改期間配置列以支持 MOB,無論是在 HBase Shell 中還是通過 Java API。兩個相關的屬性是布爾`IS_MOB`和`MOB_THRESHOLD`,它是一個對象被認為是 MOB 的字節數。只需要`IS_MOB`。如果未指定`MOB_THRESHOLD`,則使用默認閾值 100 KB。
使用 HBase Shell 為 MOB 配置列
```
hbase> create 't1', {NAME => 'f1', IS_MOB => true, MOB_THRESHOLD => 102400}
hbase> alter 't1', {NAME => 'f1', IS_MOB => true, MOB_THRESHOLD => 102400}
```
示例 23.使用 Java API 為 MOB 配置列
```
...
HColumnDescriptor hcd = new HColumnDescriptor(“f”);
hcd.setMobEnabled(true);
...
hcd.setMobThreshold(102400L);
...
```
### 76.2。配置 MOB 壓縮策略
默認情況下,將特定日期的 MOB 文件壓縮為一個大型 MOB 文件。為了更多地減少 MOB 文件數,還支持其他 MOB 壓縮策略。
每日策略 - 壓縮 MOB 文件一天進入一個大型 MOB 文件(默認策略)每周策略 - 緊湊 MOB 文件一周到一個大型 MOB 文件 montly 策略 - 緊湊 MOB 文件一個月到一個大 MOB 文件
使用 HBase Shell 配置 MOB 壓縮策略
```
hbase> create 't1', {NAME => 'f1', IS_MOB => true, MOB_THRESHOLD => 102400, MOB_COMPACT_PARTITION_POLICY => 'daily'}
hbase> create 't1', {NAME => 'f1', IS_MOB => true, MOB_THRESHOLD => 102400, MOB_COMPACT_PARTITION_POLICY => 'weekly'}
hbase> create 't1', {NAME => 'f1', IS_MOB => true, MOB_THRESHOLD => 102400, MOB_COMPACT_PARTITION_POLICY => 'monthly'}
hbase> alter 't1', {NAME => 'f1', IS_MOB => true, MOB_THRESHOLD => 102400, MOB_COMPACT_PARTITION_POLICY => 'daily'}
hbase> alter 't1', {NAME => 'f1', IS_MOB => true, MOB_THRESHOLD => 102400, MOB_COMPACT_PARTITION_POLICY => 'weekly'}
hbase> alter 't1', {NAME => 'f1', IS_MOB => true, MOB_THRESHOLD => 102400, MOB_COMPACT_PARTITION_POLICY => 'monthly'}
```
### 76.3。配置 MOB 壓縮可合并閾值
如果一個 mob 文件的大小小于這個值,它被認為是一個小文件,需要在 mob compaction 中合并。默認值為 1280MB。
```
<property>
<name>hbase.mob.compaction.mergeable.threshold</name>
<value>10000000000</value>
</property>
```
### 76.4。測試 MOB
提供實用程序`org.apache.hadoop.hbase.IntegrationTestIngestWithMOB`以幫助測試 MOB 功能。該實用程序運行如下:
```
$ sudo -u hbase hbase org.apache.hadoop.hbase.IntegrationTestIngestWithMOB \
-threshold 1024 \
-minMobDataSize 512 \
-maxMobDataSize 5120
```
* `**threshold**`是細胞被認為是 MOB 的閾值。默認值為 1 kB,以字節為單位表示。
* `**minMobDataSize**`是 MOB 數據大小的最小值。默認值為 512 B,以字節為單位表示。
* `**maxMobDataSize**`是 MOB 數據大小的最大值。默認值為 5 kB,以字節為單位表示。
### 76.5。配置 MOB 緩存
因為可以隨時存在大量 MOB 文件,與 HFiles 的數量相比,MOB 文件并不總是保持打開狀態。 MOB 文件讀取器緩存是一個 LRU 緩存,它保持最近使用的 MOB 文件打開。要在每個 RegionServer 上配置 MOB 文件讀取器的緩存,請將以下屬性添加到 R??egionServer 的`hbase-site.xml`,自定義配置以適合您的環境,然后重新啟動或滾動重新啟動 RegionServer。
示例 24.示例 MOB 緩存配置
```
<property>
<name>hbase.mob.file.cache.size</name>
<value>1000</value>
<description>
Number of opened file handlers to cache.
A larger value will benefit reads by providing more file handlers per mob
file cache and would reduce frequent file opening and closing.
However, if this is set too high, this could lead to a "too many opened file handers"
The default value is 1000.
</description>
</property>
<property>
<name>hbase.mob.cache.evict.period</name>
<value>3600</value>
<description>
The amount of time in seconds after which an unused file is evicted from the
MOB cache. The default value is 3600 seconds.
</description>
</property>
<property>
<name>hbase.mob.cache.evict.remain.ratio</name>
<value>0.5f</value>
<description>
A multiplier (between 0.0 and 1.0), which determines how many files remain cached
after the threshold of files that remains cached after a cache eviction occurs
which is triggered by reaching the `hbase.mob.file.cache.size` threshold.
The default value is 0.5f, which means that half the files (the least-recently-used
ones) are evicted.
</description>
</property>
```
### 76.6。 MOB 優化任務
#### 76.6.1。手動壓縮 MOB 文件
要手動壓縮 MOB 文件,而不是等待[配置](#mob.cache.configure)觸發壓縮,請使用`compact`或`major_compact` HBase shell 命令。這些命令要求第一個參數為表名,并將列族作為第二個參數。并將壓縮類型作為第三個參數。
```
hbase> compact 't1', 'c1’, ‘MOB’
hbase> major_compact 't1', 'c1’, ‘MOB’
```
這些命令也可通過`Admin.compact`和`Admin.majorCompact`方法獲得。
- 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