HBase的數據模型也是由表組成,每一張表裏也有數據行和列,可是在HBase數據庫中的行和列又和關係型數據庫的稍有不一樣。數據庫
表(Table): HBase會將數據組織成一張表,表名必須是能用在文件路徑裏的合法名字,由於HBase的表是映射成hdfs上面的文件,Hbase的表及表中的數據都是以二進制字節進行存儲;
行(Row): 在表裏面,每一行都是以一個行鍵(Row Key)來進行惟一標識的,行鍵並無什麼特定的數據類型,以二進制的字節來存儲。
列族(Column Family): 列族是Hbase Schema定義的一部分,列不是,列族一旦肯定後,就不能輕易修改,由於它會影響到HBase真實的物理存儲結構,可是列族中的列標識(Column Qualifier)以及其對應的值能夠動態增刪。表中的每一行都有相同的列族,可是不須要每一行的列族裏都有一致的列標識(Column Qualifier)和值,因此說是一種稀疏的表結構,這樣能夠必定程度上避免數據的冗餘;
列標識(Column Qualifier): 列族中的數據經過列標識來進行映射,即爲一個鍵值對,Column Qualifier就是Key,值是value;
單元(Cell): 每個行鍵,列族和列標識共同組成一個單元,存儲在單元裏的數據稱爲單元數據;
時間戳(Timestamp): 默認下每個單元中的數據插入時都會用時間戳來進行版本標識。讀取單元數據時,若是時間戳沒有被指定,則默認返回最新的數據,寫入新的單元數據時,若是沒有設置時間戳,默認使用當前時間。每個列族的單元數據的版本數量都被HBase單獨維護,默認狀況下HBase保留3個版本數據。數組
Hbase必定程度上又能夠當作一個多維度的Map模型去理解它的數據模型。即以行鍵(Row Key),列標識(column qualifier),時間戳(timestamp)標識的有序Map數據結構的數據庫,具備稀疏,分佈式,持久化,多維度等特色。正以下圖,一個行鍵映射一個列族數組,列族數組中的每一個列族又映射一個列標識數組,列標識數組中的每個列標識(Column Qualifier)又映射到一個時間戳數組,裏面是不一樣時間戳映射下不一樣版本的值,可是默認取最近時間的值,因此能夠當作是列標識(Column Qualifier)和它所對應的值的映射。用戶也能夠經過HBase的API去同時獲取到多個版本的單元數據的值。Row Key在HBase中也就至關於關係型數據庫的主鍵,而且Row Key在建立表的時候就已經設置好,用戶沒法指定某個列做爲Row Key。服務器
HBase也能夠當作是一個相似Redis那樣的Key-Value數據庫。以下圖,當你要查詢某一行的全部數據時,Row Key就至關於Key,而Value就是單元中的數據(列族,列族裏的列和列中時間戳所對應的不一樣版本的值);用戶要查詢指定行裏某一條單元數據時,HBase會去讀取一個數據塊,裏面除了有要查詢的單元數據,可能同時也會獲取到其它單元數據,由於這個數據塊還包含着這個Row Key所對應的其它列族或其它的列信息,這些信息實際也表明着另外一個單元數據,這也是HBase的API內部實際的工做原理。數據結構
HBase提供了豐富的API接口讓用戶去操做這些數據。主要的API接口有3個,Put,Get,Scan。Put和Get是操做指定行的數據的,因此須要提供行鍵來進行操做。Scan是操做必定範圍內的數據,經過指定開始行鍵和結束行鍵來獲取範圍,若是沒有指定開始行鍵和結束行鍵,則默認獲取全部行數據。分佈式
在HBase表設計中最重要的就是定義Row-Key的結構,要定義Row-Key的結構時要緊密結合實際業務應用場景,對這張表出現什麼樣的讀寫場景。除此以外,在設計表的時候咱們也應該要考慮HBase數據庫的一些特性。
1. HBase中表的索引是經過Key來實現的
2. 在表中是經過Row Key的字典序來對一行行的數據來進行排序的,表中每一塊區域的劃分都是經過開始Row Key和結束Row Key來決定的。
3. 全部存儲在HBase表中的數據都是二進制的字節,並無數據類型。
4. 原子性只在行內保證,HBase表中並無多行事務。
5. 列族(Column Family)在表建立以前就要定義好
6. 列族中的列標識(Column Qualifier)能夠在表建立完之後動態插入數據時添加。性能
2、Hbase 表設計示例優化
設計一張表,用來保存微博上用戶互粉的信息。加密
讀場景業務要求
1. 每一個用戶都關注了誰
2. 用戶A有沒有關注用戶B
3. 誰關注了用戶Aspa
寫場景業務要求
1. 用戶關注了另外一個用戶
2. 用戶取消關注某個用戶.net
每一行表明着某個用戶和全部他所關注的其它用戶。這個用戶ID做爲Row Key,一個列族follows,而每個列標識(Column Qualifier)就是這個用戶所關注的其餘用戶在列族裏的序號,單元數據就是這個用戶所關注的其餘用戶的用戶ID。在這種表結構的設計下,「每一個用戶都關注了誰」這個問題很好解決,但對於「用戶A有沒有關注用戶B」這個問題在列不少的時候,須要遍歷A用戶所在Row的全部單元數據去找到用戶B,這樣的開銷會十分大。而且當添加新的被關注用戶時,由於不知道給這個新用戶分配什麼樣的列族序號,須要遍歷整個列族中的全部列找出最後一個列,並將最後一個列的序號+1給新的被關注用戶做爲列族內的序號,這樣的開銷也十分大。
在初始方案的基礎上,添加一個counter記錄列族中全部列的總數量,當添加新的被關注用戶時,這個新用戶的序號就是counter+1。可是當要取消關注某個用戶時,同樣得遍歷全部的列數據,並且最大的問題是在於HBase不支持事務處理,這種經過counter來添加被關注用戶的操做邏輯得寫在客戶端中。
列標識(Column Qualifier)存儲的時候是二進制的字節,能夠存儲任何數據,並且列標識仍是動態增添的,基於這個特性咱們再改進表的設計,以下圖。此次以被關注的用戶ID作爲列標識(Column Qualifier),而後單元數據能夠是任意數字,好比所有統一成1。在這種表結構的設計下,添加新的被關注者,以及取消關注都會變得很簡單。可是對於讀場景中,誰關注了用戶A這個問題,由於HBase數據庫的索引只創建在Row Key上,這裏不得不掃描全表去統計全部關注了用戶A的用戶數量。
將Row Key設計成「followerID+followedID」的形式,好比:「Jame+Emma」,這裏的Row Key值就表明着Jame關注了Emma(其實這裏應該是「Jame的ID+Emma的ID」,只是爲了解釋方便而直接用名字),同時包含了關注者和被關注者兩個信息;還須要注意的一點就是列族的名字被設計成只有一個字母f,這樣設計的好處就是減小了HBase對數據的I/O操做壓力,同時減小了返回到客戶端的數據字節,提升響應速度,由於每個返回給客戶端的KeyValue對象都會包含列族名字。同時將被關注人的用戶名稱也保存在了表中做爲Column Qualifier,這樣作的好處就是節省了去用戶表查找用戶名的資源。在這種表結構設計下,「用戶A取消關注某個用戶B」,「用戶A有沒有關注用戶B?」的業務處理就會變得簡單高效。
在實際的生產環境中,還須要將Row Key使用MD5加密,一方面是使Row Key的長度都一致,能提升數據的存取性能。
http://0b4af6cdc2f0c5998459-c0245c5c937c5dedcca3f1764ecc9b2f.r43.cf2.rackcdn.com/9353-login1210_khurana.pdf
https://blog.csdn.net/ymh198816/article/details/51244911