HBase中的时间维度
原文鏈接:http://outerthought.org/blog/417-ot.html
原文是Bruno Dumon在一年前寫的,現(xiàn)在看了還是有很多啟發(fā),因此簡單的翻譯一下,可能有理解不準(zhǔn)確的地方,強(qiáng)烈推薦看原文。
————————————– 毫無理由的分割線 ———————————
HBase是一個(gè)類Bigtable系統(tǒng),按照Google的論文對 Bigtable的定義是“一種稀疏的,分布式的,持久的多為維度的有序Map。這個(gè)Map由row key,column key和timestamp做為索引,Map中的值是連續(xù)的byte數(shù)組”。HBase的多維度,包括table和column family等。
不是所有維度都是等同的,不同的維度有其特殊的意義。例如,row這個(gè)維度用于region切分,所以可以增長到海量。而column則不用于分 片,和row不同的是,一個(gè)row中的多個(gè)columns的put或者delete操作是一個(gè)原子事務(wù)(當(dāng)然,同一個(gè)原子事務(wù)中不可能同事put和 delete)。而這篇文章將重點(diǎn)關(guān)注時(shí)間維度。
1. 基本概念
在Bigtable論文中,一個(gè){row key,column key}對應(yīng)的是一個(gè)cell。每個(gè)cell可能包含多個(gè)版本的數(shù)據(jù),以timestamp索引,這就是本文要講述的時(shí)間索引。
1.1 時(shí)間/版本維度中的key
Row key)和column key(在HBase中也稱為qualifier)是bytes類型,而時(shí)間維度的key則是long integer類型,比較典型的是使用 java.util.Date.getTime()或者System.currentTimeMillis()來做為時(shí)間維度的key。
時(shí)間維度的各個(gè)版本是倒序排列后存儲的,所以從storefile中讀取的時(shí)候,最先讀到的就是最新的時(shí)間,這個(gè)特性在系統(tǒng)設(shè)計(jì)的時(shí)候如果能有效利用,會非常有用。
下面我們從幾個(gè)核心操作get,put和delete來看看時(shí)間維度的具體細(xì)節(jié)。
?
1.2 Get
默認(rèn)情況下,Get操作會返回每個(gè)cell的timestamp值最大的版本(但這并不一定代表是最新寫入的版本,后面會提到)。這個(gè)默認(rèn)行為可以通過下面兩種方式改變:
1. 通過設(shè)置 Get.setMaxVersions()可以返回多個(gè)版本的數(shù)據(jù)。
2. 通過設(shè)置 Get.setTimeRange()可以返回其他時(shí)間范圍的版本。
如果要返回除最新版本之外的某個(gè)特定版本,可以通過組合上面兩個(gè)條件來達(dá)成,首先設(shè)置時(shí)間范圍為0到希望返回的時(shí)間,然后設(shè)置最多返回一個(gè)版本即可。
1.3 Put
每次執(zhí)行Put,對應(yīng)的cell都會插入一個(gè)新的版本。默認(rèn)使用的是currentTimeMillis。應(yīng)用也可以使用自定義的值來做為每個(gè)列的 timestamp,只需要是一個(gè)long integer的值即可,不一定是時(shí)間,如果是時(shí)間,也可以是過去或者未來某個(gè)時(shí)間,所以前面說到方Get返回的是timestamp最大值的版本,而不 一定是最新寫入的版本。
HBase的架構(gòu)中,數(shù)據(jù)文件的寫入只能附加(Append)而不能修改。數(shù)據(jù)文件只有在執(zhí)行compact操作是才重寫。數(shù)據(jù)文件中存儲的是鍵值 對,其中鍵是{row key,column key,timestamp}的組合鍵,每次put新的值的時(shí)候,會產(chǎn)生新的鍵值對附加在數(shù)據(jù)文件中,即時(shí)你使用一個(gè)已經(jīng)存在的timestamp也一 樣。因此短時(shí)間內(nèi)對同一行做操作可能導(dǎo)致大量的鍵值對存儲到文件中,根據(jù)gc的策略,下一次執(zhí)行compact的時(shí)候才會回首老的版本。
1.4 Delete
關(guān)于Delete和時(shí)間維度有很多事要講。
1.4.1 GC(垃圾收集)
HBase有兩種方式回收舊的版本
1. 可以設(shè)置最多可以保留的版本數(shù)量。如果超過,則最老的版本會被拋棄,默認(rèn)設(shè)置是3個(gè)版本,這個(gè)可以在創(chuàng)建Column Family時(shí)通過HColumnDescriptor.setMaxVersions(int versions)設(shè)置,因此這個(gè)是Column Family級別的。當(dāng)然這個(gè)限制中讀取的時(shí)候是邏輯限制,即時(shí)生效,但老版本的物理刪除還是需要等到major compact操作中執(zhí)行。將這個(gè)值設(shè)置為1并不是說就禁用了多版本,每次Put的時(shí)候還是同樣的會生成新的版本,只是最后只保留一個(gè)版本而已。
2. 可以設(shè)置TTL(Time To Live),如果版本存在的時(shí)間超過TTL,則會被刪除。默認(rèn)的TTL是forever。通過 HColumnDescriptor.setTimeToLive(int seconds)可以設(shè)置TTL,物理清除版本還是要等到major compact,但Get/Scan等讀取操作邏輯是即時(shí)生效的。需要注意的是,如果row中所有的cell都被TTL失效以后,這一行記錄就被刪除了 (HBase中不需要顯示的建立或者刪除行,如果行中的cell有值,行就存在)。
對于上面的兩種回收方式,會有一種有趣的場景,假設(shè)你對一個(gè)cell插入了三個(gè)版本t1,t2,t3,而最大版本數(shù)設(shè)置是2,這時(shí)候請求所有版本, 則只有t2和t3會返回,這是正常的。但這時(shí)如果刪除t2或者t3,再請求所有版本,則t1可能又會出現(xiàn)在結(jié)果中了。當(dāng)然,在major compact操作之后,就不會有這個(gè)問題了。因此major compact并不是對用戶透明的操作,可能會影響用戶的查詢結(jié)果。
1.4.2 Manule delete
中HBase中執(zhí)行delete操作時(shí),有兩種方式可以刪除某個(gè)特定的版本
1. 刪除某個(gè)timestamp之前的所有老版本
2. 刪除某個(gè)timstamp點(diǎn)的版本
delete操作可以針對row,column family,或者column,只有最后一種情況下可以刪除某個(gè)timestamp點(diǎn)的版本。而針對row和column family的delete,則只能刪除某個(gè)timestamp之前的所有版本。
舉個(gè)例子,假設(shè)我們要刪除一整行數(shù)據(jù),你可以指定timestamp,或者使用currentTimeMillis,那“刪除某個(gè) timestamp之前的所有老版本”意味著什么呢?HBase并不會去修改原有數(shù)據(jù),因此刪除不是立即在原數(shù)據(jù)對應(yīng)的文件中執(zhí)行物理刪除或者物理標(biāo)記刪 除,而是將刪除的記錄保存中所謂的tombstone中,當(dāng)HBase執(zhí)行major compact的時(shí)候,再根據(jù)tombstone去執(zhí)行物理刪除。
如果你指定的timestamp比row中最新的版本大,則相當(dāng)于刪除了整行數(shù)據(jù)。
2. 使用timestamp
從上面的描述可以看到,時(shí)間維度主要是用戶多版本的,但你也可以在應(yīng)用中把它當(dāng)作column外的另外一個(gè)維度來使用,不同的是它的key是長整數(shù)型,目前這種方式還存在一些bug,因此還不是很推薦。
在jira中,有兩個(gè)和時(shí)間維度有關(guān)的bug值得比較有意思
1. 利用時(shí)間維度多版本實(shí)現(xiàn)HBase多數(shù)據(jù)中心復(fù)制,參看HBASE-1295 (PDF附件的第四頁) 或者這個(gè)郵件。
2. HBASE-2406的一個(gè)評論提到,如果要在多個(gè)表中獲得一致性數(shù)據(jù)(如二級索引表),可以通過向多個(gè)表寫入相同的timestamp版本來實(shí)現(xiàn)。
3. 限制
由于一些bug或者“不可預(yù)期的行為”,時(shí)間維度目前還有一些問題需要解決。
1. HBASE-1485 和HBASE-2406中 提到的覆寫已經(jīng)存在的timetamp版本的值的問題(在0.90版本中已經(jīng)解決),換句話說,根據(jù){row key ,column key, timestamp}修改某個(gè)cell的值,實(shí)際會產(chǎn)生一個(gè)新的鍵值對,對于HBase來說就會存在兩個(gè)相同timestamp的key,判斷最大 timestamp版本就會有問題。當(dāng)然,通過HBASE-2649中提到的寫入到HFile的時(shí)間序可以解決這個(gè)問題。
2. HBASE-2256中 提到的delete覆蓋put(即使put操作發(fā)生在delete之后)的問題。由于delete只是記錄tombstone,物理刪除需要等到 major compact操作,因此有一種情況,你刪除了所有<=T的版數(shù)據(jù),然后又put了一條<=T的數(shù)據(jù),還是會被tombstone標(biāo)記為刪 除。當(dāng)然,如果你使用的是遞增的timestamp不會有這個(gè)問題,但如果使用系統(tǒng)時(shí)間,而delete和put間隔時(shí)間非常短,還是有一定幾率兩個(gè)操作 的timestamp是相同的,這時(shí)候杯具依然會存在。
?
http://hbase.info/2011/07/20/hbase-time-dimension??
轉(zhuǎn)載于:https://www.cnblogs.com/JemBai/archive/2012/07/21/2602439.html
總結(jié)
以上是生活随笔為你收集整理的HBase中的时间维度的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 很多人都不知道,其实博客园给我们博客开了
- 下一篇: iftop 查看你的网卡流量