分佈式數據庫 HBase(全)

分佈式數據庫 HBase思維導圖下載

在這裏插入圖片描述

一、概述

1. 從BigTable說起

  1. BigTable是一個分佈式存儲系統
  2. 總的來說,BigTable 具備以下特性:支持大規模海量數據、分佈式併發數據處理效率極高、易於擴展且支持動態伸縮、適用於廉價設備、適合於讀操作不適合寫操作。

2. HBase簡介

  1. HBase是一個高可靠、高性能、面向列、可伸縮的分佈式數據庫,是谷歌BigTable的
    開源實現,主要用來存儲非結構化和半結構化的鬆散數據。
    在這裏插入圖片描述

3. HBase與傳統關係數據庫的對比分析

  1. 數據類型:關係數據庫採用關係模型,具有豐富的數據類型和存儲方式,HBase則採用了更加簡單的數據模型,它把數據存儲爲未經解釋的字符串;
  2. 數據操作:關係數據庫中包含了豐富的操作,其中會涉及複雜的多表連接。HBase操作則不存在複雜的表與表之間的關係,只有簡單的插入、查詢、刪除、清空等,因爲HBase在設計上就避免了複雜的表和表之間的關係;
  3. 存儲模式:關係數據庫是基於行模式存儲的。HBase是基於列存儲的,每個列族都由幾個文件保存,不同列族的文件是分離的;
  4. 數據索引:關係數據庫通常可以針對不同列構建複雜的多個索引,以提高數據訪問性能。HBase只有一個索引——行鍵,通過巧妙的設計,HBase中的所有訪問方法,或者通過行鍵訪問,或者通過行鍵掃描,從而使得整個系統不會慢下來;
  5. 數據維護:在關係數據庫中,更新操作會用最新的當前值去替換記錄中原來的舊值,舊值被覆蓋後就不會存在。而在HBase中執行更新操作時,並不會刪除數據舊的版本,而是生成一個新的版本,舊有的版本仍然保留;
  6. 可伸縮性:關係數據庫很難實現橫向擴展,縱向擴展的空間也比較有限。相反,HBase和BigTable這些分佈式數據庫就是爲了實現靈活的水平擴展而開發的,能夠輕易地通過在集羣中增加或者減少硬件數量來實現性能的伸縮

二、HBase訪問接口

在這裏插入圖片描述


三、HBase數據模型

HBase是一個稀疏、多維度、排序的映射表,這張表的索引是行鍵、列族、列限定符和時間戳
面向列的存儲

1. 數據模型相關概念

  1. 表:HBase採用表來組織數據,表由行和列組成,列劃分爲若干個列族;
  2. 行:每個HBase表都由若干行組成,每個行由行鍵(row key)來標識;
  3. 列族:一個HBase表被分組成許多“列族”(Column Family)的集合,它是基本的訪問控制單元,創建表的時候創建;
  4. 列限定符:列族裏的數據通過列限定符(或列)來定位;
  5. 單元格:在HBase表中,通過行、列族和列限定符確定一個“單元格”(cell);
  6. 時間戳:每個單元格都保存着同一份數據的多個版本,這些版本採用時間戳進行索引;

2. 數據座標

HBase中需要根據行鍵、列族、列限定符和時間戳來確定一個單元格,因此,可以視爲一個“四維座標”,即[行鍵, 列族, 列限定符, 時間戳]

3. 概念視圖與物理視圖

在這裏插入圖片描述
在這裏插入圖片描述


四、HBase的實現原理

1. Hbase 的功能組件

主要的功能組件:

  1. 庫函數:鏈接到每個客戶端;
  2. 一個Master主服務器:主服務器Master負責管理和維護HBase表的分區信息,維護Region服務器列表,分配Region,負載均衡;
  3. 許多個Region服務器:Region服務器負責存儲和維護分配給自己的Region,處理來自客戶端的讀寫請求;

客戶端並不是直接從Master主服務器上讀取數據,而是在獲得Region的存儲位置信息後,直接從Region服務器上讀取數據。
客戶端並不依賴Master,而是通過Zookeeper來獲得Region位置信息,大多數客戶端甚至從來不和Master通信,這種設計方式使得Master負載很小。

2. 表和Region

  1. 開始只有一個Region,後來不斷分裂;
  2. 一個HBase表被劃分成多個Region;
  3. 每個Region服務器存儲10-1000個Region;
  4. 同一個Region不會被分拆到多個Region服務器;

