天天看點

hbase rowkey設計

hbase所謂的三維有序存儲的三維是指:rowkey(行主鍵),column key(columnFamily+qualifier),timestamp(時間戳)三部分組成的三維有序存儲。

rowkey是行的主鍵,而且hbase隻能用個rowkey,或者一個rowkey範圍即scan來查找資料。是以 rowkey的設計是至關重要的,關系到你應用層的查詢效率。

rowkey是以字典順序排序的,存儲的是位元組碼。

根據rowkey範圍查詢的時候,一般是知道startRowkey,如果我們通過scan隻傳startRowKey : d開頭的,那麼查詢的是所有比d大的都查了,而我們隻需要d開頭的資料,那就要通過endRowKey來限制。我們可以通過設定endRowKey為:d 開頭,後面的根據你的rowkey組合來設定,一般是加比startKey大一位。比如說rowkey設計為:使用者ID-日期,那麼查某個使用者某天的數 據,startKEY為3231-20121212,endKey為:3231+201213,那麼你查到的就是使用者為3231在20121212這一天 的資料。

需要通路的資料rowkey連續的話,scan到的有用資料比較多,使用率高,能夠避免或減少反複記憶體倒換。

rowkey的設計和資料的分布有很大關系,rowkey設計的時候需要保證資料入庫時的并發度,但又不能過于分散。

可枚舉屬性值較少的屬性放在rowkey前面 

在rowkey中,需要放入多個屬性,這多個屬性的先後次序和通路的效率有直接的關系。一個普遍的規則是:數量較少,可控的屬性放在rowkey前面(如ServiceType,CPID等);反之放在後面(如url,mxid等)。這樣做的原因是可控屬性放在前面,對各種不同查詢需求的平衡性強一些,反之平衡性較差。

案例1:

201010-http-cp001-s-shanghai-xxx-1
201010-http-cp002-s-shenzhen-xxx-2
201010-rtsp-cp001-s-shanghai-xxx-1
201010-rtsp-cp002-s-shenzhen-xxx-2           
  • 1
  • 2
  • 3
  • 4

ServiceType可枚舉,并且數量較少,分為http和rtsp兩種,放在前面; 

而cpid可能會比較多(假設有5個cp),是以放在後面。 

這樣的設計能夠适應如下兩種需求,複雜度都比較小: 

1) 查詢2010年10月所有cp的http資料。這種需求設定scan的startrow=‘201010-http-’,endrow=‘201010-http-z’,即可。 

2) 查詢2010年10月cp001的所有協定的資料。這種需求下,根據scan rowkey連續的原則,需要将查詢劃分成兩個scan,分别查詢http類型cp001的資料和rtsp類型cp001的資料。

但是,如果将cp放在前面,如下所示,适應性就差一些,如下所示案例2:

201010-cp001-http-s-shanghai-xxx-1
201010-cp002-http-s-shenzhen-xxx-2
201010-cp001-rtsp-s-shanghai-xxx-1
201010-cp002-rtsp-s-shenzhen-xxx-2           

1) 查詢2010年10月cp001的所有協定的資料。 

這種需求下,設定scan的startrow=‘201010-cp001-’,endrow=‘201010-cp001-z’,即可。 

2) 查詢2010年10月,所有cp的http資料。 

這種需求下,根據scan的rowkey連續原則,需要将查詢分成cp001-http、cp002-http、cp003-http、cp004-http、cp005-http五個查詢進行,相對模型一複雜了一些。

業務通路中權重高的key放在前面

例如URLRecords表的主要用途是用來計算當天的URL通路排名。根據業務需求,需要通路某天的所有URL,是以date是主鍵,權重更高,放在前面,而URL則放在後面。

構造備援資料 

例如,percontent的資料包含了URL Records的資料,URL Records的資料是備援存儲的,差別在于percontent的URL放在date前面,而URL Records表的URL放在date後面。這就是由于URL在滿足不同需求的時候,權重不同,由于URL Records需要的資料量不大,是以采用備援的機制解決該沖突。 

權衡需求的重要性和系統忍受度選擇一種方案 

當兩種需求有沖突,但其中一方屬于次要需求,并且在系統忍受度範圍之内的話,可以舍棄一種方案。優先滿足需求更強的一方

時間屬性在rowkey中的使用 

如果需要經常通路特定時間段的資料,将時間屬性放在rowkey中是一個較好的選擇。 

和利用時間戳來通路特定時間段的資料方法相比,将時間屬性放在rowkey中具有可控性,容易将能夠同時通路的資料相對集中存放的優點。 

時間屬性放在rowkey中需要注意資料分布和并發度的問題:hbase資料是按照rowkey排序的,時間屬性放在rowkey中容易造成資料總是在末尾寫入的情況,這種情況下并發度很差。這種情況可以通過在時間屬性前面增加prefix和提前預分region的方法解決。

循環key使用 

(1)存在問題 

如果rowkey中有時間屬性,并且随着時間的增加,rowkey會不斷的增大下去的話,會造成region數量不斷地增加。如果使用TTL來控制資料的生命周期,一些老的資料就會過期,進而導緻老的region資料量會逐漸減少甚至成為空的region。這樣一方面region總數在不斷增加,另外一方面老的region在不斷的成為空的region,而空的region不會自動合并,進而造成過多空的region占用負載和記憶體消耗的情況。 

(2)解決辦法 

這種情況下,可以使用循環key的方法來解決。思路是根據資料的生命周期設定rowkey的循環周期,當一個周期過去以後,通過時間映射的方法,繼續使用老的過期資料的rowkey。 

例如,key的格式如下: 

YY-MM-DD-URL。如果資料的生命周期是一年,則可以使用MM-DD-URL的格式。這樣目前一年過去以後,資料已經老化,後一年的資料可以繼續寫入前一年的位置,使用前一年資料的rowkey。這樣可以避免空的region占用資源的情況。

根據hbase的原理,key的周期需要至少比TTL大2* hbase.hregion.majorcompaction(預設24小時)的時間,才能夠保證過期的資料能夠在key循環回來之前得到完全清理。 

按照時間周期進行建表的方式也可以解決空region的問題,和循環key方法相比較,循環key的優點如下:

  • 操作簡單,不需要重複建表,系統自動處理

同樣,循環key具有如下劣勢:

  • 需要使用TTL來老化資料,可能會增加compact負擔
  • 需要保證查詢操作不會查詢到過期資料,否則會影響系統性能。