1. 程式人生 > >HBase 基本入門篇

HBase 基本入門篇

目錄

  • 一、簡介
    • 有什麼特性
    • 與RDBMS的區別
  • 二、資料模型
  • 三、安裝HBase
  • 四、基本使用
    • 表操作
  • 五、FAQ
  • 參考文件

無論是 NoSQL,還是大資料領域,HBase 都是非常"炙熱"的一門資料庫。
本文將對 HBase 做一些基礎性的介紹,旨在入門。

一、簡介

HBase 是一個開源的、面向列的非關係型分散式資料庫,目前是Hadoop體系中非常關鍵的一部分。

在最初,HBase是基於谷歌的 BigTable 原型實現的,許多技術來自於Fay Chang在2006年所撰寫的Google論文"BigTable"。與 BigTable基於Google檔案系統(File System)一樣,HBase則是基於HDFS(Hadoop的分散式檔案系統)之上而開發的。

HBase 採用 Java 語言實現,在其內部實現了BigTable論文提到的一些壓縮演算法、記憶體操作和布隆過濾器等,這些能力使得HBase 在海量資料儲存、高效能讀寫場景中得到了大量應用,如 Facebook 在 2010年11 月開始便一直選用 HBase來作為訊息平臺的儲存層技術。

HBase 以 Apache License Version 2.0開源,這是一種對商業應用友好的協議,同時該專案當前也是Apache軟體基金會的頂級專案之一。

有什麼特性

  • 基於列式儲存模型,對於資料實現了高度壓縮,節省儲存成本
  • 採用 LSM 機制而不是B(+)樹,這使得HBase非常適合海量資料實時寫入的場景
  • 高可靠,一個數據會包含多個副本(預設是3副本),這得益於HDFS的複製能力,由RegionServer提供自動故障轉移的功能
  • 高擴充套件,支援分片擴充套件能力(基於Region),可實現自動、資料均衡
  • 強一致性讀寫,資料的讀寫都針對主Region上進行,屬於CP型的系統
  • 易操作,HBase提供了Java API、RestAPI/Thrift API等介面
  • 查詢優化,採用Block Cache 和 布隆過濾器來支援海量資料的快速查詢

與RDBMS的區別

對於傳統 RDBMS 來說,支援 ACID 事務是資料庫的基本能力,而 HBase 則使用行級鎖來保證寫操作的原子性,但是不支援多行寫操作的事務性,這主要是從靈活性和擴充套件性上做出的權衡。

ACID 要素包含 原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)以及永續性(Durability)

總體來說, HBase 與傳統關係資料庫的區別,如下表所示:

特性 HBase RDBMS
硬體架構 類似於 Hadoop 的分散式叢集,硬體成本低廉 傳統的多核系統,硬體成本昂貴
容錯性 由軟體架構實現,由於由多個節點組成,所以不擔心一點或幾點宕機 一般需要額外硬體裝置實現 HA 機制
資料庫大小 PB GB、TB
資料排布方式 稀疏的、分佈的多維的 Map 以行和列組織
資料型別 Bytes 豐富的資料型別
事物支援 ACID 只支援單個 Row 級別 全面的 ACID 支援,對 Row 和表
查詢語言 只支援 Java API (除非與其他框架一起使用,如 Phoenix、Hive) SQL
索引 只支援 Row-key,除非與其他技術一起應用,如 Phoenix、Hive 支援
吞吐量 百萬查詢/每秒 數千查詢/每秒

二、資料模型

下面,我們以關係型資料庫的一個數據表來演示 HBase 的不同之處。 先來看下面這張表:

ID 裝置名 狀態 時間戳
1 空調 開啟 20190712 10:05:01
2 電視機 關閉 20190712 10:05:08

這裡記錄的是一些家庭裝置上報的狀態資料(DeviceState),其中包括裝置名、狀態、時間戳這些欄位。

在 HBase 中,資料是按照列族(Column Family,簡稱CF)來儲存的,也就是說對於不同的列會被分開儲存到不同的檔案。
那麼對於上面的狀態資料表來說,在HBase中會被儲存為兩份:

列族1. 裝置名

Row-Key CF:Column-Key Timestamp Cell Value
1 DeviceState:裝置名 20190712 10:05:01 空調
2 DeviceState:裝置名 20190712 10:05:08 電視機