3. Region的定位

在這裏插入圖片描述
在這裏插入圖片描述

  1. 元數據表,又名.META.表,存儲了Region和Region服務器的映射關係;
  2. 當HBase表很大時, .META.表也會被分裂成多個Region;
  3. 根數據表,又名-ROOT-表,記錄所有元數據的具體位置;
  4. -ROOT-表只有唯一一個Region,名字是在程序中被寫死的;
  5. Zookeeper文件記錄了-ROOT-表的位置;
  6. 爲了加快訪問速度,.META.表的全部Region都會被保存在內存中,緩存失效時重新“三級尋址”;
  7. 尋址過程客戶端只需要詢問Zookeeper服務器,不需要連接Master服務器。

五、HBase運行機制

1. HBase系統架構

在這裏插入圖片描述

客戶端:

客戶端包含訪問HBase的接口,同時在緩存中維護着已經訪問過的Region位置信息,用來加快後續數據訪問過程。

Zookeeper服務器:

  1. Zookeeper可以幫助選舉出一個Master作爲集羣的總管,並保證在任何時刻總有唯一一個Master在運行,這就避了Master的“單點失效”問題
  2. Zookeeper是一個很好的集羣管理工具,被大量用於分佈式計算,
    、提供配置維護、域名服務、分佈式同步、組服務等

Master:

主服務器Master主要負責表和Region的管理工作:

  1. 管理用戶對錶的增加、刪除、修改、查詢等操作;
  2. 實現不同Region服務器之間的負載均衡;
  3. 在Region分裂或合併後,負責重新調整Region的分佈;
  4. 對發生故障失效的Region服務器上的Region進行遷移。

Region服務器:

Region服務器是HBase中最核心的模塊,負責維護分配給自己的Region,並響應用戶的讀寫請求。

2. Region服務器工作原理

用戶讀寫數據過程:

  1. 用戶寫入數據時,被分配到相應Region服務器去執行;
  2. 用戶數據首先被寫入到MemStore和Hlog中;
  3. 只有當操作寫入Hlog之後,commit()調用纔會將其返回給客戶端;
  4. 當用戶讀取數據時,Region服務器會首先訪問MemStore緩存,如果找不到,再去磁盤上面的StoreFile中尋找;

緩存的刷新:

  1. 系統會週期性地把MemStore緩存裏的內容刷寫到磁盤的StoreFile文件中,清空緩存,並在Hlog裏面寫入一個標記;
  2. 每次刷寫都生成一個新的StoreFile文件,因此,每個Store包含多個StoreFile文件;
  3. 每個Region服務器都有一個自己的HLog 文件,每次啓動都檢查該文件,確認最近一次執行緩存刷新操作之後是否發生新的寫入操作;如果發現更新,則先寫入MemStore,再刷寫到StoreFile,最後刪除舊的Hlog文件,開始爲用戶提供服務;

StoreFile 的合併:

  1. 每次刷寫都生成一個新的StoreFile,數量太多,影響查找速度;
  2. 調用Store.compact()把多個合併成一個;
  3. 合併操作比較耗費資源,只有數量達到一個閾值才啓動合併。

3. Store工作原理

•Store是Region服務器的核心
•多個StoreFile合併成一個
•單個StoreFile過大時,又觸發分裂操作,1個父Region被分裂成兩個子Region

  1. 分佈式環境必須要考慮系統出錯。HBase採用HLog保證系統恢復
  2. 用戶更新數據必須首先寫入日誌後,才能寫入MemStore緩存,並且,直到MemStore緩存內容對應的日誌已經寫入磁盤,該緩存內容才能被刷寫到磁盤;

4. HLog工作原理

  1. Zookeeper會實時監測每個Region服務器的狀態,當某個Region服務器發生故障時,Zookeeper會通知Master
  2. Master首先會處理該故障Region服務器上面遺留的HLog文件,這個遺留的HLog文件中包含了來自多個Region對象的日誌記錄;
  3. 系統會根據每條日誌記錄所屬的Region對象對HLog數據進行拆分,分別放到相應Region對象的目錄下,然後,再將失效的Region重新分配到可用的Region服務器中,並把與該Region對象相關的HLog日誌記錄也發送給相應的Region服務器;
  4. Region服務器領取到分配給自己的Region對象以及與之相關的HLog日誌記錄以後,會重新做一遍日誌記錄中的各種操作,把日誌記錄中的數據寫入到MemStore緩存中,然後,刷新到磁盤的StoreFile文件中,完成數據恢復;
  5. 共用日誌優點:提高對錶的寫操作性能;缺點:恢復時需要分拆日誌。

