HBase1.2官方文檔——Architecture

架構 Architecture

63. 概述 Overview

63.1. NoSQL?

HBase是一種 "NoSQL" 數據庫。"NoSQL"是一個通用詞表示數據庫不是RDBMS ,後者支持 SQL 做爲主要訪問語言。有許多種 NoSQL 數據庫: BerkeleyDB 是本地 NoSQL 數據庫例子, 而 HBase 是大型分佈式數據庫。技術上來講, HBase 更像是"數據存儲(Data Store)" 多於 "數據庫(Data Base)",由於缺乏不少RDBMS特性, 如列類型,第二索引,觸發器,高級查詢語言等。html

然而, HBase 有許多特徵同時支持線性化和模塊化擴充。HBase 集羣經過增長RegionServers進行擴充,RegionServer能夠運行在普通的服務器中。例如,若是集羣從10個擴充到20個RegionServer,存儲空間和處理容量都同時翻倍。RDBMS 也能很好擴充,但僅對一個點——特別是對一個單獨數據庫服務器的大小 - 同時,爲了更好的性能,須要特殊的硬件和存儲設備。 HBase的特性有:前端

  • 強一致性讀寫: HBase 不是 "最終一致性(eventually consistent)" 數據存儲. 這讓它很適合高速計數聚合類任務。java

  • 自動分片(Automatic sharding): HBase 表經過region分佈在集羣中。數據增加時,region會自動分割並從新分佈。node

  • RegionServer 自動故障恢復web

  • Hadoop/HDFS 集成: HBase 支持本機外HDFS 做爲它的分佈式文件系統。正則表達式

  • MapReduce: HBase 經過MapReduce支持大併發處理, HBase 能夠同時作源和目標。算法

  • Java 客戶端 API: HBase 支持易於使用的 Java API 進行編程訪問。sql

  • Thrift/REST API: HBase 也支持Thrift 和 REST 做爲非Java 前端.shell

  • Block Cache 和 Bloom Filters: 對於大容量查詢優化, HBase支持 Block Cache 和 Bloom Filters。數據庫

  • 運維管理: HBase提供內置網頁用於運維視角和JMX 度量.

63.2. 何時用 HBase?

HBase不適合全部問題。

首先,確信有足夠多數據,若是有上億或上千億行數據,HBase是很好的備選。 若是隻有上千或上百萬行,則用傳統的RDBMS多是更好的選擇,由於全部數據能夠在一兩個節點保存,集羣其餘節點可能閒置。

其次,確信能夠不依賴全部RDBMS的額外特性 (e.g., 列數據類型, 第二索引, 事務,高級查詢語言等.) 一個創建在RDBMS上應用,如不能僅經過改變一個JDBC驅動移植到HBase。相對於移植, 需考慮從RDBMS 到 HBase是一次徹底的從新設計。 

第三, 確信你有足夠硬件。甚至 HDFS 在小於5個數據節點時,幹很差什麼事情 (根據如 HDFS 塊複製具備缺省值 3), 還要加上一個 NameNode.

HBase 能在單獨的筆記本上運行良好。但這應僅當成開發配置。

63.3. HBase 和 Hadoop/HDFS的區別?

HDFS 是分佈式文件系統,適合保存大文件。官方宣稱它並不是普通用途文件系統,不提供文件的個別記錄的快速查詢。 另外一方面,HBase基於HDFS且提供大表的記錄快速查找(和更新)。這有時可能引發概念混亂。 HBase 內部將數據放到索引好的 "存儲文件(StoreFiles)" ,以便高速查詢。存儲文件位於 HDFS中。參考數據模型 和該章其餘內容獲取更多HBase如何達到它的目標的信息。

64. 目錄表 Catalog Tables

目錄表 -ROOT- 和 .META.(hbase:meta)做爲 HBase 表存在。他們被HBase shell的 list 命令過濾掉了, 但他們和其餘表同樣存在。

64.1. -ROOT-(在0.96.0時就已經沒有-ROOT-表了)

-ROOT- 表在HBase 0.96.0被移除了。能夠認爲這裏的信息是歷史信息。

 

 

在HBase0.96以前,-ROOT- 保存 .META. 表(這是以前的名字,如今.META表的名字是 hbase:meta)存在哪裏的蹤影。 -ROOT- 表結構以下:

Key

  • .META. region key (.META.,,1)

Values

  • info:regioninfo (序列化hbase:meta的 HRegionInfo 實例)

  • info:server (保存hbase:meta的RegionServer的server:port)

  • info:serverstartcode (保存hbase:meta的RegionServer進程啓動時間)

64.2. hbase:meta

hbase:meta表(以前名爲 .META.)保存系統中全部region列表。hbase:meta的位置以前是在 -ROOT-表中跟蹤的,可是如今存儲在ZooKeeper裏了。

hbase:meta表結構以下:

Key

  • Region key的格式 ([table],[region start key],[region id])

Values

  • info:regioninfo (當前Region的序列化的 HRegionInfo 實例)

  • info:server (含有這個Region的RegionServer的server:port)

  • info:serverstartcode (含有這個Region的RegionServer進程的啓動時間)

當一個表在分割過程當中,會建立額外的兩列, info:splitA 和 info:splitB 表明兩個女兒 region。這兩列的值一樣是序列化HRegionInfo 實例。在Region最終分割完畢後,這行會被刪除。

HRegionInfo的備註:

空 key 用於指示表的開始和結束。具備空開始鍵值的region是表內的首region。 若是 region 同時有空起始和結束key,說明它是表內的惟一region。

 

 

 

在須要編程訪問(但願不要)目錄元數據時,參考 Writables 工具。

64.3. 啓動時序 Startup Sequencing

首先,hbase:meta 地址在ZooKeeper中查詢。其次,hbase:meta會更新 server 和 startcode 的值。

須要 region-RegionServer 分配信息, 參考Region-RegionServer Assignment

65. 客戶端

HBase客戶端找到服務於特定行範圍的RegionServer。它經過查詢hbase:meta表來作這件事。參見hbase:meta獲取細節。在定位到須要的Region後,客戶端會聯繫服務這個Region的的RegionServer,而不通過master,併發起讀寫請求。這些信息會緩存在客戶端,這樣就不用每發起一個請求就去查一下。由於master load balance或者RegionServer已死,一個Region會被從新分配,客戶端就會從新查詢目錄表,以決定要去訪問的這個用戶Region的新地址。 

參考Runtime Impact  以獲取更多關於Master對HBase客戶端通訊的影響的信息

管理集羣操做是經由 Admin 實例發起的。 

65.1. 集羣鏈接 Cluster Connections

相關的API在HBase 1.0中有改變。關於鏈接配置的信息,參考 Client configuration and dependencies connecting to an HBase cluster

65.1.1. HBase 1.0.0的API

它已經被清理乾淨,返回給用戶的是用來工做的接口,而不是特定的類型。

在HBase 1.0,從ConnectionFactory獲取一個Connection對象,而後根據須要從這個Connection對象中獲取Table、Admin和RegionLocator的實例。作完了,就關掉得到的實例。最終,在退出以前確保清理你的Connection實例。Connections是重量級的對象,但它是線程安全的,因此你能夠爲你的應用建立一個Connection實例,而後保留它。Table, Admi和RegionLocator實例是輕量級的。要建立它們就去作,用完了就當即關閉它們。參考Client Package Javadoc Description,以獲取新的HBase1.0 API的使用例子。

65.1.2. HBase 1.0.0以前的API

在1.0.0以前,HTable實例是與一個HBase集羣交互的方式。Table實例不是線程安全的。在任意時間,只有一個線程能夠使用Table的一個實例。

當建立Table實例時,推薦使用相同的HBaseConfiguration實例。這將確保將ZooKeeper和套接字實例共享給RegionServer,這一般是您想要的。首選的例子是:

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");

參考ConnectionFactory 以獲取關於鏈接在HBase客戶端是如何處理的信息。

鏈接池Connection Pooling

對須要高端多線程訪問的應用 (如網頁服務器或應用服務器須要在一個JVM服務不少應用線程),你能夠事先建立一個Connection,像下面的例子展現的那樣:

