天天看點

Hbase資料模型與table設計

HBase是一個開源可伸縮的針對海量資料存儲的分布式nosql資料庫,它根據Google Bigtable資料模型來模組化并建構在hadoop的hdfs存儲系統之上。它和關系型資料庫Mysql, Oracle等有明顯的差別,HBase的資料模型犧牲了關系型資料庫的一些特性但是卻換來了極大的可伸縮性和對表結構的靈活操作。

在一定程度上,Hbase又可以看成是以行鍵(Row Key),列辨別(column qualifier),時間戳(timestamp)辨別的有序Map資料結構的資料庫,具有稀疏,分布式,持久化,多元度等特點。

Base的資料模型介紹

HBase的資料模型也是由一張張的表組成,每一張表裡也有資料行和列,但是在HBase資料庫中的行和列又和關系型資料庫的稍有不同。下面統一介紹HBase資料模型中一些名詞的概念:

         表(Table): HBase會将資料組織進一張張的表裡面,但是需要注意的是表名必須是能用在檔案路徑裡的合法名字,因為HBase的表是映射成hdfs上面的檔案。

         行(Row): 在表裡面,每一行代表着一個資料對象,每一行都是以一個行鍵(Row Key)來進行唯一辨別的,行鍵并沒有什麼特定的資料類型,以二進制的位元組來存儲。

         列族(Column Family): 在定義HBase表的時候需要提前設定好列族, 表中所有的列都需要組織在列族裡面,列族一旦确定後,就不能輕易修改,因為它會影響到HBase真實的實體存儲結構,但是列族中的列辨別(Column Qualifier)以及其對應的值可以動态增删。表中的每一行都有相同的列族,但是不需要每一行的列族裡都有一緻的列辨別(Column Qualifier)和值,是以說是一種稀疏的表結構,這樣可以一定程度上避免資料的備援。例如:{row1, userInfo: telephone —> 137XXXXX869 }{row2, userInfo: fax phone —> 0898-66XXXX } 行1和行2都有同一個列族userinfo,但是行1中的列族隻有列辨別(Column Qualifier):行動電話号碼,而行2中的列族中隻有列辨別(Column Qualifier):傳真号碼。

         列辨別(Column Qualifier): 列族中的資料通過列辨別來進行映射,其實這裡大家可以不用拘泥于“列”這個概念,也可以了解為一個鍵值對,Column Qualifier就是Key。列辨別也沒有特定的資料類型,以二進制位元組來存儲。

         單元(Cell): 每一個 行鍵,列族和列辨別共同組成一個單元,存儲在單元裡的資料稱為單中繼資料,單元和單中繼資料也沒有特定的資料類型,以二進制位元組來存儲。

         時間戳(Timestamp): 預設下每一個單元中的資料插入時都會用時間戳來進行版本辨別。讀取單中繼資料時,如果時間戳沒有被指定,則預設傳回最新的資料,寫入新的單中繼資料時,如果沒有設定時間戳,預設使用目前時間。每一個列族的單中繼資料的版本數量都被HBase單獨維護,預設情況下HBase保留3個版本資料。

Hbase資料模型與table設計

圖檔來自:http://0b4af6cdc2f0c5998459-c0245c5c937c5dedcca3f1764ecc9b2f.r43.cf2.rackcdn.com/9353-login1210_khurana.pdf

Hbase資料模型與table設計

圖檔來自:http://0b4af6cdc2f0c5998459-c0245c5c937c5dedcca3f1764ecc9b2f.r43.cf2.rackcdn.com/9353-login1210_khurana.pdf    

Hbase資料模型與table設計

        HBase提供了豐富的API接口讓使用者去操作這些資料。主要的API接口有3個,Put,Get,Scan。Put和Get是操作指定行的資料的,是以需要提供行鍵來進行操作。Scan是操作一定範圍内的資料,通過指定開始行鍵和結束行鍵來擷取範圍,如果沒有指定開始行鍵和結束行鍵,則預設擷取所有行資料。

HBase的表設計中需要注意的問題

   當開始設計HBase中的表的時候需要考慮以下的幾個問題:

        1. Row Key的結構該如何設定,而Row Key中又該包含什麼樣的資訊(這個很重要,下面的例子會有說明)

        2. 表中應該有多少的列族

        3. 列族中應該存儲什麼樣的資料

        4. 每個列族中存儲多少列資料

        5. 列的名字分别是什麼,因為操作API的時候需要這些資訊

        6. 單元中(cell)應該存儲什麼樣的資訊

        7. 每個單元中存儲多少個版本資訊

     在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)可以在表建立完以後動态插入資料時添加。