六、HBase應用方案

1. HBase實際應用中的性能優化方法

  1. 行鍵(Row Key):行鍵是按照 字典序存儲,因此,設計行鍵時,要充分利用這個排序特點,將經常一起讀取的數據存儲到一塊,將最近可能會被訪問的數據放在一塊;
  2. InMemory:創建表的時候,可以通過HColumnDescriptor.setInMemory(true)將表放到Region服務器的緩存中,保證在讀取的時候被cache命中;
  3. Max Version:創建表的時候,可以通過HColumnDescriptor.setMaxVersions(int maxVersions)設置表中數據的最大版本,如果只需要保存最新版本的數據,那麼可以設置setMaxVersions(1)。
  4. Time To Live:創建表的時候,可以通過HColumnDescriptor.setTimeToLive(int timeToLive)設置表中數據的存儲生命期,過期數據將自動被刪除,例如如果只需要存儲最近兩天的數據,那麼可以設置setTimeToLive(2 * 24 * 60 * 60)。

2. HBase性能監視

Master-status(自帶)、Ganglia、OpenTSDB、Ambari。

3. 在HBase之上構建SQL引擎

好處:

  1. 易使用
  2. 減少編碼
    方案:
    1.Hive整合HBase
    2.Phoenix

4. 構建HBase二級索引

三種訪問行的方式:

  1. 通過單個行健訪問
  2. 通過一個行健的區間來訪問
  3. 全表掃描

使用其他產品問HBase行鍵提供索引功能:
Hindex二級索引、HBase+Redis、HBase+solr


HBase編程實踐:

七、HBase 的安裝和基礎編程

7.1 安裝 HBase

​ 本節介紹HBase的安裝方法,包括下載安裝文件、配置環境變量、添加用戶權限等。

7.1.1 下載安裝文件

HBase是Hadoop生態系統中的一個組件,但是,Hadoop安裝以後,本身並不包含HBase,因此,需要單獨安裝HBase。假設已經下載了HBase安裝文件hbase-1.1.5-bin.tar.gz,被放到了Linux系統的“/home/hadoop/下載/”目錄下。

$ cd  ~/下載     # 進入下載目錄
$ wget  http://10.132.239.12:8000/file/hbase-1.1.5-bin.tar.gz     # 下載HBase軟件

下載完安裝文件以後,需要對文件進行解壓。按照Linux系統使用的默認規範,用戶安裝的軟件一般都是存放在“/usr/local/”目錄下。請使用hadoop用戶登錄Linux系統,打開一個終端,執行如下命令:

$ sudo tar -zxf ~/下載/hbase-1.1.5-bin.tar.gz -C /usr/local

​ 將解壓的文件名hbase-1.1.5改爲hbase,以方便使用,命令如下:

$ sudo mv /usr/local/hbase-1.1.5 /usr/local/hbase

7.1.2 配置環境變量

​ 將HBase安裝目錄下的bin目錄(即/usr/local/hbase/bin)添加到系統的PATH環境變量中,這樣,每次啓動HBase時就不需要到“/usr/local/hbase”目錄下執行啓動命令,方便HBase的使用。請使用vim編輯器打開“~/.bashrc”文件,命令如下:

$ vim ~/.bashrc

​ 打開.bashrc文件以後,可以看到,已經存在如下所示的PATH環境變量的配置信息,因爲,之前在安裝配置Hadoop時,我們已經爲Hadoop添加了PATH環境變量的配置信息:

export PATH=$PATH:/usr/local/hadoop/sbin:/usr/local/hadoop/bin

這裏,需要把HBase的bin目錄“/usr/local/hbase/bin”追加到PATH中。當要在PATH中繼續加入新的路徑時,只要用英文冒號“:”隔開,把新的路徑加到後面即可,追加後的結果如下:

export PATH=$PATH:/usr/local/hadoop/sbin:/usr/local/hadoop/bin:/usr/local/hbase/bin

​ 添加後,執行如下命令使設置生效:

$ source ~/.bashrc

7.1.3 添加用戶權限

​ 需要爲當前登錄Linux系統的hadoop用戶添加訪問HBase目錄的權限,將HBase安裝目錄下的所有文件的所有者改爲hadoop,命令如下:

$ cd  /usr/local
$ sudo  chown  -R  hadoop  ./hbase

