HBase詳細的安裝和使用方法

簡介

HBase的原型是Google的BigTable論文,受到了該論文思想的啓發,目前作爲Hadoop的子項目來開發維護,用於支持結構化的數據存儲。

官方網站:http://hbase.apache.org

民間中文文檔:https://hbase.apachecn.org/#/

  • 2006年Google發表BigTable白皮書
  • 2006年開始開發HBase
  • 2008年北京成功開奧運會,程序員默默地將HBase弄成了Hadoop的子項目
  • 2010年HBase成爲Apache頂級項目
  • 現在很多公司基於HBase開發出了定製版,比如阿里雲HBase

總結:

HBase是構建在HDFS之上的分佈式、【面向列】的存儲系統,在需要實時讀寫、隨機訪問的超大規模數據集是,可以使用HBase。

在這裏插入圖片描述

爲什麼需要HBase

# 海量數據存儲
	一個表百億行 百萬列;(MySQL實戰最大值500萬行,30列)
# 實時查詢
	1秒內查詢得到結果。

HBase特點

# 1. 容量大
	HBase單表百億行,百萬列。
# 2. 面向列
	HBase存儲是面向列,可以再數據存在以後動態增加新列和數據,並支持列數據的獨立操作。
# 3. 多版本
	HBase每個數據,可以同時保存多個版本,按照時間去標記。
# 4. 稀疏性
	HBase每條數據的增刪,並不是要操作所有的列,的列可以動態增加,可以存在大量空白單元格,不會佔用磁盤空間,這對於海量數據來講,非常重要。
# 5. 擴展性
	底層使用HDFS,存儲能力可以橫向擴展。
# 6. 高可靠性
	底層使用HDFS,擁有replication的數據高可靠性。
# 7. 高性能
	表數據達到一定規模,"自動分區",具備主鍵索引,緩存機制,使得HBase海量數據查詢能達到毫秒級。

HBase和RDBMS對比

HBase 關係型數據庫
數據庫以**region**的形式存在 數據庫以Table的形式存在
使用**行鍵**(row key) 支持主鍵PK
使用行表示一條數據 一條數據用row代表
使用列 column、列族 column family column代表列數據的含義
使用HBase shell命令操作數據 使用SQL操作數據
數據文件可以基於HDFS,是分佈式文件系統,
可以任意擴展,數據總量取決於服務器數量
數據總量依賴於單體服務器的配置
不支持事務、不支持ACID 支持事務和ACID
不支持表連接 支持join表連接

HBase表邏輯結構

在這裏插入圖片描述

數據相關概念

# namespace 命名空間
	hbase管理表的結構,在HDFS中對應一個文件夾。
# table 表
	hbase管理數據的結構,在HDFS中對應一個文件。
# column family 列族
	表中數據的列,要屬於某個列族,所有的列的訪問格式(列族:列名)
# rowkey 主鍵
	用來標記和檢索數據的主鍵key。
# cell 單元格
	由`row key+column family+column+version` 唯一確定的一條數據
# timestamp 時間戳
	時間戳,每個單元格可以保存多個值,每個值有對應的時間戳,每個cell中,不同版本的數據倒敘排序,排在最前面的是最新數據。

HBase單機版安裝

下載

地址:http://archive.apache.org/dist/hbase/

準備

  1. 安裝並配置hadoop
[root@hadoop10 installs]# jps
3440 Jps
3329 SecondaryNameNode
3030 NameNode
3134 DataNode
  1. 安裝並配置zookeeper
 [root@hadoop10 installs]# jps
 3329 SecondaryNameNode
 3509 QuorumPeerMain
 3030 NameNode
 3595 Jps
 3134 DataNode

 [root@hadoop10 installs]# zkServer.sh status
 ZooKeeper JMX enabled by default
 Using config: /opt/installs/zookeeper3.4.14/bin/../conf/zoo.cfg
 Mode: standalone
  1. 設置好日期同步
 # 查看linux系統時間
 [root@hadoop10 installs]# date
 # 重啓chronyd服務,同步系統時間。
 [root@hadoop10 installs]# systemctl restart chronyd
 [root@hadoop10 installs]# date
 2020年 04月 12日 星期日 22:51:31 CST

安裝

# 1. 安裝hbase
1. 解壓HBase
	[root@hadoop30 modules]# tar zxvf hbase-1.2.4-bin.tar.gz -C /opt/installs/
2. 配置環境變量
	#JAVA
    export JAVA_HOME=/opt/installs/jdk1.8
    export PATH=$PATH:$JAVA_HOME/bin
    # HADOOP
    export HADOOP_HOME=/opt/installs/hadoop2.9.2/
    export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
    # zookeeper
    export PATH=$PATH:/opt/installs/zookeeper3.4.14/bin/
    # HBase
    export HBASE_HOME=/opt/installs/hbase-1.2.4/
    export PATH=$PATH:$HBASE_HOME/bin
3. 加載profile配置
	source /etc/profile
# 2. 初始化配置文件
# 1 -------------------hbase-env.sh--------------------

# 配置Java_home
export JAVA_HOME=/opt/installs/jdk1.8

# 註釋掉如下2行。
# export HBASE_MASTER_OPTS="$HBASE_MASTER_OPTS -XX:PermSize=128m -XX:MaxPermSize=128m -XX:ReservedCodeCacheSize=256m"
# export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -XX:PermSize=128m -XX:MaxPermSize=128m -XX:ReservedCodeCacheSize=256m"

# 禁用內置zookeeper
export HBASE_MANAGES_ZK=false
# 2. -------------------hbase-site.xml-------------------------
<configuration>
    <!-- hbase的入口,ns HaHadoop的虛擬命名空間 -->
    <property>
        <name>hbase.rootdir</name>
        <value>hdfs://hadoop10:9000/hbase</value>
    </property>
    <!-- 使用僞分佈式模式 -->
    <property>
        <name>hbase.cluster.distributed</name>
        <value>true</value>
    </property>
    <!-- zookeeper集羣地址,端口默認2181不需要指定 -->
    <property>
        <name>hbase.zookeeper.quorum</name>
        <value>hadoop10</value>
    </property>
   
