1.HBase 架構
============================================
2. HBase Shell 操作
2.1. 基本操作
- 進入HBase客戶端命令行:
bin/hbase shell
- 查看幫助命令:
help
- 查看當前數據庫中有哪些表:
list
2.2. 表的操作
// 2.2.1. 創建表
create 'student','info'(列族)
// 2.2.2. 插入數據到表
put 'student','1001','info:sex','male'
put 'student','1001','info:age','18'
put 'student','1002','info:name','Janna'
put 'student','1002','info:sex','female'
put 'student','1002','info:age','20'
// 2.2.3. 掃描查看表數據
scan 'student'
scan 'student',{STARTROW => '1001', STOPROW => '1004'}
scan 'student',{STARTROW => '1001'}
// 2.2.4. 查看表結構
describe 'student'
// 2.2.5. 更新指定字段的數據
put 'student','1001','info:name','zhangsan'
put 'student','1001','info:age','22'
// 2.2.6. 查看“指定行”或“指定列族:列”的數據
get 'student','1001'
get 'student','1001','info:name'
// 2.2.7. 統計表數據行數
count 'student'
// 2.2.8. 刪除數據:
// 刪除某rowkey的全部數據
deleteall 'student','1001'
// 刪除某rowkey的某一列數據
delete 'student','1002','info:sex'
// 2.2.9. 清空表數據
// 清空表的操作順序為先disable, 然后再 truncate
truncate 'student'
// 2.2.10. 刪除表
// 先讓該表為 disable 狀態
disable 'student'
// 然后才能 drop 這個表
drop 'student'
// 2.2.11 變更表信息
// 將info列族中的數據存放3個版本
alter 'student',{NAME=>'info',VERSIONS=>3}
get 'student','1001',{COLUMN=>'info:name',VERSIONS=>3}
3. HBase 數據結構
3.1 RowKey
- RowKey 可以是任意字符串(最大長度是64KB,實際應用中長度一般為10-100bytes),在HBASE內部,RowKey 保存為字節數組。存儲時,數據按照 RowKey 的字典序排序存儲。設計 RowKey 時,要充分考慮排序存儲這個特性,將經常一起讀取的行存儲在一起。(位置相關性)
- RowKey 是用來檢索記錄的主鍵。訪問HBase table中的行,有三種方式:
- 通過單個 RowKey 訪問;
- 通過 RowKey 的 range(正則)
- 全表掃描
3.2 Column Family
- 列族:HBASE 表中的每個列,都歸屬於某個列族。列族是表的 schema 的一部分(而列不是)。必須在使用表之前定義。列名都以列族作為前綴。例如:courses:history, courses:math 都屬於 courses 這個列族。
3.3 Cell
- 由(rowkey, column Family:column, version)唯一確定的單元。cell 中的數據是沒有類型的,全部是字節碼形式存儲。
3.4 TimeStamp
- 版本通過時間戳來索引;
3.5 命名空間
- Table: 表,所有的表都是命名空間的成員,即表必屬於某個命名空間,如果沒有指定,則在 default 默認的命名空間中;
- RegionServer group:一個命名空間包含了默認的 RegionServer Group;
- Permission: 權限。命名空間能夠讓我們來定義訪問控制列表ACL(Access Control List);
- Quota:限額,可以強制一個命名空間可包含的 region 數量;
- 常用命令:
- 查看命名空間:
list_namespace
; - 創建命名空間:
create_namespace 'bigdata'
; - 在指定命名空間下,創建表:
create 'bigdata:student','info'
; - 刪除命名空間:
drop_namespace 'bigdata'
;
- 查看命名空間:
4. HBase 原理
4.1 讀流程
=========================
4.2 寫流程
- Client 向 HregionServer 發送寫請求;
- HregionServer 將數據寫到 HLog(write ahead log)。為了數據的持久化和恢復;
- HregionServer 將數據寫到內存(MemStore);
- 反饋 Client 寫成功;
=========================
4.3 數據flush過程
- 當 MemStore 數據達到閾值(默認是 128M,老版本是 64M),將數據刷到磁盤,將內存中的數據刪除,同時刪除HLog中的歷史數據;
- 將數據存儲到HDFS中;
- 在HLog中做標記點;
4.4 數據合並過程
- 當數據塊達到4塊,Hmaster 觸發合並操作, Region 將數據塊加載到本地,進行合並;
- 當合並的數據超過 256M, 進行拆分,將拆分后的 Region 分配給不同的 HregionServer 管理;
- 當 HregionServer 宕機后,將 HregionServer 上的 hlog拆分,然后分配給不同的 HregionServer 加載,修改 META;
- 注意:HLog 會同步到 HDFS;
5. HBase API 操作
5.1 環境准備
// pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.3.4</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.3.4</version>
</dependency>
<dependencies>
5.2 程序編寫
public class TestHbase {
private static Admin admin = null;
private static Connection connection = null;
private static Configuration configuration = null;
static {
// HBase 配置文件
configuration = HBaseConfiguration.create();
// zookeeper 配置
configuration.set("hbase.zookeeper.quorum", "Zookeeper地址");
configuration.set("hbase.zookeeper.property.clientPort", "2181");
// 獲取連接對象
try {
connection = ConnectionFactory.createConnection(configuration);
admin = connection.getAdmin();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void close(Connection conn, Admin admin) {
if (conn != null) {
try {
conn.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (admin != null) {
try {
admin.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// 判斷表是否存在
@Test
public void tableExist() throws IOException {
// 執行操作
Boolean student = admin.tableExists(TableName.valueOf("student"));
System.out.println("表Staff是否存在:"+student);
Boolean staff = admin.tableExists(TableName.valueOf("staff"));
System.out.println("表Staff是否存在:"+staff);
this.close(connection, admin);
}
// 創建表
@Test
public void createTable() throws IOException {
// 創建表描述器
HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf("country"));
// 創建列描述器
HColumnDescriptor hColumnDescriptor = new HColumnDescriptor("name");
// 添加列族
hTableDescriptor.addFamily(hColumnDescriptor);
// 創建表操作
admin.createTable(hTableDescriptor);
System.out.println("表已經創建成功!");
this.close(connection, admin);
}
// 刪除表
@Test
public void deleteTable() throws IOException {
// 使表不可用
admin.disableTable(TableName.valueOf("country"));
// 刪除表
admin.deleteTable(TableName.valueOf("country"));
System.out.println("表已經刪除成功!");
this.close(connection, admin);
}
// 操作表中數據:
// 增/改數據
@Test
public void putData() throws IOException {
// 獲取table對象
Table table = connection.getTable(TableName.valueOf("student"));
// 創建put對象
Put put = new Put(Bytes.toBytes("1010"));
// 添加數據
put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"), Bytes.toBytes("貂蟬"));
// 執行添加操作
table.put(put);
System.out.println("數據添加成功!");
this.close(connection, admin);
}
// 刪除數據
@Test
public void deleteData() throws IOException {
// 獲取table對象
Table table = connection.getTable(TableName.valueOf("student"));
// 創建delete對象
Delete delete = new Delete(Bytes.toBytes("1010"));
// 第一種方式:不建議使用,只是刪除最新版本
// delete.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"));
// 第二種方式:刪除所有版本
delete.addColumns(Bytes.toBytes("info"), Bytes.toBytes("name"));
// 刪除數據
table.delete(delete);
System.out.println("數據刪除成功!");
table.close();
this.close(connection, admin);
}
// 查詢數據
// 全表掃描
@Test
public void scanTable() throws IOException {
Table table = connection.getTable(TableName.valueOf("student"));
// 構建掃描器
Scan scan = new Scan();
ResultScanner results = table.getScanner(scan);
for(Result result : results) {
Cell[] cells = result.rawCells();
for (Cell cell : cells) {
System.out.println("RK:" + Bytes.toString(CellUtil.cloneRow(cell)) +
",CF:" + Bytes.toString(CellUtil.cloneFamily(cell)) +
",CN:" + Bytes.toString(CellUtil.cloneQualifier(cell)) +
",VALUE:" + Bytes.toString(CellUtil.cloneValue(cell)));
}
}
table.close();
this.close(connection, admin);
}
// 獲取指定列族:列的數據
@Test
public void scanColumnFamily() throws IOException {
Table table = connection.getTable(TableName.valueOf("student"));
// 創建get對象
Get get = new Get(Bytes.toBytes("1001"));
Result result = table.get(get);
Cell[] cells = result.rawCells();
for (Cell cell : cells) {
System.out.println("RK:" + Bytes.toString(CellUtil.cloneRow(cell)) +
",CF:" + Bytes.toString(CellUtil.cloneFamily(cell)) +
",CN:" + Bytes.toString(CellUtil.cloneQualifier(cell)) +
",VALUE:" + Bytes.toString(CellUtil.cloneValue(cell)));
}
}
}
**參考資料:** - [ubuntu 16.04 開放指定端口](https://blog.csdn.net/fancancan/article/details/81286689) - [HBase 單機啟動問題](https://blog.csdn.net/Sunday2017/article/details/80569947) - [hadoop +zookeeper + hbase 單節點安裝](https://www.cnblogs.com/chaoren399/p/5018550.html) - [Windows 環境下,出現“UnknownHostException”](https://blog.csdn.net/weixin_40861707/article/details/79979491)