7.1.4 查看HBase版本信息

​ 可以通過如下命令查看HBase版本信息,以確認HBase已經安裝成功:

$ /usr/local/hbase/bin/hbase version

7.2 HBase的配置

​ HBase有三種運行模式,即單機模式、僞分佈式模式和分佈式模式:

單機模式:採用本地文件系統存儲數據;
僞分佈式模式:採用僞分佈式模式的HDFS存儲數據;
分佈式模式:採用分佈式模式的HDFS存儲數據。
本教程僅介紹單機模式和僞分佈式模式。

在進行HBase配置之前,需要確認已經安裝了三個組件:JDK、Hadoop、SSH。HBase單機模式不需要安裝Hadoop,僞分佈式模式和分佈式模式需要安裝Hadoop。

7.2.1 單機模式配置

配置hbase-env.sh文件

使用vim編輯器打開“/usr/local/hbase/conf/hbase-env.sh”,命令如下:

$ vim /usr/local/hbase/conf/hbase-env.sh

​ 打開hbase-env.sh文件以後,需要在hbase-env.sh文件中配置JAVA環境變量,此前在安裝Hadoop的環節,已經配置了JAVA環境變量,比如,“JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64”,這裏可以直接複製該配置信息到hbase-env.sh文件中。此外,還需要添加Zookeeper配置信息,配置HBASE_MANAGES_ZK爲true,表示由HBase自己管理Zookeeper,不需要單獨的Zookeeper,由於hbase-env.sh文件中本來就存在這些變量的配置,因此,只需要刪除前面的註釋“#”符號並修改配置內容即可,修改後的hbase-env.sh文件應該包含如下兩行信息:

export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export HBASE_MANAGES_ZK=true

​ 修改完成以後,保存hbase-env.sh文件並退出vim編輯器。

配置hbase-site.xml文件

使用vim編輯器打開並編輯“/usr/local/hbase/conf/hbase-site.xml”文件,命令如下:

$ vim /usr/local/hbase/conf/hbase-site.xml

​ 在hbase-site.xml文件中,需要設置屬性hbase.rootdir,用於指定HBase數據的存儲位置,如果沒有設置,則hbase.rootdir默認爲/tmp/hbase-${user.name},這意味着每次重啓系統都會丟失數據。這裏把hbase.rootdir設置爲HBase安裝目錄下的hbase-tmp文件夾,即“/usr/local/hbase/hbase-tmp”,修改後的hbase-site.xml文件中的配置信息如下:

<configuration>
       <property>
               <name>hbase.rootdir</name>
               <value>file:///usr/local/hbase/hbase-tmp</value>
       </property>
</configuration>

​ 保存hbase-site.xml文件,並退出vim編輯器。

啓動運行HBase
現在就可以測試運行HBase,命令如下:

$ cd /usr/local/hbase
$ bin/start-hbase.sh  #啓動HBase
$ bin/hbase shell  #進入HBase shell命令行模式

​ 進入HBase Shell命令行模式以後,用戶可以通過輸入Shell命令操作HBase數據庫。

​ 最後,可以使用如下命令停止HBase運行:

$ bin/stop-hbase.sh

7.2.2 僞分佈式配置

配置hbase-env.sh文件

使用vim編輯器打開“/usr/local/hbase/conf/hbase-env.sh”,命令如下:

$ vim /usr/local/hbase/conf/hbase-env.sh

​ 打開hbase-env.sh文件以後,需要在hbase-env.sh文件中配置JAVA_HOME、HBASE_CLASSPATH和HBASE_MANAGES_ZK。其中,HBASE_CLASSPATH設置爲本機Hadoop安裝目錄下的conf目錄(即/usr/local/hadoop/conf)。JAVA_HOME和HBASE_MANAGES_ZK的配置方法和上面單機模式的配置方法相同。修改後的hbase-env.sh文件應該包含如下三行信息:

export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export HBASE_CLASSPATH=/usr/local/hadoop/conf 
export HBASE_MANAGES_ZK=true

​ 修改完成以後,保存hbase-env.sh文件並退出vim編輯器。

配置hbase-site.xml文件

使用vim編輯器打開並編輯“/usr/local/hbase/conf/hbase-site.xml”文件,命令如下:

$ vim /usr/local/hbase/conf/hbase-site.xml