</configuration>
#  -------------------配置regionservers(regionserver所在節點的ip) -------------------
hadoop10
# 3. 啓動hbase
啓動順序:
1. 啓動zookeeper
2. 啓動hdfs
3. 啓動hbase

關閉順序:
1.關閉hbase
2.關閉hdfs
3.關閉zk
# hbase啓動方式一
1. 啓動hbase
	start-hbase.sh
2. 關閉hbase
	stop-hbase.sh
	
# hbase啓動方式二
1. 啓動HMaster
[root@hadoop10 installs]# hbase-daemon.sh start master
# 關閉
[root@hadoop10 installs]# hbase-daemon.sh stop master
2. 啓動HRegionServer
[root@hadoop10 installs]# hbase-daemon.sh start regionserver
# 關閉
[root@hadoop10 installs]# hbase-daemon.sh stop master
# 4. 驗證訪問
1. java進程查看
[root@hadoop10 installs]# jps
4688 NameNode
5618 HMaster
5730 HRegionServer
4819 DataNode
3509 QuorumPeerMain
6150 Jps
4984 SecondaryNameNode
2. HMaster WebUI查看
http://ip:16010
3. 進入客戶端
hbase shell
hbase(main):001:0>

在這裏插入圖片描述

HBase 命令

1. 客戶端進出命令

# 進入客戶端:
	./hbase shell
# 退出客戶端命令:
	quit
# 幫助
	help

2. namespace操作

默認存在一個default的namespace
#1. 查看namespace
  list_namespace

#2. 創建namespace
  create_namespace "命名空間名字"

#3. 刪除namespace
  drop_namespace "命令空間名字"

3. 表操作

# 1. 查看所有表
hbase(main):024:0> list
TABLE
baizhins:t_person # namespace:表
t_user # default:表 default被省略了
2 row(s) in 0.1140 seconds

# 2. 查看某個namespace下的所有表
hbase(main):027:0> list_namespace_tables "baizhins"
TABLE
t_person
1 row(s) in 0.3970 seconds

# 3. 創建表
語法:create "namespace:表名","列族1","列族2"
hbase(main):023:0> create "baizhins:t_person","info","edu"
0 row(s) in 9.9000 seconds

