HBase的表結構你設計得不對!

普通程式設計師發表於2018-10-30

正如我在前面章節強調的,HBase資料模型跟關係型資料庫系統有非常大的差異。因此,設計Hbase的資料表的方法和思路跟關係型資料庫不一樣。設計HBASE表應該在具體業務場景的上下文中回答以下問題

1、rowkey結構應該是什麼,它應該包含什麼?

2、表(table)應該有多少個列簇?

3、各個列簇該儲存什麼資料?

4、每個列簇(column family)有多少列(column)?

5、列名應該是什麼?儘管列名不需要在表建立中定義時,但在編寫或讀取資料時需要了解它們。

6、單元格(cells)應該儲存什麼資訊?

7、每個單元格(cell)應該儲存多少個版本的資料?

設計Hbase資料表最重要的是定義rowkey結構。為了有效定義rowkey結構,有必要預先定義資料訪問模式(讀取和寫入)。為了定義模式(schema),HBase表的一些特性必須考慮。快速再看一下:

1、只有Key(rowkey)上有索引

2、表基於rowkey進行排序儲存。表中的每個區域負責儲存一部分rowkey範圍,由開始行和結束行的rowkey標識。該區域包含從開始鍵到結束鍵的行排序列表。

3、HBASE表中的所有內容都儲存為二進位制位元組(byte[]),沒有型別。

4、原子性操作只在一行(row)上得到保證。沒有跨行原子性保證,這意味著沒有多行事務。

5、列簇必須在建立表之前定義。

6、列限定符(column qualifiers)是動態的,可以在寫入時定義。它們以位元組(byte[])形式被儲存,甚至可以將資料放入其中。

透過例子可以比較好的理解這些概念。讓我們嘗試在HBase表中對Twitter的使用者關係進行建模(一些使用者關注了另一些使用者)。

關注與被關注(Follower-followed)關係本質上是圖形(graphs),有專門的圖形資料庫可以更有效地處理這些資料集。然而,這個特定的用例為HBase表中的模型提供了一個很好的例子,並允許我們強調一些有趣的概念。

資料庫表建模的第一步是定義應用程式的訪問模式。在Twitter等應用程式的Follower-followed關係的上下文中,訪問模式可以如下定義

讀取訪問模式

1、使用者關注誰?

2、特定使用者A是否關注使用者B? 

3、誰關注了特定使用者A?

寫訪問模式

1、使用者關注新使用者。 

2、使用者取消關注某人。

讓我們考慮集中表設計方式,看看它們的優缺點。從圖1中所示的表設計開始。該表一行儲存特定使用者關注的所有使用者列表,其中row key是關注者的使用者ID,每列包含被關注使用者的使用者ID。具有資料的該設計表將如圖2所示。 

HBase的表結構你設計得不對!

圖1:HBase表用於保留特定使用者正在關注的使用者列表


HBase的表結構你設計得不對!

圖2:包含設計樣本資料的表格(圖1設計)

這個設計適用於讀取模式的的第1條。它也解決了讀模式的第2條,但是如果被關注使用者列表很大,這個方法需要遍歷整個列表才能回答讀模式的第2條的問題,成本很高。在這個設計中新增使用者有點棘手,由於沒有儲存計數,所以新增一個新的關注使用者ID需要讀取整行資料,才能找到下一個使用者的編號。成本太高了!一個可能的解決方案就是保留一個計數器,現在表格如圖3所示。

HBase的表結構你設計得不對!

圖3:包含示例資料的表(圖1設計),但帶有一個計數器,用於記錄給定使用者關注的使用者數


HBase的表結構你設計得不對!

圖4:根據圖3中的表設計將新使用者新增到關注使用者列表所需的步驟


圖3中的設計比以前的設計更好,但並不能解決所有問題。取消關注使用者仍然很棘手,因為您必須閱讀整行以找出需要刪除的列。它也不是理想的計數,因為取消關注將導致空洞(編號不連續)。最大的問題是,要新增使用者,您必須在客戶端程式碼中實現某種事務邏輯,因為HBase不會跨行或跨RPC呼叫執行事務。在此方案中新增使用者的步驟如圖4所示。

我之前提到的一個特性是列限定符是動態的,並且像單元格一樣儲存為byte []。您能夠在其中放置任意資料,這點有可能改進之前的設計。考慮圖5中的表。在此設計中,不需要計數,新增使用者變簡單。取消關注也得到簡化。在這種情況下,單元格只包含一些任意小的值,且沒有任何意義。 