​ 在hbase-site.xml文件中,需要設置屬性hbase.rootdir,用於指定HBase數據的存儲位置。在HBase僞分佈式模式中,是使用僞分佈式模式的HDFS存儲數據,因此,需要把hbase.rootdir設置爲HBase在HDFS上的存儲路徑,根據Hadoop僞分佈式模式的配置可以知道,HDFS的訪問路徑爲“hdfs://localhost:9000/”,因爲,這裏設置hbase.rootdir爲“hdfs://localhost:9000/hbase”。此外,由於採用了僞分佈式模式,因此,還需要將屬性hbase.cluter.distributed設置爲true。修改後的hbase-site.xml文件中的配置信息如下:

<configuration>
       <property>
               <name>hbase.rootdir</name>
               <value>hdfs://localhost:9000/hbase</value>
       </property>
       <property>
               <name>hbase.cluster.distributed</name>
               <value>true</value>
       </property>
</configuration>

​ 保存hbase-site.xml文件,並退出vim編輯器。

啓動運行HBase

首先登陸SSH,由於之前在“Hadoop的安裝和使用”中已經設置了無密碼登錄,因此這裏不需要密碼。然後,切換至“/usr/local/hadoop”,啓動Hadoop,讓HDFS進入運行狀態,從而可以爲HBase存儲數據,具體命令如下:

$ ssh localhost
$ cd /usr/local/hadoop
$ ./sbin/start-dfs.sh

​ 輸入命令jps,如果能夠看到NameNode、DataNode和SecondaryNameNode這三個進程,則表示已經成功啓動Hadoop。

​ 然後,啓動HBase,命令如下:

$ cd /usr/local/hbase
$ bin/start-hbase.sh

​ 輸入命令jps,如果出現以下進程,則說明HBase啓動成功:

Jps
HMaster
HQuorumPeer
NameNode
HRegionServer
SecondaryNameNode
DataNode

​ 現在就可以進入HBase Shell模式,命令如下:

$ bin/hbase shell  #進入HBase shell命令行模式

​ 進入HBase shell命令行模式以後,用戶可以通過輸入shell命令操作HBase數據庫。

停止 運行HBase
最後,可以使用如下命令停止HBase運行:

$ bin/stop-hbase.sh

​ 如果在操作HBase的過程中發生錯誤,可以查看{HBASE_HOME}目錄(即/usr/local/hbase)下的logs子目錄中的日誌文件,來尋找可能的錯誤原因。

​ 關閉HBase以後,如果不再使用Hadoop,就可以運行如下命令關閉Hadoop:

$ cd /usr/local/hadoop
$ ./sbin/stop-dfs.sh

最後需要注意的是,啓動關閉Hadoop和HBase的順序一定是:啓動Hadoop—>啓動HBase—>關閉HBase—>關閉Hadoop。

7.3 HBase常用Shell命令

​ 在使用具體的Shell命令操作HBase數據之前,需要首先啓動Hadoop,然後再啓動HBase,並且啓動HBase Shell,進入Shell命令提示符狀態,具體命令如下:

$ cd /usr/local/hadoop
$ ./sbin/start-dfs.sh
$ cd /usr/local/hbase
$ ./bin/start-hbase.sh
$ ./bin/hbase shell

7.3.1 在HBase中創建表

​ 假設這裏要創建一個表student,該表包含Sname、Ssex、Sage、Sdept、course等字段。需要注意的是,在關係型數據庫(比如MySQL)中,需要首先創建數據庫,然後再創建表,但是,在HBase數據庫中,不需要創建數據庫,只要直接創建表就可以。在HBase中創建student表的Shell命令如下:

hbase> create 'student','Sname','Ssex','Sage','Sdept','course'

對於HBase而言,在創建HBasae表時,不需要自行創建行健,系統會默認一個屬性作爲行鍵,通常是把put命令操作中跟在表名後的第一個數據作爲行健。

​ 創建完“student”表後,可通過describe命令查看“student”表的基本信息,命令如下:

hbase>describe ‘student’

​ 可以使用list命令查看當前HBase數據庫中已經創建了哪些表,命令如下:

hbase> list

7.3.2 添加數據

​ HBase使用put命令添加數據,一次只能爲一個表的一行數據的一個列(也就是一個單元格,單元格是HBase中的概念)添加一個數據,所以,直接用Shell命令插入數據效率很低,在實際應用中,一般都是利用編程操作數據。因爲這裏只要插入1條學生記錄,所以,我們可以用Shell命令手工插入數據,命令如下:

hbase> put 'student','95001','Sname','LiYing'

​ 上面的put命令會爲student表添加學號爲’95001’、名字爲’LiYing’的一個單元格數據,其行鍵爲95001,也就是說,系統默認把跟在表名student後面的第一個數據作爲行健。

​ 下面繼續添加4個單元格的數據,用來記錄LiYing同學的相關信息,命令如下:

hbase> put 'student','95001','Ssex','male'
hbase> put 'student','95001','Sage','22'
hbase> put 'student','95001','Sdept','CS'
hbase> put 'student','95001','course:math','80'

7.3.3 查看數據

​ HBase中有兩個用於查看數據的命令:

get命令:用於查看錶的某一個單元格數據;
scan命令:用於查看某個表的全部數據。
比如,可以使用如下命令返回student表中95001行的數據:

hbase> get 'student','95001'

​ 下面使用scan命令查詢student表的全部數據:

hbase> scan 'student'

7.3.4 刪除數據

​ 在HBase中用delete以及deleteall命令進行刪除數據操作,二者的區別是:delete命令用於刪除一個單元格數據,是put的反向操作,而 deleteall命令用於刪除一行數據。

首先,使用delete命令刪除student表中95001這行中的Ssex列的所有數據,命令如下:

hbase > delete 'student','95001','Ssex'

​ 然後,使用deleteall命令刪除student表中的95001行的全部數據,命令如下:

hbase> deleteall 'student','95001'

7.3.5 刪除表

​ 刪除表需要分兩步操作,第一步先讓該表不可用,第二步刪除表。比如,要刪除student表,可以使用如下命令:

hbase> disable 'student'  
hbase> drop 'student'

7.3.6 查詢歷史數據

​ 在添加數據時,HBase會自動爲添加的數據添加一個時間戳。在修改數據時,HBase會爲修改後的數據生成一個新的版本(時間戳),從而完成“改”操作,舊的版本依舊保留,系統會定時回收垃圾數據,只留下最新的幾個版本,保存的版本數可以在創建表的時候指定。

​ 爲了查詢歷史數據,這裏創建一個teacher表,首先,在創建表的時候,需要指定保存的版本數(假設指定爲5),命令如下:

hbase> create 'teacher',{NAME=>'username',VERSIONS=>5}

​ 然後,插入數據,並更新數據,使其產生歷史版本數據,需要注意的是,這裏插入數據和更新數據都是使用put命令,具體如下:

hbase> put 'teacher','91001','username','Mary'
hbase> put 'teacher','91001','username','Mary1'
hbase> put 'teacher','91001','username','Mary2'
hbase> put 'teacher','91001','username','Mary3'
hbase> put 'teacher','91001','username','Mary4'  
hbase> put 'teacher','91001','username','Mary5'

​ 查詢時,默認情況下回顯示當前最新版本的數據,如果要查詢歷史數據,需要指定查詢的歷史版本數,由於上面設置了保存版本數爲5,所以,在查詢時制定的歷史版本數的有效取值爲1到5,具體命令如下:

hbase> get ‘teacher’,‘91001’,{COLUMN=>‘username’,VERSIONS=>5}
hbase> get ‘teacher’,‘91001’,{COLUMN=>‘username’,VERSIONS=>3}

7.3.7 退出HBase數據庫

​ 最後退出數據庫操作,輸入exit命令即可退出,命令如下:

hbase> exit

注意,這裏退出HBase數據庫是退出HBase Shell,而不是停止HBase數據庫後臺運行,執行exit後,HBase仍然在後臺運行,如果要停止HBase運行,需要使用如下命令:

$ bin/stop-hbase.sh

7.4 HBase編程實踐

​ HBase提供了Java API對HBase數據庫進行操作。這裏採用Eclipse進行程序開發。在進行HBase編程之前,如果還沒有啓動Hadoop和HBase,需要首先啓動Hadoop和HBase,但是,不需要啓動HBase Shell,具體命令如下:

$ cd /usr/local/hadoop
$ ./sbin/start-dfs.sh
$ cd /usr/local/hbase
$ ./bin/start-hbase.sh

7.4.1 在Eclipse中創建項目

​ Eclipse啓動以後,會彈出如下圖所示界面,提示設置工作空間(workspace)。

​ 可以直接採用默認的設置“/home/hadoop/workspace”,點擊“OK”按鈕。可以看出,由於當前是採用hadoop用戶登錄了Linux系統,因此,默認的工作空間目錄位於hadoop用戶目錄“/home/hadoop”下。