# 4. 查看錶結構
hbase(main):030:0> desc "baizhins:t_person"
Table baizhins:t_person is ENABLED
baizhins:t_person
COLUMN FAMILIES DESCRIPTION
{NAME => 'edu', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE',
 DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE =>
 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
{NAME => 'info', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE'
, DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE =
> 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
2 row(s) in 1.6400 seconds

# 5. 刪除表和禁用表
hbase(main):002:0> disable "namespace:表"
0 row(s) in 4.4790 seconds

hbase(main):002:0> drop "namespace:表"
0 row(s) in 4.4790 seconds

4.數據增刪改查

# 1. 添加數據(每次只能添加一個列)
	put "namespace:表","rowkey","列族1:列名1","值"
	
hbase(main):007:0> put 'baizhins:t_person','1001','info:name','zhangsan'
0 row(s) in 1.7250 seconds
hbase(main):008:0> put 'baizhins:t_person','1001','info:age',20
0 row(s) in 0.0210 seconds
hbase(main):009:0> put 'baizhins:t_person','1002','info:name','lisi'
0 row(s) in 0.0190 seconds
hbase(main):010:0> put 'baizhins:t_person','1002','info:age',21
0 row(s) in 0.0620 seconds

# 2. 根據rowkey查找數據
	get "namespace:表名","rowkey"

hbase(main):015:0> get 'baizhins:t_person','1001'
COLUMN                     CELL
 info:age                  timestamp=1598752891747, value=20
 info:name                 timestamp=1598752881461, value=zhangsan
2 row(s) in 0.1550 seconds
	
# 3. 根據rowkey和列族查找數據
	get "namespace:表名","rowkey","列族:列"
	
# 4. scan 查詢表中所有數據
	hbase(main):019:0> scan "baizhins:t_person"

hbase(main):024:0> scan 'baizhins:t_person'
ROW                        COLUMN+CELL
 1001                      column=info:age, timestamp=1598753486814, value=20
 1001                      column=info:name, timestamp=1598753478658, value=zhangsan
 1002                      column=info:age, timestamp=1598753520306, value=21
 1002                      column=info:name, timestamp=1598753509800, value=lisi
2 row(s) in 0.0410 seconds

# 5. scan 查詢表中前2條數據
	hbase(main):022:0> scan "baizhins:t_person",{LIMIT=>2}

# 6. 使用start row 和 end row 範圍查找
	hbase(main):029:0> scan "baizhins:t_person",{STARTROW=>"1001",STOPROW=>"1003"}
    
    
hbase(main):032:0> scan 'baizhins:t_person',{STARTROW=>'1001',STOPROW=>'1003'}
ROW                        COLUMN+CELL
 1001                      column=info:age, timestamp=1598753486814, value=20
 1001                      column=info:name, timestamp=1598753478658, value=zhangsan
 1002                      column=info:age, timestamp=1598753520306, value=21
 1002                      column=info:name, timestamp=1598753509800, value=lisi

問題:HBase中的數據是按照Rowkey的ASCII字典順序進行全局排序的
假如有5個Rowkey:"012", "0", "123", "234", "3",按ASCII字典排序後的結果爲:"0", "012", "123", "234", "3"。
Rowkey排序時會先比對兩個Rowkey的第一個字節,如果相同,然後會比對第二個字節,依次類推... 對比到第X個字節時,已經超出了其中一個Rowkey的長度,短的Rowkey排在前面。

# 7. 使用start row和limit查找
	hbase(main):032:0> scan "baizhins:t_person",{STARTROW=>"1002",LIMIT=>2}

hbase(main):033:0> scan 'baizhins:t_person',{STARTROW=>'1002',LIMIT=>2}
ROW                        COLUMN+CELL
 1002                      column=info:age, timestamp=1598753520306, value=21
 1002                      column=info:name, timestamp=1598753509800, value=lisi
 1003                      column=info:name, timestamp=1598753628840, value=wangwu

# 8. 修改數據(本質上是覆蓋)
	put "namespace:表","rowkey","列族:列名","值"
	
# 9. 刪除數據(刪除某個cell)
	delete "namespace:表","rowkey","列族:列名"
	
# 10. 刪除某個rowkey對應的數據
	deleteall "namespace:表","rowkey"
	
# 11. 統計表中所有數據
	count "namespace:表"

# 12. 清空表中的所有數據
    truncate "namespace:表"

5. 多版本問題

# 1. 創建表
hbase(main):013:0> create "baizhins:user","info"
# 2. 修改版本數
hbase(main):016:0> alter "baizhins:user",{NAME=>'info',VERSIONS=>2}

# 表的列族的VERSIONS=>2表示的該列族的數據,要保存2個版本。如果put3次,則保留最新的2個版本。

# 3. 同一個cell添加2次數據。
hbase(main):014:0> put "baizhi:user","10001","info:name","aaa"
0 row(s) in 0.2620 seconds

hbase(main):015:0> put "baizhi:user","10001","info:name","bb"
0 row(s) in 0.0290 seconds
# 4. 查看多版本
hbase(main):017:0> get "baizhi:user","10001",{COLUMN=>'info:name',VERSIONS=>3}
COLUMN                      CELL
 info:name                  timestamp=1586795010367, value=bb
 info:name                  timestamp=1586795004085, value=aaa
說明:
	1. 可以查看VERSIONS指定的版本數量的值。
	2. cell中多個版本的值,按照時間戳降序排序。
	3. 在get或者scan查詢數據,並不指定VERSIONS,默認讀取的cell中最新的1個的版本的值。

HBase API

環境準備

  • 依賴

    <dependency>
        <groupId>org.apache.hbase</groupId>
        <artifactId>hbase-client</artifactId>
        <version>1.2.4</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.hbase</groupId>
        <artifactId>hbase-server</artifactId>
        <version>1.2.4</version>
    </dependency>
  • 初始化配置

    將hbase中的conf中的 hbase-site.xml放到resource配置文件目錄中。

    conf.addResource("/hbase-site.xml")

  • windows配置ip映射

API介紹

API 含義 創建
Configuration 配置文件 HBaseConfiguration.create();
Connection 連接,用來操作數據 ConnectionFactory.createConnection(conf);
Admin 客戶端,用來操作元數據
(namespace和table結構)
conn.getAdmin();
NamespaceDescriptor 命名空間相當於database NamespaceDescriptor.create(“baizhins”).build();
TableName 表名 TableName.valueOf(“baizhi:user”);
HTableDescriptor new HTableDescriptor(tablename);
HColumnDescriptor 列族 new HColumnDescriptor(“info”);
Put 添加數據 new Put(Bytes.toBytes(“10001”));
Delete rowkey的刪除條件 new Delete(Bytes.toBytes(“10001”));
Get scan多行查詢器 new Get(Bytes.toBytes(“10019”));
Scan scan多行查詢器 new Scan();
Result 查詢結果集(單條結果) table.get(get);
ResultScanner 查詢結果集(N條結果) table.getScanner(scan);
Bytes 類型轉化工具類,HBase中數據類型爲字節,
所有類型存入後都變成字節,需要相互轉化。
 

HBase客戶端連接

注意:配置windows向linux的ip映射。

// 獲得客戶端
//1. 讀取配置文件
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum","hadoop10");
BasicConfigurator.configure();//打印日誌信息
//2. 建立連接
Connection conn = ConnectionFactory.createConnection(conf);
//3. 獲得客戶端
admin = conn.getAdmin();
// 釋放資源
admin.close();

常用API

1. 創建namespace
//1. 構建namespace信息。
NamespaceDescriptor baizhins = NamespaceDescriptor.create("baizhins").build();
//2. 創建namespace
admin.createNamespace(baizhins);
2. 表操作

操作表,使用admin

  • 判斷表是否存在

    //1. 創建表名
    TableName tableName = TableName.valueOf("baizhins:person");
    //2. 判斷表是否存在
    boolean b = admin.tableExists(tableName);
    System.out.println(b?"存在":"不存在");
  • 創建表

    //1. 初始化表名
    TableName person = TableName.valueOf("baizhins:person");
    //2. 初始化列族信息
    HColumnDescriptor info = new HColumnDescriptor("info");
    HColumnDescriptor addr = new HColumnDescriptor("addr");
    //3. 綁定表名,綁定列族
    HTableDescriptor hTableDescriptor = new HTableDescriptor(person);
    hTableDescriptor.addFamily(info);
    hTableDescriptor.addFamily(addr);
    //4. 創建表
    admin.createTable(hTableDescriptor);
3. 添加

操作數據使用conn

//1. 初始化要操作的表
Table table = conn.getTable(TableName.valueOf("baizhins:person"));
//2. 創建 添加數據
Put put = new Put(Bytes.toBytes("1001"));//構造rowkey
// Bytes是HBase提供的進行字節和java數據類型轉化的工具類
put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("name"),Bytes.toBytes("張三") );
put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("age"), Bytes.toBytes(18));
put.addColumn(Bytes.toBytes("addr"), Bytes.toBytes("zipCode"), Bytes.toBytes("45000"));
//3. 將put數據添加。
table.put(put);
//4. 釋放資源
table.close();
4. 修改
//1. 初始化要操作的表
Table table = conn.getTable(TableName.valueOf("baizhins:person"));
//2. 修改的本質就是添加,利用時間戳覆蓋舊的數據而已。
Put put = new Put(Bytes.toBytes("1001"));
put.addColumn(Bytes.toBytes("addr"), Bytes.toBytes("zipCode"), Bytes.toBytes("45001"));
//3. 添加到表中
table.put(put);
//4. 關閉table
table.close();
5. 刪除
//1. 獲得要操作的表
Table table = conn.getTable(TableName.valueOf("baizhins:person"));
//2. 創建要刪除的條件,以rowkey爲條件
Delete delete = new Delete(Bytes.toBytes("1001"));

//刪除某個列族
//delete.addFamily(Bytes.toBytes("cf2"));
//刪除某個列
//delete.addColumn(Bytes.toBytes("cf1"),Bytes.toBytes("age"));

