HBASE是一個高可靠性、高性能、面向列、可伸縮的分佈式存儲系統,利用HBASE技術可在廉價PC Server上搭建起大規模結構化存儲集羣。java
HBASE的目標是存儲並處理大型的數據,更具體來講是僅需使用普通的硬件配置,就可以處理由成千上萬的行和列所組成的大型數據。sql
HBASE是Google Bigtable的開源實現,可是也有不少不一樣之處。好比:Google Bigtable利用GFS做爲其文件存儲系統,HBASE利用Hadoop HDFS做爲其文件存儲系統;Google運行MAPREDUCE來處理Bigtable中的海量數據,HBASE一樣利用Hadoop MapReduce來處理HBASE中的海量數據;Google Bigtable利用Chubby做爲協同服務,HBASE利用Zookeeper做爲對應。shell
一、傳統數據庫遇到的問題:數據庫
1)數據量很大的時候沒法存儲apache
2)沒有很好的備份機制數組
3)數據達到必定數量開始緩慢,很大的話基本沒法支撐緩存
二、HBASE優點:app
1)線性擴展,隨着數據量增多能夠經過節點擴展進行支撐負載均衡
2)數據存儲在hdfs上,備份機制健全nosql
3)經過zookeeper協調查找數據,訪問速度塊。
一、一個或者多個主節點,Hmaster
二、多個從節點,HregionServer
用工具上傳
su – hadoop
tar -zxvf hbase-0.94.6.tar.gz
mv hbase-0.94.6 hbase
su – root
vi /etc/profile
添加內容:
export HBASE_HOME=/home/hadoop/hbase export PATH=$PATH:$HBASE_HOME/bin |
source /etc/proflie
su - hadoop
上傳配置文件
scp -r /home/hadoop/hbase hadoop@slave1:/home/hadoop/
scp -r /home/hadoop/hbase hadoop@slave2:/home/hadoop/
scp -r /home/hadoop/hbase hadoop@slave3:/home/hadoop/
注意:啓動hbase以前,必須保證hadoop集羣和zookeeper集羣是可用的。
start-hbase.sh
一、 進入命令行
hbase shell
二、 頁面監控
與nosql數據庫們同樣,row key是用來檢索記錄的主鍵。訪問HBASE table中的行,只有三種方式:
1.經過單個row key訪問
2.經過row key的range(正則)
3.全表掃描
Row key行鍵 (Row key)能夠是任意字符串(最大長度 是 64KB,實際應用中長度通常爲 10-100bytes),在HBASE內部,row key保存爲字節數組。存儲時,數據按照Row key的字典序(byte order)排序存儲。設計key時,要充分排序存儲這個特性,將常常一塊兒讀取的行存儲放到一塊兒。(位置相關性)
列簇 :HBASE表中的每一個列,都歸屬於某個列族。列族是表的schema的一部 分(而列不是),必須在使用表以前定義。列名都以列族做爲前綴。例如 courses:history,courses:math都屬於courses 這個列族。
由{row key, columnFamily, version} 惟一肯定的單元。cell中 的數據是沒有類型的,所有是字節碼形式存貯。
關鍵字:無類型、字節碼
HBASE 中經過rowkey和columns肯定的爲一個存貯單元稱爲cell。每一個 cell都保存 着同一份數據的多個版本。版本經過時間戳來索引。時間戳的類型是 64位整型。時間戳能夠由HBASE(在數據寫入時自動 )賦值,此時時間戳是精確到毫秒 的當前系統時間。時間戳也能夠由客戶顯式賦值。若是應用程序要避免數據版 本衝突,就必須本身生成具備惟一性的時間戳。每一個 cell中,不一樣版本的數據按照時間倒序排序,即最新的數據排在最前面。
爲了不數據存在過多版本形成的的管理 (包括存貯和索引)負擔,HBASE提供 了兩種數據版本回收方式。一是保存數據的最後n個版本,二是保存最近一段 時間內的版本(好比最近七天)。用戶能夠針對每一個列族進行設置。
一、hbase提供了一個shell的終端給用戶交互
#$HBASE_HOME/bin/hbase shell
二、若是退出執行quit命令
#$HBASE_HOME/bin/hbase shell
……
>quit
名稱 |
命令表達式 |
建立表 |
create '表名', '列族名1','列族名2','列族名N' |
查看全部表 |
list |
描述表 |
describe ‘表名’ |
判斷表存在 |
exists '表名' |
判斷是否禁用啓用表 |
is_enabled '表名' is_disabled ‘表名’ |
添加記錄 |
put ‘表名’, ‘rowKey’, ‘列族 : 列‘ , '值' |
查看記錄rowkey下的全部數據 |
get '表名' , 'rowKey' |
查看錶中的記錄總數 |
count '表名' |
獲取某個列族 |
get '表名','rowkey','列族' |
獲取某個列族的某個列 |
get '表名','rowkey','列族:列’ |
刪除記錄 |
delete ‘表名’ ,‘行名’ , ‘列族:列' |
刪除整行 |
deleteall '表名','rowkey' |
刪除一張表 |
先要屏蔽該表,才能對該表進行刪除 第一步 disable ‘表名’ ,第二步 drop '表名' |
清空表 |
truncate '表名' |
查看全部記錄 |
scan "表名" |
查看某個表某個列中全部數據 |
scan "表名" , {COLUMNS=>'列族名:列名'} |
更新記錄 |
就是重寫一遍,進行覆蓋,hbase沒有修改,都是追加 |
一、 保存Hmaster的地址和backup-master地址
hmaster:
a) 管理HregionServer
b) 作增刪改查表的節點
c) 管理HregionServer中的表分配
二、 保存表-ROOT-的地址
hbase默認的根表,檢索表。
三、 HRegionServer列表
表的增刪改查數據。
和hdfs交互,存取數據。
HBaseConfiguration
包:org.apache.hadoop.hbase.HBaseConfiguration
做用:經過此類能夠對HBase進行配置
用法實例:
Configuration config = HBaseConfiguration.create();
說明: HBaseConfiguration.create() 默認會從classpath 中查找 hbase-site.xml 中的配置信息,初始化 Configuration。
使用方法:
static Configuration config = null;
static {
config = HBaseConfiguration.create();
config.set("hbase.zookeeper.quorum", "slave1,slave2,slave3");
config.set("hbase.zookeeper.property.clientPort", "2181");
}
HBaseAdmin
包:org.apache.hadoop.hbase.client.HBaseAdmin
做用:提供接口關係HBase 數據庫中的表信息
用法:
HBaseAdmin admin = new HBaseAdmin(config);
HTableDescriptor
包:org.apache.hadoop.hbase.HTableDescriptor
做用:HTableDescriptor 類包含了表的名字以及表的列族信息
表的schema(設計)
用法:
HTableDescriptor htd =new HTableDescriptor(tablename);
htd.addFamily(new HColumnDescriptor(「myFamily」));
HColumnDescriptor
包:org.apache.hadoop.hbase.HColumnDescriptor
做用:HColumnDescriptor 維護列族的信息
用法:
htd.addFamily(new HColumnDescriptor(「myFamily」));
CreateTable(通常咱們用shell建立表)
static Configuration config = null;
static {
config = HBaseConfiguration.create();
config.set("hbase.zookeeper.quorum", "slave1,slave2,slave3");
config.set("hbase.zookeeper.property.clientPort", "2181");
}
HBaseAdmin admin = new HBaseAdmin(config);
HTableDescriptor desc = new HTableDescriptor(tableName);
HColumnDescriptor family1 = new HColumnDescriptor(「f1」);
HColumnDescriptor family2 = new HColumnDescriptor(「f2」);
desc.addFamily(family1);
desc.addFamily(family2);
admin.createTable(desc);
HBaseAdmin admin = new HBaseAdmin(config);
admin.disableTable(tableName);
admin.deleteTable(tableName);
HTable
包:org.apache.hadoop.hbase.client.HTable
做用:HTable 和 HBase 的表通訊
用法:
// 普通獲取表
HTable table = new HTable(config,Bytes.toBytes(tablename);
// 經過鏈接池獲取表
Connection connection = ConnectionFactory.createConnection(config);
HTableInterface table = connection.getTable(TableName.valueOf("user"));
Put
包:org.apache.hadoop.hbase.client.Put
做用:插入數據
用法:
Put put = new Put(row);
p.add(family,qualifier,value);
說明:向表 tablename 添加 「family,qualifier,value」指定的值。
示例代碼:
Connection connection = ConnectionFactory.createConnection(config);
HTableInterface table = connection.getTable(TableName.valueOf("user"));
Put put = new Put(Bytes.toBytes(rowKey));
put.add(Bytes.toBytes(family), Bytes.toBytes(qualifier),Bytes.toBytes(value));
table.put(put);
批量插入
List<Put> list = new ArrayList<Put>();
Put put = new Put(Bytes.toBytes(rowKey));//獲取put,用於插入
put.add(Bytes.toBytes(family), Bytes.toBytes(qualifier),Bytes.toBytes(value));//封裝信息
list.add(put);
table.put(list);//添加記錄
Delete
包:org.apache.hadoop.hbase.client.Delete
做用:刪除給定rowkey的數據
用法:
Delete del= new Delete(Bytes.toBytes(rowKey));
table.delete(del);
代碼實例
Connection connection = ConnectionFactory.createConnection(config);
HTableInterface table = connection.getTable(TableName.valueOf("user"));
Delete del= new Delete(Bytes.toBytes(rowKey));
table.delete(del);
Get
包:org.apache.hadoop.hbase.client.Get
做用:獲取單個行的數據
用法:
HTable table = new HTable(config,Bytes.toBytes(tablename));
Get get = new Get(Bytes.toBytes(row));
Result result = table.get(get);
說明:獲取 tablename 表中 row 行的對應數據
代碼示例:
Connection connection = ConnectionFactory.createConnection(config);
HTableInterface table = connection.getTable(TableName.valueOf("user"));
Get get = new Get(rowKey.getBytes());
Result row = table.get(get);
for (KeyValue kv : row.raw()) {
System.out.print(new String(kv.getRow()) + " ");
System.out.print(new String(kv.getFamily()) + ":");
System.out.print(new String(kv.getQualifier()) + " = ");
System.out.print(new String(kv.getValue()));
System.out.print(" timestamp = " + kv.getTimestamp() + "\n");
}
ResultScanner
包:org.apache.hadoop.hbase.client.ResultScanner
做用:獲取值的接口
用法:
ResultScanner scanner = table.getScanner(scan);
For(Result rowResult : scanner){
Bytes[] str = rowResult.getValue(family,column);
}
說明:循環獲取行中列值。
代碼示例:
Connection connection = ConnectionFactory.createConnection(config);
HTableInterface table = connection.getTable(TableName.valueOf("user"));
Scan scan = new Scan();
scan.setStartRow("a1".getBytes());
scan.setStopRow("a20".getBytes());
ResultScanner scanner = table.getScanner(scan);
for (Result row : scanner) {
System.out.println("\nRowkey: " + new String(row.getRow()));
for (KeyValue kv : row.raw()) {
System.out.print(new String(kv.getRow()) + " ");
System.out.print(new String(kv.getFamily()) + ":");
System.out.print(new String(kv.getQualifier()) + " = ");
System.out.print(new String(kv.getValue()));
System.out.print(" timestamp = " + kv.getTimestamp() + "\n");
}
}
FilterList 表明一個過濾器列表,能夠添加多個過濾器進行查詢,多個過濾器之間的關係有:
與關係(符合全部):FilterList.Operator.MUST_PASS_ALL
或關係(符合任一):FilterList.Operator.MUST_PASS_ONE
使用方法:
FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ONE);
Scan s1 = new Scan();
filterList.addFilter(new SingleColumnValueFilter(Bytes.toBytes(「f1」), Bytes.toBytes(「c1」), CompareOp.EQUAL,Bytes.toBytes(「v1」) ) );
filterList.addFilter(new SingleColumnValueFilter(Bytes.toBytes(「f1」), Bytes.toBytes(「c2」), CompareOp.EQUAL,Bytes.toBytes(「v2」) ) );
// 添加下面這一行後,則只返回指定的cell,同一行中的其餘cell不返回
s1.addColumn(Bytes.toBytes(「f1」), Bytes.toBytes(「c1」));
s1.setFilter(filterList); //設置filter
ResultScanner ResultScannerFilterList = table.getScanner(s1); //返回結果列表
過濾器的種類:
列植過濾器—SingleColumnValueFilter
過濾列植的相等、不等、範圍等
列名前綴過濾器—ColumnPrefixFilter
過濾指定前綴的列名
多個列名前綴過濾器—MultipleColumnPrefixFilter
過濾多個指定前綴的列名
rowKey過濾器—RowFilter
經過正則,過濾rowKey值。
SingleColumnValueFilter 列值判斷
相等 (CompareOp.EQUAL ),
不等(CompareOp.NOT_EQUAL),
範圍 (e.g., CompareOp.GREATER)…………
下面示例檢查列值和字符串'values' 相等...
SingleColumnValueFilter f = new SingleColumnValueFilter(
Bytes.toBytes("cFamily") Bytes.toBytes("column"), CompareFilter.CompareOp.EQUAL,
Bytes.toBytes("values"));
s1.setFilter(f);
注意:若是過濾器過濾的列在數據表中有的行中不存在,那麼這個過濾器對此行沒法過濾。
過濾器—ColumnPrefixFilter
ColumnPrefixFilter 用於指定列名前綴值相等
ColumnPrefixFilter f = new ColumnPrefixFilter(Bytes.toBytes("values"));
s1.setFilter(f);
MultipleColumnPrefixFilter 和 ColumnPrefixFilter 行爲差很少,但能夠指定多個前綴
byte[][] prefixes = new byte[][] {Bytes.toBytes("value1"),Bytes.toBytes("value2")};
Filter f = new MultipleColumnPrefixFilter(prefixes);
s1.setFilter(f);
RowFilter 是rowkey過濾器
一般根據rowkey來指定範圍時,使用scan掃描器的StartRow和StopRow方法比較好。
Filter f = new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator("^1234")); //匹配以1234開頭的rowkey
s1.setFilter(f);
一、 client向hregionserver發送寫請求。
二、 hregionserver將數據寫到hlog(write ahead log)。爲了數據的持久化和恢復。
三、 hregionserver將數據寫到內存(memstore)
四、 反饋client寫成功。
一、 當memstore數據達到閾值(默認是64M),將數據刷到硬盤,將內存中的數據刪除,同時刪除Hlog中的歷史數據。
二、 並將數據存儲到hdfs中。
三、 在hlog中作標記點。
一、 當數據塊達到4塊,hmaster將數據塊加載到本地,進行合併
二、 當合並的數據超過256M,進行拆分,將拆分後的region分配給不一樣的hregionserver管理
三、 當hregionser宕機後,將hregionserver上的hlog拆分,而後分配給不一樣的hregionserver加載,修改.META.
四、 注意:hlog會同步到hdfs
一、 經過zookeeper和-ROOT- .META.表定位hregionserver。
二、 數據從內存和硬盤合併後返回給client
三、 數據塊會緩存
一、管理用戶對Table的增、刪、改、查操做;
二、記錄region在哪臺Hregion server上
三、在Region Split後,負責新Region的分配;
四、新機器加入時,管理HRegion Server的負載均衡,調整Region分佈
五、在HRegion Server宕機後,負責失效HRegion Server 上的Regions遷移。
HRegion Server主要負責響應用戶I/O請求,向HDFS文件系統中讀寫數據,是HBASE中最核心的模塊。
HRegion Server管理了不少table的分區,也就是region。
Client
HBASE Client使用HBASE的RPC機制與HMaster和RegionServer進行通訊
管理類操做:Client與HMaster進行RPC;
數據讀寫類操做:Client與HRegionServer進行RPC。
Hbase對MapReduce提供支持,它實現了TableMapper類和TableReducer類,咱們只須要繼承這兩個類便可。
一、寫個mapper繼承TableMapper<Text, IntWritable>
參數:Text:mapper的輸出key類型; IntWritable:mapper的輸出value類型。
其中的map方法以下:
map(ImmutableBytesWritable key, Result value,Context context)
參數:key:rowKey;value: Result ,一行數據; context上下文
二、寫個reduce繼承TableReducer<Text, IntWritable, ImmutableBytesWritable>
參數:Text:reducer的輸入key; IntWritable:reduce的輸入value;
ImmutableBytesWritable:reduce輸出到hbase中的rowKey類型。
其中的reduce方法以下:
reduce(Text key, Iterable<IntWritable> values,Context context)
參數: key:reduce的輸入key;values:reduce的輸入value;
一、創建數據來源表‘word’,包含一個列族‘content’
向表中添加數據,在列族中放入列‘info’,並將短文數據放入該列中,如此插入多行,行鍵爲不一樣的數據便可
二、創建輸出表‘stat’,包含一個列族‘content’
三、經過Mr操做Hbase的‘word’表,對‘content:info’中的短文作詞頻統計,並將統計結果寫入‘stat’表的‘content:info中’,行鍵爲單詞
package com.itcast.hbase;
import java.io.IOException; import java.util.ArrayList; import java.util.List;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.client.HBaseAdmin; 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.Scan; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil; import org.apache.hadoop.hbase.mapreduce.TableMapper; import org.apache.hadoop.hbase.mapreduce.TableReducer; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; /** * mapreduce操做hbase * @author wilson * */ public class HBaseMr { /** * 建立hbase配置 */ static Configuration config = null; static { config = HBaseConfiguration.create(); config.set("hbase.zookeeper.quorum", "slave1,slave2,slave3"); config.set("hbase.zookeeper.property.clientPort", "2181"); } /** * 表信息 */ public static final String tableName = "word";//表名1 public static final String colf = "content";//列族 public static final String col = "info";//列 public static final String tableName2 = "stat";//表名2 /** * 初始化表結構,及其數據 */ public static void initTB() { HTable table=null; HBaseAdmin admin=null; try { admin = new HBaseAdmin(config);//建立表管理 /*刪除表*/ if (admin.tableExists(tableName)||admin.tableExists(tableName2)) { System.out.println("table is already exists!"); admin.disableTable(tableName); admin.deleteTable(tableName); admin.disableTable(tableName2); admin.deleteTable(tableName2); } /*建立表*/ HTableDescriptor desc = new HTableDescriptor(tableName); HColumnDescriptor family = new HColumnDescriptor(colf); desc.addFamily(family); admin.createTable(desc); HTableDescriptor desc2 = new HTableDescriptor(tableName2); HColumnDescriptor family2 = new HColumnDescriptor(colf); desc2.addFamily(family2); admin.createTable(desc2); /*插入數據*/ table = new HTable(config,tableName); table.setAutoFlush(false); table.setWriteBufferSize(5); List<Put> lp = new ArrayList<Put>(); Put p1 = new Put(Bytes.toBytes("1")); p1.add(colf.getBytes(), col.getBytes(), ("The Apache Hadoop software library is a framework").getBytes()); lp.add(p1); Put p2 = new Put(Bytes.toBytes("2"));p2.add(colf.getBytes(),col.getBytes(),("The common utilities that support the other Hadoop modules").getBytes()); lp.add(p2); Put p3 = new Put(Bytes.toBytes("3")); p3.add(colf.getBytes(), col.getBytes(),("Hadoop by reading the documentation").getBytes()); lp.add(p3); Put p4 = new Put(Bytes.toBytes("4")); p4.add(colf.getBytes(), col.getBytes(),("Hadoop from the release page").getBytes()); lp.add(p4); Put p5 = new Put(Bytes.toBytes("5")); p5.add(colf.getBytes(), col.getBytes(),("Hadoop on the mailing list").getBytes()); lp.add(p5); table.put(lp); table.flushCommits(); lp.clear(); } catch (Exception e) { e.printStackTrace(); } finally { try { if(table!=null){ table.close(); } } catch (IOException e) { e.printStackTrace(); } } } /** * MyMapper 繼承 TableMapper * TableMapper<Text,IntWritable> * Text:輸出的key類型, * IntWritable:輸出的value類型 */ public static class MyMapper extends TableMapper<Text, IntWritable> { private static IntWritable one = new IntWritable(1); private static Text word = new Text(); @Override //輸入的類型爲:key:rowKey; value:一行數據的結果集Result protected void map(ImmutableBytesWritable key, Result value, Context context) throws IOException, InterruptedException { //獲取一行數據中的colf:col String words = Bytes.toString(value.getValue(Bytes.toBytes(colf), Bytes.toBytes(col)));// 表裏面只有一個列族,因此我就直接獲取每一行的值 //按空格分割 String itr[] = words.toString().split(" "); //循環輸出word和1 for (int i = 0; i < itr.length; i++) { word.set(itr[i]); context.write(word, one); } } } /** * MyReducer 繼承 TableReducer * TableReducer<Text,IntWritable> * Text:輸入的key類型, * IntWritable:輸入的value類型, * ImmutableBytesWritable:輸出類型,表示rowkey的類型 */ public static class MyReducer extends TableReducer<Text, IntWritable, ImmutableBytesWritable> { @Override protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { //對mapper的數據求和 int sum = 0; for (IntWritable val : values) {//疊加 sum += val.get(); } // 建立put,設置rowkey爲單詞 Put put = new Put(Bytes.toBytes(key.toString())); // 封裝數據 put.add(Bytes.toBytes(colf), Bytes.toBytes(col),Bytes.toBytes(String.valueOf(sum))); //寫到hbase,須要指定rowkey、put context.write(new ImmutableBytesWritable(Bytes.toBytes(key.toString())),put); } }
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { config.set("df.default.name", "hdfs://master:9000/");//設置hdfs的默認路徑 config.set("hadoop.job.ugi", "hadoop,hadoop");//用戶名,組 config.set("mapred.job.tracker", "master:9001");//設置jobtracker在哪 //初始化表 initTB();//初始化表 //建立job Job job = new Job(config, "HBaseMr");//job job.setJarByClass(HBaseMr.class);//主類 //建立scan Scan scan = new Scan(); //能夠指定查詢某一列 scan.addColumn(Bytes.toBytes(colf), Bytes.toBytes(col)); //建立查詢hbase的mapper,設置表名、scan、mapper類、mapper的輸出key、mapper的輸出value TableMapReduceUtil.initTableMapperJob(tableName, scan, MyMapper.class,Text.class, IntWritable.class, job); //建立寫入hbase的reducer,指定表名、reducer類、job TableMapReduceUtil.initTableReducerJob(tableName2, MyReducer.class, job); System.exit(job.waitForCompletion(true) ? 0 : 1); } } |