​ Eclipse啓動以後,在界面中,選擇“FileàNewàJava Project”菜單,開始創建一個Java工程,彈出如下圖所示界面。

​ 在“Project name”後面輸入工程名稱“HBaseExample”,選中“Use default location”,讓這個Java工程的所有文件都保存到“/home/hadoop/workspace/HBaseExample”目錄下。在“JRE”這個選項卡中,可以選擇當前的Linux系統中已經安裝好的JDK,比如java-8-openjdk-amd64。然後,點擊界面底部的“Next>”按鈕,進入下一步的設置。

7.4.2爲項目添加需要用到的JAR包

進入下一步的設置以後,會彈出如下圖所示界面。

​ 爲了編寫一個能夠與HBase交互的Java應用程序,需要在這個界面中加載該Java工程所需要用到的JAR包,這些JAR包中包含了可以訪問HBase的Java API。這些JAR包都位於Linux系統的HBase安裝目錄的lib目錄下,也就是位於“/usr/local/hbase/lib”目錄下。點擊界面中的“Libraries”選項卡,然後,點擊界面右側的“Add External JARs…”按鈕,彈出如下圖所示界面。

​ 選中“/usr/local/hbase/lib”目錄下的所有JAR包(但是,不要選中“ruby”文件夾),然後,點擊界面右下角的“確定”按鈕。

添加完畢以後,就可以點擊界面右下角的“Finish”按鈕,完成Java工程HBaseExample的創建。

7.4.3 編寫Java應用程序

​ 下面編寫一個Java應用程序,對HBase數據庫進行操作。

​ 請在Eclipse工作界面左側的“Package Explorer”面板中(如下圖所示),找到剛纔創建好的工程名稱“HBaseExample”,然後在該工程名稱上點擊鼠標右鍵,在彈出的菜單中選擇“NewàClass”菜單。

​ 選擇“NewàClass”菜單以後會出現如下圖所示界面。

​ 在該界面中,只需要在“Name”後面輸入新建的Java類文件的名稱,這裏採用名稱“HBaseOperation”,其他都可以採用默認設置,然後,點擊界面右下角“Finish”按鈕,出現如下圖所示界面。

​ 可以看出,Eclipse自動創建了一個名爲“HBaseOperation.java”的源代碼文件,請在該文件中輸入以下代碼:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import java.io.IOException; 
public class HBaseOperation{
   public static Configuration configuration;
   public static Connection connection;
   public static Admin admin;
   public static void main(String[] args)throws IOException{
       createTable("t2",new String[]{"cf1","cf2"});
       insertRow("t2", "rw1", "cf1", "q1", "val1");
       getData("t2", "rw1", "cf1", "q1");
       //deleteTable("t2");  //如果不想執行本行代碼,可以註釋掉本行代碼
   } 
   //建立連接
   public static void init(){
       configuration  = HBaseConfiguration.create();
       configuration.set("hbase.rootdir","hdfs://localhost:9000/hbase");
       try{
           connection = ConnectionFactory.createConnection(configuration);
           admin = connection.getAdmin();
       }catch (IOException e){
           e.printStackTrace();
       }
   }
   //關閉連接
   public static void close(){
       try{
           if(admin != null){
               admin.close();
           }
           if(null != connection){
               connection.close();
           }
       }catch (IOException e){
           e.printStackTrace();
       }
   }
   //建表
   public static void createTable(String myTableName,String[] colFamily) throws IOException { 
       init();
       TableName tableName = TableName.valueOf(myTableName); 
       if(admin.tableExists(tableName)){
           System.out.println("talbe is exists!");
       }else {
           HTableDescriptor hTableDescriptor = new HTableDescriptor(tableName);
           for(String str:colFamily){
               HColumnDescriptor hColumnDescriptor = new HColumnDescriptor(str);
               hTableDescriptor.addFamily(hColumnDescriptor);
           }
           admin.createTable(hTableDescriptor);
       }
       close();
   }
   //刪表
   public static void deleteTable(String tableName) throws IOException {
       init();
       TableName tn = TableName.valueOf(tableName);
       if (admin.tableExists(tn)) {
           admin.disableTable(tn);
           admin.deleteTable(tn);
       }
       close();
   } 
   //查看已有表
   public static void listTables() throws IOException {
       init();
       HTableDescriptor hTableDescriptors[] = admin.listTables();
       for(HTableDescriptor hTableDescriptor :hTableDescriptors){
           System.out.println(hTableDescriptor.getNameAsString());
       }
       close();
   }
   public static void insertRow(String tableName,String rowKey,String colFamily,String col,String val) throws IOException {
       init();
       Table table = connection.getTable(TableName.valueOf(tableName));
       Put put = new Put(rowKey.getBytes());
       put.addColumn(colFamily.getBytes(), col.getBytes(), val.getBytes());
       table.put(put);
       table.close();
       close();
   }
   //刪除數據
   public static void deleteRow(String tableName,String rowKey,String colFamily,String col) throws IOException {
       init();
       Table table = connection.getTable(TableName.valueOf(tableName));
       Delete delete = new Delete(rowKey.getBytes());
       //刪除指定列族
       //delete.addFamily(Bytes.toBytes(colFamily));
       //刪除指定列
       //delete.addColumn(Bytes.toBytes(colFamily),Bytes.toBytes(col));
       table.delete(delete);
       table.close();
       close();
   }
   //根據rowkey查找數據
   public static void getData(String tableName,String rowKey,String colFamily,String col)throws  IOException{
       init();
       Table table = connection.getTable(TableName.valueOf(tableName));
       Get get = new Get(rowKey.getBytes());
       get.addColumn(colFamily.getBytes(),col.getBytes());
       Result result = table.get(get);
       showCell(result);
       table.close();
       close();
   }
   //格式化輸出
   public static void showCell(Result result){
       Cell[] cells = result.rawCells();
       for(Cell cell:cells){
           System.out.println("RowName:"+new String(CellUtil.cloneRow(cell))+" ");
           System.out.println("Timetamp:"+cell.getTimestamp()+" ");
           System.out.println("column Family:"+new String(CellUtil.cloneFamily(cell))+" ");
           System.out.println("row Name:"+new String(CellUtil.cloneQualifier(cell))+" ");
           System.out.println("value:"+new String(CellUtil.cloneValue(cell))+" ");
       }
   }
}