//3. 執行刪除
table.delete(delete);
6. 查詢
  • 根據rowkey單條查詢。

    //1. 獲得要操作的表
    Table table = conn.getTable(TableName.valueOf("baizhins:person"));
    //2. 使用rowkey作爲查詢條件
    Get get = new Get(Bytes.toBytes("10019"));
    //3. 執行查詢
    Result result = table.get(get);
    //4. 處理結果集:result.getValue;
    byte[] namebyte = result.getValue(Bytes.toBytes("info"), Bytes.toBytes("name"));
    //下面代碼雷同。
    byte[] agebyte = result.getValue(Bytes.toBytes("info"), Bytes.toBytes("age"));
    byte[] zipbyte = result.getValue(Bytes.toBytes("addr"), Bytes.toBytes("zipCode"));
    //獲得rowkey
    byte[] rowbytes = result.getRow();
    System.out.println(Bytes.toString(namebyte));
    System.out.println(Bytes.toInt(agebyte));
    System.out.println(Bytes.toString(zipbyte));
  • 多條查詢

    //1. 獲得要操作的表
    Table table = conn.getTable(TableName.valueOf("baizhins:person"));
    //2. 創建scan掃描器,多行查詢
    Scan scan = new Scan();
    //3. 指定要投射的列族。
    scan.addFamily(Bytes.toBytes("info"));
    scan.addFamily(Bytes.toBytes("addr"));
    //4. 設置起始和查詢條數
    scan.setStartRow(Bytes.toBytes("1001"));
    scan.setFilter(new PageFilter(3));
    //5. 執行查詢
    ResultScanner result = table.getScanner(scan);
    //6. 處理結果集
    for (Result res:result){
        byte[] namebyte = res.getValue(Bytes.toBytes("info"), Bytes.toBytes("name"));
        byte[] agebyte = res.getValue(Bytes.toBytes("info"), Bytes.toBytes("age"));
        byte[] zipCodebyte = res.getValue(Bytes.toBytes("addr"), Bytes.toBytes("zipCode"));
        String name = Bytes.toString(namebyte);
        int age = Bytes.toInt(agebyte);
        String zipcode = Bytes.toString(zipCodebyte);
        System.out.println(name+":"+age+":"+zipcode);
    }
    //7. 關閉table
    table.close();
  • 範圍查詢

    //1. 獲得要操作的表
    Table table = conn.getTable(TableName.valueOf("baizhins:person"));
    //2. 創建scan掃描器,多行查詢
    Scan scan = new Scan();
    //3. 指定要投射的列族。
    scan.addFamily(Bytes.toBytes("info"));
    scan.addFamily(Bytes.toBytes("addr"));
    //4. 設置起始和查詢條數
    scan.setStartRow(Bytes.toBytes("1001"));
    scan.setStopRow(Bytes.toBytes("1003"));
    //5. 執行查詢
    ResultScanner result = table.getScanner(scan);
    //6. 處理結果集
    for (Result res:result){
        byte[] namebyte = res.getValue(Bytes.toBytes("info"), Bytes.toBytes("name"));
        byte[] agebyte = res.getValue(Bytes.toBytes("info"), Bytes.toBytes("age"));
        byte[] zipCodebyte = res.getValue(Bytes.toBytes("addr"), Bytes.toBytes("zipCode"));
        String name = Bytes.toString(namebyte);
        int age = Bytes.toInt(agebyte);
        String zipcode = Bytes.toString(zipCodebyte);
        System.out.println(name+":"+age+":"+zipcode);
    }
    //7. 關閉table
    table.close();
  • 前綴查詢

    Scan scan = new Scan();
    Filter filter = new RowFilter(CompareFilter.CompareOp.EQUAL,new RegexStringComparator("a-"));
    scan.setFilter(filter);
    
    ResultScanner results = table.getScanner(scan);
    
    for (Result result : results) {
        byte[] nameByte = result.getValue(Bytes.toBytes("cf1"),Bytes.toBytes("name"));
        byte[] ageByte = result.getValue(Bytes.toBytes("cf1"),Bytes.toBytes("age"));
        System.out.println(Bytes.toString(nameByte) + "\t" + Bytes.toString(ageByte));
    }
    table.close();
  • 多版本查詢

    Get get = new Get(Bytes.toBytes("1001"));
    //可以指定查詢某一個列
    get.addColumn(Bytes.toBytes("cf1"),Bytes.toBytes("name"));
    get.setMaxVersions(5);
    Result result = table.get(get);
    
    Cell[] cells = result.rawCells();
    for (Cell cell : cells) {
        System.out.println(Bytes.toString(CellUtil.cloneValue(cell)));
    }

HBase架構原理

讀寫數據操作原理

讀數據

在這裏插入圖片描述

寫數據

HBase底層原理

HBase架構體系

架構相關概念

HRegionServer
HRegionServer(和DataNode同一節點)
1. 存儲表數據部分
2. put delete get scan等針對數據的操作
3. 定時向Master報告自身節點的狀態
4. 管理表的數據的Table的數據
HMaster
HMaster
1. Region Server狀態的管理
2. 表的管理:create drop alter
3. 實現HRegionServer的數據負載均衡,平衡HRegion的分佈
Zookeeper
Zookeeper
1. 解決HMaster的單點故障問題
2. 存放HMaster管理的HRegionServer的狀態信息,並通知HMaster
3. 存放HMaster管理的表的元數據信息
   表名、列名、key區間等。
HRegion
HRegion
   表的橫向切片的物理表現,大表的子表,有(startkey endkey),多行數據。
   爲了減小單表操作的大小,提高讀寫效率。
Store
Store
1. 表的縱向切分的物理表現,按照列族作爲切分。
2. 按照列族查詢,僅需要檢索一定範圍內的數據,減少全表掃描。

HBase底層原理

Region Split 分區

  • 分區原因

    提高Region的負載和讀寫效率。

  • 說明

    Region一拆爲二,並分佈在不同的RegionServer上。

  • 默認分區機制

    Region中數據超過128M、512M、1152M… *Region數量2hbase.hregion.memstore.flush.size … 10G、10G

    查看參數

    hbase.hregion.memstore.flush.size=128M
    hbase.hregion.max.filesize=10G
  • 問題

    默認分區容易導致數據傾斜,硬件資源無法利用。(數據熱點問題,大量的客戶端訪問,落在部分節點上,導致忙的忙死,閒的閒死。)