Example 37. Pre-Creating a Connection
// Create a connection to the cluster.
Configuration conf = HBaseConfiguration.create();
try (Connection connection = ConnectionFactory.createConnection(conf)) {
  try (Table table = connection.getTable(TableName.valueOf(tablename)) {
    // use table as needed, the table returned is lightweight
  }
}

構建HTableInterface的實現是很是輕量級的,而且能夠控制資源。

HTablePool被棄用了

這個guide以前的版本討論了在HBase 0.9四、0.95和0.96中棄用的HTablePool,因HBASE-6500它已經在0.98.1中移除了。HConnection在HBase 1.0被棄用,代之以Connection. 請使用 Connection.

 

 

65.2. 寫緩衝和批量操做方法  WriteBuffer and Batch Methods

在HBase1.0及之後,HTable被棄用了以支持使用Table。Table不使用自動flush。要緩衝寫,使用BufferedMutator類。

在Table或HTable實例被廢棄前,調用close() 或 flushCommits(),使'Put'不會丟失。

有關寫持久性的額外信息,複習ACID頁面。

要細粒度控制對放或刪除的批處理,請參閱Table上的batch方法。

65.3. 外部客戶端 External Clients

關於非Java客戶端和自定義協議信息,在Apache HBase External APIs

66. 客戶端請求過濾器 Client Request Filters

Get 和 Scan 實例能夠用 filters 配置,以應用於 RegionServer.

過濾器可能會搞混,由於有不少類型的過濾器, 最好經過理解過濾器功能組來了解他們。

66.1. 結構過濾器 Structural

結構過濾器包含其餘過濾器。

66.1.1. FilterList

FilterList 表明一個過濾器列表,過濾器間具備 FilterList.Operator.MUST_PASS_ALL 或 FilterList.Operator.MUST_PASS_ONE 關係。下面示例展現兩個過濾器的'或'關係(檢查同一屬性的'my value' 或'my other value' ).

FilterList list = new FilterList(FilterList.Operator.MUST_PASS_ONE);
SingleColumnValueFilter filter1 = new SingleColumnValueFilter(
  cf,
  column,
  CompareOp.EQUAL,
  Bytes.toBytes("my value")
  );
list.add(filter1);
SingleColumnValueFilter filter2 = new SingleColumnValueFilter(
  cf,
  column,
  CompareOp.EQUAL,
  Bytes.toBytes("my other value")
  );
list.add(filter2);
scan.setFilter(list);

66.2. 列值  Column Value

66.2.1. SingleColumnValueFilter

SingleColumnValueFilter (參見: http://hbase.apache.org/1.2/apidocs/org/apache/hadoop/hbase/filter/SingleColumnValueFilter.html) 用於測試列值相等 (CompareOp.EQUAL), 不相等 (CompareOp.NOT_EQUAL), 或範圍 (如 CompareOp.GREATER)。下面的例子是測試一個列值等於字符串值"my value"…​

SingleColumnValueFilter filter = new SingleColumnValueFilter(
  cf,
  column,
  CompareOp.EQUAL,
  Bytes.toBytes("my value")
  );
scan.setFilter(filter);

66.3. 列值比較器 Column Value Comparators

過濾器包內有好幾種比較器類須要特別說起。這些比較器和其餘過濾器一塊兒使用, 如SingleColumnValueFilter

66.3.1. RegexStringComparator

RegexStringComparator 支持值比較的正則表達式 。

RegexStringComparator comp = new RegexStringComparator("my.");   // any value that starts with 'my'
SingleColumnValueFilter filter = new SingleColumnValueFilter(
  cf,
  column,
  CompareOp.EQUAL,
  comp
  );
scan.setFilter(filter);

參考 Oracle JavaDoc 瞭解 supported RegEx patterns in Java.

66.3.2. SubstringComparator

SubstringComparator 用於檢測一個子串是否存在於值中。大小寫不敏感。

SubstringComparator comp = new SubstringComparator("y val");   // looking for 'my value'
SingleColumnValueFilter filter = new SingleColumnValueFilter(
  cf,
  column,
  CompareOp.EQUAL,
  comp
  );
scan.setFilter(filter);

66.3.3. BinaryPrefixComparator

66.3.4. BinaryComparator

66.4. 鍵值元數據 KeyValue Metadata

因爲HBase 內部採用鍵值對保存數據,鍵值元數據過濾器評估一行的鍵是否存在(如 ColumnFamily:Column qualifiers) , 對應前節所述值的狀況。

66.4.1. FamilyFilter

FamilyFilter 用於過濾列族。 一般,在Scan中選擇ColumnFamilie優於在過濾器中作。

66.4.2. QualifierFilter

QualifierFilter 用於基於列名(即 Qualifier)過濾。

66.4.3. ColumnPrefixFilter

ColumnPrefixFilter 可基於列名(即Qualifier)前綴過濾。

ColumnPrefixFilter在前面的第一個列中尋找每一行的前綴和每一個相關的列族。它能夠用於在很是寬的行中有效地獲取列的子集。

注意:相同的列標識符能夠在不一樣的列族中使用。這個過濾器返回全部匹配的列。

例: 找出一行中全部的名字開頭爲"abc"的列

HTableInterface 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();

66.4.4. MultipleColumnPrefixFilter

MultipleColumnPrefixFilter 和 ColumnPrefixFilter 行爲差很少,但能夠指定多個前綴。

和ColumnPrefixFilter類似,MultipleColumnPrefixFilter有效地尋求提早第一列匹配的最低位的前綴,而且在前綴之間尋找列的範圍。它能夠用來有效地從很是寬的行中獲取不連續的列。

例: 找出行中全部的列名開頭爲"abc" 或 "xyz"的列

HTableInterface 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();

66.4.5. ColumnRangeFilter

ColumnRangeFilter 能夠進行高效內部掃描。

ColumnRangeFilter能夠爲每一個相關的列族查找第一個匹配列。它能夠用來有效地在一個很寬的行中獲得一個列「切片」。例如,你一行有一百萬個列但你只想查看列bbbb到列bbdd的值。

注意:相同的列限定符能夠在不一樣的列族中使用。這個過濾器返回全部匹配的列。

例如: 找出一行中全部的列和列族,列範圍在"bbbb" (含bbbb) 和 "bbdd" (含bbdd)之間

HTableInterface 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中引入

66.5. 行鍵 RowKey

66.5.1. RowFilter

一般認爲行選擇時Scan採用 startRow/stopRow 方法比較好。然而RowFilter 也能夠用。

66.6. Utility

66.6.1. FirstKeyOnlyFilter

這主要用於rowcount做業。參考 FirstKeyOnlyFilter.

67. 主服務器  Master

HMaster 是Master Server的實現。主服務器(Master Server)負責監控集羣中的全部RegionServer實例,而且是全部元數據更改的接口。在一個分佈式集羣,Master一般會運行在NameNode節點上。

J Mohamed Zahoor 在發表的blog HBase HMaster Architecture中探究了關於Master結構更多的細節。

67.1. 啓動行爲 Startup Behavior

若是在一個一主多備的環境中運行,全部的備(standby Master)都爭着運行集羣。若是激活狀態的主(Master)失去了它在ZooKeeper中的租約(或者這個主關閉了),那麼剩下的備爭奪成爲主。

67.2. 運行時的影響 Runtime Impact

一個常見的問題是到當主服務器Master宕機時,HBase集羣會發生什麼狀況。由於HBase客戶端直接與RegionServer通訊,集羣仍然能夠在「穩定狀態」中運行。

另外,每一個Catalog Tableshbase:meta做爲HBase表存在,並不常駐Master。可是,Master控制關鍵的功能,好比RegionServer故障恢復和完成Region分裂。

所以,雖然集羣在沒有主服務器的狀況下仍然能夠運行很短的時間,但仍是應該儘快從新啓動主服務器。

67.3. 接口 Interface

HMasterInterface公開的方法主要是面向元數據的方法:

  • 表 (createTable, modifyTable, removeTable, enable, disable)

  • 列族 (addColumn, modifyColumn, removeColumn)

  • Region (move, assign, unassign)

例如, 當 Admin 的方法 disableTable 被調用時, 它由主服務器(Master server)提供服務。

67.4. 進程 Processes

Master 後臺運行幾種線程:

67.4.1. 負載均衡器 LoadBalancer

週期性的以及在過渡期間,當沒有任何Region時,負載平衡器將運行並移動各個Region以平衡集羣的負載。參見Balancer設置這個屬性。

參考 Region-RegionServer Assignment 以獲取更多關於Region分配的信息。

67.4.2. CatalogJanitor

週期性地檢查和清理hbase:meta 表。參見 <arch.catalog.meta> 得到更多關於元數據表的信息。

68. RegionServer

HRegionServer 是RegionServer的實現,負責Region的服務和管理。在分佈式集羣中,一個RegionServer運行在一個DataNode上。

68.1. 接口 Interface

HRegionRegionInterface聲明的方法中包含 面向數據的 和 面向Region維護的。 contain both data-oriented and region-maintenance methods:

  • 數據 (get, put, delete, next, etc.)

  • Region (splitRegion, compactRegion, etc.) 

例如,當 Admin 的方法 majorCompact 在一個表上被調用時, 客戶端其實是對指定表的全部Region進行迭代,並要求對每一個Region直接進行major compaction(緊縮)操做。

68.2. 進程 Processes

RegionServer 後臺運行幾種線程:

68.2.1. CompactSplitThread

檢查分割並處理minor compactions。

68.2.2. MajorCompactionChecker

檢查major compactions。

68.2.3. MemStoreFlusher

週期性地將寫到MemStore的內容刷到存儲文件(StoreFiles)。

68.2.4. LogRoller

週期性地檢查RegionServer的WAL。

68.3. 協處理器 Coprocessors

協處理器在0.92版添加。有一個詳細帖子 Blog Overview of CoProcessors 供參考。文檔最終會放到本參考手冊,但該blog是當前能獲取的大部分信息。

68.4. 塊緩存 Block Cache

HBase提供了兩種不一樣的塊緩存實現:默認的是使用堆內存的 LruBlockCache 和 一般使用堆外內存的 BucketCache。本節討論每一個實現的優勢和缺點,如何選擇合適的選項,以及配置每一個實現。

塊緩存報告:UI

有關緩存部署的詳細信息,請參閱RegionServer的UI。自從HBase 0.98.4起, 塊緩存的詳細信息已經被顯著地擴展了,顯示了配置、大小、當前使用、緩存的時間,甚至是塊計數和類型的細節。

 
 
 

68.4.1. 緩存的選擇Cache Choices

LruBlockCache 是最初的實現, 徹底緩存在Java堆內存中。BucketCache 主要把數據緩存到堆外內存, 然而它也能夠把數據緩存到堆內存,也能夠爲緩存在文件中的數據提供服務。

BucketCache 在HBase 0.98.6可用

要啓用 BucketCache, 你須要瞭解 HBASE-11678. 它在0.98.6中引入。

 

 

與使用本機堆內存的LruBlockCache相比,從BucketCache取回數據老是較慢。可是,延遲的時間趨於穩定,由於在使用BucketCache時使用的垃圾回收量較少,由於它管理的是塊緩存分配,而不是GC。

若是BucketCache被部署在堆外內存,這塊內存就不禁GC管理了。這就是爲何你使用了BucketCache,所以您的延遲不那麼不穩定,並減小了gc和堆的碎片。

參考 Nick Dimiduk的BlockCache 101中塊緩存在堆內存和堆外內存的比較測試。

參考Comparing BlockCache Deploys,能夠發現:若是您的數據集適合您的LruBlockCache部署,請使用它;不然若是你在經受緩存不穩定的狀況(或你想你的緩存儘可能避免java GC引起的不穩定),使用BucketCache。

當你啓用BucketCache時,你就啓用了兩層緩存系統,L1緩存由LruBlockCache的一個實例實現,使用堆外內存的L2緩存由BucketCache實現。

這兩個層的管理,以及決定塊在這兩層之間如何移動的策略由CombinedBlockCache完成。

它將全部的DATA塊保存在L2 BucketCache,將元數據塊——INDEX和BLOOM塊放在使用堆內存的L1 LruBlockCache。參考Off-heap Block Cache獲取關於堆外內存的更多信息。

68.4.2. 通常的緩存配置 General Cache Configurations

除了緩存自己的實現以外,您還能夠設置一些通用配置選項來控制緩存的執行狀況。

參考http://hbase.apache.org/1.2/devapidocs/org/apache/hadoop/hbase/io/hfile/CacheConfig.html。在設置了這些選項以後,從新啓動或依次從新啓動你的集羣以使配置生效。出現錯誤或異常行爲就檢查日誌。

也能夠參考Prefetch Option for Blockcache,它討論了一個由HBASE-9857引入的新的配置選項。

68.4.3. LruBlockCache Design 設計

LruBlockCache是一個LRU緩存,它包含三個級別的塊優先級,以應對Scan操做帶來的Cache頻繁顛簸和in-memory的列族。

The LruBlockCache is an LRU cache that contains three levels of block priority to allow for scan-resistance and in-memory ColumnFamilies:

  • Single 訪問優先級: 一個塊第一次從HDFS加載,它一般擁有這個優先級,在緩存回收時它將是首先被考慮要回收的組。這樣作的好處是,相比於獲得更多使用的塊,被掃描的塊更可能被回收。

  • Multi 訪問優先級: 若是Single優先級組中的一個塊再次被訪問,它將升級到這個優先級。所以,在緩存回收時,它是第二位被考慮回收的。

  • In-memory 訪問優先級: 若是一個塊所在的列族被配置爲 "in-memory", 它將是這個優先級的一部分,不考慮它被訪問的次數。目錄表被配置成這樣。這個組是最後被考慮回收的。

    若是用java建立表的話,要標記一個列族是 in-memory的,調用

HColumnDescriptor.setInMemory(true);

在shell中建立或修改一個表的話,設置 IN_MEMORY ⇒ true 

hbase(main):003:0> create  't', {NAME => 'f', IN_MEMORY => 'true'}

獲取更多信息,參考 LruBlockCache source

68.4.4. LruBlockCache Usage 使用

對於用戶表來講,塊緩存是默認啓用的,這意味着任意的讀操做都會被加載的LRU緩存。這對於大量的用例來講多是好的,可是爲了達到更好的性能,一般須要進一步的調優。

一個重要的概念是working set size,也稱做WSS,它是「計算一個問題的答案所需的內存數量」。對於一個網站來講,這是須要在短期內回答這些問題所需的數據。

計算HBase中有多少內存可用來作緩存的方式是:

number of region servers * heap size * hfile.block.cache.size * 0.99

塊緩存(block cache)的默認值是0.25,表示是可用堆的25%。最後一個值(99%),在回收啓動後的LRU緩存中,是默認的可接受的加載因子。它被包含在這個公式的緣由是,使用100%的可用內存作緩存是不現實的,由於這會使進程從加載新塊的地方阻塞。如下有一些例子:

  • 一個具備堆大小爲1GB的RegionServer,默認塊緩存大小將有253 MB。

  • 20個具備堆大小爲8GB的RegionServer,默認的塊緩存大小爲39.6GB。

  • 100個具備堆大小爲24GB的RegionServer,且 block cache size 爲0.5,那麼塊緩存約爲1.16TB。

你的數據並非在塊緩存中惟一駐留的數據。如下是你可能須要考慮的其餘問題:

目錄表 Catalog Tables

-ROOT- (存在於HBase 0.96以前的版本, 參考 arch.catalog.root) 和 hbase:meta 表 被強制使用塊緩存,且擁有in-memory 優先級,這意味着它們的緩存很難被回收。-ROOT-不會使用超過幾百字節的緩存,而hbase:meta可能佔用幾兆字節(取決於Region的個數)。

HFiles索引 HFiles Indexes

HFile 是HBase用來把數據存儲到HDFS上的文件格式。它包含一個多層索引,它容許HBase在不用讀取整個文件的狀況下查找數據。這些索引的大小是塊大小的一個因子(默認爲64KB),鍵的大小和存儲的數據量。對於大數據集來講,每一個RegionServer,HFile索引的大小有1GB左右也並很多見,然而並非全部的HFile索引都將在緩存中,由於LRU會回收那些不使用的索引的緩存。

鍵 Keys

每一個值都與它的鍵一塊兒存儲(行鍵、列族、列標識符和時間戳) 。參考 Try to minimize row and column sizes.

布隆過濾器 Bloom Filters

就像HFile索引同樣,這些數據結構(在啓用時)存儲在LRU中。

目前,衡量HFile索引和bloom過濾器大小的推薦方法是查看RegionServer web UI,並檢查相關的度量標準。對於鍵,能夠使用HFile命令行工具來進行抽樣,並查找平均鍵大小的度量。從HBase 0.98.3開始,你能夠在UI的 Block Cache 部分查看BlockCache統計的細節和度量。

當WSS沒有裝到內存時,使用塊緩存一般是很差的。例如,全部的RegionServer共有都有40GB可用的塊緩存空間,可是你須要處理1TB的數據。其中一個緣由是,緩存回收過程所產生的混亂會致使沒必要要的垃圾收集。這裏有兩個用例:

  • 徹底隨機讀取模式: 這個狀況是,您幾乎不可能在短期內兩次訪問同一行,這樣就能夠訪問緩存塊的概率接近於0。在這樣的表上設置塊緩存是對內存和CPU週期的浪費,更嚴重的是這樣的配置將產生更多的須要由JVM收拾的垃圾。更多關於監控GC的內容,參考JVM Garbage Collection Logs

  • Mapping a table: 在典型的MapReduce做業中,須要輸入一個表,每一行只讀取一次,所以不須要將它們放入塊緩存中。Scan對象經過setCaching方法(設置它爲false)禁用緩存。若是您須要快速隨機讀取訪問,您仍然能夠在該表上保留啓用塊緩存的配置。例如,一個示例將計算一個服務於實時通訊的表中的行數,緩存這個表的每一個塊都會形成大量的混亂,而且確定會將當前正在使用的數據的緩存回收。

只緩存元數據塊(數據塊放在fscache中) Caching META blocks only (DATA blocks in fscache)

一個有趣的設置是,咱們只緩存META塊,並在每一個訪問中讀取DATA塊。若是數據塊放到fscache,那麼當訪問在一個很是大的數據集上徹底隨機時,這種選擇多是有意義的。要啓用這樣的設置,修改你的表爲每一個列族設置 BLOCKCACHE ⇒ 'false'。您正在禁用這個列家族的塊緩存。你不能禁用META塊的緩存。由於 HBASE-4683 Always cache index and bloom blocks, 咱們會緩存META塊即便BlockCache被禁用。

68.4.5. 堆外內存塊緩存 Off-heap Block Cache

如何啓用BucketCache How to Enable BucketCache

一般BucketCache的部署是經過一個管理類,它創建了兩個緩存層:L1 on-heap緩存由LruBlockCache實現,L2 cache經過BucketCache實現。這個管理類默認是CombinedBlockCache。前面的連接描述了由CombinedBlockCache實現的緩存「策略」。簡單說,它把元數據塊  INDEX 和 BLOOM放到L1 on-heap LruBlockCache層,把DATA塊放到L2 BucketCache層。在HBase 1.0之後,能夠調整這個行爲,例如,經過設置cacheDataInL1使一個列族的元數據和DATA數據塊緩存在L1層的堆內存裏。配置方法:

 Java代碼中 HColumnDescriptor.setCacheDataInL1(true) ,或者在shell中 建立修改列族時把 CACHE_DATA_IN_L1 設置成 true:

hbase(main):003:0> create 't', {NAME => 't', CONFIGURATION => {CACHE_DATA_IN_L1 => 'true'}}

BucketCache Block Cache能夠被部署到堆內存、對外內存或者文件中。你的設置在 hbase.bucketcache.ioenginesetting。

把它設置成 heap,將部署BucketCache到分配的Java堆中。把它設置成 offheap,將使BucketCache把緩存分配到堆外內存。把它設置成 file:PATH_TO_FILE 將部署BucketCache使用一個文件作緩存(這個配置頗有用,特別是當你的機器中有一些快速的I/O設備,如SSD固態硬盤)。

咱們能夠部署L1+L2的設置而不使用CombinedBlockCache策略,將BucketCache做爲嚴格的L2緩存、LruBlockCache做爲L1緩存。要設置成這樣,設CacheConfig.BUCKET_CACHE_COMBINED_KEYfalse。在這個模式中,從L1移出的塊將放到L2中。當一個塊被緩存時,它首先被緩存到L1。當查找一個緩存的塊時,首先去L1找,若是找不到再去L2找。稱這樣的部署格式爲原始的L1+L2

其餘的BucketCache配置包括:指定一個位置以便在從新啓動時保持緩存,有多少個線程用來寫緩存,等等。參考CacheConfig.html 類獲取配置項和描述信息。

BucketCache Example Configuration

這個例子配置了 4GB off-heap BucketCache緩存、1GB on-heap緩存。

配置在RegionServer上執行。

設置 hbase.bucketcache.ioengine 和 hbase.bucketcache.size > 0 以啓用 CombinedBlockCache. 假定RegionServer已經設置爲以5G的堆內存運行:如 HBASE_HEAPSIZE=5g。

  1. 首先, 編輯RegionServer的hbase-env.sh,設置 HBASE_OFFHEAPSIZE 爲一個大於給定的off-heap大小的值,在這個例子中,off-heap大小爲4GB,咱們給HBASE_OFFHEAPSIZE設置成5GB。這樣的配置表示給off-heap緩存4GB,給其它用途的堆外內存設置1GB(堆外內存除了BlockCache還有其餘的使用者,如RegionServer中的DFSClient能夠利用off-heap內存)。參考 Direct Memory Usage In HBase

    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。咱們配置了on-heap LruBlockCache爲20%(0.2)的RegionServer堆內存大小(0.2 * 5G = 1G)。換句話說,您能夠像往常同樣配置L1 LruBlockCache(好像沒有L2緩存存在)。

HBASE-10641 介紹了爲BucketCache的buckets配置多種大小的能力,已經在HBase0.98及之後的版本中實現。要配置多個bucket的大小,就配置新屬性 hfile.block.cache.sizes (替代 hfile.block.cache.size) 給它一個由逗號分隔的塊大小的列表,從小到大排序,不能有空格。這個配置的目的是根據你的數據訪問方式優化bucket的大小。如下的例子中,配置了buckets的大小爲4096和8192.

<property>
  <name>hfile.block.cache.sizes</name>
  <value>4096,8192</value>
</property>
HBase中直接內存(Direct Memory)的使用

默認最大的直接內存因JVM而異。傳統上,它是64M,但可能和與分配的堆大小(-Xmx程序運行期間最大可佔用的內存大小)有關,也可能無關(這顯然說的是JDK7)。HBase服務器使用直接內存,特別在short-circuit reading時,服務器上的DFSClient將分配直接內存緩衝區。若是你啓用了off-heap塊緩存,你將利用直接內存。啓動你的JVM,確保在conf/hbase-env.sh中的-XX:MaxDirectMemorySize的配置值比你已經分配的off-heap BlockCache(hbase.bucketcache.size)的值要大。這個配置值要大於你的off-heap塊緩存的大小,多餘的部分用於DFSClient使用 (DFSClient 使用多少直接內存是不容易肯定的;  當HBase中的 hbase.dfs.client.read.shortcircuit.buffer.size 是128k時,它是:打開的HFile數量  * hbase.dfs.client.read.shortcircuit.buffer.size — 參考 hbase-default.xml 默認配置)。直接內存屬於Java進程堆(Java process heap)的一部分,和由-Xmx指定對象堆(object heap)是分離的。這個由 MaxDirectMemorySize 分配的值決不能超過物理RAM,要少於總共可用的RAM,由於還有其餘的內存需求和系統限制。

你能夠在UI的Server Metrics: Memory tab中查看一個RegionServer被配置了能使用多少內存,包括on-heap和off-heap/direct,以及這個RegionServer在任一時刻正在使用多少內存。它也能夠經過JMX獲得。特別地,當前被RegionServer使用的直接內存能夠在 java.nio.type=BufferPool,name=direct 的bean裏被找到。 Terracotta有一篇關於在Java中使用off-heap內存的文檔 good write up 。它是爲它的產品BigMemory所做的,可是裏面不少問題適用於廣泛使用off-heap的狀況,能夠看看。

 

博主附加Direct Memory: 

直接內存(Direct Memory)並非虛擬機運行時數據區的一部分,也不是Java虛擬機規範中定義的內存區域,可是這部份內存也被頻繁地使用,並且也可能致使OutOfMemoryError 異常出現。

這個的出現主要和java1.4後出現的NIO相關,一個基於通道和緩衝區的io方式,它能夠使用Native函數庫來直接分配堆外內存,而後經過一個存在java堆中的DirectByteBuffer這個對象來對這個java堆外的內存的引用來進行操做,能夠提升相關性能,由於避免了java堆和native堆中的來回複製數據。  

hbase.bucketcache.percentage.in.combinedcache

這是一個HBase1.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。size-of-bucket-cache 自己的值是:當指定hbase.bucketcache.size的值是一個MB的數值時,就取hbase.bucketcache.size的值;若是hbase.bucketcache.size是從0到1.0的小數時,就取 hbase.bucketcache.size * -XX:MaxDirectMemorySize的結果

在HBase 1.0中,這個設置應該更加直接。L1 LruBlockCache的大小被設置成 java heap 與 hfile.block.cache.size (不是最好的名字) 的乘積,L2被設置成要麼是一個絕對的MB的值,要麼是被分配的最大直接內存的一個比例。

 

 

 

68.4.6. 壓縮的塊緩存 Compressed BlockCache

HBASE-11331 引入了惰性的BlockCache解壓縮,更是簡單說起了壓縮的BlockCache。當壓縮的塊緩存被啓用時,數據和被編碼的數據的塊會以它們的磁盤格式緩存在BlockCache中,而不是在緩存以前進行解壓縮和解碼。

對於存儲了量多到比緩存還要大的數據的RegionServery來講,啓用這個功能並使用SNAPPY壓縮,能夠提升50%的吞吐量,平均延遲時間提升30%,然而使垃圾收集增長80%,整體CPU負載增長2%。參考HBASE-11331 以得到關於如何度量性能和實現的更多細節。對於存儲了量能夠放到緩存裏的數據的RegionServer,或者若是您的工做負載對額外的CPU或垃圾收集負載很敏感,那麼啓用這個功能您可能會獲得更少的好處。

壓縮的BlockCache默認是被禁用的。要啓用它,把全部RegionServer上的hbase-site.xml中的hbase.block.data.cachecompressed 設置爲 true

68.5. RegionServer分割的實現 RegionServer Splitting Implementation

因爲寫請求是由RegionServer處理的,因此它們會把數據寫到一個被稱爲memstore的內存存儲系統。一旦memstore填滿,它的內容就會被寫到磁盤上,做爲額外的存儲文件。這個事件被稱爲刷新(memstore flush)。隨着存儲文件的累積,區域服務器將把它們緊縮(compact)成更大的文件,從而使文件數更少。每次刷新或緊縮完成後,該Region內存儲的數據量就發生了變化。RegionServer根據Region分割策略,以肯定該Region是否增加過大,或者是否應該因另外一個特定的策略而被分割。若是策略建議分割,Region分割請求就會被排到隊列裏。

邏輯上,分割一個Region的處理是簡單的。咱們在這個Region的行鍵域(keyspace)裏找一個合適的點,這個點是咱們應該把這個Region分紅兩半的點,而後在這個點把這個Region的數據分割到兩個新的Region中去。可是處理的細節並不簡單。當一個分割發生時,新建立的子Region不會當即將全部數據從新寫入新文件。它們建立相似於符號連接文件的小文件,命名爲Reference文件,它們根據分割點,指向父存儲文件的頂部或底部部分。引用文件就像常規的數據文件同樣,可是隻有一半的記錄。若是沒有對父Region中的不可變數據文件的引用,這個子Region就能夠被分割了。那些Reference文件被緊縮操做逐漸清理,以至於這個子Region將中止對它的父文件的引用,而後它就能夠被進一步分割了

儘管分割Region是由RegionServer作出的本地決策,但分割過程自己必須與許多參與者協調。在分割Region以前和以後,RegionServer通知Master更新 .META. 表,以使客戶端可以發現新的子Region,而且RegionServer在HDFS上從新安排目錄結構和數據文件。分割(也叫作分裂)是一個由多個任務組成的過程。要啓用在錯誤時回滾的功能,RegionServer在內存中保留一個關於執行狀態的journal。RegionServer執行分割Region的步驟在RegionServer Split Process中闡述。每一步都標註了一個步驟號,RegionServers和Master內的action標紅,client的action標綠。

Figure 1. RegionServer Split Process  RegionServer分割過程
  1. RegionServer決定分割Region,併爲分割作準備。分割事務就開始了做爲第一步,RegionServer獲取表上共享的讀鎖,以防止在分割過程當中對schema進行修改。而後它在ZooKeeper的 /hbase/region-in-transition/region-name 下建立一個znode,並設置這個znode的狀態爲 SPLITTING。

  2. Master經過父Region的region-in-transition znode的watcher瞭解到在步驟1中建立的znode。

  3. RegionServer在HDFS中的父region的目錄下建立名爲「.split」的子目錄。

  4. RegionServer關閉父region,並強制刷新緩存內的數據,以後在本地數據結構中將標識爲下線狀態。正在被分割的REGION如今下線了。此時來自Client的對父region的請求會拋出NotServingRegionException ,Client將經過重試機制而從新嘗試發送請求。博主注:backoff是一種重試策略,是指失敗後多長時間進行重試。

  5. RegionServer在步驟3中建立的.split目錄下爲子regionA和B建立目錄和相關的數據結構。而後RegionServer分割store文件,這種分割是指,爲父region的每一個store文件建立兩個Reference文件。這些Reference文件將指向父region中的文件。

  6. RegionServer在HDFS中建立實際的region目錄,並移動每一個子region的Reference文件。

  7. RegionServer向.META.表發送Put請求,並在.META.中將父region改成下線狀態,添加子region的信息。此時表中並單獨存儲沒有子region信息的條目。Client掃描.META.時會看到父region爲分裂狀態,但直到子region出如今.META.表中,Client才知道他們的存在。若是Put請求成功,那麼父region將被有效地分割。若是在這條RPC成功以前RegionServer死掉了,那麼Master和打開這個region的下一個RegionServer會清理關於該region分裂的髒狀態。在.META.更新以後,region的分裂將被Master前滾。

  8. RegionServer打開子region,並行地接受寫請求。

  9. RegionServer將子region A和B的相關信息和它存儲這兩個Region的信息寫入.META.。分割好的Region(含有對父Region引用的子Region)如今上線了。此後,Client即可以掃描到新的region,而且能夠向其發送請求。Client會在本地緩存.META.的條目,但當她們向RegionServer或.META.發送請求時,這些緩存便無效了,他們竟從新學習.META.中新region的信息。

  10. RegionServer將zookeeper中 /hbase/region-in-transition/region-name下的znode更改成SPLIT狀態,以便Master能夠監測到。若是有須要,Balancer能夠自由地將子region分派到其餘RegionServer上。分割事務如今結束了。

  11. 分裂以後,.META. 和HDFS中依然包含着指向父region的引用。這些引用將在子region發生緊縮操做重寫數據文件時被刪除掉。Master中的垃圾回收任務會週期性地檢測子Region是否仍指向父region的文件,若是沒有,將刪除父region。

68.6. 預寫日誌 Write Ahead Log (WAL)

68.6.1. 目的 Purpose

Write Ahead Log (WAL)記錄了HBase中數據的全部變化,把這些變化基於文件進行存儲。在正常操做下,並不須要WAL,由於數據更改從MemStore轉移到storefile。可是,若是在MemStore刷新以前,某個RegionServer崩潰或變得不可用,那麼WAL將確保對數據的修改能夠從新進行。若是向WAL寫入失敗,那麼修改數據的整個操做就會失敗。

HBase使用WAL 接口的一個實現。一般狀況下,一個RegionServer中,一個WAL只有一個實例。在把Puts和Deletes操做記錄到受影響的Store對應的MemStore 以前,RegionServer把Puts和Deletes操做記錄到WAL中。

The HLog

在HBase2.0以前, HBase中WALs的接口名爲HLog。在 0.94, HLog 是WAL的實現的名字。你將可能在舊版本的文檔中找到HLog的內容。

 
 

 

WAL 保存在HDFS 的 /hbase/WALs/ 目錄裏(在HBase0.94 之前,它們被存儲在/hbase/.logs/中),每一個region有一個子目錄。

要想知道更多的信息,能夠訪問維基百科 Write-Ahead Log 的文章.

68.6.2. MultiWAL 多個WAL

每一個RegionServer有一個單一的WAL,RegionServer必須連續地向WAL中寫入,由於HDFS文件必須是連續的。這會致使WAL成爲性能瓶頸。

HBase1.0在HBASE-5699中引入了對多個WAL(MultiWAL)的支持。MultiWAL經過在底層的HDFS實例中使用多個管道,容許一個RegionServer並行地往多個WAL流裏寫,這增長了寫入期間的總吞吐量。這個並行是根據表的分區,進而根據表的Region實現的。所以,當前的實現對單個Region增長吞吐量沒有幫助。

使用原有的WAL實現和使用MultiWAL實現的RegionServer均可以處理任意一種WALs的恢復,所以,經過依次重啓能夠實現零停機配置更新。(不明白這個結論的緣由

RegionServers using the original WAL implementation and those using the MultiWAL implementation can each handle recovery of either set of WALs, so a zero-downtime configuration update is possible through a rolling restart.?????

Configure MultiWAL 配置 MultiWAL

要爲一個RegionServer配置MultiWAL,按下面的XML設置屬性 hbase.wal.provider 爲 multiwal 便可:

<property>
  <name>hbase.wal.provider</name>
  <value>multiwal</value>
</property>

重啓RegionServer使配置更改生效。

要在一個RegionServer上禁用MultiWAL, 不設置這個屬性而後重啓這個RegionServer便可。

68.6.3. WAL Flushing

TODO (describe).

68.6.4. WAL Splitting WAL分割

一個RegionServer能夠給許多Region提供服務。一個RegionServer中全部的Region共享相同的激活狀態下的WAL文件。在這個WAL文件的每一次編輯都包含關於此次編輯屬於哪一個Region的信息。當一個Region被打開時,在WAL文件裏屬於這個Region的編輯須要被重作。所以,WAL文件中的編輯必須按Region分組,以便特定編輯的集合能夠在特定的Region內被重作以從新生成數據。根據Region將WAL編輯分組的過程被稱做日誌分割(log splitting)。若是RegionServer失敗,它是恢復數據的一個關鍵的過程。

日誌分割由HMaster在集羣啓動時完成,或者由ServerShutdownHandler在RegionServer關閉時完成。因此一致性是能夠保障的,受影響的Regions直到數據恢復以前處於不可用狀態。在一個給定的Region再次成爲可用狀態以前,全部的WAL編輯內容須要被恢復和重作。所以,在這個過程完成以前,受日誌分割影響的Region是不可用的。

步驟: Log Splitting, Step by Step
  1. 目錄/hbase/WALs/<host>,<port>,<startcode> 被重命名

    重命名這個目錄是重要的,由於一個RegionServer可能仍處於啓動狀態並在接受請求即便HMaster認爲它已經宕了。若是這個RegionServer沒有即便響應,而且沒有和它的ZooKeeper會話保持心跳,HMaster可能會認爲這個RegionServer失敗了。重命名日誌目錄會確保存在這樣的狀況,仍被一個忙碌但活的RegionServer使用的合法的WAL文件不能被偶然的寫入。

    新的目錄根據如下模式被命名:

    /hbase/WALs/<host>,<port>,<startcode>-splitting

    一個重命名目錄的例子以下:

    /hbase/WALs/srv.example.com,60020,1254173957298-splitting
  2. 每個日誌文件都會被分割,一次一個。

    日誌分割器每次讀取日誌文件的一個條目,並把每一個編輯條目放到和這個編輯條目的Region相對應的緩衝區中。同時,日誌分割器啓動幾個寫入器線程。寫入器線程獲取相應的緩衝區,並將緩衝區中的編輯條目寫入一個臨時恢復的編輯文件。這個臨時的編輯文件如下面的命名方式存儲在磁盤上:

    /hbase/<table_name>/<region_id>/recovered.edits/.temp

    該文件用於存儲WAL日誌中屬於該Region的的全部編輯條目。在日誌分割完成後,這個.temp文件被重命名爲寫入到這個文件的第一條日誌的序列ID(sequence ID)。

    爲了肯定是否全部的編輯都已經被寫入了,新的文件名中的序列ID將與被寫入到HFile的最後一個編輯條目的序列ID進行比較。若是最後編輯條目的序列ID大於等於文件名中的序列ID,對這個文件的全部的寫操做就已經完成了。(博主注:不明白爲何比較文件名中的序列ID <= 文件中的最後一條序列ID,就能證實全部的條目都寫入成功了

  3. 日誌分割完成後,每個受影響的Region會被分配給一個RegionServer

    當Region打開時,檢查recovered.edits文件夾中恢復的編輯文件。若是存在這樣的文件,經過讀取編輯條目並把編輯條目存儲到MemStore,它們會被重作。當全部的編輯文件都被重作以後,MemStore中的內容被寫入磁盤(HFile),編輯文件被刪除。

對日誌分割期間出現的錯誤的處理  Handling of Errors During Log Splitting

若是你把 hbase.hlog.split.skip.errors 設置爲 true, 錯誤會被以下處理:

  • 分割期間所遇到的任何錯誤都會被記錄。

  • 這個出問題的WAL日誌會被移動到HBase rootdir下的 .corrupt 目錄中

  • 對WAL的處理過程將繼續

若是 hbase.hlog.split.skip.errors option 被設置爲 false, 這是默認的設置, 異常將被拋出,這個分割操做被記錄成failed。參考 HBASE-2958 When hbase.hlog.split.skip.errors is set to false, we fail the split but that’s it。 若是設置了這個標誌,咱們須要作的不只僅是使分割操做失敗。

當分割一個崩潰的RegionServer的WAL時,如何處理EOFException   How EOFExceptions are treated when splitting a crashed RegionServer’s WALs

若是一個EOFException發生在分割日誌時,分割操做繼續進行,即便 hbase.hlog.split.skip.errors 被設置成 false。在讀取要分割的日誌文件集中的最後的日誌時,可能會遇到EOFException 由於RegionServer可能在崩潰時正在寫入一條記錄。關於這個背景,參考 HBASE-2643 Figure how to deal with eof splitting logs

日誌分割時的性能改善  Performance Improvements during Log Splitting

WAL日誌分割和恢復多是資源密集型的而且須要很長時間,這取決於崩潰的RegionServer的數量和Regions的大小。[distributed.log.splitting]被開發出來用以改善日誌分割時的性能。

啓用或禁用分佈式日誌分割 Enabling or Disabling Distributed Log Splitting

分佈式日誌處理從HBase 0.92開始默認爲啓用。這個設置由屬性 hbase.master.distributed.log.splitting 控制, 能夠被設置成 true 或 false, 但默認爲 true。

分佈式日誌分割步驟  Distributed Log Splitting, Step by Step

配置了分佈式日誌分割以後,HMaster控制這個過程。HMaster把每個RegionServer記入到日誌分割的過程,實際的分割日誌的工做由RegionServer去作。非分佈式日誌分割的通常過程,如在 Distributed Log Splitting, Step by Step 描述的那樣,也適用於分佈式日誌分割。

  1. 若是分佈式日誌分割被啓用,HMaster在集羣啓動時建立一個 分割日誌管理器 實例。

    1. 這個分割日誌管理器 管理全部的須要被掃描和分割日誌文件。

    2. 這個分割日誌管理器 把全部的日誌做爲任務放到ZooKeeper的 splitlog node (/hbase/splitlog) 。

    3. 你能夠經過下列zkCli命令查看splitlog的內容。輸出的例子以下。

      ls /hbase/splitlog
      [hdfs%3A%2F%2Fhost2.sample.com%3A56020%2Fhbase%2F.logs%2Fhost8.sample.com%2C57020%2C1340474893275-splitting%2Fhost8.sample.com%253A57020.1340474893900,
      hdfs%3A%2F%2Fhost2.sample.com%3A56020%2Fhbase%2F.logs%2Fhost3.sample.com%2C57020%2C1340474893299-splitting%2Fhost3.sample.com%253A57020.1340474893931,
      hdfs%3A%2F%2Fhost2.sample.com%3A56020%2Fhbase%2F.logs%2Fhost4.sample.com%2C57020%2C1340474893287-splitting%2Fhost4.sample.com%253A57020.1340474893946]

      輸出含有一些  non-ASCII 字符。解碼後, 他看起來更簡單:

      [hdfs://host2.sample.com:56020/hbase/.logs/host8.sample.com,57020,1340474893275-splitting/host8.sample.com%3A57020.1340474893900,
      hdfs://host2.sample.com:56020/hbase/.logs/host3.sample.com,57020,1340474893299-splitting/host3.sample.com%3A57020.1340474893931,
      hdfs://host2.sample.com:56020/hbase/.logs/host4.sample.com,57020,1340474893287-splitting/host4.sample.com%3A57020.1340474893946]

      清單表示要掃描和拆分的WAL文件名,這是一個日誌分割任務列表。

  2. 分割日誌管理器監控日誌分解任務和workers。

    分割日誌管理器負責如下正在執行的任務:

    • 一旦分割日誌管理器將全部任務發佈到splitlog znode,它就會監視這些任務節點,並等待它們被處理。

    • 檢查是否有死的分割日誌的worker排隊。若是它發現由沒有響應的worker所聲明的任務,它將從新提交這些任務。若是因爲某些ZooKeeper的異常而從新提交失敗,則dead worker將再次排隊等待重試。

    • 檢查是否有未分配的任務。若是發現有未分配的任務,它就建立一個臨時的重掃描節點(rescan node),以便每一個分裂日誌的worker經過nodeChildrenChanged的ZooKeeper事件被通知去從新掃描未分配的任務。

    • 檢查分配但過時的任務。若是找到,它們會被再次設置成TASK_UNASSIGNED state 以便它們可一個被重試。這些「過時的」任務有可能被分配給慢的workers,或者可能已經完成了。這是沒問題的,由於日誌分割任務具備冪等性。換句話說,相同的日誌分割任務能夠屢次處理,而不會形成任何問題。

    • 分割日誌管理器時常監視HBase的分割日誌znodes。若是有任何分裂的日誌任務節點數據被更改,那麼分割日誌管理器將獲取節點數據。節點數據包含任務的當前狀態。你能夠使用 zkCli 的get 命令去獲取一個任務的當前狀態(state)。在下面的示例輸出中,輸出的第一行顯示當前任務是未分配的。

      get /hbase/splitlog/hdfs%3A%2F%2Fhost2.sample.com%3A56020%2Fhbase%2F.logs%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
      ...

      根據數據被更改的任務的狀態,分割日誌管理器會執行下列之一的操做:

    • 若是未分配任務,則從新提交任務。

    • 若是任務被分配,則經過心跳監控該任務的執行。(Heartbeat the task if it is assigned)

    • 若是任務被委託,則從新提交或使該任務失敗。 (參考 Reasons a Task Will Fail)

    • 若是任務完成了但有錯誤,則從新提交或使該任務失敗 (參考 Reasons a Task Will Fail)

    • 若是任務因錯誤不能完成,則從新提交或使該任務失敗 (參考 Reasons a Task Will Fail)

    • 若是任務已經成功完成或失敗了,則刪除該任務。

       
      一個任務將失敗的緣由  Reasons a Task Will Fail
      • 該任務已經被刪除了

      • 該任務在ZooKeeper的節點已經不存在了

      • 日誌狀態管理器把這個任務的狀態更新爲TASK_UNASSIGNED時失敗了

      • 從新提交的數量超過了從新提交的閾值。

     

     

     

     

  3. 每一個RegionServer的負責分割日誌的worker去執行日誌分割任務。

    每一個RegionServer運行一個被稱做分割日誌工做器(split log worker)的守護線程,由這個線程作分割日誌的工做。當RegionServer啓動時,守護線程將啓動,並註冊自身以監視HBase znode。若是任何一個splitlog znode的子節點發生變化,它就會通知一個正在休眠的工做線程把它喚醒並讓它獲取更多的任務。若是一個worker當前的任務節點數據發生變化,這個worker將檢查這個任務是否被被另外一個worker處理。若是是這樣的,這個worker線程將中止在這個當前任務上的工做。

    worker不斷地監視splitlog znode。當出現一個新任務時,分割日誌工做器將獲取任務路徑並檢查每一個任務路徑,直到找到一個未聲明的任務,並試圖聲明該任務。若是聲明成功,它將嘗試執行任務,並根據分割結果更新任務的狀態(state)屬性。此時,分割日誌的worker會掃描另外一個未聲明的任務。

    分割日誌worker如何處理一個任務 How the Split Log Worker Approaches a Task
    • 它查詢任務狀態,只有在任務處於`TASK_UNASSIGNED `狀態時纔會工做.

    • 若是任務處於 TASK_UNASSIGNED 狀態, worker嘗試本身把任務的狀態設置成 TASK_OWNED。若是設置狀態失敗, 另外一個worker將會嘗試捕獲這個任務。若是這個任務仍舊爲unassigned狀態,事後,分割日誌管理器將會要求全部的worker去從新掃描。

    • 若是worker成功地獲取這個任務的全部權,它會嘗試再次獲取這個任務的狀態,以確保它真正地得到異步。If the worker succeeds in taking ownership of the task, it tries to get the task state again to make sure it really gets it asynchronously. 同時,它啓動了一個拆分任務執行器(split task executor)來完成實際工做。

      • 獲取HBase root文件夾,在root文件夾下建立一個臨時文件夾,分割日誌文件到這個臨時文件夾中。

      • 若是分割成功,這個task executor會把這個任務的狀態設置爲 TASK_DONE。

      • 若是worker捕獲了一個預期外的IOException, 這個任務的狀態被設置爲 TASK_ERR

      • 若是worker正在關閉,會設置這個task的狀態爲 TASK_RESIGNED。

      • 若是這個任務被另外一個worker取得,只記錄這件事便可。

  4. 分割日誌管理器監視未完成的任務。

    當全部的任務都成功完成後,分割日誌管理器返回。若是全部的任務都完成了,但有一些失敗,則分割日誌管理器拋出一個異常,以便日誌分割能夠被重試。由於是一個異步實現,在及其罕見的狀況下,分割日誌管理器會失去對一些已完成任務的跟蹤。出於這個緣由,它會按期檢查Task Map或ZooKeeper裏未完成的任務。若是沒有找到,它會拋出一個異常,這樣就能夠當即重試日誌分割,而不是掛在那裏等待發生不會發生的事情。(博主注:這句話不理解,既然前面說失去對已完成任務的跟蹤,爲何後面要去找未完成的任務,並且既然沒有找到未完成任務,爲何要重試呢

分佈式日誌重作 Distributed Log Replay

在一個RegionServer失敗之後,它的失敗的Regions會被分配到其餘RegionServer中去,這些Region在ZooKeeper裏被標記成 "recovering"。一個分割日誌worker直接把失敗的RegionServer的WAL中的編輯條目重作到這些在的新位置上的Regions中。當一個Region處於"recovering" 狀態時, 它能接受寫但不接受 讀(包括Append和Increment)、Region分割或合併。

分佈式日誌重作繼承了 [distributed.log.splitting] 框架。它直接把WAL重作到另外一個 RegionServer上,而不是建立 recovered.edits 文件。對比分佈式日誌分割,它提供瞭如下優勢:

  • 它消除了讀寫recovered.edits 文件中大量數據的開銷。在RegionServer恢復的過程當中,成千上萬的recovered.edits文件被建立和寫入是很常見的。許多小的隨機寫入能夠下降整體系統性能。

  • 即便在一個Region處於恢復狀態時,它也容許寫操做。恢復中的Region只須要幾秒鐘就能夠再次接受寫操做。

啓用分佈式日誌重作 Enabling Distributed Log Replay

要啓用分佈式日誌重作,把 hbase.master.distributed.log.replay 設置成 true. 在HBase 0.99中,這是默認配置 (HBASE-10888).

你還必需要啓用HFile版本數爲3(從HBase 0.99開始,這是默認的HFile格式。參考 HBASE-10855)。 分佈式日誌重作對於滾動升級是不安全的。

68.6.5. 禁用WAL Disabling the WAL

爲了在某些特殊狀況下改善性能,禁用WAL是可能的。然而,禁用WAL會把你的數據置於風險之中。推薦的禁用WAL的狀況,只有在作批量加載(Bulk Load)的期間。這是由於,在出現問題時,能夠從新運行批量加載,不存在數據丟失的風險。

經過調用HBase客戶端中 field 的Mutation.writeToWAL(false)能夠禁用WAL。使用 Mutation.setDurability(Durability.SKIP_WAL) 和 Mutation.getDurability() 方法來設置和獲取域(field)的值。只是一個指定的表的話,沒法禁用 WAL。

若是你在批量加載之外的狀況下禁用WAL,你的數據會處於風險之中。
 

69. Regions

Regions對於表來講,是可用和分佈的基本要素,它由每一個列族的Store組成。這些對象的層級關係以下:

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)

關於HBase文件再寫入HDFS時是什麼樣子的描述,參考 Browsing HDFS for HBase Objects.

69.1. Region數量的考慮 Considerations for Number of Regions

通常來講,HBase的設計目的是在每一個服務器上運行一組少許的(20-200)Region,且Region相對較大(5-20gb)。對此的考慮以下:

69.1.1. 爲何我要保持低數量的Region? Why should I keep my Region count low?

一般,您想在HBase上保持Region數量的低水平,緣由有不少。一般,每一個RegionServer大約有100個Region會產生最好的結果。如下是保持Region數量低的一些緣由:

  1. MSLAB (MemStore-local allocation buffer) 每一個MemStore須要 2MB (每一個Region中的每一個列族要 2MB緩存)。那麼1000個Region、且每一個Region含有2個列族就須要3.9G的堆內存,而且尚未存儲數據。注意: 這個2MB 的值是能夠配置的。

  2. 若是你以某種程度上相同的速率去填充全部的Region,那麼全局內存使用(global memory usage)會在因Region太多而依次產生緊縮的時候產生微小的刷新。屢次重複寫相同的數據是你最不想要的事情。例如,一個例子是公平地向1000個Region(每一個Region有一個列族)中填充數據,讓咱們考慮一個更低的範圍來使用5GB的全局MemStore可用(該RegionServer有一個大的堆)。一旦填充的數據量達到5GB,它就會強制刷新數據量最大的Region,在那時這些Region都含有將近5M的數據,因此全局MemStore會刷新這個量的數據。5M數據刷新到文件後,會去刷新另外一個Region,這個Region這會兒有5MB多一點兒的數據,如此等等。這是目前Region數量的主要限制因素;參考 Number of regions per RS - upper bound 獲取更詳細的公式。

  3. Master原本就對大量的Region過敏,它將花費大量的時間分配這些Region而且批次量地移動這些Region。緣由是它在ZK的使用上很重,並且如今還不是很異步(已經在HBase0.96被改善了)。

  4. 在舊版HBase(pre-HFile v2, 0.90 and previous)中,大量的Region放置在不多量的RegionServer上可能引起存儲文件索引的增加、增長堆內存的使用、潛在地形成RegionServer的內存壓力或OutOfMemoryException。

另外一個問題是Region數量對MapReduce做業的影響;典型的是每一個HBase Region有一個mapper。所以,一個RegionServer有5個Region可能對一個MapReduce做業來講不能知足任務的數量,而有1000個Region將會生成很是多的任務。

參考 Determining region count and size 獲取配置指導。

69.2. Region-RegionServer 的分配

本節描述了Region是怎樣被分配到RegionServer上的。

69.2.1. Startup 啓動

當HBase啓動時,Region被以下分配(這是簡短的描述):

  1. Master啓動時調用 AssignmentManager 。

  2. AssignmentManager 在hbase:meta中查看現有的Region分配狀況

  3. 若是Region的分配依然有效(例如,若是Region被分配到的RegionServer依然在線),則保持這個分配安排。

  4. 若是Region的分配無效了,則LoadBalancerFactory 被調用以分配Region。負載均衡器(Load Balancer) (HBase1.0中默認是StochasticLoadBalancer) 分配Region到RegionServer中去。

  5. 把分配到的RegionServer(若是有須要的話)和這個RegionServer的啓動代碼(RegionServer進程的啓動時間)更新到hbase:meta 中。 and the RegionServer start codes (start time of the RegionServer process) upon region opening by the RegionServer.

69.2.2. 故障切換(失效轉義) Failover

當一個 RegionServer 失效:

  1. RegionServer中的 regions 當即成爲不可用狀態,由於這個 RegionServer 宕了.

  2. Master 將檢測到這個RegionServer已經失效了。

  3. Region原有的分配失效,並採用跟啓動時一樣順序的步驟從新分配Region

  4. 正在進行的查詢操做會從新執行,不會丟失。

  5. Region切換到新RegionServer動做要在如下時間內完成:

    ZooKeeper session timeout + split time + assignment/replay time

69.2.3. Region負載均衡 Region Load Balancing

Region能夠被 LoadBalancer 按期移動。

69.2.4. Region狀態轉換 Region State Transition

HBase爲每一個Region維護一個狀態,並把這個狀態持久化到 hbase:meta。 hbase:meta Region 的狀態自己被持久化到 ZooKeeper中。你能夠在Master Web UI中看到Region狀態的轉變。如下是Region可能的狀態的清單。

可能的Region狀態  Possible Region States
  • OFFLINE: Region處於offline 且沒有打開

  • OPENING: Region處於正在被打開的過程當中

  • OPEN: Region已經打開了,RegionServer已經通知了 Master

  • FAILED_OPEN: RegionServer沒能打開

  • CLOSING: Region處於正在被關閉的過程

  • CLOSED: RegionServer已經關閉了 Region,並通知了Master

  • FAILED_CLOSE: RegionServer沒能關閉 Region

  • SPLITTING: RegionServer 通知了 Master,Region正在分裂(分割 split)

  • SPLIT: RegionServer 通知了 Master,Region已經分裂完畢

  • SPLITTING_NEW: 這個Region正在被一個處理中的分割操做建立(this region is being created by a split which is in progress)

  • MERGING: RegionServer通知了 Master,這個Region正在與另外一個Region合併(Merge)

  • MERGED: RegionServer通知了 Master,這個Region已經被合併了。

  • MERGING_NEW: 這個Region正在被兩個Region的合併操做(Merge)操做建立
    region states

Figure 2. Region State Transitions
圖例  Graph Legend
  • 棕色: Offline 狀態, 是一個特殊的狀態,它能夠是瞬間的狀態 (Closed以後,Opening以前), 也能夠是一個最終的狀態 (被禁用表的Regions), 或者是一個初始的狀態 (新建表的Regions)

  • 淡綠色: Online 狀態,代表這個狀態的Regions能夠爲請求提供服務

  • 淡藍色: Transient(瞬間)狀態

  • 紅色: Failure(失敗)的狀態,須要OPS注意。什麼是OPS?

  • 金色: 分裂或合併的Regions的最終狀態

  • 灰色: 經過分裂或合併所建立的Region的初始狀態

狀態轉換的描述 Transition State Descriptions
  1. Master控制把一個region從OFFLINE的狀態遷移到OPENING 的狀態,而且嘗試把該region分配到一個regionServer上。RegionServer可能會也可能不會接收到打開Region的請求。直到RPC到達RegionServer或者Master的重試達到最大次數(11次)以前,master會一直嘗試發送打開Region的請求。等到RegionServer接收到打開Region的request以後,就會開始打開region。

  2. 若是master超過請求重試的次數,master經過把這個Region的狀態遷移到CLOSING並嘗試關閉它,以制止RegionServer打開Region,即便RegionServer已經開始打開這個Region。(注意,這裏即便某個regnionserver已經開始打開該region,也會強制再中止的)。

  3. 在RegionServer打開Region以後,它會一直嘗試通知Master,直到Master把該Region的狀態更改成OPEN而且通知全部的RegionServer。這個Region如今是打開的狀態了。

  4. 若是RegionServer不能打開Region, 它通知Master。Master把Region的狀態遷移爲CLOSED狀態,而且嘗試在其它RegionServer裏打開這個Region。

  5. 若是Master不能在必定數量的RegionServer上打開Region,它會把Region的狀態遷移爲 FAILED_OPEN,直到hbase shell發出相關的命令(如 從新assign)或者在該服務死掉,對這個Region將再也不會有任何操做。

  6. Master會把Region從OPEN狀態遷移到CLOSING的狀態。這個Region所在的RegionServer可能會也可能不會收到關閉Region的請求。直到RPC到達RegionServer或者Master的重試達到最大次數以前,master會一直向這個RegionServer嘗試發送關閉Region的請求。

  7. 若是RegionServer不在線, 或者拋出 NotServingRegionException, Master 把Region的狀態遷移爲 OFFLINE ,而且把它從新分配給其餘的 RegionServer。

  8. 若是RegionServer在線, 可是在Master重試屢次後仍然不可達,Master會把該Region遷移爲 FAILED_CLOSE 的狀態,而且直到HBase shell發出命令(如 從新assign),或者在該服務死掉,對這個Region將再也不會有任何操做。

  9. 若是Regionserver獲得關閉Region的請求,它會關閉Region,而且通知Master。Master會把該Region標記爲 CLOSED 的狀態,而且會把它從新分派到其它的RegionServer中去。

  10. 在分派一個Region以前,Master會自動把一個CLOSED狀態的Region標記爲OFFLINE的狀態。

  11. 當一個RegionServer準備split一個Region,它會通知Master。Master會把將要分割的Reigon從 OPEN 狀態遷移動到 SPLITTING 狀態,而後把這兩個要建立的Region添加到RegionServer中去。這兩個Region被初始化成 SPLITTING_NEW 的狀態。

  12. 通知了Master之後,RegionServer開始分割Region。若是返回超時,RegionServer會再次通知Master以便Master來更新hbase:meta表。可是Master在被RegionServer通知分割已經完成以前,Master不會更新Region的狀態。若是Region分割成功,正在被分割的Region會從 SPLITTING 狀態切換到 SPLIT 狀態,而後被分割出來的兩個新Region會從SPLITTING_NEW切換到OPEN狀態。

  13. 若是分割失敗,被切分的Region從 SPLITTING 狀態切換回 OPEN 狀態,而後兩個新建立出來的Region的狀態從SPLITTING_NEW被切換到OFFLINE的狀態。

  14. 若是RegionServer要合併兩個Region,會先通知Master。Master會把要合併的兩個Region從 OPEN 遷移到 MERGING 的狀態,而後增長一個新的Region到RegionServer,這個新的Region將用來保存被合併的Regions的內容。這個新的Region 的初始狀態是MERGING_NEW。

  15. 通知了Master以後,RegionServer開始合併兩個Region。一旦超時,RegionServer會再次通知Master以便Master來更新hbase:meta表(META)。可是Master在被RegionServer通知合併已經完成以前,Master不會更新Region的狀態。若是合併成功,兩個正在合併的region會從 MERGING 遷移到 MERGED 狀態,而新的Region會從 MERGING_NEW 遷移到 OPEN 狀態。

  16. 若是合併失敗,兩個須要合併的Region會從 MERGING 遷移回 OPEN 的狀態,而後被建立用來保存要合併的Region的內容的新的Region從 MERGING_NEW 遷移到 OFFLINE 狀態。

  17. 對於處於 FAILED_OPEN 或者 FAILED_CLOSE 狀態的Regions,當它們被HBase shell中的命令從新分配時,Master會再次嘗試關閉這些節點。

69.3. Region-RegionServer 的位置選擇

隨着時間的推移,Region-RegionServer的位置選擇經過HDFS的塊複製機制完成。HDFS客戶端在選擇寫入副本的位置時,默認步驟以下:

  1. 第一個副本寫在本地節點

  2. 第二個副本寫在另外一個機架上的任意節點

  3. 第三個副本寫在與第二個節點相同的機架上的另外一個任意的節點

  4. 後續的副本將寫到集羣中的任意節點中。 參考 Replica Placement: The First Baby Steps on this page: HDFS Architecture

所以,HBase Region在刷新或緊縮(Compaction)後最終達到某個位置,即選址是在flush或compaction以後執行的。在一個RegionServer失效轉移的狀況下,被分配到另外一個RegionServer的Regions的StoreFiles可能並不在這個RegionServer本地(由於沒有副本在本地),可是當新數據被寫入到這個Region,或者表被緊縮(Compact),StoreFiles被重寫時,數據文件塊的副本對於這個RegionServer將會「本地化」。

獲取更多信息,參考 Replica Placement: The First Baby Steps on this page: HDFS Architecture and also Lars George’s blog on HBase and HDFS locality.

69.4. Region分裂(分割)Region Splits

當Region到達設置的閾值時發生分裂。如下咱們簡短地介紹這個話題。更詳細的闡述,參考Enis Soztutar所作的 Apache HBase Region Splitting and Merging

Region分裂由RegionServer單獨運行,Master不參與。RegionServer分割一個Region,使被分割的Region下線,而後給它添加兩個子Region到 hbase:meta 中,在這個父Region所在的RegionServer中打開子Region,而後向Master報告分割操做。參考 Managed Splitting 獲取如何手動控制Region分割 (以及你爲何要這麼作)。

69.4.1. 自定義分割策略 Custom Split Policies

你能夠使用一個自定義的RegionSplitPolicy(HBase 0.94+)複寫默認的分割策略。典型的一個自定義分割策略應該繼承HBase默認的分割策略: IncreasingToUpperBoundRegionSplitPolicy

策略能夠設置成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', {METHOD => 'table_att', CONFIG => {'SPLIT_POLICY' => 'org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy'}},
{NAME => 'cf1'}

默認的分割策略能夠用自定義的 RegionSplitPolicy(HBase 0.94+) 複寫。典型的一個自定義分割策略應該繼承 HBase默認的分割策略: ConstantSizeRegionSplitPolicy

這個策略能夠經過HBaseConfiguration被設置成全局的,或者只針對一張表的:

HTableDescriptor myHtd = ...;
myHtd.setValue(HTableDescriptor.SPLIT_POLICY, MyCustomSplitPolicy.class.getName());
策略 DisabledRegionSplitPolicy 會阻止手動分割Region。

 

 

69.5. 手動分割Region Manual Region Splitting

手動分割你的表是能夠的,能夠在建立表的時候(預分割),也能夠在之後的管理操做中。你選擇手動分割你的Region可能會由於如下理由中的一個或多個。也可能會有其餘合理的理由,可是手動分割表的須要也可能會代表你的schema設計有問題。

手動分割表的理由

  • 你的數據按時間順序或其它相似的算法(把新數據排到表的結尾)排序。這意味着保存着最後的Region的RegionServer一直有數據加載進來,而其它的RegionServer會空閒。參考 Monotonically Increasing Row Keys/Timeseries Data.

  • 在你的表的一個Region中,你已經開發出了一個意想不到的熱點。例如,一個跟蹤網絡搜索的應用程序可能會被針對一個名人大量搜索出新聞所淹沒。參考 perf.one.region 獲取更多的關於這種情形的討論。

  • 在集羣中的RegionServer的數量大幅增長以後,就能夠快速地展開負載。

  • bulk-load可能會引發Region間不一樣尋常和不均勻的負載,在bulk-load以前你可能須要手動分割Region

參考 Managed Splitting 獲取關於徹底手動管理分割所帶來的危險和可能的收益的討論。

DisabledRegionSplitPolicy 會阻止手動分割Region

 

 

69.5.1. 決定分割點 Determining Split Points

手動分割你的表的目的是爲了在只經過良好的行鍵設計並不能達到這個平衡負載的狀況下,提升在集羣中平衡負載的機會。記住這一點,你分割Region的方式很是依賴於數據的特徵。也許你已經知道分割你的表的最好的方法了,若是沒有,分割你的表的方法要依賴於你的行鍵。

字母數字組成的 Rowkeys

若是你的行鍵以字母或數字開頭,你能夠在字母或數字邊界上分割你的表。例如,下面的命令建立了一個有多個Region的表,這些Region以元音做爲分割點,因此第一個Region有A-D,第二個Region有 E-H, 第三個Region有 I-N, 第四個Region有 O-V, 第五個Region有 U-Z.

使用自定義算法

HBase提供了工具 RegionSplitter,使用一個 SplitAlgorithm 來決定你的分割點。做爲參數,你給它一個算法,想要的Region數和列族。它包含了2個分割算法。第一個是 HexStringSplit 算法, 這個算法假定Row keys十六進制字符串。第二個, UniformSplit, 假定Row keys 是隨機的字節數組。你可能須要使用提供的這些參數做爲模型開發一個屬於本身的SplitAlgorithm

69.6. 在線Region合併 Online Region Merges

Master和RegionServer都參與了在線合併Region。客戶端向Master發出合併操做的RPC,而後Master把要合併的Region一塊兒移動到這些Region中數據量更大的Region所在的RegionServer。最後,Master向這個RegionServer發出merge請求,這個RegionServer是要運行merge操做的。和Region分裂的過程相似,Region合併在RegionServer上以本地事務的方式運行。它下線要merge的Region,而後在文件系統上合併這兩個Region,原子地從 hbase:meta 中刪除被合併的Region的信息,把合併操做新生成 Region 添加到 hbase:meta 中,在這個RegionServer上打開這個新的Region並把合併的狀況報告給Master。

在HBase shell中合併Region的例子

$ hbase> merge_region 'ENCODED_REGIONNAME', 'ENCODED_REGIONNAME'
$ hbase> merge_region 'ENCODED_REGIONNAME', 'ENCODED_REGIONNAME', true

它是一個異步操做,而且在不等待合併完成的狀況下當即調用返回。

傳遞 true 做爲第三個參數值(可選的)給上述命令,將會強制一個合併(merge)。一般只有相鄰的區域能夠合併。force 參數複寫了這個行爲,僅爲專家使用。

69.7. 存儲 Store

一個存儲包含了一個內存存儲(MemStore)和0或多個文件存儲(StoreFile--HFile)。一個存儲能夠定位到一個Region的表中的一個列族。

69.7.1. MemStore

MemStores是Store中的內存Store,能夠進行修改操做。修改的內容是Cell/KeyValues。當flush操做被請求時,現有的memstore會生成快照,而後被清空。HBase繼續爲重新的MemStore的編輯信息提供服務,而且直到flusher報告刷新成功以前,保存快照。flusher報告刷新成功以後,快照才被刪除。注意,當刷新發生時,屬於同一個Region的MemStores都會被刷新。

69.7.2. MemStore Flush

能夠在下面列出的任何條件下觸發MemStore刷新。最小的刷新單元是一個個Region,而不是在單獨的MemStore層。

  1. MemStore的大小達到 hbase.hregion.memstore.flush.size, 全部屬於這個MemStore的Region下的MemStores都將被刷新到磁盤。

  2. RegionServer中全部MemStore的使用率超過RegionServer中MemStore上限值(由 hbase.regionserver.global.memstore.upperLimit指定),則該RegionServer上不一樣Region的MemStore都會被刷新到磁盤上,以減小所有的MemStore使用量。

    刷新的順序是以Region的MemStore使用量倒序排列的。

    Regions將會把它們的MemStore刷新到磁盤,知道所有MemStore使用率降到或略小於 hbase.regionserver.global.memstore.lowerLimit。

  3. 當RegionServer中的WAL日誌條目數量達到 hbase.regionserver.max.logs時, RegionServer上的不一樣的Region的將會被刷新到磁盤以減小WAL中日誌的數量。

    刷新順序是基於時間的。

    有時間最先的MemStore的Region最新被刷新,直到WAL的數量降低到 hbase.regionserver.max.logs。

69.7.3. 掃描 Scans

  • 當客戶端發出在一個表上的掃描時,HBase產生 RegionScanner 對象, 每一個Region一個,用來服務於掃描請求。

  • RegionScanner 對象包含一個 StoreScanner 對象的列表,每一個列族一個。

  • 每一個 StoreScanner 對象進一步包含了一個 StoreFileScanner 對象的列表,對應每一個列族的 StoreFile 和 HFile,還包含了一個MemStore中 KeyValueScanner 對象的列表。

  • 這兩個列表合併爲一個,它以升序排序,順序是以列表結尾的MemStore的掃描對象進行排列的。

  • 當一個 StoreFileScanner 對象被構造,它就和一個 MultiVersionConcurrencyControl 的讀取位置(read point)有關, 這個位置就是當前的 memstoreTS,過濾掉在這個讀取位置之後任意新的更新。

69.7.4. StoreFile (HFile)

StoreFiles 是數據存在的地方。

HFile Format

HFile文件格式是基於BigTable [2006]論文中的SSTable,以及構建在Hadoop上的TFile(單元測試suite和壓縮工做能夠直接從TFile中獲取)。 Schubert Zhang 的博客HFile: A Block-Indexed File Format to Store Sorted Key-Value Pairs詳細介紹了HBase的HFile。Matteo Bertozzi也提供了有幫助的介紹HBase I/O: HFile

獲取更多信息,參考 HFile source code。也能夠參考 HBase file format with inline blocks (version 2) 獲取關於 0.92 引入的HFile v2 格式的信息。

HFile Tool

要想看到hfile內容的文本化版本,你能夠使用 org.apache.hadoop.hbase.io.hfile.HFile 工具。能夠這樣用:

$ ${HBASE_HOME}/bin/hbase org.apache.hadoop.hbase.io.hfile.HFile

例如,你想看文件 hdfs://10.81.47.41:8020/hbase/TEST/1418428042/DSMP/4759508618286845475, type the following:

$ ${HBASE_HOME}/bin/hbase org.apache.hadoop.hbase.io.hfile.HFile -v -f hdfs://10.81.47.41:8020/hbase/TEST/1418428042/DSMP/4759508618286845475

若是你沒有輸入-v,就僅僅能看到一個hfile的彙總信息。其餘功能的用法能夠看HFile的文檔。

StoreFile 在HDFS上的目錄結構

關於StoreFiles在HDFS上是什麼樣子、目錄結構如何的信息參考 Browsing HDFS for HBase Objects

69.7.5. Blocks 塊

StoreFiles 由塊組成。塊大小是基於每一個列族配置的。

壓縮發生在StoreFiles的塊級別上。更多關於壓縮的信息,參考 Compression and Data Block Encoding In HBase

更多關於塊的信息,參考 HFileBlock source code.

69.7.6. KeyValue

KeyValue 類 是數據存儲在HBase的關鍵。KeyValue包裝了一個字節數組,並將偏移量和長度做爲傳遞給數組,指定了從哪裏開始是KeyValue的內容。

字節數組中的KeyValue格式:

  • keylength

  • valuelength

  • key

  • value

Key被進一步分解爲

  • rowlength

  • row (i.e., the rowkey)

  • columnfamilylength

  • columnfamily

  • columnqualifier

  • timestamp

  • keytype (e.g., Put, Delete, DeleteColumn, DeleteFamily)

KeyValue實例不會跨越塊。例如,若是有一個8M的KeyValue,即便block-size是64Kb,這個KeyValue也會被做爲一個一致的塊讀取。更多信息,參考 KeyValue source code

Example

爲了強調上面的觀點,咱們來看看在同一行中,兩個不一樣的列都發生Put操做時會發生什麼:

  • Put #1: rowkey=row1, cf:attr1=value1

  • Put #2: rowkey=row1, cf:attr2=value2

即便是在同一行的,爲每一個列建立了一個KeyValue

Key portion for Put #1:

  • rowlength -----------→ 4

  • row -----------------→ row1

  • columnfamilylength --→ 2

  • columnfamily --------→ cf

  • columnqualifier -----→ attr1

  • timestamp -----------→ server time of Put

  • keytype -------------→ Put

Key portion for Put #2:

  • rowlength -----------→ 4

  • row -----------------→ row1

  • columnfamilylength --→ 2

  • columnfamily --------→ cf

  • columnqualifier -----→ attr2

  • timestamp -----------→ server time of Put

  • keytype -------------→ Put

重要的是,要理解RowKey、ColumnFamily、column(列標識符) 嵌入在KeyValue實例中。這些惟一標識越長,KeyValue就越大。

69.7.7. 緊縮 Compaction

模棱兩可的術語
  • StoreFile 是HFile的外觀門面。在緊縮的術語中,StoreFile的使用彷佛在過去更流行。

  • Store 和 ColumnFamily是同樣的。StoreFiles 和 Store 或者 ColumnFamily 相關聯。

  • 若是你想閱讀更多關於 StoreFiles versus HFiles 和 Stores versus ColumnFamilies, 參考 HBASE-11316.

當MemStore達到一個給定的大小(hbase.hregion.memstore.flush.size),它會把本身的內容刷新到一個 StoreFile。隨着時間,一個Store的StoreFiles的數量會增加。緊縮(Compaction) 是一個操做,它能經過把StoreFiles合併在一塊兒以減小Store中StoreFiles的數量,爲了增長讀取操做的性能。緊縮(Compactions)能夠是資源密集型的,能夠幫助或阻礙性能,這取決於許多因素。

有兩種類型的緊縮:次緊縮和主緊縮。次緊縮和主緊縮有如下不一樣的方式。

小緊縮(Minor compactions) 一般會選擇數個小的相鄰的文件,把它們重寫成一個大的StoreFile。Minor緊縮不會刪除(過濾掉)打上刪除標記的數據或過時版本的數據,由於會有潛在的反作用。參考 Compaction and Deletions 和 Compaction and Versions 獲取關於刪除和數據版本在緊縮中如何處理的信息。一個Minor緊縮的最終結果是爲給定的Store生成更少的、更大的StoreFile。

大緊縮(major compaction) 的最終結果是Store的一個單獨的StoreFile。Major緊縮還會處理帶有刪除標記的數據和超過最大版本數的數據(過時數據)。參考Compaction and DeletionsCompaction and Versions 獲取關於刪除和數據版本在緊縮中如何處理的信息。

Compaction and Deletions

當在HBase中出現顯式刪除時,數據實際上不會被刪除。相反,只是在數據上打了一個 墓碑(tombstone) 標記。墓碑標記能夠避免這個數據在查詢時返回。在一個Major緊縮過程當中,數據被真正地刪除了,而且從StoreFile中刪除了墓碑標記。若是刪除是由於一個過時的TTL而發生的,則沒有建立一個墓碑。相反,過時的數據會被過濾掉,不會被寫回緊縮好的StoreFile。

Compaction and Versions

當你建立一個列族時,你能夠經過指定 HColumnDescriptor.setMaxVersions(int versions) 指定要保留的最大版本數。默認值是3。若是比指定的最大版本數要多的版本出現了,多餘的版本會被過濾掉,而不會寫回壓縮好的StoreFile。

Major 緊縮會影響查詢結果

在一些情景下,若是一個較新的版本被顯式刪除,舊版本可能會被無心中恢復。參考 Major compactions change query results 獲取更深刻的解釋。這個情景只會發生在Major緊縮完成以前。

 

 

 

從理論上講,主要的壓縮能提升性能。可是,在一個高度負載的系統上,主要的壓縮操做可能須要不適當的資源,而且會對性能產生負面影響。在默認配置中,Major緊縮會自動在7天內運行一次。這有時對於生產系統來講是不合適的。你能夠手動管理Major緊縮操做。參考 Managed Compactions.

Compactions不執行Region合併。參考 Merge 獲取更多關於Region合併的信息。

緊縮策略 Compaction Policy - HBase 0.96.x and newer

緊縮大的StoreFiles,或者一次性緊縮太多的StoreFiles,會致使更多的負載,這個負載比集羣在不形成性能問題時可以處理的IO負載更大。HBase選取哪些StoreFiles進行緊縮操做(不管是Minor的仍是Major的)的方法被稱爲緊縮策略

HBase 0.96.x以前, 只有一種緊縮策略。原有的緊縮策略 RatioBasedCompactionPolicy 仍然可用。新的默認的緊縮策略被稱爲 ExploringCompactionPolicy, 已被打到了HBase 0.94 和 HBase 0.95上,而且是HBase 0.96及之後版本的默認策略。它在 HBASE-7842 被實現。簡單來講,ExploringCompactionPolicy 試圖去選擇最有可能的StoreFiles集合來以最小的工做量進行緊縮,而 RatioBasedCompactionPolicy 選取知足條件的第一個StoreFiles集合。

無論使用的緊縮策略是什麼,文件選擇都是由幾個可配置參數控制的,而且在多步驟方法中進行。這些參數將在文中進行解釋,而後將在一個表中給出它們的描述、默認值以及更改它們的含義。

被卡住 Being Stuck

當MemStore變得過大時,它須要把本身的內容刷新到一個StoreFile中。然而,一個Store只能擁有 hbase.hstore.blockingStoreFiles 個文件,因此MemStore須要等待這個Store的StoreFiles的數量經一次或屢次緊縮而變少。然而,若是MemStore 變得比 hbase.hregion.memstore.flush.size 還大的話,它將不能把本身的內容刷新到一個StoreFile中。若是MemStore過大,並且StoreFiles的數量過多,這種算法就被稱爲「被卡住」了。緊縮算法檢查這種「卡住」的狀況,並提供機制緩解這個問題。

ExploringCompactionPolicy 算法

ExploringCompactionPolicy 算法在選擇能帶來最大好處的StoreFiles的緊縮組合以前,考慮每一種可能的相鄰的StoreFiles組合。

ExploringCompactionPolicy特別好用的一個狀況是,當你批量加載數據(bulk-loading)且批量加載操做建立的StoreFiles比存有和此次批量加載的數據相比更老的數據的StoreFiles時。這能夠「欺騙」HBase在每次須要緊縮時選擇執行一個Major緊縮,並形成大量額外的開銷。使用ExploringCompactionPolicy,Major緊縮發生的頻率要低得多,由於Minor緊縮更有效。

通常來講,ExploringCompactionPolicy對於大多數狀況是正確的選擇,所以它是默認的壓縮策略。你能夠一塊兒使用 ExploringCompactionPolicy 和 Experimental: Stripe Compactions

這個策略的邏輯能夠在 hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/compactions/ExploringCompactionPolicy.java 中查看。下面是一個ExploringCompactionPolicy的演練邏輯。

  1. 建立一個Store中全部的現有的StoreFiles的列表。該算法的其他部分將過濾該列表,以得到用於緊縮的HFiles子集。

  2. 若是這是用戶請求的緊縮,則嘗試執行所請求的緊縮類型,而不考慮一般選擇的緊縮類型。注意,即便用戶請求一個Major緊縮,也可能不執行Major壓縮。這多是由於列族中不是全部的StoreFiles均可用來作緊縮,或者由於列族中有太多的Stores。

  3. 一些StoreFiles會自動被排除在考慮以外,這些StoreFiles包括:

    • 大於 hbase.hstore.compaction.max.size 的StoreFiles

    • 由批量加載操做(bulk-load)建立的StoreFile,它顯式地排除了緊縮。您可能決定把由批量加載生成的StoreFiles排除在緊縮以外。要這麼作的話,在Bulk-Load操做時指定參數 hbase.mapreduce.hfileoutputformat.compaction.exclude 。

  4. 遍歷第1步生成的列表,並生成一個列表,這個列表包含了全部的能夠額緊縮在一塊兒的StoreFiles的潛在集合。一個潛在的集合是一組由 hbase.hstore.compaction.min 個相鄰的在第1步生成的列表中的 StoreFiles。對於每一組集合,執行一些檢查並肯定這是不是能夠完成的最好的緊縮:

    • 若是這個集合中的StoreFiles的數量 (不是這些StoreFiles的大小) 小於 hbase.hstore.compaction.min 或者多於 hbase.hstore.compaction.max, 把這個集合排除在外。

    • 將這一集合中的StoreFiles的大小與目前列表中能找到的最小的可能緊縮的StoreFiles集合的大小進行比較。若是這個StoreFils集合的大小是能夠完成的最小的緊縮,那麼把這個集合存儲起來用做當算法被「卡住」時的一個fall-back,而且不須要選擇其餘的存儲文件。參考Being Stuck.

    • 在這一組存儲文件中對每一個StoreFile進行基於大小的完整性檢查。

      • 若是這個StoreFile的大小比 hbase.hstore.compaction.max.size 大,把它排除在外。

      • 若是這個StoreFile的大小大於等於 hbase.hstore.compaction.min.size, 基於文件的比率檢查它是否太大而不能被考慮。

        若是知足如下條件,這個檢查就是成功的:

      • 只有一個StoreFile在這個集合裏,或者

      • 對於每一個StoreFile, 它的大小 乘以 hbase.hstore.compaction.ratio (或者 hbase.hstore.compaction.ratio.offpeak,若是非高峯時間被設置,且在非高峯時間段)的值比這個集合中其餘HFiles的大小的和還要小。

  5. 若是這個StoreFiles的集合仍然在被考慮之中,拿它和前一個選出來的最好的緊縮組合進行比較。若是它更好,就由它來替代前一個選出來的最好緊縮組合。

  6. 當潛在緊縮的組合的整個列表都被處理完後,在找出的最好的緊縮組合上作緊縮。若是沒有StoreFiles被選出作緊縮,可是存在了不少StoreFiles,假定這個算法被卡住了(參考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。這個StoreFiles的列表以sequence ID作排序。Sequence ID是在一個Put被添加到WAL中時生成的,它被存在HFile的metadata裏。

  2. 查看算法是否被卡住(參考Being Stuck),若是被卡住,會強制執行一個Major緊縮。這是 The ExploringCompactionPolicy Algorithm 常做爲一個比RatioBasedCompactionPolicy更好的選擇的關鍵部分。

  3. 若是這是用戶請求的緊縮,則嘗試執行所請求的緊縮類型。注意,Major緊縮可能不被執行,若是全部的HFiles不可用來作緊縮,或者,若是過多的StoreFile存在(比hbase.hstore.compaction.max還要多)。

  4. 一些StoreFiles會自動被排除在考慮以外,這些StoreFiles包括:

    • 大於 hbase.hstore.compaction.max.size 的StoreFiles

    • 由批量加載操做(bulk-load)建立的StoreFile,它顯式地排除了緊縮。您可能決定把由批量加載生成的StoreFiles排除在緊縮以外。要這麼作的話,在Bulk-Load操做時指定參數 hbase.mapreduce.hfileoutputformat.compaction.exclude 。

  5. 被容許進行Major緊縮的StoreFiles的最大文件數由 hbase.hstore.compaction.max 參數控制。若是這個列表包含有大於這個數值的StoreFiles,一個Minor緊縮被執行,即便原本一個Major緊縮該被執行的。可是,即便比 hbase.hstore.compaction.max 還多的StoreFiles要作緊縮時,用戶請求的Major緊縮仍然會發生。這不是和第2條矛盾嗎?

  6. 若是這個列表包含的要作緊縮的StoreFiles 比 hbase.hstore.compaction.min 少,Minor緊縮會被停止。注意,一個Major compaction 能夠在單個HFile上執行。它的功能是移除被刪除的和過去版本的數據,並在StoreFile中重置位置。

  7. 在一個Minor緊縮過程當中, hbase.hstore.compaction.ratio 參數的值 乘以 比給定文件要小的StoreFiles的和, 用來決定這個給定的StoreFile是否被選取作緊縮。例如,若是 hbase.hstore.compaction.ratio 是 1.2, FileX 是 5MB, FileY 是 2MB, and FileZ 是 3MB:

    5 <= 1.2 x (2 + 3)            or            5 <= 6

    在這種狀況下,FileX就能夠用來作Minor緊縮了。若是FileX是7MB,它就不會用來作Minor緊縮。這個比例支持較小的StoreFile。若是你配置了 hbase.offpeak.start.hour 和 hbase.offpeak.end.hour,你能夠使用參數 hbase.hstore.compaction.ratio.offpeak,爲在非高峯時段的使用配置一個不一樣的比例值。

  8. 若是上一次的Major緊縮是好久之前作的,如今有多於一個StoreFile要被緊縮,一個Major緊縮就會運行,即便它應該運行Minor緊縮。默認狀況下,Major緊縮的最大間隔時間是7天加或減4.8小時,而且經過這些參數隨機決定。在 HBase 0.96以前,Major緊縮週期是 24 hours。參考下表中的 hbase.hregion.majorcompaction 調整或禁用基於時間的Major緊縮。

緊縮算法用到的參數  Parameters Used by Compaction Algorithm

該表包含了用於緊縮的主要配置參數。這個列表並不詳盡。要調整這些參數的默認值,編輯 hbase-default.xml 文件。要獲取完整的可用配置參數列表,參考 config.files

hbase.hstore.compaction.min

在緊縮能運行前,能夠作緊縮操做的StoreFiles的最小文件數。調整 hbase.hstore.compaction.min 的目的是爲了不有大量的小StoreFiles進行緊縮。設置這個值爲2,會致使每次在一個Store中有兩個StoreFiles時就會發生Minor緊縮,這多是不合適的。若是你把這個值設置得過高,其餘全部值都須要相應地調整。對於大多數狀況,默認值是合適的。在HBase以前的版本,參數 hbase.hstore.compaction.min 被稱做 hbase.hstore.compactionThreshold。

默認值: 3

hbase.hstore.compaction.max

不管符合作緊縮的存儲文件的數量如何,將被選擇作單個Minor緊縮的StoreFiles的最大文件數。 Effectively, hbase.hstore.compaction.max 的值控制了完成一個單個緊縮所需的時間長度。把它設置大了,意味着更多的StoreFiles能夠被緊縮。對於大多數狀況,默認值是合適的。

Default: 10

hbase.hstore.compaction.min.size

大小小於這個值的一個StoreFile將一直符合Minor緊縮。大小等於或大於這個值的 StoreFiles被 hbase.hstore.compaction.ratio 評估以決定他們是否符合作Minor緊縮。由於這個限制表明了比這個值小的全部store文件的「自動include」限制,因此這個值在寫操做密集的環境中可能須要減少,在這個環境中,1-2 MB範圍內的許多文件都被刷新了,由於每一個StoreFile都將是緊縮的目標,緊縮後生成的StoreFile可能仍然比最小的大小要小,而且須要進一步的緊縮。若是減少了這個參數,則會更快地觸發比率檢查。這解決了早期版本的HBase中出現的一些問題,可是在大多數狀況下,更改這個參數再也不是必需的。

Default:128 MB

hbase.hstore.compaction.max.size

一個大小大於這個值的StoreFile 將被排除在緊縮操做以外。增長 hbase.hstore.compaction.max.size 值的效果很小,更大的 StoreFiles 不常常被緊縮。若是你以爲緊湊的事情發生得太頻繁而沒有太多的好處,你能夠試着提升這個值。

DefaultLong.MAX_VALUE

hbase.hstore.compaction.ratio

對於Minor緊縮,這個比例被用來決定給定的StoreFile(大小大於hbase.hstore.compaction.min.size)是否符合緊縮操做。它的做用是限定大的StoreFile的緊縮。這個參數的值是一個浮點小數。

  • 一個大的比率,例如10,將會產生一個巨大的StoreFile。相反,它的值是0.25的話,將產生與BigTable緊縮算法相似的行爲,生成4個StoreFiles。

  • 推薦使用介於1.0到1.4之間的中等值。 在調優這個值時,您須要將寫成本與讀成本進行平衡。 提升值(好比1.4)將會有更多的寫成本,由於您將緊縮更大的存儲文件。可是,在讀取過程當中,HBase須要經過更少的存儲文件來完成讀取。若是你不能使用 Bloom Filters,能夠考慮這個方法。

  • 或者,您能夠將該值下降到1.0這樣的值,以減小寫操做的成本,並限制讀時接觸StoreFiles的數量。在大多數狀況下,這個默認值是合適的。

    Default1.2F

hbase.hstore.compaction.ratio.offpeak

若是非高峯時段被配置的話(見如下配置),這個緊縮比例參數在非高峯時段被使用。參數表達是一個浮點型小數值。在一個設定的時間週期,這個參數容許更積極的(或積極性少地,若是你把它設置成低於hbase.hstore.compaction.ratio的值)緊縮。若是非高峯被禁用的話(默認狀況下)就忽略它。這個參數和 hbase.hstore.compaction.ratio 的工做方式同樣。

Default5.0F

hbase.offpeak.start.hour

非高峯時段的開始時點,數值爲一個在0到23之間含0和23的整數。設置爲-1可禁用非高峯功能。

Default-1 (disabled)

hbase.offpeak.end.hour

非高峯時段的結束時點,數值爲一個在0到23之間含0和23的整數。設置爲-1可禁用非高峯功能。

Default-1 (disabled)

hbase.regionserver.thread.compaction.throttle

緊縮操做有兩個不一樣的線程池,一個用來作大的緊縮,另外一個作小的緊縮。這有助於保持瘦表(如hbase:meta)快速的緊縮。若是一個緊縮操做量(要處理的StoreFiles大小總和)大於這個閾值,它會被提交到大緊縮池。在大多數狀況下,這個默認值是合適的。

Default2 x hbase.hstore.compaction.max x hbase.hregion.memstore.flush.size (which defaults to 128)

hbase.hregion.majorcompaction

作Major緊縮的時間間隔,以毫秒爲單位。設置爲0則禁用基於時間的自動Major緊縮。用戶請求的和基於大小(size-based)的Major緊縮將會仍然執行。這個值 乘以  hbase.hregion.majorcompaction.jitter 會在給定的時間窗口中的任意時間開始Major緊縮。

Default: 7 days (604800000 milliseconds)

hbase.hregion.majorcompaction.jitter

hbase.hregion.majorcompaction 的乘數,使Major緊縮發生在給定的時間間隔內(hbase.hregion.majorcompaction設置了時間間隔的base)。這個數值越小,緊縮發生的間隔將越接近 hbase.hregion.majorcompaction 。這個值是一個浮點小數。

Default.50F

緊縮文件的選擇 Compaction File Selection
遺留信息 Legacy Information

因爲歷史緣由,這一節被保留了下來,並提到了在HBase.0.96.x以前緊縮的工做方式。若是你啓用了RatioBasedCompactionPolicy Algorithm,你仍然能夠使用它的行爲。獲取關於HBase0.96及之後版本的緊縮的工做方式,參考 Compaction

 

 

要理解選擇StoreFile的核心算法,在Store source code中有一些很是有用的代碼,能夠做爲有用的參考。

它已經拷貝以下:

/* normal skew:
 *
 *         older ----> newer
 *     _
 *    | |   _
 *    | |  | |   _
 *  --|-|- |-|- |-|---_-------_-------  minCompactSize
 *    | |  | |  | |  | |  _  | |
 *    | |  | |  | |  | | | | | |
 *    | |  | |  | |  | | | | | |
 */
重要的參數 Important knobs:
  • hbase.hstore.compaction.ratio 用於緊縮的文件選擇算法中的比例值 (默認 1.2f).

  • hbase.hstore.compaction.min (在 HBase v 0.90 時被稱爲 hbase.hstore.compactionThreshold) (files) 爲發生一個緊縮而選取的每一個Store中的StoreFiles的最小數目 (默認 2).

  • hbase.hstore.compaction.max (files) 要進行Minor緊縮的StoreFiles的最大數目  (默認 10).

  • hbase.hstore.compaction.min.size (bytes) 任何小於這個參數值的StoreFile自動成爲緊縮的候選文件。默認爲 hbase.hregion.memstore.flush.size的值 (128 mb).

  • hbase.hstore.compaction.max.size (.92) (bytes) 任何大於這個參數值的StoreFile自動被排除在緊縮操做以外 (默認 Long.MAX_VALUE).

Minor緊縮的StoreFile的選擇邏輯是基於文件大小的,當 文件大小 <= sum(文件大小小於hbase.hstore.compaction.min.size的文件的大小) * hbase.hstore.compaction.ratio時,這個文件被選擇進行緊縮操做

Minor Compaction File Selection - Example #1 (Basic Example)

這個例子反映了單元測試 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, 50, 23, 12, and 12 bytes (從舊到新排列)。基於以上的參數設置,被選中進行Minor緊縮的文件是2三、十二、12。

爲何?

  • 100 → No, 由於 sum(50, 23, 12, 12) * 1.0 = 97.

  • 50 → No, 由於 sum(23, 12, 12) * 1.0 = 47.

  • 23 → Yes, 由於 sum(12, 12) * 1.0 = 24.

  • 12 → Yes, 由於前面的文件已經被包含,且這個文件的加入沒有超過最大文件數5的限制

  • 12 → Yes, 由於前面的文件已經被包含,且這個文件的加入沒有超過最大文件數5的限制

Minor Compaction File Selection - Example #2 (文件數量不夠作緊縮 Not Enough Files ToCompact)

這個例子反映了單元測試 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, and 12 bytes (從舊到新排列)。 基於以上的參數設置,緊縮不會發生。

Why?

  • 100 → No, 由於 sum(25, 12, 12) * 1.0 = 47

  • 25 → No, 由於 sum(12, 12) * 1.0 = 24

  • 12 → No. 爲候選文件,由於 sum(12) * 1.0 = 12, 只有2個文件能夠進行緊縮操做,小於閾值3。

  • 12 → No. 爲候選文件,緣由和前一個StoreFile同樣,可是沒有足夠數量的文件作緊縮操做。

Minor Compaction File Selection - Example #3 (因文件數量超過最大限制數而限制文件作緊縮 Limiting Files To Compact)

這個例子反映了單元測試 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)

The following StoreFiles exist: 7, 6, 5, 4, 3, 2, and 1 bytes apiece (oldest to newest). With the above parameters, the files that would be selected for minor compaction are 7, 6, 5, 4, 3.

Why?

  • 7 → Yes, because sum(6, 5, 4, 3, 2, 1) * 1.0 = 21. Also, 7 is less than the min-size

  • 6 → Yes, because sum(5, 4, 3, 2, 1) * 1.0 = 15. Also, 6 is less than the min-size.

  • 5 → Yes, because sum(4, 3, 2, 1) * 1.0 = 10. Also, 5 is less than the min-size.

  • 4 → Yes, because sum(3, 2, 1) * 1.0 = 6. Also, 4 is less than the min-size.

  • 3 → Yes, because sum(2, 1) * 1.0 = 3. Also, 3 is less than the min-size.

  • 2 → No. Candidate because previous file was selected and 2 is less than the min-size, but the max-number of files to compact has been reached.

  • 1 → No. Candidate because previous file was selected and 1 is less than the min-size, but max-number of files to compact has been reached.

關鍵配置項的影響 Impact of Key Configuration Options
這個內容限制在 Parameters Used by Compaction Algorithm 的配置參數表裏

 

 

日期分層緊縮  Date Tiered Compaction

日期分層緊縮是一個基於時間的存儲文件緊縮的策略,這個策略對時間序列的數據作基於時間範圍的掃描有好處。

何時使用日期分層緊縮 When To Use Date Tiered Compactions

考慮對限定了時間範圍的數據進行的讀取操做使用日期分層緊縮,特別是掃描近期的數據。

不要在如下情景使用

  • 沒有時間範圍限定的隨機讀取  random gets without a limited time range

  • 頻繁的刪除和更新 frequent deletes and updates

  • 頻繁地從訂單數據中建立長尾,特別是用將來的時間戳寫 Frequent out of order data writes creating long tails, especially writes with future timestamps 不理解

  • 頻繁的帶有大量重疊的時間範圍的批量加載 frequent bulk loads with heavily overlapping time ranges

性能改善

性能測試展現了基於時間範圍掃描的性能在限定的時間範圍內有很大改善,特別是掃描近期的數據。

啓用時間分層緊縮 Enabling Date Tiered Compaction

你能夠對一個表或列族啓用時間分層緊縮,經過設置它的hbase.hstore.engine.class 參數爲 org.apache.hadoop.hbase.regionserver.DateTieredStoreEngine。

你還須要設置 hbase.hstore.blockingStoreFiles 爲一個大的數值, 例如 60, 若是使用全部的默認設置,而不是12的默認值。若是改變這個參數值的話,使用 1.5到2的值 乘以 Projected 文件數量,  Projected file 數量 = windows per tier x tier count + incoming window min + files older than max age

你還須要把 hbase.hstore.compaction.max 設置成和 hbase.hstore.blockingStoreFiles 同樣的值以消除Major緊縮的障礙。

過程: 啓用 Date Tiered Compaction
  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. 配置其餘的屬性項,參考 Configuring Date Tiered Compaction 獲取更多信息.

過程: 禁用 Date Tiered Compaction
  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'}}

當你經過任意一種方式改變存儲引擎時,一個Major緊縮可能在大多數Regions上執行。這在新表上不是必須的。

配置 Date Tiered Compaction

時間分層緊縮的每個設置應該被配置在表或列族上。若是你使用HBase shell, 通常的命令模式以下:

alter 'orders_table', CONFIGURATION => {'key' => 'value', ..., 'key' => 'value'}}
Tier 參數

你能夠經過改變如下參數的設置,配置你的時間分層:

Table 9. Date Tier 參數 

設置 注意
hbase.hstore.compaction.date.tiered.max.storefile.age.millis 最大時間戳小於這個值的文件不會被緊縮。默認是 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 在相同的時間窗口選擇存儲文件的策略。它不該用到即將到來的窗口。默認是Exploring Compaction。這個設置能夠避免浪費的緊縮。

 

 

 

 

 

 

緊縮臨界點 Compaction Throttler

在分層緊縮的狀況下,集羣中的全部服務器同時會將窗口提高到更高的級別,所以建議使用緊縮臨界點:

設置 hbase.regionserver.throughput.controller 爲 org.apache.hadoop.hbase.regionserver.compactions.PressureAwareCompactionThroughputController。

關於 date tiered compaction更多的信息, 請參考 https://docs.google.com/document/d/1_AmlNb2N8Us1xICsTeGDLKIqL6T-oHoRLZ323MG_uy8中的設計規格

 

 

Experimental: Stripe Compactions

Stripe compactions 在HBase0.98是一個實驗性的功能,目的在於改善大的Regions或行鍵分佈不均的Region的緊縮。爲了實現更小更細粒度的緊縮,該Region內的StoreFiles是分爲幾個行鍵子範圍或Region的「條帶(Stripe)」進行單獨維護的。這些Strips對HBase的其餘部分是透明的,所以HFile或數據上的其餘操做不須要修改就能工做。

Stripe compactions 改變了HFile的佈局,在Regions內建立了子Regions。這些子Regions容易緊縮,致使不多的Major緊縮。這種方法緩解了較大Regions的一些挑戰。

Stripe compaction與Compaction徹底兼容,而且能夠和ExploringCompactionPolicy或RatioBasedCompactionPolicy協同工做。它能夠爲現有的表啓用,若是之後禁用它,該表將繼續正常運行。

何時使用 Stripe Compactions

若是遇到如下狀況,考慮使用Stripe Compaction:

  • 較大的Regions。在沒有附加的MemStore開銷和Region管理開銷的狀況下,你能夠獲得較小Regions的積極影響。

  • 非統一的鍵(分佈不均的鍵?),例如鍵中的時間維度。只有收到新鍵的Stripes纔會被緊縮。舊數據將不會常常緊縮。

性能改善 Performance Improvements

性能測試顯示出,讀的性能稍微改善了,讀和寫性能的可變性大大下降了。在大型的非均勻的行鍵的Region上,例如一個hash前綴的時間戳鍵,整體的長期的性能獲得了改善。這些性能收益在一個已經很大的表中是最顯著的。性能改進可能會擴展到Region分割。

啓用 Stripe Compaction

你能夠爲一個表或一個列族啓用Stripe Compaction,經過設置它的 hbase.hstore.engine.class 爲 org.apache.hadoop.hbase.regionserver.StripeStoreEngine進行配置。你還須要設置 hbase.hstore.blockingStoreFiles 爲一個大的數值,如 100 (而不是默認值 10).

Procedure: Enable Stripe Compaction
  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. Configure other options if needed. See Configuring Stripe Compaction for more information.

  3. Enable the table.

Procedure: Disable Stripe Compaction
  1. Set the hbase.hstore.engine.class option to either nil or org.apache.hadoop.hbase.regionserver.DefaultStoreEngine. Either option has the same effect.

    alter 'orders_table', CONFIGURATION => {'hbase.hstore.engine.class' => 'rg.apache.hadoop.hbase.regionserver.DefaultStoreEngine'}
  2. Enable the table.

當你在以某方式改變了存儲引擎後,啓用一個大的表時,一個Major緊縮可能會在大部分Regions上執行。這在新表上不是必須的。

Configuring Stripe Compaction

Stripe緊縮的每個設置應該被配置在表或列族上。若是你使用HBase shell, 通常的命令模式以下:

alter 'orders_table', CONFIGURATION => {'key' => 'value', ..., 'key' => 'value'}}
Region 和 stripe 的大小設置

你能夠基於你的Region大小配置你的Stripe 大小。默認狀況下,你的新的Region會含有一個Stripe啓動。在Stripe增加過大(16 * MemStore flushes size)後的下次緊縮,它被拆分紅兩個Stripes。隨着Region的增加,Stripe拆分會持續進行,直到這個Region大到被拆分。

您能夠爲本身的數據改進這種模式。一個好的規則是,1個Stripe至少有1GB的大小,以及大約8-12個用於統一行鍵的Stripes。例如,若是你的Regions有30GB,12 * 2.5GB 的Stripes多是好的開端。

Table 10. Stripe Sizing Settings

Setting Notes

hbase.store.stripe.initialStripeCount

當Stripe緊縮被啓用時,建立Stripe的數量。你能夠以下使用它:

  • 對於相對一致的行鍵,若是您經過以上描述知道近似的Stripes的目標數,您能夠經過初始化多個Stripes(2,5,10)來避免一些拆分的開銷。若是早期數據不能表明整個行鍵分佈,那麼這將不會是有效的。

  • 對於具備大量數據的現有表,此設置將有效地預劃分您的Stripes。

  • 對於諸如hash前綴序列鍵這樣的鍵,每一個Region都有多個Hash前綴,預先分割多是有意義的。

hbase.store.stripe.sizeToSplit

Stripe在分裂以前的最大尺寸。根據以上的大小調整考慮,將這個參數和 hbase.store.stripe.splitPartCount 結合使用,以控制目標Stripe的大小 (sizeToSplit = splitPartsCount * target stripe size)。

hbase.store.stripe.splitPartCount

在分割Stripes時要建立的新Stripes的數量。默認爲2,這對於大多數狀況是合適的。對於非均勻的行鍵,您能夠嘗試將數字增長到3或4,從而將到達的更新隔離到更窄的區域,而不須要額外的分割。

 

MemStore 大小調整

默認狀況下,根據現有的Stripes邊界和要刷新的行鍵,刷新將從一個MemStore建立多個文件。這種方法能夠最小化寫放大,可是若是MemStore很小,而且有不少Stripes,則多是不受歡迎的,由於文件過小了。

在這種情景下,你能夠設置 hbase.store.stripe.compaction.flushToL0 爲 true。這將使一個MemStore刷新到一個單個文件。當至少有 least hbase.store.stripe.compaction.minFilesL0 個文件 (默認爲 4) 被生成時, 它們將被緊縮成Striped files。

普通的緊縮配置和Stripe緊縮 Normal Compaction Configuration and Stripe Compaction

全部適用於普通緊縮的設置 (參考 Parameters Used by Compaction Algorithm) 都適用於Stripe緊縮。除了最小文件數和最大文件數,這兩個值默認設置大一些,由於Stripes的文件要小一些。要控制Stripe緊縮的最小和最大文件數,使用 hbase.store.stripe.compaction.minFiles 和 hbase.store.stripe.compaction.maxFiles, 而不是 hbase.hstore.compaction.min 和 hbase.hstore.compaction.max。


70. Bulk Loading 批量加載

70.1. Overview

HBase 有幾種把數據加載到表中的方法。最直接的方法是在MapReduce做業中使用 TableOutputFormat類,或者使用普通的客戶端APIs;可是這些一般不是最有效率的方法。

批量加載功能使用一個MapReduce做業,以HBase內部數據的格式輸出表數據,而後直接把生成的StoreFiles加載到運行中的集羣裏去。和簡單地使用HBase API相比,使用bulk load將會佔用更少的CPU和網絡資源。

70.2. Bulk Load Limitations限制

因爲批量加載繞過了寫路徑,因此WAL並無做爲過程當中的一部分被寫下來。副本經過讀取WAL進行工做,因此它不能看到批量加載進來的數據 - 對編輯使用 Put.setDurability(SKIP_WAL)也會有相同的效果。處理的一種方式是把原始的文件或HFile傳到其餘集羣,而且以其餘的方式處理

70.3. Bulk Load Architecture 結構

HBase bulk load 過程有兩個主要步驟組成。

70.3.1. 經過MapReduce做業準備數據 Preparing data via a MapReduce job

批量加載的第一步是經過一個使用了 HFileOutputFormat2的MapReduce做業生成HBase數據文件(StoreFiles)。這個輸出格式以HBase內部的存儲格式寫出數據,以便於它們事後被有效地加載到集羣中

爲了有效率地運行,HFileOutputFormat2 必須配置成每一個輸出的HFile都要放在一個單獨的Region內。爲了作到這一點,輸出將要被加載到HBase裏的做業使用Hadoop的 TotalOrderPartitioner 類來把map的輸出劃分到爲分開的鍵空間中不相交的範圍裏去,對應於表中Regions的鍵的範圍。

HFileOutputFormat2 有一個方便的函數, configureIncrementalLoad(), 能夠基於一個表裏當前的Region邊界自動地創建一個 TotalOrderPartitioner 。

70.3.2. 完成數據加載 Completing the data load

經過結合「importtsv.bulk.output」配置項使用 importtsv 工具 或者 經過一些使用了HFileOutputFormat2的其餘MapReduce做業,把數據導入準備完以後,completebulkload 工具被用來把數據導入到運行中的集羣中。這個命令行工具遍歷準備好的數據文件,爲每一個文件劃分它所屬的Region。而後,它將與適合接收HFile的RegionServer聯繫,將HFile移動到這個RegionServer的存儲目錄中,並使數據對客戶端可用。

若是Region的邊界在批量加載數據的準備過程當中發生了變化,或者在準備和完成步驟之間發生了變化,那麼 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 (此外,若是ZooKeeper不禁HBase管理的話,CLASSPATH 必須包含擁有ZooKeeper配置文件的目錄)中提供這個文件的話。

若是目標表在HBase中還不存在,這個工具將會自動生成這個表。

 

 

70.4. See Also

要獲取更多關於所引用工具的信息,參考 ImportTsv 和 CompleteBulkLoad.

參考 How-to: Use HBase Bulk Loading, and Why 獲取最近關於批量加載的最新博客。

70.5. Advanced Usage

雖然 importtsv 工具在不少狀況下都有用,高級用戶可能想以編程的方式生成數據,或者從其餘格式導入數據。要開始這麼作,先研究 ImportTsv.java ,查看關於HFileOutputFormat2的JavaDoc。

批量加載的Import步驟能夠編寫程序完成。參考 LoadIncrementalHFiles 類以獲取信息。


71. HDFS

因爲 HBase 在 HDFS 上運行(每一個存儲文件也被寫爲HDFS的文件),必須理解 HDFS 結構,特別是它如何存儲文件,處理故障轉移,備份塊。

參考 Hadoop 文檔 HDFS Architecture 獲取更多信息。

71.1. NameNode

NameNode 負責維護文件系統元數據。參考上述HDFS結構連接獲取更多信息。

71.2. DataNode

DataNode 負責存儲HDFS 塊。 參考上述HDFS結構連接獲取更多信息。


72. 基於時間軸一致性的高可用讀取 Timeline-consistent High Available Reads

72.1. Introduction

HBase架構從一開始就保證了強一致性,全部的讀寫都是經過一個region server,保證全部的寫按順序發生,全部的讀都會看到最近提交的數據。

然而,因爲在單一的位置讀取,若是服務器不可用,表的那些在不可用的RegionServer中的region在某些時間是不可用的。Region恢復進程須要三個階段:檢測、分配和恢復。檢測一般是耗時最長的,根據Zookeeper會話超時,目前在20-30秒。在此期間和完成恢復以前,客戶端不能讀取到region數據。

然而對於某些使用案例來講,數據多是隻讀的,或者能夠接受讀取陳舊的數據。有了基於時間軸一致性的高可用讀取,HBase能夠用於這些對延遲敏感的用例,在這些用例中,應用程序能夠指望給讀完成時設置一個時間限制。

爲實現高可用的讀取,HBase提供了一個特性叫作region副本。在這個模型中,一個表的每一個region會在不一樣的RegionServer中有多個副本。默認狀況下,Region副本數爲1,因此只有一個region副本被部署,這樣原來的模型中不會有任何的變化。若是region副本被設置爲2或者更多,master就會分配這個表的Regions的副本。負載均衡器會保證region副本不會都存儲在相同的region server上但會在相同的機架上(若是可能的話)。

一個單獨的Region的全部的副本上都會有一個惟一的replica_id,從0開始。Region副本有replica_id==0被稱爲主region,其餘的爲二級region。客戶端的寫只有主region能夠接收,主region包含着最新的變化。全部的寫都會先經過主region,從必定意義上講這不會是高可用的表現(意味着它們可能在Region不可用時會有一段時間阻礙客戶端的寫操做)。

72.2. 時間軸一致性 Timeline Consistency

有了這個功能,HBase引入了一致性定義,這個一致性能夠被提供給每一次讀取操做 (get or scan).

public enum Consistency {
    STRONG,
    TIMELINE
}

Consistency.STRONG 是HBase提供的默認的一致性模型(強一致性)。若是region複製=1,或者region副本只在一個表中,可是讀取的一致性是這麼作的,讀取老是會從主region來執行,因此和前一次的行爲相比不會有任何變化,客戶端老是能觀察到最新的數據。

若是執行讀操做是經過 Consistency.TIMELINE, 而後讀RPC將會首先發送到主region服務器上。在短期內 (hbase.client.primaryCallTimeout.get, 默認10ms ), 若是主region沒有響應,並行的RPC會被髮送到二級region。以後結果會從第一個完成RPC的返回。若是響應是來自主region副本,咱們就會知道數據是最新的。Result.isStale() API是檢查過時數據。若是結果是從二級region返回,那麼Result.isStale()爲true,而後用戶就能夠檢查關於過時數據可能的緣由。

HBase實現的 時間軸一致性和純粹的最終一致性在如下方面有所不一樣:

  • 單宿主和有序的更新:在寫方面,只有一個主region副本被定義能夠接收寫操做,此副本負責有序的編輯和防止衝突。這可以保證兩個不一樣的寫操做經過不一樣的副本和數據發散的狀況下不能在相同的時間提交。這樣就沒有必要作read-repair或者last-timestamp-wins這兩種衝突的解決方法。(read-repair:從CassandraWiki中找到這個概念。當對給定鍵進行查詢時,咱們將對全部鍵的副本執行摘要查詢,並將最新版本推到任何過時的副本上。若是比ALL弱的一致性級別被指定的話,這個操做將在從最近的副本返回數據到客戶端後在後後臺進行;不然它在返回數據前進行。)

  • 二級Region也按照主Region提交的編輯順序,將這些編輯寫入本身。經過這種方式,在任什麼時候間二級region包含主region上的一個數據鏡像,相似於關係型數據庫的複製,無論HBase在多數據中心仍是在單個集羣中。

  • 在讀取端,客戶端能夠發現讀取的是來自最新的數據或者是陳舊的數據。此外,客戶端能夠在每一個操做的基礎上發出不一樣一致性要求的讀請求,以確保本身的語義獲得保證。

  • 此外,客戶端在每一個操做客戶端仍然能夠觀察到無序的編輯,能夠追溯到過去的時間點,若是它首先看到一個從副本的讀,而後是另外一個從副本。對於Region副本或基於事務id的保證,不存在粘性。若是須要,這能夠在稍後實現。

Figure 3. Timeline Consistency

上圖能夠幫助咱們更好的理解TIMELINE的語義。假定有兩個客戶端,最早的寫是x=1,而後是x=2,最後是x=3。如上,全部的寫操做都被主Region副本處理。寫會被保存到預寫日誌 (WAL)中, 而且會被異步複製到其餘的副本中。在上圖能夠注意到replica_id=1的接收到了兩個更新操做,它顯示爲x=2,而replica_id=2的則只接收到1個更新操做,它顯示爲x=1。

若是Client1是經過STRONG一致性(強一致性)進行讀取,它只會從replica_id=0讀取從而保證觀察到最新的值x=3。若是客戶端使用TIMELINE方式(時間軸一致性)讀取,那麼RPC會被髮送到全部的副本中(在主region超時後),從第一個響應獲得的結果會被返回。所以客戶端能夠看到1,2或者3之中的任意一個值做爲x的值。假設主Region已經失敗了,那麼日誌複製就有一段時間不能持續進行。若是客戶端使用時間軸一致性從2個二級Region進行多路讀取,它能夠先看到 x=2,而後是 x=1,等等。

72.3. 權衡取捨 Tradeoffs

擁有二級Regions而得到的讀取可用性會有一些權衡取捨,對於每一個應用案例來講都應該對這裏的權衡取捨進行當心地評估。如下是它的優點和劣勢。

Advantages
  • 只讀表的高可用性。

  • 舊數據讀取的高可用性。

  • 以很是低的延時讀取新數據,以高百分比(99.9%)的延遲讀取舊數據。Ability to do very low latency reads with very high percentile (99.9%+) latencies for stale reads 延遲究竟是低仍是高?

Disadvantages
  • 表的Region複製量 > 1時,兩倍/三倍的MemStore的使用量 (取決於region複製的數量)

  • 增長block緩存的使用

  • 對於log複製會有額外的網絡傳輸

  • 爲副本備份額外的RPCs

要爲從多個副本里返回的Region數據進行服務,HBase在RegionServers以Secondary模式打開Regions。以Secondary模式打開的Regions將和主Region副本共享相同的數據文件,可是每一個Secondary Region副本將擁有本身的MemStore以保存未刷新的數據(只有主Region能夠作刷新)。爲了從Secondary Region讀取數據,數據文件塊也能夠緩存在Secondary Region的塊緩存中。

副本Region在主Region可用的狀況下不在生成新的HFile?

72.4. Where is the code

該特性由兩個階段交付,第一階段和第二階段。第一階段在HBase-1.0.0發佈時完成,意味着使用HBase-1.0.0的話,你能夠使用第一階段的全部特性。第二階段在HBase-1.1.0被提交,意味着全部在1.1.0以後的HBase版本都包含第二階段的特性。

72.5. 將寫入操做傳播到Region副本中 Propagating writes to region replicas

正如上面所討論的,寫入操做只到主Region副本中進行。要把寫入操做從主Region副本傳播到二級Region副本中,有兩個不一樣的機制。對於只讀表,你不須要使用下列任何方法。禁用和啓用該表應該使全部Region的副本里的數據都是可用的。對於變化的表,你必須只能下列機制中的一種:StoreFile Refresher, 或 Async WAL replication。 推薦使用後者。

72.5.1. StoreFile Refresher

第一種機制是 store file refresher,在 HBase-1.0+ 引入。Store file refresher 是在每個RegionServer中的線程,週期性地運行,而且爲二級Region副本作主Region存儲文件的刷新操做。若是它被啓用,這個refresher將保證二級Region副本及時地看到主Region中新刷新的、緊縮的或批量加載的文件。可是,這意味着只有刷新的數據能夠從二級Region副本中讀取到,而且在這個refresher運行以後,正在較長的一段時間內,二級Region副本中的數據將會落後主Region副本。

要調整這個功能特性,你應該配置 hbase.regionserver.storefile.refresh.period 爲一個非零的值。參考下面的配置小節。

72.5.2. Asnyc WAL replication

把寫入傳播到二級Region副本的第二種機制經過「異步WAL複製(Async WAL Replication)」的功能完成,而且只在HBase-1.1+中可用。這個功能的工做方式相似於HBase的多數據中心複製,但不一樣的是數據從一個Region被複制到二級Regions中。每一個二級副本一直以和主Region提交的寫入操做相同的順序接收和觀察寫入操做。在某種程度上,這個設計能夠被認爲是「集羣中複製」,而不是複製到一個不一樣的數據中心,數據被複制到二級Region以使二級Region內存中的數據保持是最新的。數據文件在主Region和其它副本中共享,以便沒有額外的存儲開銷。可是,二級Region將在它們的MemStore中保有最近的沒有被刷新到磁盤的數據,這會增長內存的開銷。主Region把刷新到磁盤、緊縮和批量加載的事件寫入它的WAL,這些內容也會經過WAL複製操做複製到二級Regions。當它們觀察到 刷新/緊縮 或 批量加載事件時,二級Regions重放事件以獲取新文件並刪除舊文件。

和主Region中同樣的順序提交寫入操做,保證二級Region不會與主Region中的數據分離,可是由於log複製是異步的,在二級Regions中的數據可能仍然是舊的。因爲該特性是以端點複製的方式工做,所以性能和延遲特性將相似於跨集羣複製。

Async WAL Replication 默認被禁用。你能夠經過設置 hbase.region.replica.replication.enabled 爲 true 啓用這個功能。當你第一次建立一個Region複製大於1的表,Asyn WAL Replication 功能將添加一個新的名爲 region_replica_replication 複製點。一旦被啓用,若是你想禁用這個功能,你須要作2件事:1. 在hbase-site.xml中把屬性 hbase.region.replica.replication.enabled 設置爲 false (參考下面的 Configuration section) ;2. 使用HBase shell或ReplicationAdmin類,在集羣中,禁用名爲 region_replica_replication 的複製點:

hbase> disable_peer 'region_replica_replication'

72.6. 存儲文件的TTL Store File TTL

在上面提到的兩種寫傳播方法中,主服務器的存儲文件將在獨立於主Region的二級Regions中打開。所以,對於那些被主Region緊縮的文件,二級Region可能仍然是引用這些文件供讀取,這就致使文件已經被compact掉而讀取不到。這兩種功能都使用HFlieLinks引用文件,可是對於文件不會過早地刪除的保證(目前)沒有任何保障。所以,你應該設置屬性參數 hbase.master.hfilecleaner.ttl 爲一個較大值,例如 1 小時,以保障在請求副本時你將不會受到IOException。

72.7. 元數據表的Region的副本複製 Region replication for META table’s region

目前,異步WAL複製作不了META表的WAL複製。META表的二級副本仍然把持久化的存儲文件中的內容刷新到本身。所以咱們能夠設置hbase.regionserver.meta.storefile.refresh.period屬性爲非0值,用以刷新元數據存儲文件。注意這個配置和hbase.regionserver.storefile.refresh.period配置不一樣。

72.8. 內存處理 Memory accounting

二級Region副本參考主Region副本的數據文件,可是它們有它們本身的MemStores(在 HBase-1.1+),而且還使用塊緩存。可是,其中一個差異是,當二級Region的MemStore產生內存壓力時,二級Region副本不能刷新MemStore中的數據到磁盤上。只有主Region作刷新操做而且這個刷新被複制到二級Region時,二級Region才能釋放memstore的內存。由於在一個RegionServer中有一些Regions的主Regions,也有一些其餘Regions的二級Regions,因此這些二級Region可能會引起同一臺Server上的主Region的額外刷新(爲何??)。在極端狀況下,可能沒有內存用來添加新的寫入內容,這個寫入內容是經過WAL複製過來的主Region的內容。爲了避免受這種狀況(而且因爲二級不能自行刷新)的影響,二級Region能夠經過執行文件系統的list操做以便從主Region中獲取新文件,來執行「存儲文件刷新」,並可能刪除它的memstore。這個刷新 只有在最大的二級Region副本的MemStore的大小至少是一個主Region副本的最大MemStore大小的 hbase.region.replica.storefile.refresh.memstore.multiplier (默認爲 4) 倍時 纔會執行。一個警告是,若是這個刷新被執行,二級Region能夠觀察到部分行在多個列族的更新(由於列族的刷新是獨立的)。默認狀況下,不要頻繁地執行這個操做。若是須要,你能夠將這個值設置爲一個大的數字以禁用該功能,可是要警告你的是它可能致使複製永久地阻塞。

72.9. 二級副本故障轉移 Secondary replica failover

當一個二級region副本第一次上線或者失敗時,它可能服務過一些來自它的memstore的編輯。由於對於二級副本,恢復的處理方式不一樣,必須確認它在分配以後開啓服務以前沒法上線。爲了作到這一點,這個二級Region會等待,直到它觀察到一個完整的刷新週期(啓動刷新、提交刷新)或從主Region複製了一個「Region打開事件」。在這種狀況發生以前,這個二級Region副本將經過拋出一個帶有消息「The region’s reads are disabled」的IOException以拒絕全部讀取請求。可是,其餘副本可能仍然可用來讀取,所以不會對具備時間軸一致性(TIMELINE)的rpc形成任何影響。爲了便於更快的恢復,當這個二級Region打開時將會觸發一個來自主Region的刷新請求。配置參數 hbase.region.replica.wait.for.primary.flush (默認啓用) 能夠被用來禁用這個功能,若是須要的話。

72.10. 配置參數 Configuration properties

要使用高可用讀取,你應該在 hbase-site.xml 文件中設置以下參數。沒有特定的配置來啓用或禁用Region副本,替代的方法是,你能夠在建立表或者修改表結構時,改變(增或減)每一個表的Region副本數量。下列配置是用來配置使用異步WAL複製和配置元數據副本爲3。

72.10.1. 服務端屬性 Server side properties

<property>
    <name>hbase.regionserver.storefile.refresh.period</name>
    <value>0</value>
    <description>
    爲二級Regions進行存儲文件Refresh的週期(單位爲毫秒)。0意味着該功能被禁用。
一旦二級Region看到了主Region中經過刷新到磁盤和緊縮生成的新的存儲文件,這個二級Region會刷新(Refresh)在這個Region中的文件(沒有通知機制)。
可是過於頻繁的Refresh會給NameNode形成額外的壓力。若是文件沒有被refresh的時間比HFile的TTL(hbase.master.hfilecleaner.ttl)的值還長的話,這個refresh請求會被拒絕。
給HFile TTL配置一個大的值以配合這個參數的配置是推薦的。
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> 是否啓用異步WAL複製 到二級Region副本。
若是這個功能被啓用,一個名爲"region_replica_replication"的複製點會被建立,對於Region副本>1的表,這個複製點會tail日誌,並把更改複製到Region副本中。
一旦這個功能被啓用,禁用這個複製也須要用shell或者ReplicationAdmin java類來禁用它的複製點。到二級Region副本的複製在標準的跨集羣複製上工做。
因此複製,若是顯示地被禁用,也不得不經過設置"hbase.replication"爲true被啓用,以使異步WAL複製的功能能夠工做。
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 ReplicationAdmin java class. Replication to secondary region replicas works over standard inter-cluster replication. So replication, if disabled explicitly, also has to be enabled by setting "hbase.replication"· to true for this feature to work.
</description> </property> <property> <name>hbase.region.replica.replication.memstore.enabled</name> <value>true</value> <description> 若是你設置這個值爲`false`,副本不會接收主Region所在的RegionServer的MemStore的更新。
若是你設置這個值爲`true`,你仍然能夠經過設置表的"REGION_MEMSTORE_REPLICATION"屬性爲`false`以在這個表上禁用MemStore複製。
若是MemStore複製被禁用,二級Region只會接收例如刷新到磁盤和批量加載這類事件的更新,將不會訪問主Region尚未刷新到磁盤到的數據。
這個功能保持了行級一致性的保證,即便讀取請求是`Consistency.TIMELINE`。
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> 二級Region副本的"存儲文件刷新"操做的 乘數。
若是一個RegionServer存在內存壓力,當最大的二級副本的MemStore的大小比最大的主副本的MemStore大小大這個參數值的倍數時,二級Region將會刷新它的存儲文件。
把這個值設置的很大會禁用這個功能,這是不推薦的。
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> 在一個二級Region開始服務數據以前,是否等待觀察主Region的一個完整的flush週期。禁用這個功能可能會形成二級Region副本在Region移動間讀取時後退。(不太明白設置爲false的意爲着什麼)
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>

須要記住的一點是,Region副本放置策略只由 StochasticLoadBalancer 執行,它是默認的均衡器。若是你在hbase-site.xml(hbase.master.loadbalancer.class)使用一個自定義的加載均衡器,Region副本可能會被放置在同一個Server中。

72.10.2. 客戶端屬性 Client side properties

確保在全部要使用Region副本的客戶端(和服務器)設置如下的參數屬性。

<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.

72.11. User Interface
在Master UI中,一個表的Region副本和主Region一塊兒展現。你能夠注意到,一個Region的副本將共享相同的開始和結束keys和相同的Region名前綴。惟一不一樣的是,追加的replica_id(編碼成16進制),而且Region編碼後的名字將會不一樣。你能夠在UI看顯示出來的副本ID。

72.12. Creating a table with region replication

Region複製是針對表的一個屬性。全部的表都默認有 REGION_REPLICATION = 1 ,意味着對於每一個Region只有一個副本。你能夠設置和改變一個表的每一個Region的副本數,經過在Table Descriptor裏設置 REGION_REPLICATION 屬性。

72.12.1. Shell

create 't1', 'f1', {REGION_REPLICATION => 2}

describe 't1'
for i in 1..100
put 't1', "r#{i}", 'f1:c1', i
end
flush 't1'

72.12.2. Java

HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(「test_table」));
htd.setRegionReplication(2);
...
admin.createTable(htd);

你還能夠使用 setRegionReplication() 和 alter table 來增長、減小表的Region副本數。

72.13. Read API and Usage
72.13.1. Shell
你能夠以下在Shell中使用 Consistency.TIMELINE 語義 讀取數據

hbase(main):001:0> get 't1','r6', {CONSISTENCY => "TIMELINE"}

你能夠模擬一個RegionServer 暫停或成不可用狀態,而後從一個二級副本中讀取:

$ kill -STOP <pid or primary region server>

hbase(main):001:0> get 't1','r6', {CONSISTENCY => "TIMELINE"}

使用Scan也同樣

hbase> scan 't1', {CONSISTENCY => 'TIMELINE'}

72.13.2. Java
你能夠設置Gets和Scans的一致性:

Get get = new Get(row);
get.setConsistency(Consistency.TIMELINE);
...
Result result = table.get(get);

也能夠傳遞給多個Gets:

Get get1 = new Get(row);
get1.setConsistency(Consistency.TIMELINE);
...
ArrayList<Get> gets = new ArrayList<Get>();
gets.add(get1);
...
Result[] results = table.get(gets);

And Scans:

Scan scan = new Scan();
scan.setConsistency(Consistency.TIMELINE);
...
ResultScanner scanner = table.getScanner(scan);

你能夠檢查結果是否從主Region返回,經過調用 Result.isStale():

Result result = table.get(get);
if (result.isStale()) {
  ...
}

72.14. Resources

1. 關於設計和執行更多的信息,能夠參考: HBASE-10070

2. HBaseCon 2014 talk also contains some details and slides.


73. Storing Medium-sized Objects (MOB)

保存到HBase中的全部數據大小各異,包括二進制數據像圖片或者文檔是比較合適的(MOB技術存儲和檢索非結構化的數據)。Hbase從技術上能夠處理大於100KB的cells二進制對象,HBase正常讀寫路徑小於100KB是最優的。當HBase處理超過這個閥值的大對象,這兒稱之爲中等大小對象或者MOBs,因爲拆分和緊縮形成的寫入放大致使性能降低。使用MOBs時,對象大小最好在100KB-10M之間。HBase FIX_VERSION_NUMBER能夠更好的管理大量的MOBs以保持性能,一致性和低成本的運營。對MOB的支持由HBase-11339中的實現提供。要發揮MOB的優點須要使用HFile的版本3。可選的配置是,爲每個RegionServer配置MOB文件的讀緩存(參考 Configuring the MOB Cache),而後配置特定的列保存MOB數據。客戶端代碼不須要改變就能夠使用HBase中的 MOB。這個功能對客戶端是透明的。

73.1. MOB方式配置列 Configuring Columns for MOB
在表的建立和修改時,你能夠配置列以支持MOB,能夠經過HBase Shell,也能夠經過Java API。這兩個相關的屬性是boolean類型的IS_MOB 和 MOB_THRESHOLD(能夠把一個對象看作是MOB的字節數)。只有 IS_MOB 是要求設置的。若是沒有指定MOB_THRESHOLD, 默認值爲 100 KB。

Example 38. Configure a Column for MOB Using HBase Shell

hbase> create 't1', {NAME => 'f1', IS_MOB => true, MOB_THRESHOLD => 102400}
hbase> alter 't1', {NAME => 'f1', IS_MOB => true, MOB_THRESHOLD => 102400}

Example 39. Configure a Column for MOB Using the Java API

HColumnDescriptor hcd = new HColumnDescriptor(「f」);
hcd.setMobEnabled(true);
...
hcd.setMobThreshold(102400L);
...

73.2. Testing MOB
工具 org.apache.hadoop.hbase.IntegrationTestIngestMOB 被用來輔助測試MOB功能。運行以下:

$ sudo -u hbase hbase org.apache.hadoop.hbase.IntegrationTestIngestMOB \
            -threshold 102400 \
            -minMobDataSize 512 \
            -maxMobDataSize 5120

threshold 肯定cell是否能夠看做爲MOB的閾值。默認爲1KB,值爲字節數。

minMobDataSize MOB數據大小的最小值。默認爲512B,值爲字節數。

maxMobDataSize MOB數據大小的最大值。默認爲5KB,值爲字節數。

73.3. Configuring the MOB Cache
由於和HFiles的數量相比,在任什麼時候候均可能有大量的MOB文件,因此MOB文件不是一直保持打開狀態。MOB文件讀緩存是一個LRU緩存,它保持了最近使用的MOB文件爲打開狀態。要在每個RegionServer上配置MOB文件的讀緩存,添加下列屬性到RegionServer的 hbase-site.xml, 配置符合你環境的參數值,重啓或依次啓動RegionServer。

Example 40. Example MOB Cache Configuration

<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>

73.4. MOB Optimization Tasks
73.4.1. Manually Compacting MOB Files
要手動緊縮MOB文件,而不是等到達到配置的條件觸發緊縮,使用 compact_mob 或 major_compact_mob HBase shell 命令。這些命令須要的第一個參數是代表,第二個參數是可選的,傳入列族名。若是不指定列族名,全部啓用了MOB的列族都將被緊縮。

hbase> compact_mob 't1', 'c1'
hbase> compact_mob 't1'
hbase> major_compact_mob 't1', 'c1'
hbase> major_compact_mob 't1'

這些命令也能夠經過 Admin.compactMob 和 Admin.majorCompactMob 來實現。

73.4.2. MOB Sweeper MOB清掃器
HBase MOB 有一個叫作Sweeper工具的MapReduce做業作優化工做。這個Sweeper工具合併小MOB文件或者有不少刪除和更新的MOB文件。若是你使用不依賴MapReduce的MOB緊縮,這個 Sweeper tool 就不是必須的。

要配置Sweeper工具,配置以下:

<property>
    <name>hbase.mob.sweep.tool.compaction.ratio</name>
    <value>0.5f</value>
    <description>
      If there are too many cells deleted in a mob file, it's regarded
      as an invalid file and needs to be merged.
      If existingCellsSize/mobFileSize is less than ratio, it's regarded
      as an invalid file. The default value is 0.5f.
    </description>
</property>
<property>
    <name>hbase.mob.sweep.tool.compaction.mergeable.size</name>
    <value>134217728</value>
    <description>
      If the size of a mob file is less than this value, it's regarded as a small
      file and needs to be merged. The default value is 128MB.
    </description>
</property>
<property>
    <name>hbase.mob.sweep.tool.compaction.memstore.flush.size</name>
    <value>134217728</value>
    <description>
      The flush size for the memstore used by sweep job. Each sweep reducer owns such a memstore.
      The default value is 128MB.
    </description>
</property>
<property>
    <name>hbase.master.mob.ttl.cleaner.period</name>
    <value>86400</value>
    <description>
      The period that ExpiredMobFileCleanerChore runs. The unit is second.
      The default value is one day.
    </description>
</property>

接着,添加HBase安裝目錄 `$HBASE_HOME`/*, 和 HBase library 目錄到 yarn-site.xml。調整這個例子裏的配置以適用於你的環境。

<property>
    <description>Classpath for typical applications.</description>
    <name>yarn.application.classpath</name>
    <value>
        $HADOOP_CONF_DIR,
        $HADOOP_COMMON_HOME/*,$HADOOP_COMMON_HOME/lib/*,
        $HADOOP_HDFS_HOME/*,$HADOOP_HDFS_HOME/lib/*,
        $HADOOP_MAPRED_HOME/*,$HADOOP_MAPRED_HOME/lib/*,
        $HADOOP_YARN_HOME/*,$HADOOP_YARN_HOME/lib/*,
        $HBASE_HOME/*, $HBASE_HOME/lib/*
    </value>
</property>

最後,在每個配置爲MOB的列族上運行sweeper工具。

$ org.apache.hadoop.hbase.mob.compactions.Sweeper _tableName_ _familyName_
相關文章
相關標籤/搜索