文章目錄
一、概述
1. 從BigTable說起
- BigTable是一個分佈式存儲系統
- 總的來說,BigTable 具備以下特性:支持大規模海量數據、分佈式併發數據處理效率極高、易於擴展且支持動態伸縮、適用於廉價設備、適合於讀操作不適合寫操作。
2. HBase簡介
- HBase是一個高可靠、高性能、面向列、可伸縮的分佈式數據庫,是谷歌BigTable的
開源實現,主要用來存儲非結構化和半結構化的鬆散數據。
3. HBase與傳統關係數據庫的對比分析
- 數據類型:關係數據庫採用關係模型,具有豐富的數據類型和存儲方式,HBase則採用了更加簡單的數據模型,它把數據存儲爲未經解釋的字符串;
- 數據操作:關係數據庫中包含了豐富的操作,其中會涉及複雜的多表連接。HBase操作則不存在複雜的表與表之間的關係,只有簡單的插入、查詢、刪除、清空等,因爲HBase在設計上就避免了複雜的表和表之間的關係;
- 存儲模式:關係數據庫是基於行模式存儲的。HBase是基於列存儲的,每個列族都由幾個文件保存,不同列族的文件是分離的;
- 數據索引:關係數據庫通常可以針對不同列構建複雜的多個索引,以提高數據訪問性能。HBase只有一個索引——行鍵,通過巧妙的設計,HBase中的所有訪問方法,或者通過行鍵訪問,或者通過行鍵掃描,從而使得整個系統不會慢下來;
- 數據維護:在關係數據庫中,更新操作會用最新的當前值去替換記錄中原來的舊值,舊值被覆蓋後就不會存在。而在HBase中執行更新操作時,並不會刪除數據舊的版本,而是生成一個新的版本,舊有的版本仍然保留;
- 可伸縮性:關係數據庫很難實現橫向擴展,縱向擴展的空間也比較有限。相反,HBase和BigTable這些分佈式數據庫就是爲了實現靈活的水平擴展而開發的,能夠輕易地通過在集羣中增加或者減少硬件數量來實現性能的伸縮
二、HBase訪問接口
三、HBase數據模型
HBase是一個稀疏、多維度、排序的映射表,這張表的索引是行鍵、列族、列限定符和時間戳
面向列的存儲
1. 數據模型相關概念
- 表:HBase採用表來組織數據,表由行和列組成,列劃分爲若干個列族;
- 行:每個HBase表都由若干行組成,每個行由行鍵(row key)來標識;
- 列族:一個HBase表被分組成許多“列族”(Column Family)的集合,它是基本的訪問控制單元,創建表的時候創建;
- 列限定符:列族裏的數據通過列限定符(或列)來定位;
- 單元格:在HBase表中,通過行、列族和列限定符確定一個“單元格”(cell);
- 時間戳:每個單元格都保存着同一份數據的多個版本,這些版本採用時間戳進行索引;
2. 數據座標
HBase中需要根據行鍵、列族、列限定符和時間戳來確定一個單元格,因此,可以視爲一個“四維座標”,即[行鍵, 列族, 列限定符, 時間戳]
3. 概念視圖與物理視圖
四、HBase的實現原理
1. Hbase 的功能組件
主要的功能組件:
- 庫函數:鏈接到每個客戶端;
- 一個Master主服務器:主服務器Master負責管理和維護HBase表的分區信息,維護Region服務器列表,分配Region,負載均衡;
- 許多個Region服務器:Region服務器負責存儲和維護分配給自己的Region,處理來自客戶端的讀寫請求;
客戶端並不是直接從Master主服務器上讀取數據,而是在獲得Region的存儲位置信息後,直接從Region服務器上讀取數據。
客戶端並不依賴Master,而是通過Zookeeper來獲得Region位置信息,大多數客戶端甚至從來不和Master通信,這種設計方式使得Master負載很小。
2. 表和Region
- 開始只有一個Region,後來不斷分裂;
- 一個HBase表被劃分成多個Region;
- 每個Region服務器存儲10-1000個Region;
- 同一個Region不會被分拆到多個Region服務器;
3. Region的定位
- 元數據表,又名.META.表,存儲了Region和Region服務器的映射關係;
- 當HBase表很大時, .META.表也會被分裂成多個Region;
- 根數據表,又名-ROOT-表,記錄所有元數據的具體位置;
- -ROOT-表只有唯一一個Region,名字是在程序中被寫死的;
- Zookeeper文件記錄了-ROOT-表的位置;
- 爲了加快訪問速度,.META.表的全部Region都會被保存在內存中,緩存失效時重新“三級尋址”;
- 尋址過程客戶端只需要詢問Zookeeper服務器,不需要連接Master服務器。
五、HBase運行機制
1. HBase系統架構
客戶端:
客戶端包含訪問HBase的接口,同時在緩存中維護着已經訪問過的Region位置信息,用來加快後續數據訪問過程。
Zookeeper服務器:
- Zookeeper可以幫助選舉出一個Master作爲集羣的總管,並保證在任何時刻總有唯一一個Master在運行,這就避了Master的“單點失效”問題
- Zookeeper是一個很好的集羣管理工具,被大量用於分佈式計算,
、提供配置維護、域名服務、分佈式同步、組服務等
Master:
主服務器Master主要負責表和Region的管理工作:
- 管理用戶對錶的增加、刪除、修改、查詢等操作;
- 實現不同Region服務器之間的負載均衡;
- 在Region分裂或合併後,負責重新調整Region的分佈;
- 對發生故障失效的Region服務器上的Region進行遷移。
Region服務器:
Region服務器是HBase中最核心的模塊,負責維護分配給自己的Region,並響應用戶的讀寫請求。
2. Region服務器工作原理
用戶讀寫數據過程:
- 用戶寫入數據時,被分配到相應Region服務器去執行;
- 用戶數據首先被寫入到MemStore和Hlog中;
- 只有當操作寫入Hlog之後,commit()調用纔會將其返回給客戶端;
- 當用戶讀取數據時,Region服務器會首先訪問MemStore緩存,如果找不到,再去磁盤上面的StoreFile中尋找;
緩存的刷新:
- 系統會週期性地把MemStore緩存裏的內容刷寫到磁盤的StoreFile文件中,清空緩存,並在Hlog裏面寫入一個標記;
- 每次刷寫都生成一個新的StoreFile文件,因此,每個Store包含多個StoreFile文件;
- 每個Region服務器都有一個自己的HLog 文件,每次啓動都檢查該文件,確認最近一次執行緩存刷新操作之後是否發生新的寫入操作;如果發現更新,則先寫入MemStore,再刷寫到StoreFile,最後刪除舊的Hlog文件,開始爲用戶提供服務;
StoreFile 的合併:
- 每次刷寫都生成一個新的StoreFile,數量太多,影響查找速度;
- 調用Store.compact()把多個合併成一個;
- 合併操作比較耗費資源,只有數量達到一個閾值才啓動合併。
3. Store工作原理
•Store是Region服務器的核心
•多個StoreFile合併成一個
•單個StoreFile過大時,又觸發分裂操作,1個父Region被分裂成兩個子Region
- 分佈式環境必須要考慮系統出錯。HBase採用HLog保證系統恢復
- 用戶更新數據必須首先寫入日誌後,才能寫入MemStore緩存,並且,直到MemStore緩存內容對應的日誌已經寫入磁盤,該緩存內容才能被刷寫到磁盤;
4. HLog工作原理
- Zookeeper會實時監測每個Region服務器的狀態,當某個Region服務器發生故障時,Zookeeper會通知Master
- Master首先會處理該故障Region服務器上面遺留的HLog文件,這個遺留的HLog文件中包含了來自多個Region對象的日誌記錄;
- 系統會根據每條日誌記錄所屬的Region對象對HLog數據進行拆分,分別放到相應Region對象的目錄下,然後,再將失效的Region重新分配到可用的Region服務器中,並把與該Region對象相關的HLog日誌記錄也發送給相應的Region服務器;
- Region服務器領取到分配給自己的Region對象以及與之相關的HLog日誌記錄以後,會重新做一遍日誌記錄中的各種操作,把日誌記錄中的數據寫入到MemStore緩存中,然後,刷新到磁盤的StoreFile文件中,完成數據恢復;
- 共用日誌優點:提高對錶的寫操作性能;缺點:恢復時需要分拆日誌。
六、HBase應用方案
1. HBase實際應用中的性能優化方法
- 行鍵(Row Key):行鍵是按照 字典序存儲,因此,設計行鍵時,要充分利用這個排序特點,將經常一起讀取的數據存儲到一塊,將最近可能會被訪問的數據放在一塊;
- InMemory:創建表的時候,可以通過HColumnDescriptor.setInMemory(true)將表放到Region服務器的緩存中,保證在讀取的時候被cache命中;
- Max Version:創建表的時候,可以通過HColumnDescriptor.setMaxVersions(int maxVersions)設置表中數據的最大版本,如果只需要保存最新版本的數據,那麼可以設置setMaxVersions(1)。
- Time To Live:創建表的時候,可以通過HColumnDescriptor.setTimeToLive(int timeToLive)設置表中數據的存儲生命期,過期數據將自動被刪除,例如如果只需要存儲最近兩天的數據,那麼可以設置setTimeToLive(2 * 24 * 60 * 60)。
2. HBase性能監視
Master-status(自帶)、Ganglia、OpenTSDB、Ambari。
3. 在HBase之上構建SQL引擎
好處:
- 易使用
- 減少編碼
方案:
1.Hive整合HBase
2.Phoenix
4. 構建HBase二級索引
三種訪問行的方式:
- 通過單個行健訪問
- 通過一個行健的區間來訪問
- 全表掃描
使用其他產品問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’