接下來我們考慮一個這樣的場景,我們要設計一張表,用來儲存微網誌上使用者互粉的資訊。是以設計表之前,我們要考慮業務中的讀寫場景。

讀場景中我們要考慮:

1. 每個使用者都關注了誰

2. 使用者A有沒有關注使用者B

3. 誰關注了使用者A

寫場景中我們要考慮:

1. 使用者關注了另一個使用者

2. 使用者取消關注某個使用者

下面我們來看幾種表結構的設計:

第一種表結構設計中,在這種表結構設計中,每一行代表着某個使用者和所有他所關注的其它使用者。這個使用者ID就是Row Key,而每一個列辨別(Column Qualifier)就是這個使用者所關注的其他使用者在列族裡的序号,單中繼資料就是這個使用者所關注的其他使用者的使用者ID。在這種表結構的設計下,“每個使用者都關注了誰”這個問題很好解決,但對于“使用者A有沒有關注使用者B”這個問題在列很多的時候,需要周遊所有單中繼資料去找到使用者B,這樣的開銷會十分大。并且當添加新的被關注使用者時,因為不知道給這個新使用者配置設定什麼樣的列族序号,需要周遊整個列族中的所有列找出最後一個列,并将最後一個列的序号+1給新的被關注使用者作為列族内的序号,這樣的開銷也十分大。

Hbase資料模型與table設計

是以衍生出了第二種表結構設計,如下圖,添加一個counter記錄列族中所有列的總數量,當添加新的被關注使用者時,這個新使用者的序号就是counter+1。但是當要取消關注某個使用者時,一樣得周遊所有的列資料,而且最大的問題是在于HBase不支援事務處理,這種通過counter來添加被關注使用者的操作邏輯得寫在用戶端中。

Hbase資料模型與table設計

回想一下,列辨別(Column Qualifier)存儲的時候是二進制的位元組,是以列辨別可以存儲任何資料,而且列辨別還是動态增添的,基于這個特性我們再改進表的設計,如下圖。這次以被關注的使用者ID做為列辨別(Column Qualifier),然後單中繼資料可以是任意數字,比如全部統一成1。在這種表結構的設計下,添加新的被關注者,以及取消關注都會變得很簡單。但是對于讀場景中,誰關注了使用者A這個問題,因為HBase資料庫的索引隻建立在Row Key上,這裡不得不掃描全表去統計所有關注了使用者A的使用者數量,是以下面的這個表結構設計也存在一定的性能問題。這裡也引出一個思路,被關注者需要以某種方式添加索引。

Hbase資料模型與table設計

針對上面的表結構有三種優化方案,第一種是建立另一張表,裡面儲存某個使用者和所有關注他的使用者。第二種解決方案就是在同一張表中也存儲某個使用者和所有關注他的使用者的資訊,并從Row Key中區分開來,比如:Row key為Jame_001_following的這行儲存着所有Jame關注的人的資訊,而Row_Key為Jame_001_followed的這行儲存着所有關注Jame的人的資訊。最後一種優化方案就是,如下圖,将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?”的業務處理就會變得簡單高效。

Hbase資料模型與table設計
Hbase資料模型與table設計

還有一個需要注意的問題,就是在實際的生産環境中,還需要将Row Key使用MD5加密,一方面是使Row Key的長度都一緻,能提高資料的存取性能。這方面的優化不在本文的讨論範圍内。

Hbase資料模型與table設計

總結:

整篇文章概述了HBase的資料模型和基本的表設計思路。下面是HBase一些關鍵特性的總結:

   1. Row Key是HBase表結構設計中很重要的一環,它設計的好壞直接影響程式和HBase互動的效率和資料存儲的性能。

   2. Base的表結構比傳統關系型資料庫更靈活,你能存儲任何二進制資料在表中,而且無關資料類型。

   3. 在相同的列族中所有資料都具有相同的Access模式

   4. 主要是通過Row Key來建立索引

   5. 以縱向擴張為主設計的表結構能快速簡單的擷取資料,但犧牲了一定的原子性,就比如上文中最後一種表結構;而以橫向擴張為主設計的表結構,也就是列族中有很多列,比如上文中第一種表結構,能在行裡面保持一定的原子性。

   6. HBase并不支援事務,所有盡量在一次API請求操作中擷取到結果

   7. 對Row Key的Hash優化能獲得固定長度的Row Key并使資料分布更加均勻一些,而不是集中在一台伺服器上,但是也犧牲了一定的資料排序和讀取性能。

   8. 可以利用列辨別(Column Qualifier)來存儲資料。

   9. 列辨別(Column Qualifier)名字的長度和列族名字的長度都會影響I/O的讀寫性能和發送給用戶端的資料量,是以它們的命名應該簡潔!

Hbase資料模型與table設計