團隊內部要分享HBase的知識,以前研究了一段時間,知識比較零散,這一次就係統化的整理一番,以後在想到Hbase的時候,看着一篇就夠了。html
Hbase是一種NoSQL數據庫,這意味着它不像傳統的RDBMS數據庫那樣支持SQL做爲查詢語言。Hbase是一種分佈式存儲的數據庫,技術上來說,它更像是分佈式存儲而不是分佈式數據庫,它缺乏不少RDBMS系統的特性,好比列類型,輔助索引,觸發器,和高級查詢語言等待。那Hbase有什麼特性呢?以下:java
Hbase不適合解決全部的問題:node
Hbase在單機環境也能運行,可是請在開發環境的時候使用。web
不過在公司使用的時候,通常不使用原生的Hbase API,使用原生的API會致使訪問不可監控,影響系統穩定性,以至於版本升級的不可控。shell
HMaster是Master Server的實現,負責監控集羣中的RegionServer實例,同時是全部metadata改變的接口,在集羣中,一般運行在NameNode上面,這裏有一篇更細的HMaster介紹數據庫
HRegionServer是RegionServer的實現,服務和管理Regions,集羣中RegionServer運行在DataNodeapache
Regions,表明table,Region有多個Store(列簇),Store有一個Memstore和多個StoreFiles(HFiles),StoreFiles的底層是Block。vim
在Hbase中,表被分割成多個更小的塊而後分散的存儲在不一樣的服務器上,這些小塊叫作Regions,存放Regions的地方叫作RegionServer。Master進程負責處理不一樣的RegionServer之間的Region的分發。在Hbase實現中HRegionServer和HRegion類表明RegionServer和Region。HRegionServer除了包含一些HRegions以外,還處理兩種類型的文件用於數據存儲緩存
MasterProcWAL:HMaster記錄管理操做,好比解決衝突的服務器,表建立和其它DDLs等操做到它的WAL文件中,這個WALs存儲在MasterProcWALs目錄下,它不像RegionServer的WALs,HMaster的WAL也支持彈性操做,就是若是Master服務器掛了,其它的Master接管的時候繼續操做這個文件。bash
WAL記錄全部的Hbase數據改變,若是一個RegionServer在MemStore進行FLush的時候掛掉了,WAL能夠保證數據的改變被應用到。若是寫WAL失敗了,那麼修改數據的完整操做就是失敗的。
WAL的配置:
// 啓用multiwal
<property>
<name>hbase.wal.provider</name>
<value>multiwal</value>
</property>
複製代碼
HFile是Hbase在HDFS中存儲數據的格式,它包含多層的索引,這樣在Hbase檢索數據的時候就不用徹底的加載整個文件。索引的大小(keys的大小,數據量的大小)影響block的大小,在大數據集的狀況下,block的大小設置爲每一個RegionServer 1GB也是常見的。
探討數據庫的數據存儲方式,其實就是探討數據如何在磁盤上進行有效的組織。由於咱們一般以如何高效讀取和消費數據爲目的,而不是數據存儲自己。
起初,HFile中並無任何Block,數據還存在於MemStore中。
Flush發生時,建立HFile Writer,第一個空的Data Block出現,初始化後的Data Block中爲Header部分預留了空間,Header部分用來存放一個Data Block的元數據信息。
然後,位於MemStore中的KeyValues被一個個append到位於內存中的第一個Data Block中:
注:若是配置了Data Block Encoding,則會在Append KeyValue的時候進行同步編碼,編碼後的數據再也不是單純的KeyValue模式。Data Block Encoding是HBase爲了下降KeyValue結構性膨脹而提供的內部編碼機制。
這一次來部署一個單機版的Hbase,單獨的Hbase daemon(Master,RegionServers和ZooKeeper)運行在同一個JVM進程中,而後持久化存儲到文件系統中。這是最簡單的部署,可是卻能幫助咱們更好的理解Hbase。安裝完成以後,咱們在演示一下hbase命令行的用法。
yum install java-1.8.0-openjdk* -y
複製代碼
tar -xf hbase-1.2.8-bin.tar.gz
cd hbase-1.2.8
複製代碼
vim conf/hbase-env.sh
// 注意這個是在CentOS上的java位置
export JAVA_HOME=/etc/alternatives/java_sdk_1.8.0/
複製代碼
我將hbase的目錄放在hadoop用戶家目錄的hbase目錄下。咱們不用事先建立好hbase的data目錄,hbase會自動幫咱們建立好的,若是已經存在了data目錄,hbase會將存在的目錄進行遷移。
useradd -s /sbin/nologin -m hadoop
vim conf/hbase-site.xml
<configuration>
<property>
<name>hbase.rootdir</name>
<value>file:///home/hadoop/hbase</value>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/home/hadoop/zookeeper</value>
</property>
<property>
<name>hbase.unsafe.stream.capability.enforce</name>
<value>false</value>
<description>
Controls whether HBase will check for stream capabilities (hflush/hsync).
Disable this if you intend to run on LocalFileSystem, denoted by a rootdir
with the 'file://' scheme, but be mindful of the NOTE below.
WARNING: Setting this to false blinds you to potential data loss and
inconsistent system state in the event of process and/or node failures. If
HBase is complaining of an inability to use hsync or hflush it's most likely not a false positive. </description> </property> </configuration> 複製代碼
./bin/start-hbase.sh
複製代碼
若是啓動以後,能夠打開http://localhost:16010查看Hbase的Web UI
咱們能夠先用Hbase提供的命令行工具,位於hbase的/bin/目錄下
./hbase shell
複製代碼
>help
複製代碼
hbase(main):003:0> create 'test', 'cf'
0 row(s) in 1.6320 seconds
=> Hbase::Table - test
複製代碼
其他的命令能夠自行嘗試
退出shell,使用quit
這裏演示了下單機版的hbase如何安裝,瞭解hbase shell的基本用法,關於Hbase更深刻的東西,能夠了解下官方文檔。
在Hbase中,有一些術語須要提早了解。以下:
HBase 是一個稀疏的、分佈式、持久、多維、排序的映射,它以行鍵(row key),列鍵(column key)和時間戳(timestamp)爲索引。
Hbase在存儲數據的時候,有兩個SortedMap,首先按照rowkey進行字典排序,而後再對Column進行字典排序。
create 'user','info','ship';
put 'user', '524382618264914241', 'info:name', 'zhangsan'
put 'user', '524382618264914241', 'info:age',30
put 'user', '524382618264914241', 'info:height',168
put 'user', '524382618264914241', 'info:weight',168
put 'user', '524382618264914241', 'info:phone','13212321424'
put 'user', '524382618264914241', 'ship:addr','beijing'
put 'user', '524382618264914241', 'ship:email','sina@sina.com'
put 'user', '524382618264914241', 'ship:salary',3000
put 'user', '224382618261914241', 'info:name', 'lisi'
put 'user', '224382618261914241', 'info:age',24
put 'user', '224382618261914241', 'info:height',158
put 'user', '224382618261914241', 'info:weight',128
put 'user', '224382618261914241', 'info:phone','13213921424'
put 'user', '224382618261914241', 'ship:addr','chengdu'
put 'user', '224382618261914241', 'ship:email','qq@sina.com'
put 'user', '224382618261914241', 'ship:salary',5000
put 'user', '673782618261019142', 'info:name', 'zhaoliu'
put 'user', '673782618261019142', 'info:age',19
put 'user', '673782618261019142', 'info:height',178
put 'user', '673782618261019142', 'info:weight',188
put 'user', '673782618261019142', 'info:phone','17713921424'
put 'user', '673782618261019142', 'ship:addr','shenzhen'
put 'user', '673782618261019142', 'ship:email','126@sina.com'
put 'user', '673782618261019142', 'ship:salary',8000
put 'user', '813782218261011172', 'info:name', 'wangmazi'
put 'user', '813782218261011172', 'info:age',19
put 'user', '813782218261011172', 'info:height',158
put 'user', '813782218261011172', 'info:weight',118
put 'user', '813782218261011172', 'info:phone','12713921424'
put 'user', '813782218261011172', 'ship:addr','xian'
put 'user', '813782218261011172', 'ship:email','139@sina.com'
put 'user', '813782218261011172', 'ship:salary',10000
put 'user', '510824118261011172', 'info:name', 'yangyang'
put 'user', '510824118261011172', 'info:age',18
put 'user', '510824118261011172', 'info:height',188
put 'user', '510824118261011172', 'info:weight',138
put 'user', '510824118261011172', 'info:phone','18013921626'
put 'user', '510824118261011172', 'ship:addr','shanghai'
put 'user', '510824118261011172', 'ship:email','199@sina.com'
put 'user', '510824118261011172', 'ship:salary',50000
複製代碼
只要是數據庫都存在,模式設計的問題,關係型中有模式設計的範式,Hbase做爲列式存儲數據庫,其模式設計也很是重要。
設計時須要關注的屬性,如何設計這些屬性等
屬性 | Hbase | RDBMS |
---|---|---|
數據類型 | 只有字符串 | 豐富的數據類型 |
數據操做 | 增刪改查,不支持join | 各類各樣的函數與錶鏈接 |
存儲模式 | 基於列式存儲 | 基於表結構和行式存儲 |
數據保護 | 更新後仍然保留舊版本 | 替換 |
可伸縮性 | 輕易增長節點 | 須要中間層,犧牲性能 |
Hbase關鍵概念:表,rowkey,列簇,時間戳
關鍵部分,直接關係到後續服務的訪問性能。若是行健設計不合理,後續查詢服務效率會成倍的遞減。
列簇是一些列的集合,一個列簇的成員有相同的前綴,以冒號(:)做爲分隔符。
如今Hbase不能很好處理2~3個以上的列簇,因此儘量讓列簇少一些,若是表有多個列簇,列簇A有100萬行數據,列簇B有10億行,那麼列簇A會分散到不少的Region致使掃描列簇A的時候效率底下。
列簇名的長度要儘可能小,一個爲了節省空間,另外加快效率,好比d表示data,v表示value
> create 'mytable',{NAME => 'cf1', BLOCKSIZE => '65536'}
複製代碼
> create 'mytable',{NAME => 'cf1', BLOCKCACHE => 'FALSE'}
複製代碼
> create 'mytable',{NAME => 'cf1', COMPRESSION => 'SNAPPY'}
複製代碼
Hbase表設計是和需求相關的,可是遵照表設計的一些硬性指標對性能的提高仍是頗有幫助的,這裏整理了一些設計時用到的要點。
Hbase有多種不一樣的客戶端,如REST客戶端,Thift客戶端,ORM框架Kundera等等。 Hbase也提供了Java的API來操做表與列簇等信息,它的shell就是對Java的API作了一層封裝。
Hbase的Java API提供了不少高級的特性:
咱們仍是直接看代碼這樣理解的更容易
Hbase的客戶端版本不一致實驗結果很容易出現問題,儘可能採用一樣的版本。由於服務端實驗的是Hbase0.98,客戶端也用0.98,另外因爲Hadoop 2.x的版本現對於1.x作了很大的提高,建議採用Hbase-hadoop 2.x的客戶端。
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>0.98.24-hadoop2</version>
</dependency>
複製代碼
直接新建HTable("tableName"),可是這種每次建立表的時候由於都要查詢.meta表,來判斷表是否是存在,致使建立表的過程會有點慢,因此不建議每一個請求都建立一個Htable
使用HTablePool,它和HTable的建立方式很像,可是若是採用鏈接池的話,它就不會給每一個請求都單首創建一個Htable了。
在建立Htable或者HtablePool的時候均可以指定更詳細的配置信息。
HTablePool hTablePool = new HTablePool();
hTablePool.getTable("user");
複製代碼
rowkey是表明Hbase中表的惟一一個行,同時像列簇 ,時間戳等用來定位表中的部分數據,Java的API對Hbas的CURD提供了以下的類:
咱們詳細的討論幾個類,剩餘的能夠觸類旁通。
當寫請求收到的時候,默認數據同步的寫到Hlog中和MemStore,同時在兩個地方寫是爲了保證數據的持久性,Memstore最終會持久化到磁盤中的Hfile中。每次MemStore進行Flush的時候,就會建立一個新的Hfile。
Put類用於向Hbase的表中存儲數據,存儲數據時,Put的實例必需要指定Rowkey
建立完Put實例後,再向其中添加數據
public void put() throws IOException {
// 獲取默認的配置
Configuration conf = HBaseConfiguration.create();
// 獲取Table實例
HTable table = new HTable(conf, "tab1");
// 建立Put實例,而且指定rowKey
Put put = new Put(Bytes.toBytes("row-1"));
// 添加一個 column,值爲 "Hello",在 "cf1:greet" 列中
put.add(Bytes.toBytes("cf1"), Bytes.toBytes("greet"), Bytes.toBytes("Hello"));
// 添加一個 column,值爲 "John",在 "cf1:person" 列中
put.add(Bytes.toBytes("cf1"), Bytes.toBytes("person"), Bytes.toBytes("John"));
table.put(put);
table.close();
}
複製代碼
數據也能夠批量的進行插入:
// table對象能夠傳入List參數 table.put(final List puts)
執行結果:
Hbase使用LRU緩存讀取數據。Htable對象使用下面的方法讀取數據
而Get實例的構造方法和Put很像,構造方法要指定一個rowkey。
若是要查找特定的cell,就是特定列的數據,能夠採用額外的方法進行更加精細的調控。
看一下以下的案例代碼:
public void get() throws IOException {
// 獲取默認的配置
Configuration conf = HBaseConfiguration.create();
// 獲取Table實例
HTable table = new HTable(conf, "tab1");
// 建立Put實例,而且指定rowKey
Get get = new Get(Bytes.toBytes("row-1"));
//
get.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("greet"));
// 添加一個 column,值爲 "John",在 "cf1:person" 列中
Result result = table.get(get);
byte[] value = result.getValue(Bytes.toBytes("cf1"), Bytes.toBytes("greet"));
System.out.println("獲取到的值" + new String(value));
table.close();
}
複製代碼
執行結果
更新數據與寫數據基本一致,只是在Put實例賦值的時候,在相同的列上設置不一樣的值,操做的時候就會更新爲新的值。
代碼以下:
public void update() throws IOException {
Configuration conf = HBaseConfiguration.create();
// 獲取Table實例
HTable table = new HTable(conf, "tab1");
// 建立Put實例,而且指定rowKey
Put put = new Put(Bytes.toBytes("row-1"));
// 添加一個 column,值爲 "Hello",在 "cf1:greet" 列中
put.add(Bytes.toBytes("cf1"), Bytes.toBytes("greet"), Bytes.toBytes("Good Morning"));
// 添加一個 column,值爲 "John",在 "cf1:person" 列中
// put.add(Bytes.toBytes("cf1"), Bytes.toBytes("person"), Bytes.toBytes("John"));
table.put(put);
table.close();
}
複製代碼
執行結果:
Delete命令只是標記當前的數據爲刪除狀態,而不是馬上的刪除,也就是先進行邏輯刪除。實際上的刪除是在Hfile進行壓縮的時候,這些被標記的記錄就會被刪除掉。
Delete對象與Put和Get也很像
構造Delete實例
若是想要進行更加詳細的指定,能夠再指定具體的列等信息
看下面的案例代碼:
public void delete() throws IOException {
Configuration conf = HBaseConfiguration.create();
// 獲取Table實例
HTable table = new HTable(conf, "tab1");
// 建立Delete實例,而且指定rowKey
Delete delete = new Delete(Bytes.toBytes("row-1"));
// 刪除 column "cf1:greet"
delete.deleteColumn(Bytes.toBytes("cf1"), Bytes.toBytes("greet"));
table.delete(delete);
table.close();
}
複製代碼
執行結果:連續執行兩次刪除
一個系統上線以後,開發和調優將一直貫穿系統的生命週期中,HBase也不列外。這裏主要說一些Hbase的調優
做爲NoSQL數據庫,增刪改查是其最基本的功能,其中查詢是最經常使用的一項。
HBase中Scan查詢能夠設置緩存,方法是setCaching(),這樣能夠有效的減小服務端與客戶端的交互,更有效的提高掃描查詢的性能。
/** * Set the number of rows for caching that will be passed to scanners. * If not set, the default setting from {@link HTable#getScannerCaching()} will apply. * Higher caching values will enable faster scanners but will use more memory. * @param caching the number of rows for caching * 設置scanners緩存的行數 */
public void setCaching(int caching) {
this.caching = caching;
}
複製代碼
當使用Scan或者GET獲取大量的行時,最好指定所須要的列,由於服務端經過網絡傳輸到客戶端,數據量太大多是瓶頸。若是能有效過濾部分數據,能很大程度的減小網絡I/O的花費。
/** * Get all columns from the specified family. * <p> * Overrides previous calls to addColumn for this family. * @param family family name * @return this * 獲取指定列簇的全部列 */
public Scan addFamily(byte [] family) {
familyMap.remove(family);
familyMap.put(family, null);
return this;
}
/** * Get the column from the specified family with the specified qualifier. * <p> * Overrides previous calls to addFamily for this family. * @param family family name * @param qualifier column qualifier * @return this * 獲取指定列簇的特定列 */
public Scan addColumn(byte [] family, byte [] qualifier) {
NavigableSet<byte []> set = familyMap.get(family);
if(set == null) {
set = new TreeSet<byte []>(Bytes.BYTES_COMPARATOR);
}
if (qualifier == null) {
qualifier = HConstants.EMPTY_BYTE_ARRAY;
}
set.add(qualifier);
familyMap.put(family, set);
return this;
}
複製代碼
通常用: scan.addColumn(...)
若是在使用table.getScanner以後,忘記關閉該類,它會一直和服務端保持鏈接,資源沒法釋放,從而致使服務端的某些資源不可用。
因此在用完以後,須要執行關閉操做,這點與JDBS操做MySQL相似
scanner.close()
若是批量進行全表掃描,默認是有緩存的,若是此時有緩存,會下降掃描的效率。
scan.setCacheBlocks(true|false);
對於常常讀到的數據,建議使用默認值,開啓塊緩存
對於頻繁查詢HBase的應用場景,能夠考慮在應用程序和Hbase之間作一層緩存系統,新的查詢先去緩存查,緩存沒有再去查Hbase。
寫也是Hbase常有的操做之一,而且Hbase在寫入操做上有着其餘NoSQL沒法比擬的優點,下面講如何優化寫入操做
通常爲了保證系統的高可用性,WAL日誌默認是開啓狀態,WAL主要用於災難恢復的,若是應用能夠容忍必定的數據丟失風險,能夠在寫數據的時候,關閉寫WAL。
風險: 當RegionServer宕機時,寫入的數據出現丟失,且沒法恢復
Htable有一個屬性是AutoFlush,該屬性用於支持客戶端的批量更新,默認是true,當客戶端每收到一條數據,馬上發送到服務端,若是設置爲false,當客戶端提交put請求時候,先將該請求在客戶端緩存,到達閾值的時候或者執行hbase.flushcommits(),才向RegionServer提交請求。
風險 在請求未發送到RegionServer以前客戶端崩潰,數據也會丟失
table.setAutoFlush(false);
table.setWriteBufferSize( 12 * 1024 * 1024 );
複製代碼
通常表剛開始只有一個Region,插入該表的數據都會保存在此Region中,插入該表的全部塑化劑都會保存在該Region中,當到達必定的閾值時,才發生分裂。 這樣開始時刻針對該表的寫操做都集中在某臺服務器上,形成這臺服務器的壓力很緊張,同時對整個集羣資源的浪費
建議剛開始的時候預建立Region,可使用Hbase自帶的RegionSplitter
默認寫入操做,首先寫入WAL,而且在1S內寫入HDFS,這個時間默認是1S,能夠經過參數配置
hbase.regionserver.optionallogflushinterval
能夠配置大一點的值,好比5s,這段時間數據會保留在內存中,直到RegionServer週期性的執行flush操做。
Scan是操做Hbase中很是經常使用的一個操做,雖然前面的Hbase API操做簡單的介紹了Scan的操做,但不夠詳細,因爲Scan很是經常使用,關於其詳細的整理也是頗有必要的。
HBase中的數據表經過劃分紅一個個的Region來實現數據的分片,每個Region關聯一個RowKey的範圍區間,而每個Region中的數據,按RowKey的字典順序進行組織。
正是基於這種設計,使得HBase可以輕鬆應對這類查詢:"指定一個RowKey的範圍區間,獲取該區間的全部記錄", 這類查詢在HBase被稱之爲Scan。
1 . 構建Scan,指定startRow與stopRow,若是未指定的話會進行全表掃描 2 . 獲取ResultScanner 3 . 遍歷查詢結果 4 . 關閉ResultScanner
public void stringFilter() throws IOException {
Configuration conf = HBaseConfiguration.create();
// 獲取Table實例
HTable table = new HTable(conf, "user");
// 構建Scan
Scan scan = new Scan();
scan = scan.setStartRow(Bytes.toBytes("startRowxxx")).setStopRow(Bytes.toBytes("StopRowxxx"));
RowFilter filter = new RowFilter(
CompareFilter.CompareOp.EQUAL,
new BinaryComparator(Bytes.toBytes("224382618261914241"))
);
scan.setFilter(filter);
// 獲取resultScanner
ResultScanner scanner = table.getScanner(scan);
Result result = null;
// 處理結果
while ((result = scanner.next()) != null) {
byte[] value = result.getValue(Bytes.toBytes("ship"), Bytes.toBytes("addr"));
if (value == null || value.length == 0) {
continue;
}
System.out.println(
new String(value)
);
System.out.println("hello World");
}
// 關閉ResultScanner
scanner.close();
table.close();
}
複製代碼
其它的設置參數
下面的示例代碼設定了一次讀取回來的Results數量爲100:
scan.setCaching(100);
複製代碼
Client每一次往RegionServer發送scan請求,都會批量拿回一批數據(由Caching決定過了每一次拿回的Results數量),而後放到本次的Result Cache中:
應用每一次讀取數據時,都是從本地的Result Cache中獲取的。若是Result Cache中的數據讀完了,則Client會再次往RegionServer發送scan請求獲取更多的數據。
下面的示例代碼設定了每個Result中的列的數量的限制值爲3:
scan.setBatch(3);
複製代碼
該參數適用於一行數據過大的場景,這樣,一行數據被請求的列會被拆成多個Results返回給Client。
舉例說明以下:
假設一行數據中共有十個列: {Col01,Col02,Col03,Col04,Col05,Col06,Col07,Col08,Col09, Col10} 假設Scan中設置的Batch爲3,那麼,這一行數據將會被拆成4個Results返回:
Result1 -> {Col01,Col02,Col03}
Result2 -> {Col04,Col05,Col06}
Result3 -> {Col07,Col08,Col09}
Result4 -> {Col10}
複製代碼
關於Caching參數,咱們說明了是Client每一次從RegionServer側獲取到的Results的數量,上例中,一行數據被拆成了4個Results,這將會致使Caching中的計數器被減了4次。結合Caching與Batch,咱們再列舉一個稍複雜的例子:
假設,Scan的參數設置以下:
final byte[] start = Bytes.toBytes("Row1"); final byte[] stop = Bytes.toBytes("Row5"); Scan scan = new Scan(); scan.withStartRow(start).withStopRow(stop); scan.setCaching(10); scan.setBatch(3);
待讀取的數據RowKey與所關聯的列集以下所示:
Row1: {Col01,Col02,Col03,Col04,Col05,Col06,Col07,Col08,Col09,Col10}
Row2: {Col01,Col02,Col03,Col04,Col05,Col06,Col07,Col08,Col09,Col10,Col11}
Row3: {Col01,Col02,Col03,Col04,Col05,Col06,Col07,Col08,Col09,Col10}
再回顧一下Caching與Batch的定義:
Caching: 影響一次讀取返回的Results數量。
Batch: 限定了一個Result中所包含的列的數量,若是一行數據被請求的列的數量超出Batch限制,那麼這行數據會被拆成多個Results。
那麼, Client往RegionServer第一次請求所返回的結果集以下所示:
Result1 -> Row1: {Col01,Col02,Col03} Result2 -> Row1: {Col04,Col05,Col06} Result3 -> Row1: {Col07,Col08,Col09} Result4 -> Row1: {Col10} Result5 -> Row2: {Col01,Col02,Col03} Result6 -> Row2: {Col04,Col05,Col06} Result7 -> Row2: {Col07,Col08,Col09} Result8 -> Row2: {Col10,Col11} Result9 -> Row3: {Col01,Col02,Col03} Result10 -> Row3: {Col04,Col05,Col06}
同SQL語法中的limit子句,限制一次Scan操做所獲取的行的總量:
scan.setLimit(10000);
注意:Limit參數是在2.0版本中新引入的。但在2.0.0版本中,當Batch與Limit同時設置時,彷佛還存在一個BUG,初步分析問題緣由應該與BatchScanResultCache中的numberOfCompletedRows計數器邏輯處理有關。所以,暫時不建議同時設置這兩個參數。
scan.setCacheBlocks(true);
e) Raw Scan: 是否能夠讀取到刪除標識以及被刪除但還沒有被清理的數據
scan.setRaw(true);
下面的示例代碼將返回結果集的最大值設置爲5MB:
scan.setMaxResultSize(5 * 1024 * 1024);
普通的Scan操做是按照字典順序從小到大的順序讀取的,而Reversed Scan則剛好相反:
scan.setReversed(true);
Filter能夠在Scan的結果集基礎之上,對返回的記錄設置更多條件值,這些條件能夠與RowKey有關,能夠與列名有關,也能夠與列值有關,還能夠將多個Filter條件組合在一塊兒,等等。
最經常使用的Filter是SingleColumnValueFilter,基於它,能夠實現以下相似的查詢:
"返回知足條件{列I:D的值大於等於10}的全部行"
示例代碼以下:
Filter豐富了HBase的查詢能力,但使用Filter以前,須要注意一點:Filter可能會致使查詢響應時延變的不可控制。由於咱們沒法預測,爲了找到一條符合條件的記錄,背後須要掃描多少數據量,若是在有效限制了Scan範圍區間(經過設置StartRow與StopRow限制)的前提下,該問題可以獲得有效的控制。這些信息都要求使用Filter以前應該詳細調研本身的業務數據模型。
本文有點長,做爲參考吧