Region預分區

  • 爲什麼

    • 增加讀寫效率。(多個region分佈在不同的RegionServer中,可以提高併發效率)
    • 儘量保證每個Region中的數據量相當,防止數據傾斜。(合理利用計算資源)
  • 分區的效果

    每個Region維護一對StartKey和EndKey,限定維護輸入rowkey範圍。

    添加數據時,將rowkey放入匹配的region中。

  • 創建表時分區,手動指定

    命令:

    create "namespace:表","列族",SPLITS=>["100000","200000","300000","400000"]

    效果:(http://ip:16030)訪問RegionServers

在這裏插入圖片描述

  • java代碼分區

MemStore Flush刷寫

  • 說明

    簡言:持久化,保護數據不丟失。

    將RegionServer中內存中的數據Memstore,寫入到硬盤中。


  • 在這裏插入圖片描述

  • 時機

    1. 當 region server 中 memstore 的總大小達到java_heapsize的閾值,默認值 0.4

    對應參數:hbase.regionserver.global.memstore.size

    1. 到達自動刷寫的時間,默認 1 小時

    對應參數:hbase.regionserver.optionalcacheflushinterval

    1. 單個Region中的數據文件大小超過128M。

    對應參數:hbase.hregion.memstore.flush.size

  • 手動flush

    命令:flush "namespace:表名"

  • 文件位置:

    hdfs:ip:50070/hbase/data/baizhins/user2/faf64f7f6cfa6282c2a92864faa3909d

Store File Compaction 合併

  • 目的

    storefile小文件過多,查詢時,需要遍歷所有文件,效率低。

    storefile中遍佈過期數據,佔用空間,且查詢效率低。

  • 說明

    簡言:爲提高檢索效率,合併store。

  • 在這裏插入圖片描述

  • 分類和時機

    • minor compact(局部合併)
    特點:少量相鄰(加速合併,並有序)文件的合併

    時機:發生頻率較高,不影響性能。

    手動命令:compact "namespace:表名"

    • major compact(全局合併)
    特點:
    1. 全局的所有store file文件的合併。
    2. 去除刪除被覆蓋的文件。
    3. 特別消耗RegionServer的性能資源。(重點)

    時機:每7天執行一次:參數:hbase.hregion.majorcompaction

    一般手動觸發。手動觸發命令:major_compact "namespace:表名"

rowkey設計

# rowkey對hbase有什麼影響
1. 影響region數據分佈,負載均衡,不好rowkey設計,會導致數據傾斜,導致數據熱點。
   希望:一段時間內,新增數據(訪問請求),儘可能均勻分佈到不同的HRegion。
2. 唯一標記1條數據
   希望:rowkey唯一性。
3. 爲查詢業務服務。
   希望:rowkey設計必須滿足查詢業務需求

爲什麼HBase數據讀取速度快BlockCache

# 1 Memstore
  Region內存中
  特點:
  	(內存)
  	(數據最新的)
  	(有序)
# 2 BlockCache(LRU)
   HBase緩存中。
   緩存策略:LRU(數據淘汰機制),最近最少使用原則,保留最近最新使用多的數據。
# 3:磁盤storeFile(每個小file中rowkey是有序的) LSM
	磁盤的檢索速度慢是因爲尋道。
    磁盤合併大storeFile(減少file數量,可以提高磁盤檢索效率)
  1. storefile文件數量少,減少遍歷。
  2. 文件內以及文件在磁盤中,rowkey有序,代碼檢索,磁盤尋道大大節省時間。

HBase架構完整版

注意

  1. 編輯regionservers,使用vi編輯
  2. 安裝hbase之前,同步系統時間

在這裏插入圖片描述

集羣規劃
192.168.199.11: HMaster
192.168.199.12: HRegionServer
192.168.199.13: HRegionServer
# 0 確保HDFS HA已經搭建完畢
[root@hadoop11 ~]# jps
1259 JournalNode
1965 NameNode
1758 DFSZKFailoverController
2110 Jps
1215 QuorumPeerMain
# 1. 安裝HBase
1. 解壓HBase
	[root@hadoop11 modules]# tar zxvf hbase-1.2.4-bin.tar.gz -C /opt/installs/
2. 配置環境變量
	#JAVA
    export JAVA_HOME=/opt/installs/jdk1.8
    export PATH=$PATH:$JAVA_HOME/bin
    # HADOOP
    export HADOOP_HOME=/opt/installs/hadoop2.9.2/
    export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
    # zookeeper
    export PATH=$PATH:/opt/installs/zookeeper3.4.14/bin/
    # HBase
    export HBASE_HOME=/opt/installs/hbase-1.2.4
    export PATH=$PATH:$HBASE_HOME/bin
3. 加載profile配置
	source /etc/profile
# 2. 初始化HBase 配置文件
# 1 -------------------hbase-env.sh--------------------

# 配置Java_home
export JAVA_HOME=/opt/installs/jdk1.8

# 註釋掉如下2行。
# export HBASE_MASTER_OPTS="$HBASE_MASTER_OPTS -XX:PermSize=128m -XX:MaxPermSize=128m -XX:ReservedCodeCacheSize=256m"
# export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -XX:PermSize=128m -XX:MaxPermSize=128m -XX:ReservedCodeCacheSize=256m"

# 禁用內置zookeeper
export HBASE_MANAGES_ZK=false
# 2. -------------------hbase-site.xml-------------------------
<configuration>
    <!-- hbase的入口,ns HaHadoop的虛擬命名空間 -->
    <property>
        <name>hbase.rootdir</name>
        <value>hdfs://ns/hbase</value>
    </property>
    <!-- 使用分佈式模式 -->
    <property>
        <name>hbase.cluster.distributed</name>
        <value>true</value>
    </property>
    <!-- zookeeper集羣地址,端口默認2181不需要指定 -->
    <property>
        <name>hbase.zookeeper.quorum</name>
        <value>hadoop10,hadoop11,hadoop12</value>
    </property>

    <!--配置hdfs的hflush:否則該版本啓動會報錯-->
    <property>
        <name>hbase.unsafe.stream.capability.enforce</name>
        <value>false</value>
    </property>
</configuration>
# 3. -------------------regionservers--------------------
hadoop12
hadoop13
#** 4. 將hadoop的配置文件拷貝到hbase的conf目錄中。(core-site.xml  hdfs-site.xml)
[root@hadoop11 installs]# ln -s /opt/installs/hadoop2.9.2/etc/hadoop/core-site.xml /opt/installs/hbase-1.2.4/conf/core-site.xml
[root@hadoop11 installs]# ln -s /opt/installs/hadoop2.9.2/etc/hadoop/hdfs-site.xml /opt/installs/hbase-1.2.4/conf/hdfs-site.xml
# 3. 遠程拷貝
1. 拷貝profile文件
[root@hadoop11 installs]# scp /etc/profile root@hadoop12:/etc/
[root@hadoop11 installs]# scp /etc/profile root@hadoop13:/etc/
2. 拷貝hbase安裝軟件和配置文件
[root@hadoop11 installs]# scp -r hbase1.2.4/ root@hadoop12:/opt/installs/
[root@hadoop11 installs]# scp -r hbase1.2.4/ root@hadoop13:/opt/installs/
3. 重新加載profile
[root@hadoop11 ~]# source /etc/profile
[root@hadoop12 ~]# source /etc/profile
[root@hadoop13 ~]# source /etc/profile
# 3. 啓動HBase
1. 啓動hbase
	start-hbase.sh
2. 關閉hbase
	stop-hbase.sh

false


~~~shell
# 3. -------------------regionservers--------------------
hadoop12
hadoop13
#** 4. 將hadoop的配置文件拷貝到hbase的conf目錄中。(core-site.xml  hdfs-site.xml)
[root@hadoop11 installs]# ln -s /opt/installs/hadoop2.9.2/etc/hadoop/core-site.xml /opt/installs/hbase-1.2.4/conf/core-site.xml
[root@hadoop11 installs]# ln -s /opt/installs/hadoop2.9.2/etc/hadoop/hdfs-site.xml /opt/installs/hbase-1.2.4/conf/hdfs-site.xml
# 3. 遠程拷貝
1. 拷貝profile文件
[root@hadoop11 installs]# scp /etc/profile root@hadoop12:/etc/
[root@hadoop11 installs]# scp /etc/profile root@hadoop13:/etc/
2. 拷貝hbase安裝軟件和配置文件
[root@hadoop11 installs]# scp -r hbase1.2.4/ root@hadoop12:/opt/installs/
[root@hadoop11 installs]# scp -r hbase1.2.4/ root@hadoop13:/opt/installs/
3. 重新加載profile
[root@hadoop11 ~]# source /etc/profile
[root@hadoop12 ~]# source /etc/profile
[root@hadoop13 ~]# source /etc/profile
# 3. 啓動HBase
1. 啓動hbase
	start-hbase.sh
2. 關閉hbase
	stop-hbase.sh

HBASE默認端口_hbase端口-CSDN博客

對於管控比較嚴格的場景,僅能開通特定端口。
查詢工具,只要開通zookeeper、Hbase Master和Hbase RegionServer即可。

節點 端口號 協議 使用 說明
zookeeper 2181   zkCli.sh -server zookeeper1:2181 客戶端接入
2888,3888   N/A 集羣內部通訊
HDFS Namenode 9000 HDFS hdfs dfs -ls hdfs://namenode1:9000/ 客戶端接入
50070 HTTP http://namenode1:50070/ 集羣監控
HDFS SecondaryNamenode 50090 HTTP http://namenode1:50090/ secondary監控
HDFS Datanode 50010   N/A 客戶端接入/其他節點接入
50020   N/A  
50075 HTTP http://datanode1:50075/ 節點監控
HBase Master 16000   hbase-client-1.x.x.jar RegionServer接入
16010 HTTP http://namenode1:16010/ 集羣監控
HBase RegionServer 16020   N/A 客戶端接入
16030 HTTP http://datanode1:16030/ 節點監控

Java客戶端連接Hbase_java連接hbase-CSDN博客

使用

	下面介紹了Java客戶端連接Hbase的使用,1.2.0版本和2.3.4版本親測下面使用的API都是一致的。(也猜測1.x版本
和2.x版本的應該基本一致)。Java連接Hbase也很簡單,Maven中導入對應的 `hbase-client` 依賴即可。

1.pom配置

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.apache.hbase/hbase-client -->
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-client</artifactId>
            <version>1.2.0</version>
        </dependency>
    </dependencies>
    
    <repositories>
        <repository>
            <id>cloudera</id>
            <url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
        </repository>
        <repository>
            <id>apache release</id>
            <url>https://repository.apache.org/content/repositories/releases/</url>
        </repository>
    </repositories>

語法

0)初始化

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellScanner;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
    public static void main(String[] args) {
        Configuration config = null;
        Connection conn = null;
        Table table = null;
        // 創建配置
        config = HBaseConfiguration.create();
        config.set("hbase.zookeeper.quorum", "192.168.100.98");
        config.set("hbase.zookeeper.property.clientPort", "2181");

        try {
            // 創建連接
            conn = ConnectionFactory.createConnection(config);
            // 獲取表
            table = conn.getTable(TableName.valueOf("FEI:WEN"));

            // 查詢指定表的全部數據
//            queryAllTableData(table);

            // 查詢指定rowkey的數據
            queryRowKey(table);

			// 略。。。

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (conn != null) {
                    conn.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                if (table != null) {
                    table.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
         * 輸出
         * @param result
         * @throws IOException
         */
    private static void output(Result result) throws IOException {
        CellScanner cellScanner = result.cellScanner();
        while (cellScanner.advance()) {
            Cell cell = cellScanner.current();
            byte[] rowArray = cell.getRowArray();  //本kv所屬的行鍵的字節數組
            byte[] familyArray = cell.getFamilyArray();  //列族名的字節數組
            byte[] qualifierArray = cell.getQualifierArray();  //列名的字節數據
            byte[] valueArray = cell.getValueArray(); // value的字節數組

            System.out.printf("|%10s|%10s|%10s|%10s|\n",
                              new String(rowArray, cell.getRowOffset(), cell.getRowLength()),
                              new String(familyArray, cell.getFamilyOffset(), cell.getFamilyLength()),
                              new String(qualifierArray, cell.getQualifierOffset(), cell.getQualifierLength()),
                              new String(valueArray, cell.getValueOffset(), cell.getValueLength()));
        }
    }

1)創建命名空間

/**
 * 創建命名空間
 * @param conn
 * @throws IOException
 */
private static void createNamespace(Connection conn) throws IOException {
    Admin admin = conn.getAdmin();

    NamespaceDescriptor.Builder builder = NamespaceDescriptor.create("FEI");
    NamespaceDescriptor build = builder.build();

    admin.createNamespace(build);

    admin.close();
}

2)查看命名空間

查看指定命名空間
/**
 * 查看指定命名空間
 * @param conn
 */
private static void queryOneNamespace(Connection conn) throws IOException {
    Admin admin = conn.getAdmin();

    NamespaceDescriptor test = admin.getNamespaceDescriptor("FEI");
    System.out.println(test);

    Map<String, String> configuration = test.getConfiguration();
    System.out.println(configuration);

    String name = test.getName();
    System.out.println(name);

    admin.close();
}

輸出:

{NAME => 'FEI'}
{}
FEI
查看全部命名空間
/**
 * 查看全部命名空間
 * @param conn
 */
private static void queryAllNamespace(Connection conn) throws IOException {
    Admin admin = conn.getAdmin();

    NamespaceDescriptor[] namespaceDescriptors = admin.listNamespaceDescriptors();

    for (NamespaceDescriptor namespaceDescriptor : namespaceDescriptors) {
        System.out.println(namespaceDescriptor);
    }
    admin.close();
}

輸出:

{NAME => 'FEI'}
{NAME => 'SYSTEM'}
{NAME => 'TEST'}
{NAME => 'default'}
{NAME => 'hbase'}

3)查看指定命名空間下表

/**
 * 查看指定命名空間下的表
 * @param conn
 */
private static void queryTableByNamespace(Connection conn) throws IOException {
    Admin admin = conn.getAdmin();

    HTableDescriptor[] feis = admin.listTableDescriptorsByNamespace("FEI");

    for (HTableDescriptor fei : feis) {
        System.out.println(fei.getNameAsString());
    }

    admin.close();
}

輸出:

FEI:EMP
FEI:IMAGES
FEI:STUDENTS
FEI:TWO
FEI:WEN

4)查看所有表

