一、HBASE概述
(1)概述
基于hadoop的數據庫工具
來源于google的一片論文BigTable 后來由Apache做了開源實現 就是HBase
是一種 NoSQL 非關系型的數據庫 不符合關系型數據庫的范式
適合存儲 半結構化 非結構化 的數據
適合存儲 稀疏的數據 空的數據不占用空間
面向列(族)進行存儲
提供實時增刪改查的能力 是一種真正的數據庫
可以存儲海量數據 性能也很強大 可以實現上億條記錄的毫秒級別的查詢
但是不能提供嚴格的事務控制 只能在行級別保證事務
Hbase是一個高可靠性 高性能 面向列 可伸縮的分布式存儲系統 利用hbase技術可以在廉價的PC上搭建起大規模結構化存儲集群。
HBase利用HadoopHDFS作為其文件存儲系統,利用Hadoop的MapReduce來處理HBase中的海量數據,利用Zookeeper作為協調工具
(2)邏輯結構
hbase通過表來存儲數據 但是表的結構和關系型數據庫非常的不一樣
行鍵 - RowKey - 即hbase的主鍵,訪問hbase中的數據有三種方式:
1.通過單一行鍵訪問
2.通過一組行鍵訪問
3.全表掃描
列族(簇) - Column Family?
是表的元數據的一部分,需要在建表時聲明,不能后期增加,如果需要增加只能alter表,一個列族可以包含一個或多個列
列 - Column
可以動態增加列,不需要提前聲明,不是表的元數據一部分
單元格與時間戳 - cell timestamp
通過row和columns確定的一個存儲單元。每個存儲單元中都保存著一個數據的多個版本,版本通過時間戳來區別,而由row column 和 timestamp確定出來的唯一的存儲數據的單元 稱之為一個 cell 單元格。
數據都以二進制形式存儲,沒有數據類型的區別。
所有空數據都不占用空間。
二、安裝配置
前提條件,安裝jdk 和 hadoop,并配置了環境變量
1.單機模式
直接解壓安裝包
tar -zxvf xxxxx.tar.gz
修改conf/hbase-site.xml,配置hbase使用的數據文件的位置,默認在/tmp/hbase-[username],此目錄是linux的臨時目錄,可能會被系統清空,所以最好修改一下
<property>
<name>hbase.rootdir</name>
<value>file:///<path>/hbase</value>
</property>
2.偽分布式模式
修改conf/hbase-env.sh修改JAVA_HOME
export JAVA_HOME=xxxx
修改hbase-site.xml,配置使用hdfs
<property>
<name>hbase.rootdir</name>
<value>hdfs://hadoop01:9000/hbase</value>
</property>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
啟動hbase
3.完全分布式模式
修改conf/hbase-env.sh修改JAVA_HOME
export JAVA_HOME=xxxx
修改hbase-site.xml,配置開啟完全分布式模式
配置hbase.cluster.distributed為true。
配置hbase.rootdir設置為HDFS訪問地址
<property>
<name>hbase.rootdir</name>
<value>hdfs://hadoop00:9000/hbase</value>
</property>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>hadoop01:2181,hadoop02:2181,hadoop03:2181</value>
</property>
修改conf/hbase-env.sh禁用對zookeeper的自動管理
export HBASE_MANAGES_ZK false
配置region服務器,修改conf/regionservers文件,其中配置所有hbase主機,每個主機名獨占一行,hbase啟動或關閉時會按照該配置順序啟動或關閉主機中的hbase
--------------------------------------------------
~HBASE配置文件說明
hbase-env.sh配置HBase啟動時需要的相關環境變量
hbase-site.xml配置HBase基本配置信息
HBASE啟動時默認使用hbase-default.xml中的配置,如果需要可以修改hbase-site.xml文件,此文件中的配置將會覆蓋hbase-default.xml中的配置
修改配置后要重啟hbase才會起作用
--------------------------------------------------
啟動集群
啟動zookeeper
啟動hadoop
啟動hbase
訪問http://xxxxx:60010來訪問web界面,通過web見面管理hbase
也可以通過hbase shell腳本來訪問bhase
啟動備用master實現高可用
hbase-daemon.sh start master
關閉集群
stop-hbase.sh
三、HBASE原理?
HBase的工作方式:
1.region的分裂和結構
hbase表中的數據按照行鍵的字典順序排序
hbase表中的數據按照行的的方向切分為多個region
最開始只有一個region 隨著數據量的增加 產生分裂 這個過程不停的進行 一個表可能對應一個或多個region
region是hbase表分布式存儲和負載均衡的基本單元 一個表的多個region可能分布在多臺HRegionServer上
region是分布式存儲的基本單元 但不是存儲的基本單元 內部還具有結構
一個region由多個Store來組成
有幾個store取決于表的列族的數量 一個列族對應一個store 之所以這么設計 是因為 一個列族中的數據往往數據很類似 方便與進行壓縮 節省存儲空間
表的一個列族對應一個store store的數量由表中列族的數量來決定
一個store由一個memstore 和零個或多個storefile組成
storefile其實就是hdfs中的hfile 只能寫入不能修改 所以hbase寫入數據到hdfs的過程其實是不斷追加hfile的過程
2.hbase寫入數據
數據寫入hbase時 先在hlog中記錄日志 再修改memstore 直接返回成功 這樣 不需要真正等待寫入hdfs的過程 所以很快
memstore 內存有限 當寫入數量達到一定的閾值的時候 就會創建一個新的memstore繼續工作 而舊的memstore 會用一個單獨的線程 寫出到storefile中 最終清空舊的memstore 并在zookeeper中記錄最后寫出數據時間的redo point信息
由于storefile 不能修改 所以數據的更新其實是不停創建新的storefile的過程
這樣多個storefile中可能存在對同一個數據的多個版本 其中舊的版本其實是垃圾數據 時間一長 垃圾數據就可能很多 浪費磁盤空間
所以當達到一定的閾值的時候 會自動合并storefile 在合并的過程中將垃圾數據清理
而當合并出來的文件達到一定程度時 再從新進行切分 防止文件過大
雖然看起來是小變大再變小 但是經過這個過程垃圾數據就被清理掉了
所以store中的數據 其實是memstore和storefile來組成的
而memstore由于是內存中的數據 一旦斷電就會丟失
為了解決可能的意外造成數據丟失的問題 hbase在整個hregionserver中 通過記錄hlog 來保存了所有數據操作的記錄
當hbase啟動時 會檢查zookeeper中的redopoint信息 從hlog中恢復 這個時間點之后的數據 解決數據容易丟失的問題
hlog整個hregionServer中只有一個 所有這臺機器中的所有HRegion都公用這個文件 這樣整個機器的磁盤性能都可以為這一個文件提供支持 提升文件的讀寫效率
hlog文件最終對應的是hdfs中的文件 也是分布式存儲的 保證了日志文件的可靠性
3.hbase讀取數據
**hfile的內部由以下部分組成:
Data Blocks 段–保存表中的數據,這部分可以被壓縮
Meta Blocks 段 (可選的)–保存用戶自定義的kv對,可以被壓縮。
File Info 段–Hfile的元信息,不被壓縮,用戶也可以在這一部分添加自己的元信息。
Data Block Index 段–Data Block的索引。每條索引的key是被索引的block的第一條記錄的key。
Meta Block Index段 (可選的)–Meta Block的索引。
Trailer–這一段是定長的。保存了每一段的偏移量,讀取一個HFile時,會首先 讀取Trailer,Trailer保存了每個段的起始位置(段的Magic Number用來做安全check),然后,DataBlock Index會被讀取到內存中,這樣,當檢索某個key時,不需要掃描整個HFile,而只需從內存中找到key所在的block,通過一次磁盤io將整個 block讀取到內存中,再找到需要的key。DataBlock Index采用LRU機制淘汰。
HFile的Data Block,Meta Block通常采用壓縮方式存儲,壓縮之后可以大大減少網絡IO和磁盤IO,隨之而來的開銷當然是需要花費cpu進行壓縮和解壓縮。
在查詢數據時,先查找內存,如果內存中有當前鍵對應的數據,獲取數據直接返回。如果沒有在內存中找到數據,就去查找region對應的hfile,注意不是將所有hfile中的數據恢復到內存,而是查找每個hfile的Trailer,通過trailer找到Data Block Index,如果在這里發現了要找的數據,通過索引找到Data Blocks中對應的Data Block,將Data Block數據送回內存組裝,最終多個hfile中獲取到的數據 合并后 返回最新的。
由于hbase中的數據天然排序 再加上索引 整個查詢也可以非常的快
4.hbase中region的尋址
在hbase的hbase名稱空間下有一張meta表,其中存放了 表和region和regionSever 之間的對應關系信息,這個表很特別,規定只能有一個region
并且這個meta表的這個region的位置信息被存放在了zookeeper的meta-region-server節點下
在客戶端從hbase中查找數據時,需要先聯系zookeeper找到meta表對應的region的位置,連接這個位置讀取到meta表中的信息,才能知道要查詢的表 和 表的region和region對應的regionServer的信息
再根據這些信息連接真正要查詢的表 對應的region的regionServer進行讀取
這個過程就稱之為region的尋址過程。
這樣的尋址過程是相當耗費時間的,為了提高性能,客戶端通常會緩存之前已經知道的region尋址信息,當客戶端再次讀取同一個表中的數據時,可以通過本地緩存的region地址信息 直接定位讀取,提高效率。
5.存儲系統三種結構
目前常見的主要的三種存儲引擎是:哈希、B+樹、LSM樹:
哈希存儲引擎:是哈希表的持久化實現,支持增、刪、改以及隨機讀取操作,但不支持順序掃描,對應的存儲系統為key-value存儲系統。對于key-value的插入以及查詢,哈希表的復雜度都是O(1),明顯比樹的操作O(n)快,如果不需要有序的遍歷數據,哈希表性能最好。
B+樹存儲引擎是B+樹的持久化實現,不僅支持單條記錄的增、刪、讀、改操作,還支持順序掃描(B+樹的葉子節點之間的指針),對應的存儲系統就是關系數據庫(Mysql等)。
LSM樹(Log-Structured MergeTree)存儲引擎和B+樹存儲引擎一樣,同樣支持增、刪、讀、改、順序掃描操作。而且通過批量存儲技術規避磁盤隨機寫入問題。當然凡事有利有弊,LSM樹和B+樹相比,LSM樹犧牲了部分讀性能,用來大幅提高寫性能。
上面三種引擎中,LSM樹存儲引擎的代表數據庫就是HBase.
LSM樹核心思想的核心就是放棄部分讀能力,換取寫入的最大化能力。LSM Tree ,這個概念就是結構化合并樹的意思,它的核心思路其實非常簡單,就是假定內存足夠大,因此不需要每次有數據更新就必須將數據寫入到磁盤中,而可以先將最新的數據駐留在內存中,等到積累到足夠多之后,再使用歸并排序的方式將內存內的數據合并追加到磁盤隊尾(因為所有待排序的樹都是有序的,可以通過合并排序的方式快速合并到一起)。
日志結構的合并樹(LSM-tree)是一種基于硬盤的數據結構,與B+tree相比,能顯著地減少硬盤磁盤臂的開銷,并能在較長的時間提供對文件的高速插入(刪除)。然而LSM-tree在某些情況下,特別是在查詢需要快速響應時性能不佳。通常LSM-tree適用于索引插入比檢索更頻繁的應用系統。
LSM樹和B+樹的差異主要在于讀性能和寫性能進行權衡。在犧牲的同時尋找其余補救方案:
(a)LSM具有批量特性,存儲延遲。當寫讀比例很大的時候(寫比讀多),LSM樹相比于B樹有更好的性能。因為隨著insert操作,為了維護B+樹結構,節點分裂。讀磁盤的隨機讀寫概率會變大,性能會逐漸減弱。
(b)B樹的寫入過程:對B樹的寫入過程是一次原位寫入的過程,主要分為兩個部分,首先是查找到對應的塊的位置,然后將新數據寫入到剛才查找到的數據塊中,然后再查找到塊所對應的磁盤物理位置,將數據寫入去。當然,在內存比較充足的時候,因為B樹的一部分可以被緩存在內存中,所以查找塊的過程有一定概率可以在內存內完成,不過為了表述清晰,我們就假定內存很小,只夠存一個B樹塊大小的數據吧。可以看到,在上面的模式中,需要兩次隨機尋道(一次查找,一次原位寫),才能夠完成一次數據的寫入,代價還是很高的。
(c)LSM優化方式:
Bloom filter: 就是個帶隨機概率的bitmap,可以快速的告訴你,某一個小的有序結構里有沒有指定的那個數據的。于是就可以不用二分查找,而只需簡單的計算幾次就能知道數據是否在某個小集合里啦。效率得到了提升,但付出的是空間代價。
compact:小樹合并為大樹:因為小樹性能有問題,所以要有個進程不斷地將小樹合并到大樹上,這樣大部分的老數據查詢也可以直接使用log2N的方式找到,不需要再進行(N/m)*log2n的查詢了
6.hbase系統架構:
hbase中的老大叫hmaster 小弟叫hregionServer
客戶端叫Client
Zookeepr為hbase提供集群協調
client:訪問hbase 保留一些緩存信息提升效率
zookeeper:
保證任何時候集群只有一個HMaster
監控regionServer的狀態 將其上線下線信息通知mater
存儲所有Region的尋址地址
存儲hbase的元數據信息 包括 有哪些表 有哪些列族等等
Mater:
為RegionServer分配Region
為RegionServer進行負載的均衡
GFS上的垃圾回收
處理對Schema數據的更新請求
RegionServer:
維護Master分配給它的region,處理對這些region的IO請求
負責切分在運行過程中變得過大的region
為什么hbase可以很快?
從邏輯結構上來說:
表按照行鍵進行了排序,所以查詢時可以很快定位
數據按照行鍵切分為多個HRegion,分布在多個RegionServer中,查詢大量數據時,多個RegionServer可以一起工作,從而提高速度
從物理結構上來說:
HRegion是存活在RegionServer的內存中的,讀寫會非常的高效
還有HFile的支持保證大量的數據可以持久化的保存
數據最終落地到HDFS中,分布式的存儲,保證數據段可靠性和可擴展性
為什么hbase可以存儲很多數據:
基于hdfs,所以支持可擴展性,可以通過增加大量的廉價的硬件提高存儲容量
按列存儲,空的數據不占用空間,當存儲稀疏數據時,不會浪費空間
按例存儲,同一列的數據存放在一起,而同一列的數據一般都是同樣的類型的內容相似的數據,可以實現非常高效的壓縮,節省空間
為什么hbase的數據是可靠的:
基于hdfs,由hdfs的可靠性保證了hbase的可靠性--即數據可以有多個備份
利用zookeeper實現了HA,即使某一臺機器掛掉另外的機器也可以很快的替換它
hbase和hive和傳統的關系型數據庫的比較:
比起傳統的關系型數據庫,可以存儲半結構化非結構化的數據,可以存儲和處理更大級別的數據,提供高效的查詢,對于稀疏數據的處理更好,具有更好的橫向擴展性,免費開源性價比很高。但是不能支持非常好的事務特性,只支持行級的事務。只能通過行鍵來查詢,表設計時難度更高。而mysql用來存儲結構化的數據提供更好的事務控制。
比起hive,hive只是在mapreduce上包了一層殼,本質上還是離線數據的處理的工具,實時查詢性能有限,本質上是一個基于hadoop的數據倉庫工具,不能支持行級別的新增修改和刪除。hbase可以提供實時的數據的處理能力,適用于在線數據查詢處理,本質上是一種數據庫工具。
六、HBase的表設計
HBase表的設計 會直接影響hbase使用的效率 和 使用的便利性
HBase表的設計 主要是 列族的設計 和 行鍵的設計
1.列族的設計
在設計hbase表時候,列族不宜過多,越少越好,官方推薦hbase表的列族不宜超過3個。
經常要在一起查詢的數據最好放在一個列族中,盡量的減少跨列族的數據訪問。
如果有多個列族 多個列族中的數據應該設計的比較均勻
2.行鍵的設計
hbase表中行鍵是唯一標識一個表中行的字段,所以行鍵設計的好不好將會直接影響未來對hbase的查詢的性能和查詢的便利性
所以hbase中的行鍵是需要進行設計的
行鍵設計的基本原則:
行鍵必須唯一,必須唯一才能唯一標識數據
行鍵必須有意義,這樣才能方便數據的查詢
行鍵最好是字符串類型,因為數值類型在不同的系統中處理的方式可能不同
行鍵最好具有固定的長度,不同長度的數據可能會造成自然排序時排序的結果和預期不一致
行鍵不宜過長,行鍵最多可以達到64KB,但是最好是在10~100字節之間,最好不要超過16字節,越短越好,最好是8字節的整數倍。
散列原則:
行鍵的設計將會影響數據在hbase表中的排序方式,這會影響region切分后的結果,要注意,在設計行鍵時應該讓經常要查詢的數據分散在不同的region中,防止某一個或某幾個regionserver成為熱點。
有序原則:
行鍵的設計將會影響數據在hbase表中的排序方式,所以一種策略是將經常連續查詢的條件作為行鍵最前面的數據,這樣一來可以方便批量查詢
實踐:工作實際使用中,列族一般都為1個,rowkey根據實際查詢情況進行拼接,一般先查詢的字段會放前面,并在最前面加上某個字段的reverse值。
當rowkey查詢不滿足需求時,使用全局索引(實際就是給索引再建表)和全文索引(基于ES)進行高并發的檢索查詢。