​ 上述代碼輸入到HBaseOperation.java中以後,Eclipse可能會顯示一些錯誤信息,如下圖所示。

Syntax error, ‘for each’ statements are only available if source level is 1.5 or greater
​ 之所以出現這個錯誤,是因爲HBaseOperation.java代碼中的一些語句的語法(比如for(String str:colFamily)),是在JDK1.5以上版本才支持的,JDK1.4以及之前的版本不支持這些語法。

​ 現在可以查看一下Linux系統中安裝的Eclipse的相關設置,如下圖所示,請在頂部菜單中選擇“Project”,在彈出的子菜單中選擇“Properties”。

​ 在該界面中,點擊左側欄目的“Java Compiler”,在右邊出現的信息中可以看出,“Compiler compliance level”當前默認的設置爲1.4,不支持HBaseOperation.java代碼中的一些語句的語法(比如for(String str:colFamily))。

爲了解決這個錯誤,如下圖所示,用鼠標左鍵點擊錯誤提示圖標,在彈出的對話框中,在“Change project compliance and JRE to 1.5”這行文字上雙擊鼠標左鍵,就可以讓錯誤信息消失。

7.4.4 編譯運行程序

​ 再次強調,在開始編譯運行程序之前,請一定確保Hadoop和HBase已經啓動運行。現在就可以編譯運行上面編寫的代碼。可以直接點擊Eclipse工作界面上部的運行程序的快捷按鈕,當把鼠標移動到該按鈕上時,在彈出的菜單中選擇“Run as”,繼續在彈出來的菜單中選擇“Java Application”,如下圖所示。

​ 程序運行結束後,結果如下圖所示,“Console”面板中還會顯示一些類似“log4j:WARN…”的警告信息,可以不用理會。
​ 現在可以在Linux的終端中啓動HBase Shell,來查看生成的t1表,啓動HBase Shell的命令如下:

$ cd /usr/local/hbase
$ ./bin/hbase shell

​ 進入HBase Shell以後,可以使用list命令查看HBase數據庫中是否存在名稱爲t1的表。

hbase> list

​ 然後,可以使用get命令查詢剛纔插入到t2中的一行數據:

hbase> get ‘t2’,’rw1’

​ 最後,如果要重複調試HBaseOperation.java代碼,則需要刪除HBase中已經創建的表t2,可以使用Shell命令刪除t2,命令如下:

hbase> disable ‘t2’
hbase> drop ‘t2’
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章