/**
 * 查看所有表
 * @param conn
 */
private static void queryAllTable(Connection conn) throws IOException {
    Admin admin = conn.getAdmin();

    TableName[] tableNames = admin.listTableNames();

    for (TableName tableName : tableNames) {
        System.out.println(tableName);
    }

    admin.close();
}

輸出:

FEI:EMP
FEI:IMAGES
FEI:STUDENTS
FEI:TWO
FEI:WEN
SYSTEM:CATALOG
SYSTEM:FUNCTION
SYSTEM:LOG
SYSTEM:MUTEX
SYSTEM:SEQUENCE
SYSTEM:STATS
US_POPULATION
user

5)查看指定表

/**
 * 查看指定表元數據
 * @param conn
 */
private static void queryOneTableMetadata(Connection conn) throws IOException {
    Admin admin = conn.getAdmin();

    HTableDescriptor fei_wen = admin.getTableDescriptor(TableName.valueOf("FEI:WEN"));

    System.out.println(fei_wen);

    String name = fei_wen.getNameAsString();
    System.out.println("\n命名空間+表名: " + name);

    HColumnDescriptor[] columnFamilies = fei_wen.getColumnFamilies();
    for (HColumnDescriptor columnFamily : columnFamilies) {
        System.out.println("\n列族: " + columnFamily);
    }

    Map<String, String> configuration = fei_wen.getConfiguration();
    System.out.println("\n表配置: " + configuration);

    TableName tableName = fei_wen.getTableName();
    System.out.println("\n命名空間+表名: " + tableName.getNameAsString());
    System.out.println("\n命名空間: " + tableName.getNamespaceAsString());
    System.out.println("\n表名: " + tableName.getQualifierAsString());

    admin.close();
}

