11.大資料學習之旅——HBase
一、HBASE概述
官方網址:http://hbase.apache.org/
HBase是一個分散式的、面向列的開源資料庫,該技術來源於Fay Chang 所撰寫的Google論文《Bigtable》一個結構
化資料的分散式儲存系統"。就像Bigtable利用了Google檔案系統(File System)所提供的分散式資料儲存一樣,HBase
在Hadoop之上提供了類似於Bigtable的能力(低延遲的資料查詢能力)。HBase是Apache的Hadoop專案的子項
目。HBase不同於一般的關係資料庫,Hbase同BigTable一樣,都是NoSQL資料庫,即非關係型資料庫,此外,
HBase和BigTable一樣,是基於列的而不是基於行的模式。
HBase特點總結
- 非關係型資料庫,可以儲存海量資料(基於Hadoop的HDFS)
- 提供了低延遲的資料查詢能力。低延遲指的是能夠在秒級甚至毫秒級給出響應。
- 面向列儲存的資料庫。(mysql,oracle都是面向行儲存的)
HDFS來源於《Google File System》
Hadoop的MapReduce《Google MapReduce》
HBase來源於Google的《Bigtable》
Zookeeper來源Google的《The Chubby lock service for loosely coupled distributed system》
非關係型資料庫和關係型資料庫
傳統關係型資料庫的缺陷
隨著網際網路Web 2.0的興起,傳統的關係資料庫在應付Web 2.0網站,特別是超大規模和高併發的SNS型別動態網
站時已經力不從心,暴露了很多難以克服的問題。
1)高併發讀寫的瓶頸
Web 2.0網站要根據使用者個性化資訊來實時生成動態頁面和提供動態資訊,所以基本上無法使用靜態化技術,因
此資料庫併發負載非常高,可能峰值會達到每秒上萬次讀寫請求。關係型資料庫應付上萬次SQL查詢還勉強頂得
住,但是應付上萬次SQL寫資料請求,硬碟I/O卻無法承受。其實對於普通的BBS網站,往往也存在相對高併發寫
請求的需求,例如,人人網的實時統計線上使用者狀態,記錄熱門帖子的點選次數,投票計數等,這是一個相當普
遍的業務需求。
2)可擴充套件性的限制
在基於Web的架構中,資料庫是最難以進行橫向擴充套件的,當應用系統的使用者量和訪問量與日俱增時,資料庫系統
卻無法像Web Server和App Server那樣簡單地通過新增更多的硬體和服務節點來擴充套件效能和負載能力。對於很多需
要提供24小時不間斷服務的網站來說,對資料庫系統進行升級和擴充套件是非常痛苦的事情,往往需要停機維護和數
據遷移,而不能通過橫向新增節點的方式實現無縫擴充套件。
3)事務一致性的負面影響
事務執行的結果必須是使資料庫從一個一致性狀態變到另一個一致性狀態。保證資料庫一致性是指當事務完成
時,必須使所有資料都具有一致的狀態。在關係型資料庫中,所有的規則必須應用到事務的修改上,以便維護所
有資料的完整性,這隨之而來的是效能的大幅度下降。很多Web系統並不需要嚴格的資料庫事務,對讀一致性的
要求很低,有些場合對寫一致性要求也不高。因此資料庫事務管理成了高負載下的一個沉重負擔。
4)複雜SQL查詢的弱化
任何大資料量的Web系統都非常忌諱幾個大表間的關聯查詢,以及複雜的資料分析型別的SQL查詢,特別是SNS類
型的網站,從需求以及產品設計角度就避免了這種情況的產生。更多的情況往往只是單表的主鍵查詢,以及單表
的簡單條件分頁查詢,SQL的功能被極大地弱化了,所以這部分功能不能得到充分發揮。
NoSQL資料庫的優勢
1)擴充套件性強
NoSQL資料庫種類繁多,但是一個共同的特點就是去掉關係型資料庫的關係特性,若資料之間是弱關係,則非常
容易擴充套件。一般來說,NoSql資料庫的資料結構都是Key-Value字典式儲存結構。例如,HBase、Cassandra等系
統的水平擴充套件效能非常優越,非常容易實現支撐資料從TB到PB級別的過渡。
2)併發效能好
NoSQL資料庫具有非常良好的讀寫效能,尤其在大資料量下,同樣表現優秀。當然這需要有優秀的資料結構和算
法做支撐。
3)資料模型靈活
NoSQL無須事先為要儲存的資料建立欄位,隨時可以儲存自定義的資料格式。而在關係型資料庫中,增刪欄位是
一件非常麻煩的事情。對於資料量非常大的表,增加欄位簡直就是一場噩夢。NoSQL允許使用者隨時隨地新增字
段,並且欄位型別可以是任意格式。
總結
HBase作為NoSQL資料庫的一種,當然也具備上面提到的種種優勢。
Hadoop最適合的應用場景是離線批量處理資料,其離線分析的效率非常高,Hadoop針對資料的吞吐量做了大量
優化,能在分鐘級別處理TB級的資料,但是Hadoop不能做到低延遲的資料訪問,所以一般的應用系統並不適合
批量模式訪問,更多的還是使用者的隨機訪問,就類似訪問關係型資料庫中的某條記錄一樣。
比如Google這個搜尋引擎,儲存了海量的網頁資料,當我們通過搜尋引擎檢索一個網頁時,之所以Google能夠
快速的響應結果,核心的技術就是利用了BigTable,可以實現低延遲的資料訪問。
HBase的列式儲存的特性支撐它實時隨機讀取、基於KEY的特殊訪問需求。當然,HBase還有不少新特性,其中不乏有趣的特性,在接下來的內容中將會詳細介紹。
BigTable介紹
BigTable是Google設計的分散式資料儲存系統,用來處理海量的資料的一種非關係型的資料庫。
BigTable是非關係的資料庫,是一個稀疏的、分散式的、持久化儲存的多維度排序Map。Bigtable的設計目的是可靠
的處理PB級別的資料,並且能夠部署到上千臺機器上。Bigtable已經實現了下面的幾個目標:適用性廣泛、可擴
展、高效能和高可用性。Bigtable已經在超過60個Google的產品和專案上得到了應用,包括 Google
Analytics、GoogleFinance、Orkut、Personalized Search、Writely和GoogleEarth。這些產品對Bigtable提出了迥異的
需求,有的需要高吞吐量的批處理,有的則需要及時響應,快速返回資料給終端使用者。它們使用的Bigtable叢集的
配置也有很大的差異,有的叢集只有幾臺伺服器,而有的則需要上千臺伺服器、儲存幾百TB的資料。
Bigtable的用三維表來儲存資料,分別是行鍵(row key)、列鍵(column key)和時間戳(timestamp),
本質上說,Bigtable是一個鍵值(key-value)對映。按作者的說法,Bigtable是一個稀疏的,分散式的,持久化
的,多維的排序對映。可以用(row:string, column:string, time:int64)→string 來表示一條鍵值對記錄。
行儲存 VS 列儲存
概述
目前大資料儲存有兩種方案可供選擇:行儲存(Row-Based)和列儲存(Column-Based)。業界對兩種儲存方案有很多爭
持,集中焦點是:誰能夠更有效地處理海量資料,且兼顧安全、可靠、完整性。從目前發展情況看,關係資料庫已經不適應這
種巨大的儲存量和計算要求,基本是淘汰出局。在已知的幾種大資料處理軟體中,Hadoop的HBase採用列儲存,MongoDB是
文件型的行儲存,Lexst是二進位制型的行儲存。
什麼是列儲存?
列式儲存(column-based)是相對於傳統關係型資料庫的行式儲存(Row-basedstorage)來說的。簡單來說兩者的區別就是如
何組織表:
Ø Row-based storage stores atable in a sequence of rows.
Ø Column-based storage storesa table in a sequence of columns.
從上圖可以很清楚地看到,行式儲存下一張表的資料都是放在一起的,但列式儲存下都被分開儲存了。所以它們就有了如下
這些優缺點對比:
在資料寫入上的對比
1)行儲存的寫入是一次完成。如果這種寫入建立在作業系統的檔案系統上,可以保證寫入過程的成功或者失敗,資料的完整
性因此可以確定。
2)列儲存由於需要把一行記錄拆分成單列儲存,寫入次數明顯比行儲存多(意味著磁頭排程次數多,而磁頭排程是需要時間
的,一般在1ms~10ms),再加上磁頭需要在碟片上移動和定位花費的時間,實際時間消耗會更大。所以,行儲存在寫入上佔
有很大的優勢。
3)還有資料修改,這實際也是一次寫入過程。不同的是,資料修改是對磁碟上的記錄做刪除標記。行儲存是在指定位置寫入一
次,列儲存是將磁碟定位到多個列上分別寫入,這個過程仍是行儲存的列數倍。所以,資料修改也是以行儲存佔優。
在資料讀取上的對比
1)資料讀取時,行儲存通常將一行資料完全讀出,如果只需要其中幾列資料的情況,就會存在冗餘列,出於縮短處理時間的
考量,消除冗餘列的過程通常是在記憶體中進行的。
2)列儲存每次讀取的資料是集合的一段或者全部,不存在冗餘性問題。
3) 兩種儲存的資料分佈。由於列儲存的每一列資料型別是同質的,不存在二義性問題。比如說某列資料型別為整型(int),那
麼它的資料集合一定是整型資料。這種情況使資料解析變得十分容易。相比之下,行儲存則要複雜得多,因為在一行記錄中
儲存了多種型別的資料,資料解析需要在多種資料型別之間頻繁轉換,這個操作很消耗CPU,增加了解析的時間。所以,列存
儲的解析過程更有利於分析大資料。
4)從資料的壓縮以及更效能的讀取來對比
優缺點
顯而易見,兩種儲存格式都有各自的優缺點:
1)行儲存的寫入是一次性完成,消耗的時間比列儲存少,並且能夠保證資料的完整性,缺點是資料讀取過程中會產生冗餘數
據,如果只有少量資料,此影響可以忽略;數量大可能會影響到資料的處理效率。
2)列儲存在寫入效率、保證資料完整性上都不如行儲存,它的優勢是在讀取過程,不會產生冗餘資料,這對資料完整性要求
不高的大資料處理領域,比如網際網路,猶為重要。
兩種儲存格式各自的特性都決定了它們的使用場景。
列儲存的適用場景
1)一般來說,一個OLAP型別的查詢可能需要訪問幾百萬甚至幾十億個數據行,且該查詢往往只關心少數幾個資料列。例
如,查詢今年銷量最高的前20個商品,這個查詢只關心三個資料列:時間(date)、商品(item)以及銷售量(sales
amount)。商品的其他資料列,例如商品URL、商品描述、商品所屬店鋪,等等,對這個查詢都是沒有意義的。
而列式資料庫只需要讀取儲存著“時間、商品、銷量”的資料列,而行式資料庫需要讀取所有的資料列。因此,列式資料庫
大大地提高了OLAP大資料量查詢的效率
OLTP OnLine Transaction Processor 線上聯機事務處理系統(比如Mysql,Oracle等產品)
OLAP OnLine Analaysier Processor 線上聯機分析處理系統(比如Hive Hbase等)
2)很多列式資料庫還支援列族(column group,Bigtable系統中稱為locality group),即將多個經常一起訪問的資料列的
各個值存放在一起。如果讀取的資料列屬於相同的列族,列式資料庫可以從相同的地方一次性讀取多個數據列的值,避免了
多個數據列的合併。列族是一種行列混合儲存模式,這種模式能夠同時滿足OLTP和OLAP的查詢需求。
3)此外,由於同一個資料列的資料重複度很高,因此,列式資料庫壓縮時有很大的優勢。
例如,Google Bigtable列式資料庫對網頁庫壓縮可以達到15倍以上的壓縮率。另外,可以針對列式儲存做專門的索引優化。
比如,性別列只有兩個值,“男”和“女”,可以對這一列建立點陣圖索引:
如下圖所示
“男”對應的點陣圖為100101,表示第1、4、6行值為“男”
“女”對應的點陣圖為011010,表示第2、3、5行值為“女”
如果需要查詢男性或者女性的個數,只需要統計相應的點陣圖中1出現的次數即可。另外,建立點陣圖索引後0和1的重複度高,可
以採用專門的編碼方式對其進行壓縮。
當然,如果每次查詢涉及的資料量較小或者大部分查詢都需要整行的資料,列式資料庫並不適用。
最後總結如下
###傳統行式資料庫的特性如下:
①資料是按行儲存的。
②沒有索引的查詢使用大量I/O。比如一般的資料庫表都會建立索引,通過索引加快查詢效率。
③建立索引和物化檢視需要花費大量的時間和資源。
④面對查詢需求,資料庫必須被大量膨脹才能滿足需求。
列式資料庫的特性如下:
①資料按列儲存,即每一列單獨存放。
②資料即索引。
③只訪問查詢涉及的列,可以大量降低系統I/O。
④每一列由一個執行緒來處理,即查詢的併發處理效能高。
⑤資料型別一致,資料特徵相似,可以高效壓縮。比如有增量壓縮、字首壓縮演算法都是基於列儲存的型別定製的,所以可以
大幅度提高壓縮比,有利於儲存和網路輸出資料頻寬的消耗。
HBASE單機安裝
單機模式安裝
特點:不依賴於Hadoop的HDFS,配置完既可使用,好處是便於測試。壞處是不具備分散式
儲存資料的能力。
安裝配置
- 安裝JDK及配置環境變數
- 上傳解壓Hbase安裝包
- 修改Hbase的配置檔案,(修改安裝目錄下的conf/hbase-site.xml)
配置示例:
<property>
<name>hbase.rootdir</name>
<value>file:///home/software/hbase/tmp</value>
</property>
這個是配置hbase儲存資料的目錄,如果不配置,預設是放在Linux的/tmp目錄下。
- 啟動hbase,進入bin目錄
執行:sh start-hbase.sh
然後可以通過jps檢視是否有HMaster程序,如果有,證明hbase啟動成功 - 在bin目錄執行:
./hbase shell
進入shell客戶端操作hbase
HBASE基本概念
HBase以表的形式儲存資料。表有行和列族組成。列族劃分為若干個列
1)R ow Key
hbase本質上也是一種Key-Value儲存系統。Key相當於RowKey,Value相當於列族資料的集
合。
與nosql資料庫們一樣,row key是用來檢索記錄的主鍵。訪問hbase table中的行,只有三種方
式:
1 通過單個row key訪問
2 通過row key的range
3 全表掃描
Row key行鍵 (Row key)可以是任意字串( (最大長度是 64KB,實際應用中長度一般為
10-100bytes),在hbase內部,row key儲存為位元組陣列。
儲存時,資料按照Row key的字典序(byte order)排序儲存。設計key時,要充分排序儲存這個
特性,將經常一起讀取的行儲存放到一起。(位置相關性)
注意:
字典序對int排序的結果是
1,10,100,11,12,13,14,15,16,17,18,19,2,20,21,…,9,91,92,93,94,95,96,97,98,99。要保
持整形的自然序,行鍵必須用0作左填充。
2)列族(列簇)
hbase表中的每個列,都歸屬與某個列族。列族是表的schema的一部分(而列不是),列族必須
在使用表之前定義。列名都以列族作為字首。例如 courses:history , courses:math 都屬於
courses 這個列族。
訪問控制、磁碟和記憶體的使用統計都是在列族層面進行的。實際應用中,列族上的控制權限能
幫助我們管理不同型別的應用:我們允許一些應用可以新增新的基本資料、一些應用可以讀取
基本資料並建立繼承的列族、一些應用則只允許瀏覽資料(甚至可能因 為隱私的原因不能瀏
覽所有資料)。
3)Cell與時間戳
由 {row key, column( = + < label> ), version} 唯一確定的單元。cell中的資料是
沒有型別的,全部是位元組碼形式存貯。
每個 cell都儲存著同一份資料的多個版本。版本通過時間戳來索引。時間戳的型別是 64位整
型。時間戳可以由hbase(在資料寫入時自動 )賦值,此時時間戳是精確到毫秒的當前系統時
間。時間戳也可以由客戶顯式賦值。如果應用程式要避免資料版本衝突,就必須自己生成具有
唯一性的時間戳。每個 cell中,不同版本的資料按照時間倒序排序,即最新的資料排在最前
面。
為了避免資料存在過多版本造成的的管理 (包括存貯和索引)負擔,hbase提供了兩種資料版本
回收方式。一是儲存資料的最後n個版本,二是儲存最近一段時間內的版本(比如最近七
天)。使用者可以針對每個列族進行設定。
HBASE基礎指令
常用命令
檔案->屬性->終端->鍵盤
->delete鍵序列[VT220Del]
->backspace鍵序列[ASCII127]
HBASE完全分散式安裝
實現步驟
- 準備三臺虛擬機器,01作為主節點,02、03作為從節點。(把每臺虛擬機器防火牆都關掉,配
置免密碼登入,配置每臺的主機名和hosts檔案。) - 01節點上安裝和配置:Hadoop+Hbase+JDK+Zookeeper
- 02、03節點上安裝和配置:Hbase+JDK+Zookeeper
- 修改conf/hbase-env.sh
配置示例:
#修改JAVA_HOME
export JAVA_HOME=xxxx
#修改Zookeeper和Hbase的協調模式,hbase預設使用自帶的zookeeper,如果需要使用外
部zookeeper,需要先關閉。
export HBASE_MANAGES_ZK=false - 修改hbase-site.xml,配置開啟完全分散式模式
配置示例:
<property>
</property>
<name>hbase.cluster.distributed</name>
<value>true</value>
<property>
</property>
#配置Zookeeper的連線地址與埠號
<name>hbase.zookeeper.quorum</name>
<value>hadoop01:2181,hadoop02:2181,hadoop03:2181</value>
<property>
</property>
- 配置region伺服器,修改conf/regionservers檔案,每個主機名獨佔一行,hbase啟動或關閉
時會按照該配置順序啟動或關閉主機中的hbase
配置示例:
hadoop01
hadoop02
hadoop03
- 將01節點配置好的hbase通過遠端複製拷貝到02,03節點上
- 啟動01,02,03的Zookeeper服務
- 啟動01節點的Hadoop
- 啟動01節點的Hbase,進入到hbase安裝目錄下的bin目錄
執行:sh start-hbase.sh - 檢視各節點的java程序是否正確
- 通過瀏覽器訪問http://xxxxx:60010來訪問web介面,通過web見面管理hbase
- 關閉Hmaster,進入到hbase安裝目錄下的bin目錄
執行:stop-hbase.sh - 關閉regionserver,進入到hbase安裝目錄下的bin目錄
執行:sh hbase-daemon.sh stop regionserver
注:HBASE配置檔案說明
hbase-env.sh配置HBase啟動時需要的相關環境變數
hbase-site.xml配置HBase基本配置資訊
HBASE啟動時預設使用hbase-default.xml中的配置,如果需要可以修改hbase-site.xml文
件,此檔案中的配置將會覆蓋hbase-default.xml中的配置
修改配置後要重啟hbase才會起作用
HBASE API
實現步驟:
1.匯入開發包將hbase安裝包中lib下包匯入java專案
建立表:
@Test
public void testCreateTable() throws Exception{
Configuration conf=HBaseConfiguration.create();
"192.168.234.11:2181,192.168.234.210:2181,192.168.234.211:2181");
conf.set("hbase.zookeeper.quorum",
HBaseAdmin admin = new HBaseAdmin(conf);
//指定表名
HTableDescriptor tab1=new HTableDescriptor(TableName.valueOf("tab1"));
//指定列族名
HColumnDescriptor colfam1=new HColumnDescriptor("colfam1".getBytes());
HColumnDescriptor colfam2=new HColumnDescriptor("colfam2".getBytes());
//指定歷史版本存留上限
colfam1.setMaxVersions(3);
tab1.addFamily(colfam1);
tab1.addFamily(colfam2);
//建立表
admin.createTable(tab1);
admin.close();
}
插入資料:
@Test
public void testInsert() throws Exception{
Configuration conf=HBaseConfiguration.create();
"192.168.234.11:2181,192.168.234.210:2181,192.168.234.211:2181");
conf.set("hbase.zookeeper.quorum",
//儘量複用Htable物件
HTable table=new HTable(conf,"tab1");
Put put=new Put("row-1".getBytes());
//列族,列,值
put.add("colfam1".getBytes(),"col1".getBytes(),"aaa".getBytes());
put.add("colfam1".getBytes(),"col2".getBytes(),"bbb".getBytes());
table.put(put);
table.close();
}
試驗: 100萬條資料的寫入
@Test
Configuration conf=HBaseConfiguration.create();
"192.168.234.11:2181,192.168.234.210:2181,192.168.234.211:2181");
conf.set("hbase.zookeeper.quorum",
HTable table=new HTable(conf,"tab1");
List<Put> puts=new ArrayList<>();
long begin=System.currentTimeMillis();
Put put=new Put(("row"+i).getBytes());
put.add("colfam1".getBytes(),"col".getBytes(),(""+i).getBytes());
puts.add(put);
//批處理,批大小為:10000
table.put(puts);
puts=new ArrayList<>();
if(i%10000==0){
}
for(int i=1;i<1000000;i++){
}
long end=System.currentTimeMillis();
System.out.println(end-begin);
}
獲取資料:
@Test
Configuration conf=HBaseConfiguration.create();
"192.168.234.11:2181,192.168.234.210:2181,192.168.234.211:2181");
conf.set("hbase.zookeeper.quorum",
HTable table=new HTable(conf,"tab1");
Get get=new Get("row1".getBytes());
Result result=table.get(get);
byte[] col1_result=result.getValue("colfam1".getBytes(),"col".getBytes());
System.out.println(new String(col1_result));
table.close();
public void testGet() throws Exception{
}
獲取資料集:
@Test
Configuration conf=HBaseConfiguration.create();
"192.168.234.11:2181,192.168.234.210:2181,192.168.234.211:2181");
conf.set("hbase.zookeeper.quorum",
public void testScan() throws Exception{
HTable table = new HTable(conf,"tab1");
//獲取row100及以後的行鍵的值
Scan scan = new Scan("row100".getBytes());
ResultScanner scanner = table.getScanner(scan);
Iterator it = scanner.iterator();
Result result = (Result) it.next();
byte [] bs = result.getValue(Bytes.toBytes("colfam1"),Bytes.toBytes("col"));
String str = Bytes.toString(bs);
System.out.println(str);
while(it.hasNext()){
Result result = (Result) it.next();
byte [] bs = result.getValue(Bytes.toBytes("colfam1"),Bytes.toBytes("col"));
String str = Bytes.toString(bs);
System.out.println(str);
}
table.close();
}
刪除資料:
@Test
Configuration conf=HBaseConfiguration.create();
"192.168.234.11:2181,192.168.234.210:2181,192.168.234.211:2181");
conf.set("hbase.zookeeper.quorum",
public void testDelete() throws Exception{
HTable table = new HTable(conf,"tab1");
Delete delete=new Delete("row1".getBytes());
table.delete(delete);
table.close();
}
刪除表
@Test
Configuration conf=HBaseConfiguration.create();
"192.168.234.11:2181,192.168.234.210:2181,192.168.234.211:2181");
conf.set("hbase.zookeeper.quorum",
HBaseAdmin admin=new HBaseAdmin(conf);
admin.disableTable("tab1".getBytes());
admin.deleteTable("tab1".getBytes());
admin.close();
public void testDeleteTable() throws Exception, IOException{
}