列族2. 狀態

Row-Key CF:Column-Key Timestamp Cell Value
1 DeviceState:狀態 20190712 10:05:01 開啟
2 DeviceState:狀態 20190712 10:05:08 關閉

這裡Row-key是唯一定位資料行的ID欄位,而Row-key 加上 CF、Column-Key,再加上一個時間戳才可以定位到一個單元格資料。
其中時間戳用來表示資料行的版本, 在HBase中預設會有 3 個時間戳的版本資料,這意味著對同一條資料(同一個Rowkey關聯的資料)進行寫入時,最多可以儲存3個版本。

在查詢某一行的資料時,HBase需要同時從兩個列族(檔案)中進行查詢,最終將結果合併後返回給客戶端。 由此可見如果列族太多,則會影響讀取的效能,在設計時就需要做一些權衡。

由此可見,HBase的使用方式與關係型資料庫是大不相同的,在使用 HBase 時需要拋棄許多關係型資料庫的思維及做法,比如強型別、二級索引、表連線、觸發器等等。

然而 HBase 的靈活性及高度可伸縮性卻是傳統 RDBMS 無法比擬的。

三、安裝HBase

單機環境安裝

  1. 準備JDK環境

確保環境上JDK已經裝好,可執行java -version確認:

host:/home/hbase # java -version
openjdk version "1.8.0_201"
OpenJDK Runtime Environment (build 1.8.0_201-Huawei_JDK_V100R001C00SPC060B003-b10)
OpenJDK 64-Bit Server VM (build 25.201-b10, mixed mode)
  1. 下載軟體

官網的下載地址頁面:
http://archive.apache.org/dist/hbase/

選擇合適的版本,比如1.4.10。 下載後解壓:

wget http://archive.apache.org/dist/hbase/2.1.5/hbase-2.1.5-bin.tar.gz
tar -xzvf hbase-2.1.5-bin.tar.gz
mkdir -p /opt/local
mv hbase-2.1.5 /opt/local/hbase

配置HBase執行命令路徑:

export HBASE_HOME=/opt/local/hbase
export PATH=$PATH:$HBASE_HOME/bin
  1. 配置軟體

vim conf/hbase-env.sh

#JDK安裝目錄
export JAVA_HOME=/usr/local/jre1.8.0_201
#配置hbase自己管理zookeeper
export HBASE_MANAGES_ZK=true

vim conf/hbase-site.xml

<configuration>

  <!-- zookeeper埠  -->
  <property>
      <name>hbase.zookeeper.property.clientPort</name>
      <value>2182</value>                                                                                                                                           
  </property>

  <!--  HBase 資料儲存目錄 -->
  <property>
    <name>hbase.rootdir</name>
    <value>file:///opt/local/hbase/data</value>
  </property>

  <!-- 用於指定 ZooKeeper 資料儲存目錄 -->
  <property>
    <name>hbase.zookeeper.property.dataDir</name>
    <value>/opt/local/hbase/data/zookeeper</value>
  </property>

  <!-- 用於指定臨時資料儲存目錄 -->
  <property>
    <name>hbase.tmp.dir</name>
    <value>/opt/local/hbase/temp/hbase-${user.name}</value>
  </property>
</configuration>

其中 hbase.rootdir 和 hbase.zookeeper.property.dataDir 都用來指定資料存放的目錄,預設情況下hbase會使用/tmp目錄,這顯然是不合適的。
配置了這兩個路徑之後,hbase會自動建立相應的目錄。

關於更多的引數設定可參考這裡

  1. 啟動軟體
start-hbase.sh

此時檢視 logs/hbase-root-master-host-xxx.log,如下:

2019-07-11 07:37:23,654 INFO  [localhost:33539.activeMasterManager] hbase.MetaMigrationConvertingToPB: hbase:meta doesn't have any entries to update.
2019-07-11 07:37:23,654 INFO  [localhost:33539.activeMasterManager] hbase.MetaMigrationConvertingToPB: META already up-to date with PB serialization
2019-07-11 07:37:23,664 INFO  [localhost:33539.activeMasterManager] master.AssignmentManager: Clean cluster startup. Assigning user regions
2019-07-11 07:37:23,665 INFO  [localhost:33539.activeMasterManager] master.AssignmentManager: Joined the cluster in 11ms, failover=false
2019-07-11 07:37:23,672 INFO  [localhost:33539.activeMasterManager] master.TableNamespaceManager: Namespace table not found. Creating...