輸出:

'FEI:WEN', {NAME => 'co', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}

命名空間+表名: FEI:WEN

列族: {NAME => 'co', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}

表配置: {}

命名空間+表名: FEI:WEN

命名空間: FEI

表名: WEN

6)創建表

/**
 * 創建表
 *
 * 可以用多個HColumnDescriptor來定義多個列族,然後通過hTableDescriptor.addFamily添加,但是目前只建議一個表創建一個列族,
 * 防止對性能有影響
 * @param conn
 */
private static void createTable(Connection conn) {
    Admin admin = null;
    try {
        // 獲取表管理器對象
        admin = conn.getAdmin();

        // 創建一個表描述對象
        HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf("FEI:CLASS"));
        // 創建一個列族描述對象
        HColumnDescriptor base_info = new HColumnDescriptor("base_info");
        // 通過列族描述定義對象,可以設置列族的很多重要屬性信息
        base_info.setMaxVersions(3); // 設置該列族中存儲數據的最大版本數,默認是1

        
        hTableDescriptor.addFamily(base_info);

        admin.createTable(hTableDescriptor);

    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        try {
            if (admin != null) {
                admin.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

7)修改表

新增列族
    public static void updateTable(Connection conn) {
        Admin admin = null;

        try {
            admin = conn.getAdmin();

            HTableDescriptor fei_class = admin.getTableDescriptor(TableName.valueOf("FEI:CLASS"));

            // 增加列族
            HColumnDescriptor newFamily = new HColumnDescriptor("test_info".getBytes());
            newFamily.setBloomFilterType(BloomType.ROWCOL); // 設置布隆過濾器的類型

            fei_class.addFamily(newFamily);

            admin.modifyTable(TableName.valueOf("FEI:CLASS"),fei_class);
            
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (admin != null) {
                    admin.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
刪除列族
    public static void updateTable(Connection conn) {
        Admin admin = null;

        try {
            admin = conn.getAdmin();

            HTableDescriptor fei_class = admin.getTableDescriptor(TableName.valueOf("FEI:CLASS"));

            // 刪除列族
            fei_class.removeFamily("test_info".getBytes());

            admin.modifyTable(TableName.valueOf("FEI:CLASS"),fei_class);

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (admin != null) {
                    admin.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

8)刪除表

/**
 * 刪除表
 *
 * 想刪除表,必須先關閉表
 * @param conn
 */
public static void deleteTable(Connection conn) {
    Admin admin = null;

    try {
        admin = conn.getAdmin();
		// 關閉表
        admin.disableTable(TableName.valueOf("FEI:CLASS"));
        // 刪除表
        admin.deleteTable(TableName.valueOf("FEI:CLASS"));

    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        try {
            if (admin != null) {
                admin.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

9)查詢表全部數據

    /**
     * 查詢指定表的全部數據
     */
    private static void queryAllTableData(Table table) {

        try {
            ResultScanner scanner = table.getScanner(new Scan());

            System.out.printf("|%10s|%10s|%10s|%10s|\n", "row key", "family", "qualifier", "value");
            for (Result result : scanner) {
                output(result);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

輸出:

|   row key|    family| qualifier|     value|
|         1|        co|       age|        28|
|         1|        co|        id|         1|
|         1|        co|      name|      jack|
|         2|        co|       age|        33|
|         2|        co|        id|         2|
|         2|        co|      name|      roes|

9)查詢指定rowkey的數據

/**
 * 查詢指定rowkey的數據
 */
public static void queryRowKey(Table table) {
    try {
        // get對象指定行鍵
        Get get = new Get("1".getBytes(StandardCharsets.UTF_8));

        Result result = table.get(get);

        System.out.printf("|%10s|%10s|%10s|%10s|\n", "row key", "family", "qualifier", "value");

        output(result);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

輸出:

|   row key|    family| qualifier|     value|
|         1|        co|       age|        28|
|         1|        co|        id|         1|
|         1|        co|      name|      jack|

10)根據rowkey查詢指定列

    /**
     * 根據rowkey查詢指定列
     */
    public static void queryValueByRowKey(Table table) {
        try {
            // get對象指定行鍵
            Get get = new Get("1".getBytes(StandardCharsets.UTF_8));

            Result result = table.get(get);

            byte[] value = result.getValue("co".getBytes(), "name".getBytes());

            System.out.println(new String(value));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

輸出:

jack

11)插入數據

插入單條數據
/**
 * 插入單條數據
 * @param table
 */
private static void insertOneData(Table table) {

    Put put = new Put("3".getBytes());

    put.addColumn("co".getBytes(), "class".getBytes(), "一班".getBytes());

    try {
        table.put(put);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
批量插入數據
/**
 * 批量插入數據
 * @param table
 */
private static void insertBatchData(Table table) {

    List<Put> puts = new ArrayList<>();

    for (int i = 0; i < 10; i++) {
        Put put = new Put((i+"").getBytes());
        put.addColumn("co".getBytes(), "id".getBytes(), ((i + 3) + "").getBytes());
        put.addColumn("co".getBytes(), "name".getBytes(), ("張"+ i).getBytes());
        put.addColumn("co".getBytes(), "age".getBytes(), (i + "").getBytes());

        puts.add(put);
    }

    try {
        table.put(puts);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

12)修改數據

通過Put覆蓋,格式和插入一樣

/**
 * 修改數據
 * @param table
 */
private static void updateData(Table table) throws IOException {
    Put put1 = new Put("9".getBytes());
    put1.addColumn("co".getBytes(), "name".getBytes(), "劉胡蘭".getBytes());
    Put put2 = new Put("8".getBytes());
    put2.addColumn("co".getBytes(), "name".getBytes(), "王偉".getBytes());
    Put put3 = new Put("7".getBytes());
    put3.addColumn("co".getBytes(), "name".getBytes(), "金素榮".getBytes());
    Put put4 = new Put("6".getBytes());
    put4.addColumn("co".getBytes(), "name".getBytes(), "小日本".getBytes());

    List<Put> puts = new ArrayList<>();

    puts.add(put1);
    puts.add(put2);
    puts.add(put3);
    puts.add(put4);

    table.put(puts);
}

13)刪除數據

/**
 * 刪除數據
 * @param table
 */
private static void deleteData(Table table) throws IOException {
    Delete d1 = new Delete("1".getBytes());
    Delete d2 = new Delete("2".getBytes());
    Delete d3 = new Delete("3".getBytes());
    Delete d4 = new Delete("4".getBytes());

    List<Delete> deletes = new ArrayList<>();

    deletes.add(d1);
    deletes.add(d2);
    deletes.add(d3);
    deletes.add(d4);

    table.delete(deletes);
}

14)圖片轉爲Base64,存入Hbase

/**
 * 圖片轉爲Base64,存入Hbase
 */
private static void imageToBase64(Table table) throws IOException {

    String imageFile = "C:\\Users\\fei\\Desktop\\superset處理500頁面.png";

    InputStream in = null;

    byte[] data = null;

    String encode = null; // 返回Base64編碼過的字節數組字符串

    BASE64Encoder encoder = new BASE64Encoder();
    try {
        in = new FileInputStream(imageFile);
        data = new byte[in.available()];
        in.read(data);

        encode = encoder.encode(data);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (in != null) {
                in.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 將字符串存入Hbase
    if (encode != null) {
        Put put = new Put("1".getBytes());

        put.addColumn("image".getBytes(), "test".getBytes(), encode.getBytes());
        table.put(put);
    }
}

15)從Hbase獲取base64,轉換爲圖表

/**
 * 從Hbase獲取base64,轉換爲圖表
 */
private static void base64ToImage(Table table) throws IOException {

    // 從Hbase獲取base64
    Get get = new Get("1".getBytes(StandardCharsets.UTF_8));

    Result result = table.get(get);

    byte[] value = result.getValue("image".getBytes(), "test".getBytes());

    // 將字節數組字符串轉換爲圖片

    String encode = new String(value);

    OutputStream out = null;

    String outFile = "D:\\test.png";

    BASE64Decoder decoder = new BASE64Decoder();

    try {
        out = new FileOutputStream(outFile);

        byte[] b = decoder.decodeBuffer(encode);

        for (int i = 0; i < b.length; i++) {
            if (b[i] < 0) {
                b[i] += 256;
            }
        }
        out.write(b);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (out != null) {
                out.flush();
                out.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章