# Apache HBase 性能調優
## 114.操作系統
### 114.1。記憶
RAM,RAM,RAM。不要餓死 HBase。
### 114.2。 64 位
使用 64 位平臺(和 64 位 JVM)。
### 114.3。交換
注意交換。將`swappiness`設置為 0。
### 114.4。中央處理器
確保已將 Hadoop 設置為使用本機硬件校驗和。見鏈接:[hadoop.native.lib]。
## 115.網絡
避免網絡問題降低 Hadoop 和 HBase 性能的最重要因素可能是使用的交換硬件,在項目范圍的早期做出的決策可能會導致群集大小增加一倍或三倍(或更多)時出現重大問題。
需要考慮的重要事項:
* 設備的切換容量
* 連接的系統數量
* 上行容量
### 115.1。單開關
此配置中最重要的一個因素是硬件的交換容量能夠處理連接到交換機的所有系統可能產生的流量。一些較低價格的商用硬件可以具有比完整交換機可以使用的更慢的交換容量。
### 115.2。多個開關
多個交換機是架構中的潛在缺陷。低價硬件的最常見配置是從一個交換機到另一個交換機的簡單 1Gbps 上行鏈路。這種經常被忽視的夾點很容易成為集群通信的瓶頸。特別是對于同時讀取和寫入大量數據的 MapReduce 作業,此上行鏈路上的通信可能已經飽和。
緩解此問題非常簡單,可以通過多種方式完成:
* 使用適當的硬件來處理您嘗試構建的群集的規模。
* 使用較大的單開關配置,即單個 48 端口而不是 2 個 24 端口
* 配置上行鏈路的端口中繼,以利用多個接口來增加交叉交換機帶寬。
### 115.3。多個機架
多個機架配置帶來與多個交換機相同的潛在問題,并且可能會從兩個主要方面降低性能:
* 開關容量性能不佳
* 上行鏈路到另一個機架的能力不足
如果機架中的交換機具有適當的交換容量以全速處理所有主機,則下一個最可能的問題將是通過在機架中引導更多群集引起的。跨越多個機架時避免問題的最簡單方法是使用端口中繼來創建到其他機架的綁定上行鏈路。然而,該方法的缺點在于可能使用的端口的開銷。這樣做的一個例子是,從機架 A 到機架 B 創建一個 8Gbps 端口通道,使用 24 個端口中的 8 個在機架之間進行通信會降低投資回報率,使用太少但是可能意味著您無法充分利用簇。
在機架之間使用 10Gbe 鏈路將大大提高性能,并且假設您的交換機支持 10Gbe 上行鏈路或允許擴展卡,則允許您為機器而不是上行鏈路保存端口。
### 115.4。網絡接口
所有網絡接口都正常運行嗎?你確定嗎?請參閱[案例研究#1(單節點上的性能問題)](#casestudies.slownode)中的故障排除案例研究。
### 115.5。網絡一致性和分區容忍度
[CAP 定理](http://en.wikipedia.org/wiki/CAP_theorem)指出分布式系統可以保持以下三個特征中的兩個: - _C_ onsistency - 所有節點都看到相同的數據。 - _A_ 可用性 - 每個請求都會收到有關它是成功還是失敗的響應。 - _P_ 的動作容忍度 - 即使其他組件無法使用,系統也會繼續運行。
HBase 支持一致性和分區容忍度,必須做出決定。 Coda Hale 在 [http://codahale.com/you-cant-sacrifice-partition-tolerance/](http://codahale.com/you-cant-sacrifice-partition-tolerance/) 中解釋了為什么分區容差如此重要。
羅伯特 Yokota 使用一個名為 [Jepson](https://aphyr.com/tags/jepsen) 的自動化測試框架來測試 HBase 在網絡分區面前的分區容忍度,使用 Aphyr 的 [Call Me Maybe](https://aphyr.com/posts/281-call-me-maybe-carly-rae-jepsen-and-the-perils-of-network-partitions) 系列之后建模的技術。結果,作為[博客文章](https://rayokota.wordpress.com/2015/09/30/call-me-maybe-hbase/)和[附錄](https://rayokota.wordpress.com/2015/09/30/call-me-maybe-hbase-addendum/),顯示 HBase 正確執行。
## 116\. Java
### 116.1。垃圾收集器和 Apache HBase
#### 116.1.1。長 GC 暫停
在他的演講中,[避免使用 MemStore-本地分配緩沖區](http://www.slideshare.net/cloudera/hbase-hug-presentation),Todd Lipcon 描述了 HBase 中常見的兩種世界性垃圾收集案例,特別是在加載過程中; CMS 故障模式和老一代堆碎片帶來了。
要解決第一個問題,請通過添加`-XX:CMSInitiatingOccupancyFraction`并將其設置為默認值來啟動早于默認值的 CMS。從 60%或 70%開始(降低閾值越低,GCing 越多,使用的 CPU 越多)。為了解決第二個碎片問題,Todd 添加了一個實驗工具(MSLAB),必須在 Apache HBase 0.90.x 中明確啟用(它在 Apache 0.92.x HBase 中默認為上的 _)。在`Configuration`中將`hbase.hregion.memstore.mslab.enabled`設置為 true。有關背景和細節,請參閱引用的幻燈片。最新的 JVM 更好地考慮碎片,因此請確保您運行的是最新版本。在消息中讀入,[識別由碎片引起的并發模式故障](http://osdir.com/ml/hotspot-gc-use/2011-11/msg00002.html)。請注意,啟用后,每個 MemStore 實例將至少占用一個 MSLAB 內存實例。如果您有數千個區域或許多區域,每個區域都有許多列族,那么 MSLAB 的這種分配可能會導致很大一部分堆分配,并且在極端情況下會導致您進入 OOME。在這種情況下禁用 MSLAB,或者降低它使用的內存量或每個服務器浮動更少的區域。_
如果您的工作量很大,請查看 [HBASE-8163 MemStoreChunkPool:使用 MSLAB](https://issues.apache.org/jira/browse/HBASE-8163) 時對 JAVA GC 的改進。它描述了在寫入負載期間降低年輕 GC 數量的配置。如果您沒有安裝 HBASE-8163,并且您正在嘗試改善年輕的 GC 時間,那么我們需要考慮的一個訣竅 - 我們的梁燮 - 是在 _hbase-env.sh 中設置 GC 配置`-XX:PretenureSizeThreshold`_ 只是小于`hbase.hregion.memstore.mslab.chunksize`的大小所以 MSLAB 分配直接發生在終身空間而不是年輕時代。你這樣做是因為這些 MSLAB 分配很可能無論如何都要用于舊版本,而不是在 eden 空間中支付 s0 和 s1 之間的拷貝價格,然后在 MSLABs 之后從年輕到舊代復制。取得了足夠的任期,節省了一點 YGC 流失并直接分配到舊版。
長 GC 的其他來源可以是 JVM 本身的日志記錄。請參閱[消除由后臺 IO 流量引起的大型 JVM GC 暫停](https://engineering.linkedin.com/blog/2016/02/eliminating-large-jvm-gc-pauses-caused-by-background-io-traffic)
有關 GC 日志的更多信息,請參閱 [JVM 垃圾收集日志](#trouble.log.gc)。
還要考慮啟用堆外塊緩存。這已被證明可以緩解 GC 暫停時間。見 [Block Cache](#block.cache)
## 117\. HBase 配置
參見[推薦配置](#recommended_configurations)。
### 117.1。改善第 99 百分位數
嘗試鏈接:[hedged_reads]。
### 117.2。管理壓縮
對于較大的系統,管理鏈接:[compactions 和 splits]可能是您想要考慮的事情。
### 117.3。 `hbase.regionserver.handler.count`
見 [[hbase.regionserver.handler.count]](#hbase.regionserver.handler.count) 。
### 117.4。 `hfile.block.cache.size`
見 [[hfile.block.cache.size]](#hfile.block.cache.size) 。 RegionServer 進程的內存設置。
### 117.5。 Blockcache 的預取選項
[HBASE-9857](https://issues.apache.org/jira/browse/HBASE-9857) 添加了一個新選項,用于在打開 BlockCache 時預取 HFile 內容,如果設置了 Column 系列或 RegionServer 屬性。此選項適用于 HBase 0.98.3 及更高版本。目的是在打開緩存后,使用內存中的表數據盡可能快地加熱 BlockCache,而不將預取計為緩存未命中。這對于快速讀取非常有用,但如果要預加載的數據不適合 BlockCache,則不是一個好主意。它可用于調整預取的 IO 影響與所有數據塊在緩存中的時間之間的關系。
要在給定列族上啟用預取,可以使用 HBase Shell 或使用 API??。
使用 HBase Shell 啟用預取
```
hbase> create 'MyTable', { NAME => 'myCF', PREFETCH_BLOCKS_ON_OPEN => 'true' }
```
示例 38.使用 API??啟用預取
```
// ...
HTableDescriptor tableDesc = new HTableDescriptor("myTable");
HColumnDescriptor cfDesc = new HColumnDescriptor("myCF");
cfDesc.setPrefetchBlocksOnOpen(true);
tableDesc.addFamily(cfDesc);
// ...
```
請參閱 [CacheConfig](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/io/hfile/CacheConfig.html) 的 API 文檔。
要查看運行中的預取,請在 hbase-2.0 +中的`org.apache.hadoop.hbase.io.hfile.HFileReaderImpl`或 HBase 的早期版本 hbase-1.x 中的`org.apache.hadoop.hbase.io.hfile.HFileReaderV2`上啟用 TRACE 級別日志記錄。
### 117.6。 `hbase.regionserver.global.memstore.size`
見 [[hbase.regionserver.global.memstore.size]](#hbase.regionserver.global.memstore.size) 。通常根據需要為 RegionServer 進程調整此內存設置。
### 117.7。 `hbase.regionserver.global.memstore.size.lower.limit`
見 [[hbase.regionserver.global.memstore.size.lower.limit]](#hbase.regionserver.global.memstore.size.lower.limit) 。通常根據需要為 RegionServer 進程調整此內存設置。
### 117.8。 `hbase.hstore.blockingStoreFiles`
參見 [[hbase.hstore.blockingStoreFiles]](#hbase.hstore.blockingStoreFiles) 。如果 RegionServer 日志中存在阻塞,則增加此功能會有所幫助。
### 117.9。 `hbase.hregion.memstore.block.multiplier`
參見 [[hbase.hregion.memstore.block.multiplier]](#hbase.hregion.memstore.block.multiplier) 。如果有足夠的 RAM,增加這個可以幫助。
### 117.10。 `hbase.regionserver.checksum.verify`
讓 HBase 將校驗和寫入數據塊,并保存在您閱讀時必須進行校驗和搜索。
見 [[hbase.regionserver.checksum.verify]](#hbase.regionserver.checksum.verify) , [[hbase.hstore.bytes.per.checksum]](#hbase.hstore.bytes.per.checksum) 和 [[hbase.hstore.checksum.algorithm]](#hbase.hstore.checksum.algorithm) 。有關更多信息,請參閱 HBase 塊緩存中 [HBASE-5074 支持校驗和的發行說明。](https://issues.apache.org/jira/browse/HBASE-5074)
### 117.11。調整`callQueue`選項
[HBASE-11355](https://issues.apache.org/jira/browse/HBASE-11355) 引入了幾種可以提高性能的 callQueue 調整機制。有關基準信息,請參閱 JIRA。
要增加呼叫隊列的數量,請將`hbase.ipc.server.num.callqueue`設置為大于`1`的值。要將 callqueue 拆分為單獨的讀寫隊列,請將`hbase.ipc.server.callqueue.read.ratio`設置為`0`和`1`之間的值。此因子將隊列加權寫入(如果低于.5)或讀取(如果高于.5)。另一種說法是,該因子決定了拆分隊列中有多少百分比用于讀取。以下示例說明了一些可能性。請注意,無論您使用何種設置,始終至少有一個寫入隊列。
* `0`的默認值不會拆分隊列。
* 值`.3`使用 30%的隊列進行讀取,60%用于寫入。給定`hbase.ipc.server.num.callqueue`的`10`值,3 個隊列將用于讀取,7 個用于寫入。
* 值`.5`使用相同數量的讀取隊列和寫入隊列。給定`hbase.ipc.server.num.callqueue`的`10`值,5 個隊列將用于讀取,5 個用于寫入。
* 值`.6`使用 60%的隊列進行閱讀,30%進行閱讀。給定`hbase.ipc.server.num.callqueue`的`10`值,7 個隊列將用于讀取,3 個用于寫入。
* 值`1.0`使用一個隊列來處理寫請求,所有其他隊列處理讀請求。高于`1.0`的值與`1.0`的值具有相同的效果。給定`hbase.ipc.server.num.callqueue`的`10`值,9 個隊列將用于讀取,1 個用于寫入。
您還可以拆分讀取隊列,以便通過設置`hbase.ipc.server.callqueue.scan.ratio`選項將單獨的隊列用于短讀取(來自 Get 操作)和長讀取(來自掃描操作)。此選項是介于 0 和 1 之間的因子,它決定了用于獲取和掃描的讀取隊列的比率。如果值低于`.5`,則將更多隊列用于獲取;如果值高于`.5`,則將更多隊列用于掃描。無論您使用何種設置,至少有一個讀取隊列用于 Get 操作。
* 值`0`不會拆分讀取隊列。
* 值`.3`使用 60%的讀取隊列獲取,30%用于掃描。給定`hbase.ipc.server.num.callqueue`的`20`值和`hbase.ipc.server.callqueue.read.ratio`的`.5`值,將有 10 個隊列用于讀取,其中 10 個,7 個用于獲取,3 個用于掃描。
* 值`.5`使用獲取的一半讀取隊列和掃描的一半。給定`hbase.ipc.server.num.callqueue`的`20`值和`hbase.ipc.server.callqueue.read.ratio`的`.5`值,將有 10 個隊列用于讀取,其中 10 個用于獲取,5 個用于掃描。
* 值`.6`使用 30%的讀取隊列獲取,60%用于掃描。給定`hbase.ipc.server.num.callqueue`的`20`值和`hbase.ipc.server.callqueue.read.ratio`的`.5`值,將有 10 個隊列用于讀取,其中 10 個用于獲取,3 個用于掃描。
* 值`1.0`使用除掃描隊列之外的所有讀取隊列。給定`hbase.ipc.server.num.callqueue`的`20`值和`hbase.ipc.server.callqueue.read.ratio`的`.5`值,將有 10 個隊列用于讀取,其中 10 個用于獲取,1 個用于掃描。
您可以使用新選項`hbase.ipc.server.callqueue.handler.factor`以編程方式調整隊列數:
* 值`0`在所有處理程序之間使用單個共享隊列。
* 值`1`為每個處理程序使用單獨的隊列。
* `0`和`1`之間的值會根據處理程序的數量調整隊列數。例如,`.5`的值在每兩個處理程序之間共享一個隊列。
擁有更多隊列(例如,在每個處理程序中有一個隊列的情況下)可以在將任務添加到隊列或從隊列中選擇任務時減少爭用。權衡的是,如果你有一些長時間運行任務的隊列,處理程序可能最終等待從該隊列執行而不是處理另一個具有等待任務的隊列。
要使這些值在給定的 RegionServer 上生效,必須重新啟動 RegionServer。這些參數僅用于測試目的,應謹慎使用。
## 118\. ZooKeeper
有關配置 ZooKeeper 的信息,請參閱 [ZooKeeper](#zookeeper) ,并參閱有關具有專用磁盤的部分。
## 119.架構設計
### 119.1。列族數
參見[關于列族數](#number.of.cfs)。
### 119.2。鍵和屬性長度
請參閱[嘗試最小化行和列大小](#keysize)。另見[但是......](#perf.compression.however) 用于壓縮警告。
### 119.3。表 RegionSize
在某些表需要與配置的默認區域大小不同的區域大小的情況下,可以通過 [HTableDescriptor](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/HTableDescriptor.html) 上的`setFileSize`在每個表的基礎上設置區域大小。
有關詳細信息,請參閱[確定區域計數和大小](#ops.capacity.regions)。
### 119.4。布隆過濾器
以其創建者 Burton Howard Bloom 命名的 Bloom 過濾器是一種數據結構,旨在預測給定元素是否是一組數據的成員。 Bloom 過濾器的陽性結果并不總是準確的,但保證陰性結果是準確的。布隆過濾器被設計成對于數據集“足夠準確”,這些數據集非常大以至于傳統的散列機制是不切實際的。有關 Bloom 過濾器的更多信息,請參閱 [http://en.wikipedia.org/wiki/Bloom_filter](http://en.wikipedia.org/wiki/Bloom_filter) 。
就 HBase 而言,Bloom 過濾器提供了一個輕量級的內存結構,以便將給定 Get 操作(Bloom 過濾器不能與 Scans 一起使用)的磁盤讀取次數減少到僅可能包含所需 Row 的 StoreFiles。潛在的性能增益隨著并行讀取的數量而增加。
Bloom 過濾器本身存儲在每個 HFile 的元數據中,永遠不需要更新。當因為區域部署到 RegionServer 而打開 HFile 時,Bloom 過濾器將加載到內存中。
HBase 包括一些調整機制,用于折疊 Bloom 過濾器以減小大小并將誤報率保持在所需范圍內。
在 [HBASE-1200](https://issues.apache.org/jira/browse/HBASE-1200) 中引入了 Bloom 過濾器。自 HBase 0.96 起,默認情況下啟用基于行的 Bloom 過濾器。 ( [HBASE-8450](https://issues.apache.org/jira/browse/HBASE-8450) )
有關與 HBase 相關的布隆過濾器的更多信息,請參閱[布隆過濾器](#blooms)以獲取更多信息,或參考以下 Quora 討論:[如何在 HBase 中使用布隆過濾器?](http://www.quora.com/How-are-bloom-filters-used-in-HBase) 。
#### 119.4.1。何時使用布隆過濾器
自 HBase 0.96 起,默認情況下啟用基于行的 Bloom 過濾器。您可以選擇禁用它們或更改某些表以使用行+列 Bloom 過濾器,具體取決于數據的特征以及如何將其加載到 HBase 中。
要確定 Bloom 過濾器是否會產生積極影響,請檢查 RegionServer 度量標準中的`blockCacheHitRatio`值。如果啟用了布隆過濾器,則`blockCacheHitRatio`的值應該增加,因為布隆過濾器正在過濾掉絕對不需要的塊。
您可以選擇為行或行+列組合啟用 Bloom 過濾器。如果您通常掃描整行,則行+列組合不會提供任何好處。基于行的 Bloom 過濾器可以在行+列 Get 上運行,但不能相反。但是,如果您有大量的列級 Puts,這樣每個 StoreFile 中可能存在一行,則基于行的過濾器將始終返回正結果并且不會帶來任何好處。除非每行有一列,否則行+列布隆過濾器需要更多空間,以便存儲更多鍵。當每個數據條目的大小至少為幾千字節時,Bloom 過濾器最有效。
當您的數據存儲在幾個較大的 StoreFiles 中時,開銷將減少,以避免在低級掃描期間額外的磁盤 IO 以查找特定行。
Bloom 過濾器需要在刪除時重建,因此可能不適合具有大量刪除的環境。
#### 119.4.2。啟用布隆過濾器
在列族上啟用布隆過濾器。您可以使用 HColumnDescriptor 的 setBloomFilterType 方法或使用 HBase API 來完成此操作。有效值為`NONE`,`ROW`(默認值)或`ROWCOL`。有關`ROW`與`ROWCOL`的更多信息,請參見[何時使用布隆過濾器](#bloom.filters.when)。另請參閱 [HColumnDescriptor](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/HColumnDescriptor.html) 的 API 文檔。
以下示例創建一個表,并在`colfam1`列族上啟用 ROWCOL Bloom 過濾器。
```
hbase> create 'mytable',{NAME => 'colfam1', BLOOMFILTER => 'ROWCOL'}
```
#### 119.4.3。配置 Bloom 過濾器的服務器范圍行為
您可以在 _hbase-site.xml_ 中配置以下設置。
| 參數 | 默認 | 描述 |
| --- | --- | --- |
| io.storefile.bloom.enabled | 是 | 如果出現問題,設置為 no 以殺死服務器范圍內的 bloom 過濾器 |
| io.storefile.bloom.error.rate | 0.01 | 布隆過濾器的平均誤報率。折疊用于維持誤報率。表示為百分比的十進制表示。 |
| io.storefile.bloom.max.fold | 7 | 保證最大折疊率。不需要更改此設置,不建議這樣做。 |
| io.storefile.bloom.max.keys | 1.28 | 對于默認(單塊)布隆過濾器,它指定最大鍵數。 |
| io.storefile.delete.family.bloom.enabled | 真正 | 主開關啟用 Delete Family Bloom 過濾器并將其存儲在 StoreFile 中。 |
| io.storefile.bloom.block.size | 131072 | 目標 Bloom 塊大小。大約這個大小的布隆過濾器塊與數據塊交織。 |
| hfile.block.bloom.cacheonwrite | 假 | 為復合布隆過濾器的內聯塊啟用寫入高速緩存。 |
### 119.5。 ColumnFamily BlockSize
可以為表中的每個 ColumnFamily 配置 blocksize,默認為 64k。較大的單元值需要較大的塊大小。 blocksize 與生成的 StoreFile 索引之間存在反比關系(即,如果塊大小加倍,則結果索引應大致減半)。
有關詳細信息,請參閱 [HColumnDescriptor](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/HColumnDescriptor.html) 和 [Store](#store) 。
### 119.6。內存列家庭
ColumnFamilies 可以選擇定義為內存中。數據仍然保留在磁盤上,就像任何其他 ColumnFamily 一樣。內存塊在[塊緩存](#block.cache)中具有最高優先級,但不保證整個表將在內存中。
有關詳細信息,請參閱 [HColumnDescriptor](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/HColumnDescriptor.html) 。
### 119.7。壓縮
生產系統應使用其 ColumnFamily 定義進行壓縮。有關詳細信息,請參閱 HBase 中的[壓縮和數據塊編碼。](#compression)
#### 119.7.1。然而...
壓縮會壓縮磁盤上的數據 _。當它在內存中(例如,在 MemStore 中)或在線上(例如,在 RegionServer 和 Client 之間傳輸)時,它會膨脹。因此,雖然使用 ColumnFamily 壓縮是最佳做法,但它不會完全消除過大的 Keys,超大的 ColumnFamily 名稱或超大的列名稱的影響。_
請參閱[嘗試最小化模式設計技巧的行和列大小](#keysize),以及 [KeyValue](#keyvalue) 以獲取有關 HBase 內部存儲數據的更多信息。
## 120\. HBase 一般模式
### 120.1。常量
當人們開始使用 HBase 時,他們傾向于編寫如下代碼:
```
Get get = new Get(rowkey);
Result r = table.get(get);
byte[] b = r.getValue(Bytes.toBytes("cf"), Bytes.toBytes("attr")); // returns current version of value
```
但特別是當內部循環(和 MapReduce 作業)時,將 columnFamily 和 column-names 重復轉換為字節數組的成本非常高。最好對字節數組使用常量,如下所示:
```
public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Get get = new Get(rowkey);
Result r = table.get(get);
byte[] b = r.getValue(CF, ATTR); // returns current version of value
```
## 121.寫給 HBase
### 121.1。批量加載
如果可以,請使用批量加載工具。參見[批量加載](#arch.bulk.load)。否則,請注意以下內容。
### 121.2。表創建:預創建區域
默認情況下,HBase 中的表最初是使用一個區域創建的。對于批量導入,這意味著所有客戶端都將寫入同一區域,直到它足夠大,可以拆分并在集群中分布。加速批量導入過程的有用模式是預先創建空白區域。在這方面要保守一些,因為太多的地區實際上會降低性能。
使用 HBase API 預創建拆分有兩種不同的方法。第一種方法是依賴默認的`Admin`策略(在`Bytes.split`中實現)...
```
byte[] startKey = ...; // your lowest key
byte[] endKey = ...; // your highest key
int numberOfRegions = ...; // # of regions to create
admin.createTable(table, startKey, endKey, numberOfRegions);
```
另一種使用 HBase API 的方法是自己定義分割...
```
byte[][] splits = ...; // create your own splits
admin.createTable(table, splits);
```
使用 HBase Shell 可以通過指定拆分選項來創建表,從而實現類似的效果。
```
# create table with specific split points
hbase>create 't1','f1',SPLITS => ['\x10\x00', '\x20\x00', '\x30\x00', '\x40\x00']
# create table with four regions based on random bytes keys
hbase>create 't2','f1', { NUMREGIONS => 4 , SPLITALGO => 'UniformSplit' }
# create table with five regions based on hex keys
create 't3','f1', { NUMREGIONS => 5, SPLITALGO => 'HexStringSplit' }
```
有關理解鍵空間和預創建區域的相關問題,請參閱 [RowKeys 和 Region Splits](#rowkey.regionsplits) 之間的關系。有關手動預分割區域的討論,請參見[手動區域分割決策](#manual_region_splitting_decisions)。有關使用 HBase Shell 預分割表的更多詳細信息,請參見[使用 HBase Shell](#tricks.pre-split) 預分割表。
### 121.3。表創建:延遲日志刷新
使用預寫日志(WAL)的 Puts 的默認行為是將立即寫入`WAL`編輯。如果使用延遲日志刷新,則 WAL 編輯將保留在內存中直到刷新周期。好處是聚合和異步`WAL` - 寫入,但潛在的缺點是如果 RegionServer 發生故障,則尚未刷新的編輯將丟失。然而,這比使用 Puts 完全不使用 WAL 更安全。
可以通過 [HTableDescriptor](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/HTableDescriptor.html) 在表上配置延遲日志刷新。 `hbase.regionserver.optionallogflushinterval`的默認值為 1000ms。
### 121.4。 HBase 客戶端:在 Puts 上關閉 WAL
經常請求禁用 WAL 以提高 Puts 的性能。這僅適用于批量加載,因為它會在區域服務器崩潰時通過刪除 WAL 的保護來使您的數據處于危險之中。在發生崩潰時可以重新運行批量加載,幾乎沒有數據丟失的風險。
> 如果禁用 WAL 而不是批量加載,則數據存在風險。
通常,最好使用 WAL for Puts,而使用批量加載技術時,加載吞吐量是一個問題。對于正常的 Puts,您不太可能看到性能改善超過風險。要禁用 WAL,請參閱[禁用 WAL](#wal.disable) 。
### 121.5。 HBase 客戶端:GroupServer 放置的組
除了使用 writeBuffer 之外,通過 RegionServer 對`Put`進行分組可以減少每個 writeBuffer flush 的客戶端 RPC 調用次數。當前在 MASTER 上有一個實用程序`HTableUtil`可以執行此操作,但您可以復制該實用程序,也可以為仍在 0.90.x 或更早版本的版本實現自己的版本。
### 121.6。 MapReduce:跳過 Reducer
當從 MR 作業向 HBase 表寫入大量數據時(例如,使用 [TableOutputFormat](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/mapreduce/TableOutputFormat.html) ),特別是從 Mapper 發出 Puts 的地方,跳過 Reducer 步驟。當使用 Reducer 步驟時,來自 Mapper 的所有輸出(Puts)將被假脫機到磁盤,然后排序/改組到其他很可能是非節點的 Reducers。直接寫入 HBase 效率更高。
對于將 HBase 用作源和接收器的摘要作業,寫入將來自 Reducer 步驟(例如,匯總值然后寫出結果)。這是與上述情況不同的處理問題。
### 121.7。反模式:一個熱點區域
如果所有數據一次寫入一個區域,則重新閱讀有關處理時間序列數據的部分。
此外,如果您正在預分割區域并且所有數據仍然是 _ 仍然 _ 在單個區域中清理,即使您的密鑰沒有單調增加,請確認您的密鑰空間實際上與分離策略一起使用。區域可能出現“分裂”的原因有多種,但不適用于您的數據。由于 HBase 客戶端直接與 RegionServers 通信,因此可以通過 [RegionLocator.getRegionLocation](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/RegionLocator.html#getRegionLocation-byte:A-) 獲得。
參見[表創建:預創建區域](#precreate.regions),以及 [HBase 配置](#perf.configurations)
## 122.從 HBase 讀
如果您遇到性能問題,郵件列表可以提供幫助。例如,這里是關于解決讀取時間問題的一個很好的通用線程: [HBase 隨機讀取延遲> 100 毫秒](http://search-hadoop.com/m/qOo2yyHtCC1)
### 122.1。掃描緩存
例如,如果將 HBase 用作 MapReduce 作業的輸入源,請確保 MapReduce 作業的輸入 [Scan](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Scan.html) 實例將`setCaching`設置為大于默認值(即 1)的值。使用默認值意味著 map-task 將為處理的每個記錄回調 region-server。例如,將此值設置為 500 將一次傳輸 500 行到要處理的客戶端。緩存值很大是有成本/收益的,因為客戶端和 RegionServer 的內存成本更高,因此更大并不總是更好。
#### 122.1.1。在 MapReduce 作業中掃描緩存
MapReduce 作業中的掃描設置值得特別注意。如果在客戶端返回到 RegionServer 以獲取下一組數據之前處理一批記錄需要更長時間,則可能會在 Map 任務中導致超時(例如,UnknownScannerException)。發生此問題的原因是每行發生非平凡處理。如果快速處理行,請將緩存設置得更高。如果您更慢地處理行(例如,每行進行大量轉換,寫入),則將緩存設置得更低。
超時也可能發生在非 MapReduce 用例(即執行掃描的單線程 HBase 客戶端)中,但通常在 MapReduce 作業中執行的處理往往會加劇此問題。
### 122.2。掃描屬性選擇
每當使用掃描處理大量行(特別是用作 MapReduce 源)時,請注意選擇了哪些屬性。如果調用`scan.addFamily`,則 _ 指定 ColumnFamily 中屬性的所有 _ 將返回給客戶端。如果只處理少量可用屬性,則只應在輸入掃描中指定那些屬性,因為屬性過度選擇對大型數據集而言是一個非常重要的性能損失。
### 122.3。避免掃描尋求
當使用`scan.addColumn`顯式選擇列時,HBase 將調度搜索操作以在所選列之間進行搜索。當行包含很少的列而每列只有幾個版本時,這可能效率很低。如果不尋求至少過去 5-10 列/版本或 512-1024 字節,則查找操作通常較慢。
為了機會性地向前看幾個列/版本以查看在調度搜索操作之前是否可以找到下一列/版本,可以在 Scan 對象上設置新屬性`Scan.HINT_LOOKAHEAD`。以下代碼指示 RegionServer 在調度搜索之前嘗試下一次迭代:
```
Scan scan = new Scan();
scan.addColumn(...);
scan.setAttribute(Scan.HINT_LOOKAHEAD, Bytes.toBytes(2));
table.getScanner(scan);
```
### 122.4。 MapReduce - 輸入拆分
對于使用 HBase 表作為源的 MapReduce 作業,如果存在“慢”映射任務似乎具有相同輸入拆分的模式(即,為服務數據提供服務的 RegionServer),請參閱[案例研究中的故障排除案例研究#1(單節點上的性能問題)](#casestudies.slownode)。
### 122.5。關閉 ResultScanners
這不是提高性能,而是 _ 避免 _ 性能問題。如果您忘記關閉 [ResultScanners](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/ResultScanner.html) ,可能會導致 RegionServers 出現問題。始終將 ResultScanner 處理包含在 try / catch 塊中。
```
Scan scan = new Scan();
// set attrs...
ResultScanner rs = table.getScanner(scan);
try {
for (Result r = rs.next(); r != null; r = rs.next()) {
// process result...
} finally {
rs.close(); // always close the ResultScanner!
}
table.close();
```
### 122.6。塊緩存
[Scan](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Scan.html) 實例可以通過`setCacheBlocks`方法設置為使用 RegionServer 中的塊緩存。對于輸入掃描到 MapReduce 作業,這應該是`false`。對于頻繁訪問的行,建議使用塊緩存。
通過在堆外移動塊緩存來緩存更多數據。請參閱[堆外塊緩存](#offheap.blockcache)
### 122.7。行密鑰的最佳加載
執行僅需要行鍵的表[掃描](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Scan.html)時(無族,限定符,值或時間戳),使用`setFilter`將帶有`MUST_PASS_ALL`運算符的 FilterList 添加到掃描儀。過濾器列表應包括 [FirstKeyOnlyFilter](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/FirstKeyOnlyFilter.html) 和 [KeyOnlyFilter](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/KeyOnlyFilter.html) 。使用此過濾器組合將導致 RegionServer 讀取磁盤中的單個值以及單個行的客戶端最小網絡流量的最壞情況。
### 122.8。并發:監控數據傳播
執行大量并發讀取時,監視目標表的數據傳播。如果目標表具有太少的區域,則可能從太少的節點提供讀取。
See [Table Creation: Pre-Creating Regions](#precreate.regions), as well as [HBase Configurations](#perf.configurations)
### 122.9。布隆過濾器
啟用 Bloom 過濾器可以節省您必須轉到磁盤并有助于改善讀取延遲。
[Bloom 過濾器](http://en.wikipedia.org/wiki/Bloom_filter)是在 [HBase-1200 Add bloomfilters](https://issues.apache.org/jira/browse/HBASE-1200) 中開發的。有關開發過程的描述 - 為什么是靜態綻放而不是動態 - 以及有關 HBase 中的綻放的獨特屬性的概述,以及可能的未來方向,請參閱文檔的 _ 開發過程 _ 部分 [HBase](https://issues.apache.org/jira/secure/attachment/12444007/Bloom_Filters_in_HBase.pdf) 中的 BloomFilters 附著于 [HBASE-1200](https://issues.apache.org/jira/browse/HBASE-1200) 。這里描述的布隆過濾器實際上是 HBase 中的第二版布隆。在高達 0.19.x 的版本中,HBase 根據[歐盟委員會一個實驗室項目 034819](http://www.onelab.org) 所做的工作有一個動態綻放選項。 HBase bloom 工作的核心后來被引入 Hadoop 以實現 org.apache.hadoop.io.BloomMapFile。 HBase 綻放的第 1 版從未如此順利。版本 2 是從頭開始重寫,但它再次從單實驗室工作開始。
另請參見[布隆過濾器](#schema.bloom)。
#### 122.9.1。 Bloom StoreFile 足跡
布隆過濾器向`StoreFile`通用`FileInfo`數據結構添加條目,然后向`StoreFile`元數據部分添加兩個額外條目。
##### `StoreFile``FileInfo`數據結構中的 BloomFilter
`FileInfo`有一個`BLOOM_FILTER_TYPE`條目,設置為`NONE`,`ROW`或`ROWCOL.`
##### `StoreFile`元數據中的 BloomFilter 條目
`BLOOM_FILTER_META`保存 Bloom Size,使用的哈希函數等。它的大小很小,并且在`StoreFile.Reader`加載時緩存
`BLOOM_FILTER_DATA`是實際的 bloomfilter 數據。按需獲得。存儲在 LRU 緩存中,如果已啟用(默認情況下已啟用)。
#### 122.9.2。布隆過濾器配置
##### `io.storefile.bloom.enabled`全局殺戮開關
如果出現問題,`Configuration`中的`io.storefile.bloom.enabled`將作為終止開關。默認= `true`。
##### `io.storefile.bloom.error.rate`
`io.storefile.bloom.error.rate` =平均誤報率。默認值= 1%。每個布魯德條目減少?(例如降至 0.5%)== +1 比特。
##### `io.storefile.bloom.max.fold`
`io.storefile.bloom.max.fold` =保證最低折疊率。大多數人應該單獨留下這個。默認值= 7,或者可以折疊到原始大小的至少 1/128。有關此選項的含義的更多信息,請參閱 HBase 文檔 [BloomFilters 的 _ 開發過程 _ 部分。](https://issues.apache.org/jira/secure/attachment/12444007/Bloom_Filters_in_HBase.pdf)
### 122.10。對沖讀數
對沖讀取是 HDFS 的一個特性,在 Hadoop 2.4.0 中引入了 [HDFS-5776](https://issues.apache.org/jira/browse/HDFS-5776) 。通常,為每個讀取請求生成一個線程。但是,如果啟用了對沖讀取,則客戶端會等待一些可配置的時間,如果讀取未返回,則客戶端會針對相同數據的不同塊副本生成第二個讀取請求。無論先使用哪個讀取返回,都會丟棄另一個讀取請求。
對沖讀取是“......非常擅長消除異常數據節點,這反過來使它們成為延遲敏感設置的非常好的選擇。但是,如果您正在尋找最大化吞吐量,對沖讀取往往會產生負載放大,因為一般情況下變慢。簡而言之,需要注意的是當您運行接近某個吞吐量閾值時,非優雅的性能下降。“ (引自 Ashu Pachauri 的 HBASE-17083)。
在啟用對沖讀取的情況下運行時要記住的其他問題包括:
* 它們可能導致網絡擁塞。見 [HBASE-17083](https://issues.apache.org/jira/browse/HBASE-17083)
* 確保將線程池設置得足夠大,以便池上的阻塞不會成為瓶頸(再次參見 [HBASE-17083](https://issues.apache.org/jira/browse/HBASE-17083) )
(來自 HBASE-17083 的 Yu Li)
由于 HBase RegionServer 是 HDFS 客戶端,因此您可以在 HBase 中啟用對沖讀取,方法是將以下屬性添加到 R??egionServer 的 hbase-site.xml 并調整值以適合您的環境。
對沖讀數的配置
* `dfs.client.hedged.read.threadpool.size` - 專用于服務對沖讀取的線程數。如果將其設置為 0(默認值),則禁用對沖讀取。
* `dfs.client.hedged.read.threshold.millis` - 產生第二個讀取線程之前等待的毫秒數。
例 39.對沖讀取配置示例
```
<property>
<name>dfs.client.hedged.read.threadpool.size</name>
<value>20</value> <!-- 20 threads -->
</property>
<property>
<name>dfs.client.hedged.read.threshold.millis</name>
<value>10</value> <!-- 10 milliseconds -->
</property>
```
使用以下指標調整群集上對沖讀取的設置。有關詳細信息,請參閱 [HBase 指標](#hbase_metrics)。
對沖讀數的指標
* hedgedReadOps - 已觸發對沖讀取線程的次數。這可能表明讀取請求通常很慢,或者對沖讀取的觸發過快。
* hedgeReadOpsWin - 對沖讀取線程比原始線程快的次數。這可能表示給定的 RegionServer 在處理請求時遇到問題。
## 123.從 HBase 刪除
### 123.1。使用 HBase 表作為隊列
HBase 表有時用作隊列。在這種情況下,必須特別注意定期對以這種方式使用的表格進行主要壓縮。如[數據模型](#datamodel)中所述,將行標記為已刪除會創建額外的 StoreFiles,然后需要在讀取時對其進行處理。墓碑只能通過主要壓縮來清理。
另見[壓縮](#compaction)和 [Admin.majorCompact](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Admin.html#majorCompact-org.apache.hadoop.hbase.TableName-) 。
### 123.2。刪除 RPC 行為
請注意`Table.delete(Delete)`不使用 writeBuffer。它將在每次調用時執行 RegionServer RPC。對于大量刪除,請考慮`Table.delete(List)`。
見 [hbase.client.Delete](https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Table.html#delete-org.apache.hadoop.hbase.client.Delete-)
## 124\. HDFS
因為 HBase 在 [HDFS](#arch.hdfs) 上運行,所以了解它是如何工作以及它如何影響 HBase 是很重要的。
### 124.1。低延遲讀取的當前問題
HDFS 的原始用例是批處理。因此,低延遲讀取在歷史上不是優先事項。隨著 Apache HBase 的采用日益增多,這種情況正在發生變化,并且已經在開發中進行了一些改進。有關 HBase 的 HDFS 改進,請參閱 [Umbrella Jira Ticket。](https://issues.apache.org/jira/browse/HDFS-1599)
### 124.2。利用本地數據
由于 Hadoop 1.0.0(也是 0.22.1,0.23.1,CDH3u3 和 HDP 1.0)通過 [HDFS-2246](https://issues.apache.org/jira/browse/HDFS-2246) ,DFSClient 可以進行“短路”并直接從磁盤讀取當數據是本地數據時,而不是通過 DataNode。對于 HBase 來說,這意味著 RegionServers 可以直接讀取其機器的磁盤,而不必打開套接字與 DataNode 通信,前者通常要快得多。參見 JD 的 [Performance Talk](http://files.meetup.com/1350427/hug_ebay_jdcryans.pdf) 。另請參閱 [HBase,郵件#dev - 讀取短路](http://search-hadoop.com/m/zV6dKrLCVh1)線程,以獲得有關短路讀取的更多討論。
要啟用“短路”讀取,它將取決于您的 Hadoop 版本。在 [HDFS-347](https://issues.apache.org/jira/browse/HDFS-347) 中,Hadoop 2 中的原始短路讀取補丁得到了很大改善。參見 [http://blog.cloudera.com/blog/2013/08/how-improved-short-circuit-local-reads-bring-better-performance-and-security-to-hadoop/](http://blog.cloudera.com/blog/2013/08/how-improved-short-circuit-local-reads-bring-better-performance-and-security-to-hadoop/) for 有關舊實現和新實現之間差異的詳細信息。參見 [Hadoop 短路讀取配置頁面](http://archive.cloudera.com/cdh4/cdh/4/hadoop/hadoop-project-dist/hadoop-hdfs/ShortCircuitLocalReads.html),了解如何啟用后者,更好的短路版本。例如,這是一個最小配置。啟用短路讀取添加到 _hbase-site.xml_ :
```
<property>
<name>dfs.client.read.shortcircuit</name>
<value>true</value>
<description>
This configuration parameter turns on short-circuit local reads.
</description>
</property>
<property>
<name>dfs.domain.socket.path</name>
<value>/home/stack/sockets/short_circuit_read_socket_PORT</value>
<description>
Optional. This is a path to a UNIX domain socket that will be used for
communication between the DataNode and local HDFS clients.
If the string "_PORT" is present in this path, it will be replaced by the
TCP port of the DataNode.
</description>
</property>
```
注意托管共享域套接字的目錄的權限;如果對 hbase 用戶以外的其他人開放,dfsclient 會抱怨。
如果您運行的是舊的 Hadoop,沒有 [HDFS-347](https://issues.apache.org/jira/browse/HDFS-347) ,但有 [HDFS-2246](https://issues.apache.org/jira/browse/HDFS-2246) ,則必須設置兩個配置。首先,需要修改 hdfs-site.xml。將屬性`dfs.block.local-path-access.user`設置為可以使用快捷方式的 _ 僅 _ 用戶。這必須是啟動 HBase 的用戶。然后在 hbase-site.xml 中,將`dfs.client.read.shortcircuit`設置為`true`
服務 - 至少是 HBase RegionServers - 需要重新啟動才能獲取新配置。
> dfs.client.read.shortcircuit.buffer.size
>
> 在高流量的 HBase 上運行時,此值的默認值太高。在 HBase 中,如果尚未設置此值,我們將其從默認值 1M 設置為 128k(自 HBase 0.98.0 和 0.96.1 起)。請參閱 Hadoop 2 上的 [HBASE-8143 HBase,本地短路讀取(ssr)會導致 OOM](https://issues.apache.org/jira/browse/HBASE-8143) 。 HBase 中的 Hadoop DFSClient 將為 _ 分配一個這個大小的直接字節緩沖區,每個 _ 塊已打開;鑒于 HBase 始終保持其 HDFS 文件打開,這可以快速加起來。
### 124.3。 HBase 與 HDFS 的性能比較
關于 dist-list 的一個相當常見的問題是為什么 HBase 不如批處理上下文中的 HDFS 文件那樣高效(例如,作為 MapReduce 源或接收器)。簡短的回答是 HBase 比 HDFS 做得更多(例如,讀取 KeyValues,返回最新的行或指定的時間戳等),因此 HBase 在此處理環境中比 HDFS 慢 4-5 倍。還有改進的余地,隨著時間的推移,這個差距會縮小,但在這個用例中 HDFS 總是會更快。
## 125.亞馬遜 EC2
性能問題在 Amazon EC2 環境中很常見,因為它是一個共享環境。您將看不到與專用服務器相同的吞吐量。在 EC2 上運行測試時,出于同樣的原因多次運行它們(即,它是共享環境,您不知道服務器上還發生了什么)。
如果您在 EC2 上運行并在 dist-list 上發布性能問題,請事先說明這一事實,因為 EC2 問題實際上是一類獨立的性能問題。
## 126.配置 HBase 和 MapReduce
通常建議為 HBase 和 MapReduce 使用不同的集群。對此更好的限定是:不要將提供實時請求的 HBase 與重 MR 工作負載并置。 OLTP 和 OLAP 優化的系統具有相互沖突的要求,而另一個將失去另一個,通常是前者。例如,短暫的延遲敏感磁盤讀取將不得不排在較長的讀取后面,這些讀取試圖擠出盡可能多的吞吐量。寫入 HBase 的 MR 作業也會產生刷新和壓縮,這反過來會使 [Block Cache](#block.cache) 中的塊無效。
如果需要處理 MR 中的實時 HBase 集群中的數據,可以使用 [CopyTable](#copy.table) 發送增量,或使用復制在 OLAP 集群上實時獲取新數據。在最壞的情況下,如果您確實需要并置兩者,請將 MR 設置為使用比您通常配置的更少的 Map 和 Reduce 插槽,可能只需一個。
當 HBase 用于 OLAP 操作時,最好以強化的方式設置它,例如將 ZooKeeper 會話超時配置得更高并為 MemStores 提供更多內存(因為工作負載是因為塊緩存不會被使用很多通常很長的掃描)。
## 127.案例研究
有關性能和故障排除案例研究,請參閱 [Apache HBase 案例研究](#casestudies)。
- 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