HBase的特點:
- 海量儲存: 底層基於HDFS儲存海量資料
- 列式儲存:HBase表的資料是基於列族進行儲存的,一個列族包含若干列
- 極易擴充套件:底層依賴HDFS,當磁碟空間不足的時候,只需要動態增加DataNode服務節點就可以
- 高併發:支援高併發的讀寫請求
- 稀疏:稀疏主要是針對HBase列的靈活性,在列族中,你可以指定任意多的列,在列資料為空的情 況下,是不會佔用儲存空間的。
- 資料的多版本:HBase表中的資料可以有多個版本值,預設情況下是根據版本號去區分,版本號就 是插入資料的時間戳
- 資料型別單一:所有的資料在HBase中是以位元組陣列進行儲存
HBase的應用場景:
HBase適合海量明細資料的儲存,並且後期需要有很好的查詢效能(單表超千萬、上億, 且併發要求高)
HBase資料模型:
HBase整體架構:
Zookeeper
- 實現了HMaster的高可用
- 儲存了HBase的後設資料資訊,是所有HBase表的定址入口
- 對HMaster和HRegionServer實現了監控
HMaster(Master)
- 為HRegionServer分配Region 維護整個叢集的負載均衡
- 維護叢集的後設資料資訊
- 發現失效的Region,並將失效的Region分配到正常的HRegionServer上
HRegionServer(RegionServer)
- 負責管理Region 接受客戶端的讀寫資料請求
- 切分在執行過程中變大的Region
Region
- 每個HRegion由多個Store構成, 每個Store儲存一個列族(Columns Family),表有幾個列族,則有幾個Store,
- 每個Store由一個MemStore和多個StoreFile組成,MemStore是Store在記憶體中的內容,寫到檔案 後就是StoreFile。
- StoreFile底層是以HFile的格式儲存
HBase shell 基本操作:
入口:hbase shell
hbase(main):001:0> create 'lagou', 'base_info', 'extra_info' 或者(Hbase建表必須指定列族資訊) create 'lagou', {NAME => 'base_info', VERSIONS => '3'},{NAME => 'extra_info',VERSIONS => '3'} VERSIONS 是指此單元格內的資料可以保留最近的 3 個版本
新增資料操作:
向lagou表中插入資訊,row key為 rk1,列族base_info中新增name列標示符,值為wang put 'lagou', 'rk1', 'base_info:name', 'wang' 向lagou表中插入資訊,row key為rk1,列族base_info中新增age列標示符,值為30 put 'lagou', 'rk1', 'base_info:age', 30
向lagou表中插入資訊,row key為rk1,列族extra_info中新增address列標示符,值為shanghai put 'lagou', 'rk1', 'extra_info:address', 'shanghai'
查詢,更新,刪除:
獲取表中row key為rk1的所有資訊 get 'lagou', 'rk1' 獲取lagou表中row key為rk1,base_info列族的所有資訊 get 'lagou', 'rk1', 'base_info' 獲取表中row key為rk1,base_info列族的name、age列標示符的資訊 get 'lagou', 'rk1', 'base_info:name', 'base_info:age' 獲取lagou表中row key為rk1,base_info、extra_info列族的資訊 hbase(main):010:0> get 'lagou', 'rk1', 'base_info', 'extra_info' 或者 hbase(main):011:0> get 'lagou', 'rk1', {COLUMN => ['base_info', 'extra_info']} 或者 hbase(main):012:0> get 'lagou', 'rk1', {COLUMN => ['base_info:name', 'extra_info:address']} 獲取表中row key為rk1,cell的值為wang的資訊 get 'lagou', 'rk1', {FILTER => "ValueFilter(=, 'binary:wang')"} 獲取表中row key為rk1,列標示符中含有a的資訊 get 'lagou', 'rk1', {FILTER => " (QualifierFilter(=,'substring:a'))"} 查詢lagou表中的所有資訊: scan 'lagou' 查詢表中列族為 base_info 的資訊: hbase(main):001:0> scan 'lagou', {COLUMNS => 'base_info'} hbase(main):002:0> scan 'lagou', {COLUMNS => 'base_info', RAW => true, VERSIONS => 3} ## Scan時可以設定是否開啟Raw模式,開啟Raw模式會返回包括已新增刪除標記但是未實際刪除的資料 ## VERSIONS指定查詢的最大版本數 指定多個列族與按照資料值模糊查詢: 查詢lagou表中列族為 base_info 和 extra_info且列標示符中含有a字元的資訊 hbase(main):001:0> scan 'lagou', {COLUMNS => ['base_info', 'extra_info'], FILTER => "(QualifierFilter(=,'substring:a'))"} rowkey的範圍值查詢(非常重要) 查詢lagou表中列族為base_info,rk範圍是[rk1, rk3)的資料(rowkey底層儲存是字典序) 按rowkey順序儲存。 scan 'lagou', {COLUMNS => 'base_info', STARTROW => 'rk1', ENDROW => 'rk3'} 查詢lagou表中row key以rk字元開頭的 hbase(main):001:0> scan 'lagou',{FILTER=>"PrefixFilter('rk')"} 更新資料值: 把lagou表中rowkey為rk1的base_info列族下的列name修改為liang put 'lagou', 'rk1', 'base_info:name', 'liang' 刪除資料和表: 刪除lagou表row key為rk1,列標示符為 base_info:name 的資料 > delete 'lagou', 'rk1', 'base_info:name' 指定rowkey,列名以及時間戳資訊進行刪除 刪除lagou表row key為rk1,列標示符為base_info:name的資料 delete 'lagou', 'rk1', 'base_info:name',1600660619655 刪除 base_info 列族 alter 'lagou', 'delete' => 'base_info' 刪除lagou表資料 truncate 'lagou' 刪除lagou表 #先disable 再drop hbase(main):036:0> disable 'lagou' hbase(main):037:0> drop 'lagou' #如果不進行disable,直接drop會報錯 ERROR: Table user is enabled. Disable it first.
HBase JAVA API:
<dependencies> <dependency> <groupId>org.apache.hbase</groupId> <artifactId>hbase-client</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.14.3</version> <scope>test</scope> </dependency> </dependencies>
建立連線:
package com.lagou.hbase.client; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.*; import org.apache.hadoop.hbase.client.*; import org.apache.hadoop.hbase.util.Bytes; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; public class HbaseClientDemo { Configuration conf = null; Connection conn = null; @Before public void init() throws IOException { //獲取一個配置檔案物件 conf = HBaseConfiguration.create(); conf.set("hbase.zookeeper.quorum", "linux121,linux122"); conf.set("hbase.zookeeper.property.clientPort", "2181"); //通過conf獲取到hbase叢集的連線 conn = ConnectionFactory.createConnection(conf); } //釋放連線 @After public void realse() { if (conn != null) { try { conn.close(); } catch (IOException e) { e.printStackTrace(); } } } }
建立表:
//建立一張hbase表 @Test public void createTable() throws IOException { //獲取HbaseAdmin物件用來建立表 HBaseAdmin admin = (HBaseAdmin) conn.getAdmin(); //建立Htabledesc描述器,表描述器 final HTableDescriptor worker = new HTableDescriptor(TableName.valueOf("worker")); //指定列族 worker.addFamily(new HColumnDescriptor("info")); admin.createTable(worker); System.out.println("worker表建立成功!!"); }
插入資料:
//插入一條資料 @Test public void putData() throws IOException { //需要獲取一個table物件 final Table worker = conn.getTable(TableName.valueOf("worker")); //準備put物件 final Put put = new Put(Bytes.toBytes("110"));//指定rowkey put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("addr"), Bytes.toBytes("beijing")); //插入資料,引數型別是put worker.put(put); //準備list<puts>,可以執行批量插入 //關閉table物件 worker.close(); System.out.println("插入資料到worker表成功!!"); }
查詢資料:
//查詢資料 @Test public void getData() throws IOException { //準備table物件 final Table worker = conn.getTable(TableName.valueOf("worker")); //準備get物件 final Get get = new Get(Bytes.toBytes("110")); //指定查詢某個列族或者列 get.addFamily(Bytes.toBytes("info")); //執行查詢 final Result result = worker.get(get); //獲取到result中所有cell物件 final Cell[] cells = result.rawCells(); //遍歷列印 for (Cell cell : cells) { final String rowkey = Bytes.toString(CellUtil.cloneRow(cell)); final String f = Bytes.toString(CellUtil.cloneFamily(cell)); final String column = Bytes.toString(CellUtil.cloneQualifier(cell)); final String value = Bytes.toString(CellUtil.cloneValue(cell)); System.out.println("rowkey-->" + rowkey + "--;cf-->" + f + "---;column--->" + column + "--;value-->" + value); } worker.close(); }
刪除資料:
//刪除一條資料 @Test public void deleteData() throws IOException { //需要獲取一個table物件 final Table worker = conn.getTable(TableName.valueOf("worker")); //準備delete物件 final Delete delete = new Delete(Bytes.toBytes("110")); //執行刪除 worker.delete(delete); //關閉table物件 worker.close(); System.out.println("刪除資料成功!!"); }
通過Scan全表掃描:
/** * 全表掃描 */ @Test public void scanAllData() throws IOException { HTable teacher = (HTable) conn.getTable(TableName.valueOf("teacher")); Scan scan = new Scan(); ResultScanner resultScanner = teacher.getScanner(scan); for (Result result : resultScanner) { Cell[] cells = result.rawCells();//獲取改行的所有cell物件 for (Cell cell : cells) { //通過cell獲取rowkey,cf,column,value String cf = Bytes.toString(CellUtil.cloneFamily(cell)); String column = Bytes.toString(CellUtil.cloneQualifier(cell)); String value = Bytes.toString(CellUtil.cloneValue(cell)); String rowkey = Bytes.toString(CellUtil.cloneRow(cell)); System.out.println(rowkey + "----" + cf + "--" + column + "---" + value); } } teacher.close(); }
通過startRowKey和endRowKey進行掃描:
//指定scan 開始rowkey和結束rowkey,這種查詢方式建議使用,指定開始和結束rowkey區間避免全表掃描 @Test public void scanStartEndData() throws IOException { //準備table物件 final Table worker = conn.getTable(TableName.valueOf("worker")); //準備scan物件 final Scan scan = new Scan(); //指定查詢的rowkey區間,rowkey在hbase中是以字典序排序 scan.setStartRow(Bytes.toBytes("001")); scan.setStopRow(Bytes.toBytes("004")); //執行掃描 final ResultScanner resultScanner = worker.getScanner(scan); for (Result result : resultScanner) { //獲取到result中所有cell物件 final Cell[] cells = result.rawCells(); //遍歷列印 for (Cell cell : cells) { final String rowkey = Bytes.toString(CellUtil.cloneRow(cell)); final String f = Bytes.toString(CellUtil.cloneFamily(cell)); final String column = Bytes.toString(CellUtil.cloneQualifier(cell)); final String value = Bytes.toString(CellUtil.cloneValue(cell)); System.out.println("rowkey-->" + rowkey + "--;cf-->" + f + ";column--->" + column + "--;value-->" + value); } } worker.close(); }