HBase的表結構你設計得不對!

圖5:被關注使用者名稱作為列限定符,任意字串作為單元格值


這種最新設計實現了我們定義的幾乎所有訪問模式,除了讀取模式第3條:誰關注了特定使用者A?在當前設計中,由於索引僅在row key上有效,因此您需要執行全表掃描來回答這個問題。您需要為關注(特定使用者)的使用者建立某種索引。有兩種方法可以解決這個問題。首先是維護另一個包含反向列表的表(使用者和所有關注這個使用者的使用者列表)。第二種是使用不同的row key將該資訊儲存在同一個表中(它全是位元組陣列,而HBase並不關心你放在那裡的內容)。這兩種方式,您都需要單獨處理該資訊,這樣就無需進行大規模掃描,可以快速訪問它。

當前的表結構中還可以進一步最佳化。看看圖6: 

HBase的表結構你設計得不對!

圖6:包含關注者和被關注使用者的row key設計的表


在這個設計中有兩點需要注意:row key現在包含關注者和被關注使用者;列族名稱已縮短為f。短列族名稱是一個不相關的概念,之前的表設計也能很好實現功能。短列簇名只是透過減少需要從HBase讀取/寫入的資料來減少I / O負載(磁碟和網路),列簇名稱是返回給客戶端的每個KeyValue 物件的一部分。第一點在這裡更重要。獲取關注使用者列表從get操作變為簡短的scan操作。由於get在內部實現是長度為1的掃描,因此效能影響很小。取消關注與回答“A是否關注B?”分別成為簡單的delete和get操作,並不需要像之前那樣遍歷整個使用者列表。這個設計顯然成本更低,尤其是當被關注使用者列表很大的時候。

基於此設計的樣本資料的表格如圖7所示。 

HBase的表結構你設計得不對!

圖7:基於圖6設計,帶有樣本資料的表


請注意,row key長度在表中是可變的。由於每次呼叫表傳輸的資料長度不定,因此難以推斷效能。這個問題的解決方案是在row key中使用雜湊值。就其本身而言,這是一個有趣的概念,並且具有超出本文範圍的row key設計相關的其他含義。要在當前表中獲得統一的row key長度,您可以雜湊各個使用者ID並將它們連線起來,而不是串聯使用者ID本身。由於您始終知道要查詢的使用者,因此可以使用使用者ID生成的雜湊值去查詢資料表。具有雜湊值的表將如圖8所示。 

HBase的表結構你設計得不對!

圖8:使用MD5作為row key的一部分來實現固定長度。這也允許你擺脫我們到目前為止所需的+分隔符。row key現在由固定長度部分組成,每個使用者ID為16個位元組。

這個表設計有效地回答我們之前概述的所有訪問模式問題。

總結

本文介紹了HBase架構設計的基礎知識。我首先介紹了資料模型(這部分沒有翻譯,可以參看HBase官方文件),然後討論了設計HBase表時要考慮的一些因素。在HBase表設計中還有更多可供探索和學習的東西,這些東西可以建立在這些基礎之上。本文的主要內容是:

  • row key是HBase表設計中最重要的一個方面,它決定了應用程式與HBase表的互動方式,還會影響您從HBase中提取資料的效能。 

  • HBase表非常靈活,可以以byte []的形式儲存任何內容。

  • 將具有相似訪問模式的資料儲存在同一列族中。

  • 只有Keys上有索引,好好利用它。

  • 高表(tall table),可以讓操作更快更簡單,但你要權衡原子性。寬表(wide table),每行有很多列,允許行級原子性

  • 思考如何在單個API呼叫中完成訪問模式,而不是透過多個API呼叫。HBase沒有跨行事務,您需要避免在客戶端程式碼中構建該邏輯。

  • Hashing允許使用固定長度的keys,具有更好的資料分佈,但她移除了使用字串作為keys的資料順序。

  • 列限定符(Column qualifiers)可用於儲存資料就像單元格本身一樣

  • 列限定符(Column qualifiers)的長度會影響儲存空間,因為您可以將資料放入其中。訪問資料時,長度也會影響磁碟和網路I / O成本。列限定符要簡明扼要。

  • 列簇名稱的長度會影響透過線路傳送到客戶端的資料大小(在KeyValue物件中)。列簇名要簡明扼要。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31556438/viewspace-2218078/,如需轉載,請註明出處,否則將追究法律責任。

相關文章