HBase架構(gòu)圖理解

18.png
- HMaster鏈接Zookeeper的目得:HMaster需要知道哪些HRegionServere是活的及HRegionServer所在的位置,然后管理HRegionServer。
- HBase內(nèi)部是通過DFS client把數(shù)據(jù)寫到HDFS上的
- 每一個(gè)HRegionServer有多個(gè)HRegion,每一個(gè)HRegion有多個(gè)Store,每一個(gè)Store對(duì)應(yīng)一個(gè)列簇。
- HFile是HBase中KeyValue數(shù)據(jù)的存儲(chǔ)格式,HFile是Hadoop的二進(jìn)制格式文件,StoreFile就是對(duì)HFile進(jìn)行了封裝,然后進(jìn)行數(shù)據(jù)的存儲(chǔ)。
- HStore由MemStore和StoreFile組成。
- HLog記錄數(shù)據(jù)的所有變更,可以用來做數(shù)據(jù)恢復(fù)。
-
hdfs對(duì)應(yīng)的目錄結(jié)構(gòu)為
namespace->table->列簇->列->單元格
17.png
寫數(shù)據(jù)流程
- zookeeper中存儲(chǔ)了meta表的region信息,從meta表獲取相應(yīng)region信息,然后找到meta表的數(shù)據(jù)
- 根據(jù)namespace、表名和rowkey根據(jù)meta表的數(shù)據(jù)找到寫入數(shù)據(jù)對(duì)應(yīng)的region信息
- 找到對(duì)應(yīng)的regionserver
- 把數(shù)據(jù)分別寫到HLog和MemStore上一份
- MemStore達(dá)到一個(gè)閾值后則把數(shù)據(jù)刷成一個(gè)StoreFile文件。若MemStore中的數(shù)據(jù)有丟失,則可以總HLog上恢復(fù)
- 當(dāng)多個(gè)StoreFile文件達(dá)到一定的大小后,會(huì)觸發(fā)Compact合并操作,合并為一個(gè)StoreFile,這里同時(shí)進(jìn)行版本的合并和數(shù)據(jù)刪除。
-
當(dāng)Compact后,逐步形成越來越大的StoreFIle后,會(huì)觸發(fā)Split操作,把當(dāng)前的StoreFile分成兩個(gè),這里相當(dāng)于把一個(gè)大的region分割成兩個(gè)region。如下圖:
19.png
讀數(shù)據(jù)流程
- zookeeper中存儲(chǔ)了meta表的region信息,所以先從zookeeper中找到meta表region的位置,然后讀取meta表中的數(shù)據(jù)。meta中又存儲(chǔ)了用戶表的region信息。
- 根據(jù)namespace、表名和rowkey在meta表中找到對(duì)應(yīng)的region信息
- 找到這個(gè)region對(duì)應(yīng)的regionserver
- 查找對(duì)應(yīng)的region
- 先從MemStore找數(shù)據(jù),如果沒有,再到StoreFile上讀(為了讀取的效率)。
HBase Java API基本使用
package org.apache.hadoop.hbase;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.PrefixFilter;
import org.apache.hadoop.hbase.util.Bytes;
public class HbaseClientTest {
/*
* 跟去表名獲取表的實(shí)例
*/
public static HTable getTable (String name) throws Exception{
//get the hbase conf instance
Configuration conf = HBaseConfiguration.create();
//get the hbase table instance
HTable table = new HTable(conf, name);
return table;
}
/**
* get the data from the hbase table
*
* get 'tbname','rowkey','cf:col'
*
* 列簇-》列名-》value-》timestamp
*/
public static void getData(HTable table) throws Exception {
// TODO Auto-generated method stub
Get get = new Get(Bytes.toBytes("20161119_10003"));
//conf the get
//get.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"));
get.addFamily(Bytes.toBytes("info"));
//load the get
Result rs = table.get(get);
//print the data
for(Cell cell : rs.rawCells()){
System.out.println(
Bytes.toString(CellUtil.cloneFamily(cell))
+"->"+
Bytes.toString(CellUtil.cloneQualifier(cell))
+"->"+
Bytes.toString(CellUtil.cloneValue(cell))
+"->"+
cell.getTimestamp()
);
System.out.println("------------------------------");
}
}
/**
* put the data to the hbase table
*
* put 'tbname','rowkey','cf:col','value'
*
*/
public static void putData(HTable table) throws Exception {
//get the put instance
Put put = new Put(Bytes.toBytes("20161119_10003"));
//conf the put
put.add(
Bytes.toBytes("info"),
Bytes.toBytes("age"),
Bytes.toBytes("20")
);
//load the put
table.put(put);
//print
getData(table);
}
/**
* delete the data from the hbase table
*
* delete 'tbname','rowkey','cf:col'
*
*/
public static void deleteData(HTable table) throws Exception {
//get the delete instance
Delete del = new Delete(Bytes.toBytes("20161119_10003"));
//conf the del
//del.deleteColumn(Bytes.toBytes("info"),Bytes.toBytes("age"));
del.deleteColumns(Bytes.toBytes("info"),Bytes.toBytes("age"));
//load the del
table.delete(del);
//print
getData(table);
}
/**
* scan the all table
* scan 'tbname'
*
*/
public static void scanData(HTable table) throws Exception {
//get the scan instance
Scan scan = new Scan();
//load the scan
ResultScanner rsscan = table.getScanner(scan);
for(Result rs : rsscan){
System.out.println(Bytes.toString(rs.getRow()));
for(Cell cell : rs.rawCells()){
System.out.println(
Bytes.toString(CellUtil.cloneFamily(cell))
+"->"+
Bytes.toString(CellUtil.cloneQualifier(cell))
+"->"+
Bytes.toString(CellUtil.cloneValue(cell))
+"->"+
cell.getTimestamp()
);
}
System.out.println("------------------------------");
}
}
/**
* scan the table with limit
*
* scan 'tbname',{STARTROW => 'row1',STOPROW => 'row2'}
*/
public static void rangeData(HTable table) throws Exception {
//get the scan instance
Scan scan = new Scan();
//conf the scan
//scan.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"));
//scan.addFamily(family);
//scan.setStartRow(Bytes.toBytes("20161119_10002"));
//scan.setStopRow(Bytes.toBytes("20161119_10003"));
Filter filter = new PrefixFilter(Bytes.toBytes("2016111"));
scan.setFilter(filter);
//hbase conf
//是否啟動(dòng)緩存
scan.setCacheBlocks(true);
//設(shè)置緩存的條數(shù)
scan.setCaching(100);
//每一次取多少條
scan.setBatch(10);
//共同決定了請(qǐng)求RPC的次數(shù)
//load the scan
ResultScanner rsscan = table.getScanner(scan);
for(Result rs : rsscan){
System.out.println(Bytes.toString(rs.getRow()));
for(Cell cell : rs.rawCells()){
System.out.println(
Bytes.toString(CellUtil.cloneFamily(cell))
+"->"+
Bytes.toString(CellUtil.cloneQualifier(cell))
+"->"+
Bytes.toString(CellUtil.cloneValue(cell))
+"->"+
cell.getTimestamp()
);
}
System.out.println("------------------------------");
}
}
public static void main(String[] args) throws Exception {
HTable table = getTable("test:tb1");
getData(table);
putData(table);
deleteData(table);
scanData(table);
rangeData(table);
}
}
HBase架構(gòu)中各個(gè)模塊的功能再次總結(jié)
- ** Client **
整個(gè)HBase集群的訪問入口;
使用HBase RPC機(jī)制與HMaster和HRegionServer進(jìn)行通信;
與HMaster進(jìn)行通信進(jìn)行管理表的操作;
與HRegionServer進(jìn)行數(shù)據(jù)讀寫類操作;
包含訪問HBase的接口,并維護(hù)cache來加快對(duì)HBase的訪問 - ** Zookeeper **
保證任何時(shí)候,集群中只有一個(gè)HMaster;
存貯所有HRegion的尋址入口;
實(shí)時(shí)監(jiān)控HRegion Server的上線和下線信息,并實(shí)時(shí)通知給HMaster;
存儲(chǔ)HBase的schema和table元數(shù)據(jù);
Zookeeper Quorum存儲(chǔ)表地址、HMaster地址。 - ** HMaster **
HMaster沒有單點(diǎn)問題,HBase中可以啟動(dòng)多個(gè)HMaster,通過Zookeeper的Master Election機(jī)制保證總有一個(gè)Master在運(yùn)行,主負(fù)責(zé)Table和Region的管理工作。
管理用戶對(duì)表的創(chuàng)建、刪除等操作;
管理HRegionServer的負(fù)載均衡,調(diào)整Region分布;
Region Split后,負(fù)責(zé)新Region的分布;
在HRegionServer停機(jī)后,負(fù)責(zé)失效HRegionServer上Region遷移工作。 - ** HRegion Server **
維護(hù)HRegion,處理對(duì)這些HRegion的IO請(qǐng)求,向HDFS文件系統(tǒng)中讀寫數(shù)據(jù);
負(fù)責(zé)切分在運(yùn)行過程中變得過大的HRegion。
Client訪問hbase上數(shù)據(jù)的過程并不需要master參與(尋址訪問Zookeeper和HRegion Server,數(shù)據(jù)讀寫訪問HRegione Server),HMaster僅僅維護(hù)這table和Region的元數(shù)據(jù)信息,負(fù)載很低。
hbase與mapreduce的集成
可以把hbase表中的數(shù)據(jù)作為mapreduce計(jì)算框架的輸入,或者把mapreduce的計(jì)算結(jié)果輸出到hbase表中。
我們以hbase中自帶的mapreduce程序舉例
- 直接運(yùn)行會(huì)發(fā)現(xiàn)報(bào)錯(cuò)缺少jar包,所以運(yùn)行前需引入環(huán)境變量
$ export HBASE_HOME=/opt/modules/hbase-0.98.6-hadoop2
$ export HADOOP_HOME=/opt/modules/hadoop-2.5.0
# $HBASE_HOME/bin/hbase mapredcp可以列出hbase在yarn上運(yùn)行所需的jar包
$ export HADOOP_CLASSPATH=`$HBASE_HOME/bin/hbase mapredcp`
- 運(yùn)行示例
$ $HADOOP_HOME/bin/yarn jar lib/hbase-server-0.98.6-hadoop2.jar rowcounter test:tb1
HBase的數(shù)據(jù)遷移的importsv的使用
HBase數(shù)據(jù)來源于日志文件或者RDBMS,把數(shù)據(jù)遷移到HBase表中。常見的有三種方法:(1)使用HBase Put API;(2)使用HBase批量加載工具;(3)自定義MapReduce job實(shí)現(xiàn)。
importtsv是HBase官方提供的基于mapreduce的批量數(shù)據(jù)導(dǎo)入工具,同時(shí)也是hbase提供的一個(gè)命令行工具,可以將存儲(chǔ)在HDFS上的自定義分隔符(默認(rèn)是\t)的數(shù)據(jù)文件,通過一條命令方便的導(dǎo)入到HBase中。
** 測(cè)試 **
- 準(zhǔn)備數(shù)據(jù)文件
[wulei@bigdata-00 datas]$ cat tb1.tsv
10001 zhangsan 20
10002 lisi 22
10003 wangwu 30
- 把數(shù)據(jù)文件上傳到hdsf上
$ bin/hdfs dfs -put /opt/datas/tb1.tsv /
- 在hbase中創(chuàng)建表
> create 'student','info' - 將HDFS中的數(shù)據(jù)導(dǎo)入到hbase表中
$HADOOP_HOME/bin/yarn jar lib/hbase-server-0.98.6-hadoop2.jar importtsv -Dimporttsv.separator=\t -Dimporttsv.columns=HBASE_ROW_KEY,info:name,info:age student /tb1.tsv
Dimporttsv.columns為指定分隔符
Dimporttsv.columns指定數(shù)據(jù)文件中每一列如何對(duì)應(yīng)表中的rowkey和列
/tb1.tsv為hdfs上的數(shù)據(jù)文件的路徑
- 查看執(zhí)行結(jié)果
hbase(main):010:0> scan 'student'
ROW COLUMN+CELL
10001 column=info:age, timestamp=1480123167099, value=20
10001 column=info:name, timestamp=1480123167099, value=zhangsan
10002 column=info:age, timestamp=1480123167099, value=22
10002 column=info:name, timestamp=1480123167099, value=lisi
2 row(s) in 0.8210 seconds

