HBase版本

2018-03-13 13:39 更新

在 HBase 中,一個(gè){row,column,version}元組精確指定了一個(gè) cell??赡苡袩o限數(shù)量的單元格,其中行和列是相同的,但單元格地址僅在其版本維度上有所不同。

雖然行和列鍵以字節(jié)表示,但版本是使用長整數(shù)指定的。通常,這個(gè)long包含時(shí)間實(shí)例,如由java.util.Date.getTime() 或者 System.currentTimeMillis() 返回的時(shí)間實(shí)例,即:1970年1月1日UTC的當(dāng)前時(shí)間和午夜之間的差值(以毫秒為單位)。

HBase 版本維度按遞減順序存儲(chǔ),因此從存儲(chǔ)文件讀取時(shí),會(huì)先查找最新的值。

在 HBase 中,cell 版本的語義有很多混淆。尤其是:

  • 如果對(duì)一個(gè)單元的多次寫入具有相同的版本,則只有最后一次寫入是可以讀取的。
  • 以非遞增版本順序編寫單元格是可以的。

下面我們描述 HBase 當(dāng)前的版本維度是如何工作的。HBase 中的彎曲時(shí)間使得 HBase 中的版本或時(shí)間維度得到很好的閱讀。它在版本控制方面的細(xì)節(jié)比這里提供的更多。

在撰寫本文時(shí),文章中提到的限制覆蓋現(xiàn)有時(shí)間戳的值不再適用于HBase。本節(jié)基本上是 Bruno Dumon 撰寫的文章的簡介。

指定要存儲(chǔ)的HBase版本數(shù)量

為給定列存儲(chǔ)的最大版本數(shù)是列架構(gòu)的一部分,并在創(chuàng)建表時(shí)通過 alter 命令 HColumnDescriptor.DEFAULT_VERSIONS 指定 。在 HBase 0.96 之前,保留的版本的默認(rèn)數(shù)量是3,但在 0.96 以及新版本中已更改為1。 

示例 - 修改一個(gè)列族的最大版本數(shù)量

本示例使用HBase Shell來保留列族中所有列的最多5個(gè)版本f1。你也可以使用HColumnDescriptor。

hbase> alter ‘t1′, NAME => ‘f1′, VERSIONS => 5

示例 - 修改列族的最小版本數(shù)

您還可以指定每列家族存儲(chǔ)的最低版本數(shù)。默認(rèn)情況下,它被設(shè)置為0,這意味著該功能被禁用。下面的示例通過 HBase Shell 將在列族 f1 中的所有列的最小版本數(shù)設(shè)置為2。你也可以使用 HColumnDescriptor。

hbase> alter't1',NAME =>'f1',MIN_VERSIONS => 2

從 HBase 0.98.2 開始,您可以通過在 hbase-site.xml 中設(shè)置 hbase.column.max.version 為所有新創(chuàng)建列保留的最大版本數(shù)指定一個(gè)全局默認(rèn)值。

版本和 HBase 操作

在下面的內(nèi)容中,我們將了解每個(gè)核心 HBase 操作的版本維度的行為。

獲取/掃描(Get/Scan)

獲取在 Scans 之上實(shí)現(xiàn)。以下關(guān)于 Get 的討論同樣適用于 Scans。

默認(rèn)情況下,即如果你沒有指定明確的版本,則在執(zhí)行“get”操作時(shí),會(huì)返回其版本值最大的單元格(可能是也可能不是最新版本,請(qǐng)參閱后面的內(nèi)容)。默認(rèn)行為可以通過以下方式進(jìn)行修改:

  • 要返回多個(gè)版本,請(qǐng)參閱 Get.setMaxVersions()
  • 要返回除最新版本以外的其他版本,請(qǐng)參閱 Get.setTimeRange(),要檢索小于或等于給定值的最新版本,從而在某個(gè)時(shí)間點(diǎn)給出記錄的“最新”狀態(tài),只需使用從0到所需版本的范圍,并將最大版本設(shè)置為1 。

默認(rèn)獲取示例

以下獲取將只檢索行的當(dāng)前版本:

public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Get get = new Get(Bytes.toBytes("row1"));
Result r = table.get(get);
byte[] b = r.getValue(CF, ATTR);  // returns current version of value

版本化獲取示例

以下 Get 將返回該行的最后3個(gè)版本。

public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Get get = new Get(Bytes.toBytes("row1"));
get.setMaxVersions(3);  // will return last 3 versions of row
Result r = table.get(get);
byte[] b = r.getValue(CF, ATTR);  // returns current version of value
List<KeyValue> kv = r.getColumn(CF, ATTR);  // returns all versions of this column

Put(寫)

在某個(gè)時(shí)間戳處進(jìn)行Put(寫)操作總是會(huì)創(chuàng)建一個(gè)新版本的 cell。默認(rèn)情況下,系統(tǒng)使用服務(wù)器的 currentTimeMillis,但您可以在每列級(jí)別上自己指定版本(等于長整數(shù))。這意味著您可以分配過去或未來的時(shí)間,或?qū)㈤L時(shí)間值用于非時(shí)間目的。

要覆蓋現(xiàn)有值,請(qǐng)執(zhí)行與要覆蓋的單元格中的行、列和版本完全相同的 put。

隱式版本示例:

HBase 會(huì)在當(dāng)前時(shí)間隱式地對(duì)以下 Put 進(jìn)行版本管理。

public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Put put = new Put(Bytes.toBytes(row));
put.add(CF, ATTR, Bytes.toBytes( data));
table.put(put);

顯示版本示例:

以下 Put 具有明確設(shè)置的版本時(shí)間戳。