檢查程序情況,發現程序已經啟動

ps -ef |grep hadoop
root     11049 11032  2 07:37 pts/1    00:00:20 /usr/local/jre1.8.0_201/bin/java -Dproc_master -XX:OnOutOfMemoryError=kill -9 %p -XX:+UseConcMarkSweepGC -XX:PermSize=128m -XX:MaxPermSize=128m -XX:ReservedCodeCacheSize=256m -Dhbase.log.dir=/opt/local/hbase/logs -Dhbase.log.file=hbase-root-master-host-192-168-138-148.log -Dhbase.home.dir=/opt/local/hbase -Dhbase.id.str=root -Dhbase.root.logger=INFO,RFA -Dhbase.security.logger=INFO,RFAS org.apache.hadoop.hbase.master.HMaster start
root     18907 30747  0 07:50 pts/1    00:00:00 grep --color=auto hadoop

通過JPS(JDK自帶的檢查工具) 可以看到當前啟動的Java程序:

# jps
5701 Jps
4826 HMaster
1311 jar

檢視 data目錄,發現生成了對應的檔案:

host:/opt/local/hbase/data # ls -lh .
total 36K
drwx------. 4 root root 4.0K Jul 11 08:08 data
drwx------. 4 root root 4.0K Jul 11 08:08 hbase
-rw-r--r--. 1 root root   42 Jul 11 08:08 hbase.id
-rw-r--r--. 1 root root    7 Jul 11 08:08 hbase.version
drwx------. 2 root root 4.0K Jul 11 08:08 MasterProcWALs
drwx------. 2 root root 4.0K Jul 11 08:08 oldWALs
drwx------. 3 root root 4.0K Jul 11 08:08 .tmp
drwx------. 3 root root 4.0K Jul 11 08:08 WALs
drwx------. 3 root root 4.0K Jul 11 08:08 zookeeper

關於執行模式
HBase啟動時預設會使用單機模式,此時 Zookeeper和 HMaster/RegionServer 會執行在同一個JVM中。
以standalone模式啟動的HBase會包含一個HMaster、RegionServer、Zookeeper例項,此時 HBase 會直接使用本地檔案系統而不是HDFS。

通過將 conf/hbase-site.xml中的 hbase.cluster.distributed 配置為true,就是叢集模式了。
在這個模式下,你可以使用分散式環境進行部署,或者是"偽分散式"的多程序環境。

<configuration>
  <property>
    <name>hbase.cluster.distributed</name>
    <value>true</value>
  </property>
</configuration>

需要注意的是,如果以standalone啟動的話,HMaster、RegionServer埠都是隨機的,無法通過配置檔案指定。

四、基本使用

開啟HBase Shell

hbase shell

執行status命令

Version 2.1.5, r76ab087819fe82ccf6f531096e18ad1bed079651, Wed Jun  5 16:48:11 PDT 2019

hbase(main):001:0> status
1 active master, 0 backup masters, 1 servers, 0 dead, 2.0000 average load

這表示有一個Master在執行,一個RegionServer,每個RegionServer包含2個Region。

表操作

  • 建立DeviceState表
hbase(main):002:0> create "DeviceState", "name:c1", "state:c2"

=> Hbase::Table - DeviceState

此時,已經建立了一個DeviceState表,包含name(裝置名稱)、state(狀態)兩個列。

查看錶資訊:

hbase(main):003:0> list
TABLE
DeviceState
1 row(s) in 0.0090 seconds

=> ["DeviceState"]

hbase(main):003:0> describe "DeviceState"
Table DeviceState is ENABLED
DeviceState
COLUMN FAMILIES DESCRIPTION
{NAME => 'name', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSIO
N => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
{NAME => 'state', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSI
ON => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
2 row(s) in 0.0870 seconds
  • 寫入資料

通過下面的命令,向DeviceState寫入兩條記錄,由於有兩個列族,因此需要寫入四個單元格資料:

put "DeviceState", "row1", "name", "空調"
put "DeviceState", "row1", "state", "開啟"
put "DeviceState", "row2", "name", "電視機"
put "DeviceState", "row2", "state", "關閉"
  • 查詢資料

查詢某行、某列

hbase(main):012:0> get "DeviceState","row1"
COLUMN                                      CELL
 name:                                      timestamp=1562834473008, value=\xE7\x94\xB5\xE8\xA7\x86\xE6\x9C\xBA
 state:                                     timestamp=1562834474630, value=\xE5\x85\xB3\xE9\x97\xAD
1 row(s) in 0.0230 seconds

hbase(main):013:0> get "DeviceState","row1", "name"
COLUMN                                      CELL
 name:                                      timestamp=1562834473008, value=\xE7\x94\xB5\xE8\xA7\x86\xE6\x9C\xBA
1 row(s) in 0.0200 seconds

掃描表

hbase(main):026:0> scan "DeviceState"
ROW                                         COLUMN+CELL
 row1                                       column=name:, timestamp=1562834999374, value=\xE7\xA9\xBA\xE8\xB0\x83
 row1                                       column=state:, timestamp=1562834999421, value=\xE6\x89\x93\xE5\xBC\x80
 row2                                       column=name:, timestamp=1562834999452, value=\xE7\x94\xB5\xE8\xA7\x86\xE6\x9C\xBA
 row2                                       column=state:, timestamp=1562835001064, value=\xE5\x85\xB3\xE9\x97\xAD
2 row(s) in 0.0250 seconds

查詢數量

hbase(main):014:0> count "DeviceState"
2 row(s) in 0.0370 seconds

=> 1
  • 清除資料

刪除某列、某行

delete "DeviceState", "row1", "name"
0 row(s) in 0.0080 seconds

hbase(main):003:0> deleteall "DeviceState", "row2"
0 row(s) in 0.1290 seconds

清空整個表資料

hbase(main):021:0> truncate "DeviceState"
Truncating 'DeviceState' table (it may take a while):
 - Disabling table...
 - Truncating table...
0 row(s) in 3.5060 seconds

刪除表(需要先disable)

hbase(main):006:0> disable "DeviceState"
0 row(s) in 2.2690 seconds

hbase(main):007:0> drop "DeviceState"
0 row(s) in 1.2880 seconds

五、FAQ

  • 啟動時提示 ZK 埠監聽失敗:
    Could not start ZK at requested port of 2181. ZK was started at port: 2182. Aborting as clients (e.g. shell) will not be able to find this ZK quorum

原因
HBase需要啟動Zookeeper,而本地的2181埠已經被啟用(可能有其他Zookeeper例項)

解決辦法
conf/hbase-site.xml中修改hbase.zookeeper.property.clientPort的值,將其修改為2182,:

<configuration>
  <property>
      <name>hbase.zookeeper.property.clientPort</name>
      <value>2182</value>                                                                                                                                           
  </property>
</configuration>
  • 啟動HBase Shell時提示java.lang.UnsatisfiedLinkError

原因
在執行hbase shell期間,JRuby會在“java.io.tmpdir”路徑下建立一個臨時檔案,該路徑的預設值為“/tmp”。如果為“/tmp”目錄設定NOEXEC許可權,然後hbase shell會啟動失敗並丟擲“java.lang.UnsatisfiedLinkError”錯誤。

解決辦法

  1. 取消/tmp的noexec許可權(不推薦)
  2. 設定java.io.tmpdir變數,指向可用的路徑,編輯conf/hbase-env.sh檔案:
export HBASE_TMP_DIR=/opt/local/hbase/temp
export HBASE_OPTS="-XX:+UseConcMarkSweepGC -Djava.io.tmpdir=$HBASE_TMP_DIR"

參考文件

HBase 官方權威指南
https://hbase.apache.org/book.html#quickstart

HBase 單機模式搭建
https://my.oschina.net/jackieyeah/blog/712019

HBase 深入淺出
較詳細介紹了HBase的由來以及特性,文中提供了HBase叢集、儲存機制的一些簡介,非常適合入門閱讀
https://www.ibm.com/developerworks/cn/analytics/library/ba-cn-bigdata-hbase/index.