public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Put put = new Put( Bytes.toBytes(row));
long explicitTimeInMs = 555;  // just an example
put.add(CF, ATTR, explicitTimeInMs, Bytes.toBytes(data));
table.put(put);

注意:版本時(shí)間戳由 HBase 內(nèi)部使用,用于諸如生存時(shí)間計(jì)算之類的事情。通常最好避免自己設(shè)置時(shí)間戳。優(yōu)先使用該行的單獨(dú)時(shí)間戳屬性,或者將時(shí)間戳記作為行鍵的一部分,或者同時(shí)使用兩者。

刪除(delete)

有三種不同類型的內(nèi)部刪除標(biāo)記。并添加另一個(gè)掃描 HBase:Prefix Delete Marker。

  • 刪除(Delete):針對(duì)特定版本的列。
  • 刪除列(Delete column):適用于所有版本的列。
  • 刪除系列(Delete family):針對(duì)特定 ColumnFamily 的所有列

當(dāng)刪除整行時(shí),HBase 將在內(nèi)部為每個(gè) ColumnFamily(即不是每個(gè)單獨(dú)的列)創(chuàng)建一個(gè)邏輯刪除。

通過創(chuàng)建 tombstone 標(biāo)記來刪除作品。例如,假設(shè)我們想要?jiǎng)h除一行。為此,您可以指定一個(gè)版本,或者默認(rèn)情況下使用該 currentTimeMillis。這意味著刪除版本小于或等于此版本的所有單元格。HBase 從不修改數(shù)據(jù),例如刪除不會(huì)立即刪除(或標(biāo)記為已刪除)存儲(chǔ)文件中對(duì)應(yīng)于刪除條件的條目。相反,所謂的 tombstone 被寫入,這將掩蓋已刪除的值。當(dāng) HBase 進(jìn)行重大壓縮時(shí),tombstone 將被處理以實(shí)際移除不能用的值以及 tombstone 本身。如果您在刪除行時(shí)指定的版本大于行中任何值的版本,則可以考慮刪除整行。

除非在列族中設(shè)置了 KEEP_DELETED_CELLS 選項(xiàng),否則刪除標(biāo)記在存儲(chǔ)區(qū)的下一個(gè)主要壓縮過程中被清除。如果要將刪除保留為可配置的時(shí)間量,可以通過hbase-site.xml 中的 hbase.hstore.time.to.purge.deletes 屬性設(shè)置刪除 TTL 。如果 hbase.hstore.time.to.purge.deletes 未設(shè)置或設(shè)置為 0,則將在下一次主要壓縮過程中清除所有刪除標(biāo)記,包括將來使用時(shí)間戳的標(biāo)記。否則,將保留在將來具有時(shí)間戳的刪除標(biāo)記,直到在由標(biāo)記時(shí)間戳表示的時(shí)間加上hbase.hstore.time.to.purge.deletes 的值(以毫秒為單位)之后發(fā)生的主要壓縮為止。

HBase-2.0.0中的可選新版本和刪除行為

在 hbase-2.0.0 中,操作員可以通過將列描述符屬性 NEW_VERSION_BEHAVIOR 設(shè)置為 true 來指定備用版本和刪除處理(若要在列族描述符上設(shè)置屬性,您必須首先禁用表,然后改變列族描述符)。

“新版本行為”解除了以下列出的局限性,取消了以下所列的限制,即如果在同一位置,Delete 總是會(huì)超過一個(gè)Put(即相同的行,列族,限定符和時(shí)間戳),而不管哪一個(gè)先到達(dá)。版本記帳也會(huì)因?yàn)閯h除版本考慮到版本總數(shù)而發(fā)生變化。這是為了確保在重大壓縮情況下不會(huì)改變結(jié)果。

運(yùn)行這個(gè)新配置目前的成本;我們將每個(gè)比較的 Cell MVCC 因素考慮在內(nèi),因此我們消耗更多的 CPU,這是減速所取決于的,在測(cè)試中,我們已經(jīng)看到0%到25%的降級(jí)。

如果正在復(fù)制,建議您使用新的串行復(fù)制功能運(yùn)行,因?yàn)楝F(xiàn)在突變到達(dá)的順序是因子。

HBase目前的局限性

以下限制在 hbase-2.0.0 中解決。請(qǐng)參閱上面的“HBase-2.0.0 中的可選新版本和刪除行為”部分。

刪除標(biāo)記Put

刪除掩碼放入,甚至在輸入刪除后發(fā)生。請(qǐng)記住,刪除操作會(huì)寫入邏輯刪除,只有在下一次主要壓縮運(yùn)行后才會(huì)消失。假設(shè)你刪除了所有的? T 的內(nèi)容,然后你做了一個(gè)帶有時(shí)間戳 ? T 的新放。這種情況下,即使在刪除后發(fā)生,也會(huì)被刪除 tombstone 屏蔽。執(zhí)行投入不會(huì)失敗,但是當(dāng)你做出投注時(shí),你會(huì)注意到投注沒有任何效果。重大壓縮后,它將再次開始工作。如果您使用不斷增加的版本進(jìn)行新的放置,則這些問題不應(yīng)該是一個(gè)問題。但即使您不在乎時(shí)間,也可能發(fā)生這種情況:只需刪除并立即放置在對(duì)方之后,并且有可能在同一毫秒內(nèi)發(fā)生。

主要的壓縮改變了查詢結(jié)果

在 t1,t2 和 t3 中創(chuàng)建三個(gè)單元格版本,最大版本設(shè)置為 2。因此,獲取所有版本時(shí),只會(huì)返回 t2 和 t3 的值。但是如果在 t2 或 t3 刪除版本,則 t1 中的版本將再次出現(xiàn)。顯然,一旦主要的壓實(shí)運(yùn)行后,這種行為將不會(huì)是這樣了。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)