HBase 模式定義 (Schema Definition)

在 HBase 中創建一個表包括表模式(table schema)的定義, 以及所包含的列族的模式(schemas for all contained column families). 它們定義瞭如何,
以及何時存儲表和列的數據。在更高級別上,每個表是一個名稱空間(namespace)的一部分。


1.1 名稱空間 (Namespaces)
-----------------------------------------------------------------------------------------------------------------------------------------
名稱空間在 HBase 0.96 版本引入,它的引入是爲了解決 HBase 中組織多個表的問題。在這個特性引入之前,所有表構成一個扁平的列表,包括系統目錄表
(system catalog tables). 這在擴展,特別是當有幾百個表時非常難於管理。利用名稱空間可以將多個表按組組織,使相關的表可以一起處理。除此之外,
名稱空間可以更進一步抽象類屬概念,例如安全性。可以在 namespace 級別定義訪問控制,以在所有包含的表上快速應用規則。

HBase 在啓動時創建兩個 namespace: default 和 hbase. hbase 是爲系統目錄表使用的,用戶不能在此名稱空間內創建用戶表。

使用 shell 可以列出 namespace 及其包含的內容:

    hbase(main):001:0> list_namespace
    NAMESPACE
    default
    hbase
    2 row(s) in 0.0090 seconds

    hbase(main):002:0> list_namespace_tables 'hbase'
    TABLE
    foobar
    meta
    namespace
    3 row(s) in 0.0120 seconds

所有未指定名稱空間的表都放到 default 名稱空間內。因此在創建表時不必一定指定一個名稱空間,它會被加入到 default 名稱空間內。

通過下面的 shell 操作看看發生的變化:

    hbase(main):001:0> list_namespace_tables 'default'
    TABLE
    0 row(s) in 0.0170 seconds

    hbase(main):002:0> create 'testtable', 'colfam1'
    0 row(s) in 0.1650 seconds
    => Hbase::Table - testtable

    hbase(main):003:0> list_namespace_tables 'default'
    TABLE
    testtable
    1 row(s) in 0.0130 seconds

新表(testtable) 被創建並加入到了 default 名稱空間中。

因爲 namespace 將表分組管理, namespace 名稱成爲一個表定義固定的一部分,因此可以在不同的 namespace 中可以隨意創建具有相同名稱的表。

    hbase(main):001:0> create_namespace 'booktest'
    0 row(s) in 0.0970 seconds
    
    hbase(main):002:0> create 'booktest:testtable', 'colfam1'
    0 row(s) in 0.1560 seconds
    => Hbase::Table - booktest:testtable
    
    hbase(main):003:0> create_namespace 'devtest'
    0 row(s) in 0.0140 seconds
    
    hbase(main):004:0> create 'devtest:testtable', 'colfam1'
    0 row(s) in 0.1490 seconds
    => Hbase::Table - devtest:testtable

在代碼中處理名稱空間,圍繞着 NamespaceDescriptor 類,使用下面方法構建 Builder:

    static Builder create(String name)
    static Builder create(NamespaceDescriptor ns)

可以爲新實例手動輸入一個名稱字符串,或者傳入一個已存在的 NamespaceDescriptor 實例,方法會從該實例中複製配置信息創建新實例。返回的 Builder
實例可以更進一步添加配置信息到這個新名稱空間,構成最終的實例。

示例: Example how to create a NamespaceDescriptor in code

    NamespaceDescriptor.Builder builder = NamespaceDescriptor.create("testspace");
    builder.addConfiguration("key1", "value1");
    NamespaceDescriptor desc = builder.build();
    System.out.println("Namespace: " + desc);

輸出結果:

    Namespace: {NAME => 'testspace', key1 => 'value1'}

NamespaceDescriptor 類還有幾個方法:

    String getName()
    String getConfigurationValue(String key)
    Map<String, String> getConfiguration()
    void setConfiguration(String key, String value)
    void removeConfiguration(final String key)
    String toString()

詳細信息查閱 API 文檔


1.2 表 (Tables)
-----------------------------------------------------------------------------------------------------------------------------------------
在 HBase 中的數據最終會存儲到一個或多個表中,使用表的主要原因是控制表中的所有列共享表內某些特性。定義一個表最典型的工作是爲其定義列族(
column families)。表描述符在 Java 中的構造器如下:

    HTableDescriptor(final TableName name)
    HTableDescriptor(HTableDescriptor desc)

使用一個名稱或一個已存在的描述符創建表描述符實例。必須使用 TableName 類實例指定表名稱,這允許指定表的名稱,以及可選的 namespace 作爲表名。
在使用已存在的描述符作爲參數構造時,構造器從該實例中複製所有的設置和狀態創建一個新的實例。

創建表名的字符有一定的限制。表名用於實際存儲文件路徑的一部分,因此它必須遵循文件名規則。TableName 類強制這些規則。

示例: Example how to create a TableName in code

private static void print(String tablename) {
    print(null, tablename);
}

private static void print(String namespace, String tablename) {
    
    System.out.print("Given Namespace: " + namespace + ", Tablename: " + tablename + " -> ");
    
    try {
        System.out.println(namespace != null ?     TableName.valueOf(namespace, tablename) : TableName.valueOf(tablename));
    } catch (Exception e) {
        System.out.println(e.getClass().getSimpleName() +     ": " + e.getMessage());
    }
}

public static void main(String[] args) throws IOException, InterruptedException
{
    print("testtable");
    print("testspace:testtable");
    print("testspace", "testtable");
    print("testspace", "te_st-ta.ble");
    print("", "TestTable-100");
    print("tEsTsPaCe", "te_st-table");
    print("");
    // VALID_NAMESPACE_REGEX = "(?:[a-zA-Z_0-9]+)";
    // VALID_TABLE_QUALIFIER_REGEX = "(?:[a-zA-Z_0-9][a-zAZ_
    0-9-.]*)";
    print(".testtable");
    print("te_st-space", "te_st-table");
    print("tEsTsPaCe", "te_st-table@dev");
}

輸出結果:
    Given Namespace: null, Tablename: testtable -> testtable
    Given Namespace: null, Tablename: testspace:testtable -> testspace:    testtable
    Given Namespace: testspace, Tablename: testtable -> testspace:testtable
    Given Namespace: testspace, Tablename: te_st-ta.ble ->    testspace:te_st-ta.ble
    Given Namespace: , Tablename: TestTable-100 -> TestTable-100
    Given Namespace: tEsTsPaCe, Tablename: te_st-table ->tEsTsPaCe:te_st-table
    Given Namespace: null, Tablename: -> IllegalArgumentException:Table qualifier must not be empty
    Given Namespace: null, Tablename: .testtable ->    IllegalArgumentException: Illegal first character at 0.
    User-space table qualifiers can only start with 'alphanumeric
    characters':
    i.e. [a-zA-Z_0-9]: .testtable
    Given Namespace: te_st-space, Tablename: te_st-table -> IllegalArgumentException: Illegal character at 5. Namespaces can
    only contain 'alphanumeric characters': i.e. [a-zA-Z_0-9]: te_stspace
    Given Namespace: tEsTsPaCe, Tablename: te_st-table@dev ->
    IllegalArgumentException: Illegal character code:64, <@> at 11. User-space
    table qualifiers can only contain 'alphanumeric characters':
    i.e. [a-zA-Z_0-9-.]: te_st-table@dev

雖然,在概念上,HBase 中的一個表是行與列的集合,但在物理上,它們被存儲在不同的分區上,稱爲 region. 每個 region 只在一個 region server
上提供服務,因而 region 會將存儲的值直接提供給客戶端。

 

1.2.1 序列化 (Serialization)
-----------------------------------------------------------------------------------------------------------------------------------------
很多客戶端 API 類都有如下方法:

    byte[] toByteArray()
    static HTableDescriptor parseFrom(final byte[] bytes)
    TableSchema convert()
    static HTableDescriptor convert(final TableSchema ts)

每個遠程系統間的通信都是使用 RPC framework 完成的。它利用 Google 的 Protocol Buffer (或簡寫 Protobuf) 庫實現序列化和反序列化對象。
以上方法由 framework 調用以將數據寫入到 output stream, 然後由接收系統讀回。爲此,framework 在發送端調用 toByteArray() 序列化對象的字段,
framework 精心維護類名和其它細節信息。返回值爲 HTableDescriptor 的 convert() 方法用於將整個實例轉換爲 Protobuf 類。

在接收端,framework 讀取 metadata, 並通過靜態方法 parseFrom() 使用匹配的類創建類實例,這會讀回字段數據並初始化發送對象的副本。使用匹配的
convert() 調用實現,得到一個 Protobuf 對象而不是底層的字節數組。

 
1.2.2 The RegionLocator Class
-----------------------------------------------------------------------------------------------------------------------------------------
RegionLocator 類提供了一些方法,這些方法總是運行在特定表的上下文中(always runs in a context of a specific table):

    public HRegionLocation getRegionLocation(final byte[] row) throws IOException
    public HRegionLocation getRegionLocation(final byte[] row, boolean reload) throws IOException
    public List<HRegionLocation> getAllRegionLocations() throws IOException

    public byte[][] getStartKeys() throws IOException
    public byte[][] getEndKeys() throws IOException
    public Pair<byte[][], byte[][]> getStartEndKeys() throws IOException

    TableName getName()

基本構建塊與 Table 用法相同,從共享的連接接收一個實例,該連接指定了要處理的表,並且一旦工作完成,可以通過調用 close() 方法釋放資源:

    Configuration conf = HBaseConfiguration.create();
    Connection connection = ConnectionFactory.createConnection(conf);
    TableName tn = TableName.valueOf(tableName);
    RegionLocator locator = connection.getRegionLocator(tn);
    Pair<byte[][], byte[][]> pair = locator.getStartEndKeys();
    ...
    locator.close();

region 由包含的起始鍵(start key inclusive),但不包含的結束鍵(end key exclusive)設定。

RegionLocator 可用於訪問 region 細節信息,例如存儲該 region 的服務器,或者與之相關聯的 HRegionInfo 對象:

    HRegionInfo getRegionInfo()
    String getHostname()
    int getPort()
    String getHostnamePort()
    ServerName getServerName()
    long getSeqNum()
    String toString()

    
1.2.3 服務器和 region 名稱 (Server Names and Region Names)
-----------------------------------------------------------------------------------------------------------------------------------------
有兩個基本信息需要準確介紹:服務器和 region 名稱(the server name and region name). 它們出現在很多地方,如 HBase shell, web-based UI, 以及
系統管理和客戶端 API. 有時候它們表現爲人類可讀的形式,包括編碼不可打印字符爲代碼點。有時它們通過方法返回,如 HRegionInfo 的getServerName()
或 getRegionNameAsString(), 或者作爲系統管理 API 方法要求的輸入參數。

下面示例創建了一個表,並且定位到包含行 Foo 的 region. 一旦獲取到 region, 打印出服務器名稱和 region 名稱。

示例: Shows the use of server and region names

    TableName tableName = TableName.valueOf("testtable");
    HColumnDescriptor coldef1 = new HColumnDescriptor("colfam1");
    HTableDescriptor desc = new HTableDescriptor(tableName)
        .addFamily(coldef1)
        .setValue("Description", "Chapter 5 - ServerAndRegionNameExample");
    
    byte[][] regions = new byte[][] { Bytes.toBytes("ABC"),
        Bytes.toBytes("DEF"), Bytes.toBytes("GHI"), Bytes.toBytes("KLM"),
        Bytes.toBytes("OPQ"), Bytes.toBytes("TUV")
        };
        
    admin.createTable(desc, regions);
    RegionLocator locator = connection.getRegionLocator(tableName);
    HRegionLocation location = locator.getRegionLocation(Bytes.toBytes("Foo"));
    HRegionInfo info = location.getRegionInfo();
    System.out.println("Region Name: " + info.getRegionNameAsString());
    System.out.println("Server Name: " + location.getServerName());

輸出結果類似:
    Region Name: testtable,DEF,1428681822728.acdd15c7050ec597b484b30b7c744a93.
    Server Name: srv1.foobar.com,63360,1428669931467

region name:
    聯合 table 和 region 信息(start key, 以及 region 的創建時間),加上一個可選的名稱前綴的 MD5 哈希值,由(.) 包圍起來:
    
        <table name>,<region start key>,<region creation time>[.<md5hash(prefix)>.]

    在例子中 "acdd15c7050ec597b484b30b7c744a93" 是 "testtable,DEF,1428681822728" 的 MD5 哈希值。HRegionInfo 的 getEncodedName() 方法返回的
    僅僅是這個哈希值,而不是可讀的前綴。
    
    這個哈希值本身用於系統在存儲層內創建底層文件結構。例如,列出 HBase 存儲目錄內容時會看到例子中的 region 哈希值,在存儲路徑中:
    
    $ bin/hdfs dfs -ls -R /hbase
    drwxr-xr-x - larsgeorge supergroup 0 2015-04-10 18:03 /hbase/data/default/testtable/acdd15c7050ec597b484b30b7c744a93/colfam1

    region creation timestamp 在一個 region 創建時產生,例如,當一個表創建時,或者一個存在的 region 拆分時。
    
server name:
    也是幾個不同部分的組合,包括主機名稱:
    
        <host name>,<RPC port>,<server start time>
    
    server start time 用於處理在同一物理機器上多個進程。
    
    ServerName 類將細節封裝到一個方便的結構中。有些 API 調用要求接收該類的一個實例,可以直接創建該類的實例,但實踐方法是通過 API 獲取一個
    存在的實例,例如,使用 getServerName() 方法。

 

1.3 表屬性 (Table Properties)
-----------------------------------------------------------------------------------------------------------------------------------------
表描述符提供了 getter 和 setter 來設置表的很多選項。由於可以通過這些選項調節表的性能,因此瞭解它們很重要。按選項影響的屬性將這些方法分組
討論:

    ● 表名 (Name)
    -------------------------------------------------------------------------------------------------------------------------------------    
    構造器已經有了指定 table name 的參數,Java API 有另外的方法可以訪問表的名稱:

        TableName getTableName()
        String getNameAsString()    

    這兩個方法返回表的名稱。

    ● 列族 (Column Families)
    -------------------------------------------------------------------------------------------------------------------------------------
    這是一個表定義最重要的部分。創建表時需要指定想要使用的列族(column families):

        HTableDescriptor addFamily(final HColumnDescriptor family)
        HTableDescriptor modifyFamily(final HColumnDescriptor family)
        HColumnDescriptor removeFamily(final byte[] column)
        HColumnDescriptor getFamily(final byte[] column)
        boolean hasFamily(final byte[] familyName)
        Set<byte[]> getFamiliesKeys()
        HColumnDescriptor[] getColumnFamilies()
        Collection<HColumnDescriptor> getFamilies()

    可以添加列族,修改列族,檢查其是否存在,獲取所有列族的列表,以及獲取或移除一個列族。


    ● 最大文件大小 (Maximum File Size)
    -------------------------------------------------------------------------------------------------------------------------------------
    這個參數限制了表中 region 可以增長的大小。文件大小由字節單位設置,通過如下方法讀取和這種:
    
        long getMaxFileSize()
        HTableDescriptor setMaxFileSize(long maxFileSize)

    最大文件大小在 region 增長到配置的限制時幫助切分 region. 在 HBase 中,擴展和負載均衡單元就是 region. 因此用戶需要確定設置這個值爲多少
    合適。默認情況下,該值設爲 10 GB(實際的值爲 10737418240, 因爲以字節爲單位,這個值在默認配置文件的 hbase.hregion.max.filesize 屬性設置)
    這個值對於大多數場景都是合適的。
        

    ● Memstore 刷寫大小 (Memstore Flush Size)
    -------------------------------------------------------------------------------------------------------------------------------------
    之前討論過存儲模型,並指出 HBase 利用一個 in-memory 存儲來緩存數據,在某個操作中將數據作爲一個新的存儲文件寫入磁盤,這個過程稱爲刷寫(
    flush). 這個參數用於控制何時進行刷寫操作,單位爲字節。通過如下方法控制:
    
        long getMemStoreFlushSize()
        HTableDescriptor setMemStoreFlushSize(long memstoreFlushSize)

    默認值爲 128 MB(默認配置文件中,由屬性 hbase.hregion.memstore.flush.size 設置爲 134217728 bytes)。


    ● Memstore 刷寫大小 (Compactions)
    -------------------------------------------------------------------------------------------------------------------------------------
    可以設置每個表的底層存儲文件是否將壓縮作爲自動處理的一部分。利用如下方法設置和讀取該標記:
    
        boolean isCompactionEnabled()
        HTableDescriptor setCompactionEnabled(final boolean isEnable)


    ● 拆分策略 (Split Policy)
    -------------------------------------------------------------------------------------------------------------------------------------
    除了設置 maximum file size ,還可以進一步影響 region 拆分。使用如下方法設置一個不同的拆分策略類,會覆蓋系統範圍設定的拆分策略,該策略由
    默認配置文件的 hbase.regionserver.region.split.policy 屬性設置:
    
        HTableDescriptor setRegionSplitPolicyClassName(String clazz)
        String getRegionSplitPolicyClassName()


    ● Region 複本數 (Region Replicas)
    -------------------------------------------------------------------------------------------------------------------------------------
    爲表設置 region 複本數。默認爲 1,意爲着只有一個主 region. 例如,將該屬性設置爲 2,會爲這個表的每個 region 添加另外一個複本。由表描述
    符的如下方法控制:
    
        int getRegionReplication()
        HTableDescriptor setRegionReplication(int regionReplication)

        
    ● Durability
    -------------------------------------------------------------------------------------------------------------------------------------
    在表級別控制數據持久化 durability 方面的保證。
    通過如下方法控制:

        HTableDescriptor setDurability(Durability durability)
        Durability getDurability()


    ● 只讀 (Read-only)
    -------------------------------------------------------------------------------------------------------------------------------------
    默認情況下,所有表都是可寫的(writable), 但將某個特殊表設定爲只讀選項有時是有意義的。如果該參數設爲 true, 只能從這個表中讀取數據而不能
    修改它。
    
    通過如下方法控制:
        
        boolean isReadOnly()
        HTableDescriptor setReadOnly(final boolean readOnly)


    ● 協處理器 (Coprocessors)
    -------------------------------------------------------------------------------------------------------------------------------------
    下面列出可以爲表配置協處理器的方法調用。這些方法可以在當前表描述符實例上添加、檢查、列出、以及移除協處理器的方法:

        HTableDescriptor addCoprocessor(String className) throws IOException
        HTableDescriptor addCoprocessor(String className, Path jarFilePath, int priority, final Map<String, String> kvs) throws IOException
        boolean hasCoprocessor(String className)
        List<String> getCoprocessors()
        void removeCoprocessor(String className)

        
    ● 描述符參數 (Descriptor Parameters)
    -------------------------------------------------------------------------------------------------------------------------------------
    如下方法可用於設置任意的 key/value 對:
    
        byte[] getValue(byte[] key)
        String getValue(String key)
        Map<ImmutableBytesWritable,ImmutableBytesWritable> getValues()
        HTableDescriptor setValue(byte[] key, byte[] value)
        HTableDescriptor setValue(final ImmutableBytesWritable key, final ImmutableBytesWritable value)
        HTableDescriptor setValue(String key, String value)
        void remove(final String key)
        void remove(ImmutableBytesWritable key)
        void remove(final byte[] key)


    ● 配置 (Configuration)
    -------------------------------------------------------------------------------------------------------------------------------------
    允許用戶在每個表的基礎上,覆蓋任何 HBase 配置屬性。在運行時它會與默認值,以及集羣範圍的配置文件合併。注意只有與 region 和 table 相關的
    屬性設置有用。其它不相關的屬性不會起作用,即便覆蓋了它們。

        String getConfigurationValue(String key)
        Map<String, String> getConfiguration()
        HTableDescriptor setConfiguration(String key, String value)
        void removeConfiguration(final String key)


    ● 雜項調用 (Miscellaneous Calls)
    -------------------------------------------------------------------------------------------------------------------------------------
        boolean isRootRegion()
        boolean isMetaRegion()
        boolean isMetaTable()
        
        String toString()
        String toStringCustomizedValues()
        String toStringTableAttributes()    


1.4 列族 (Column Families)
-----------------------------------------------------------------------------------------------------------------------------------------
我們已經看到 HTableDescriptor 類提供的方法向一個表中添加列族。與此相關,HColumnDescriptor 類封裝了每個列族的設置。

    NOTE
    -------------------------------------------------------------------------------------------------------------------------------------
    在 Java 中這個類的名稱有點兒詞不達意。更適合的名稱應該爲 HColumnFamilyDescriptor, 這樣才能給表達定義列族屬性的真正含義。

列族定義了在其中創建的所有列的公共特徵。客戶端通過列限定符(column qualifier)可以在其中創建任意數量的列。定位某一列可以聯合列族名稱和列限
定符(有時也稱爲 column key),其間由冒號(:)分隔:

    `family:qualifier`

列族名稱必須是由可打印字符組成,並且不能以冒號(:)開始,或者完全爲空。列限定符(column qualifier) 可以由任意的二進制字節組成。回顧之前提到
過的 Bytes 類,可以利用它將選擇的名稱轉換爲字節數組。列族名稱必須是由可打印字符組成的原因是,這個名稱會用作低級存儲層目錄的一部分。列族名
被加入到路徑中,並且必須遵循文件名規範。

也需要對空列限定符(empty column qualifier)有所瞭解。可以簡單地忽略限定符而只適應列族名,HBase 使用特殊的空限定符創建該列。用戶可以讀寫這
個列,就像其它列一樣,但很明顯,一個列族內只能有一個這樣的列,必須給其它列命名以與該列區別。對於簡單的應用,使用沒有限定符是一種選擇,但
在查看數據時沒什麼意義,例如,使用 HBase shell.

應該在一開始時就給列命名,因爲不能在之後簡單地重命名列限定符。

使用 HBase Shell, 嘗試創建一個沒有名稱的列:

    hbase(main):001:0> create 'testtable', 'colfam1'
    0 row(s) in 0.1400 seconds

    => Hbase::Table - testtable
    hbase(main):002:0> put 'testtable', 'row1', 'colfam1:', 'val1'
    0 row(s) in 0.1130 seconds

    hbase(main):003:0> scan 'testtable'
    ROW COLUMN+CELL
    row1 column=colfam1:, timestamp=1428488894611, value=val1
    1 row(s) in 0.0590 seconds

    hbase(main):004:0> create 'testtable', 'col/fam1'

    ERROR: Illegal character <47>. Family names cannot contain control
    characters or colons: col/fam1
    Here is some help for this command:
    ...

可以使用靜態的幫助方法驗證名稱:

    static byte[] isLegalFamilyName(final byte[] b)

在自己的程序中使用該方法驗證用戶提供的輸入是否遵循名稱規範。這個方法不返回 boolean 標誌,而是在名稱非法時拋出 IllegalArgumentException
異常,如果合法,它直接返回給定的參數值。


    NOTE
    -------------------------------------------------------------------------------------------------------------------------------------
    列族不能重命名。重命名一個列族一般的方法是,使用新名創建一個新的列族,然後使用 API 將數據拷貝到新列族中去.
    
創建列族時,有多個構造器可以創建實例:

    HColumnDescriptor(final String familyName)
    HColumnDescriptor(final byte[] familyName)
    HColumnDescriptor(HColumnDescriptor desc)    
    
前兩個構造器簡單地接收 String 類型或 byte[] 數組類型的 familyName. 另外一個接收一個已存在的 HColumnDescriptor 實例,從其中拷貝所有狀態和
設置創建新實例。不通過構造器,也可以使用 getter 和 setter 來設置各種細節信息,下面按其作用分組討論:
    
    
    ● 列族名稱 (Name)
    -------------------------------------------------------------------------------------------------------------------------------------    
    每個列族都有一個名稱,並且可以使用如下方法從一個已存在的 HColumnDescriptor 實例上獲取到該名稱:
    
        byte[] getName();
        String getNameAsString();
    
    不能設置列族名稱,但可以通過構造器設定它。
    
        NOTE
        ---------------------------------------------------------------------------------------------------------------------------------
        列族名稱不能以句點(.)開始,並且不能包含冒號(:), 斜線(/), 或者 ISO 控制符。
    
    
    ● 最大版本數 (Maximum Versions)
    -------------------------------------------------------------------------------------------------------------------------------------
    對於每個列族,可以設定每個值可以保留的版本數量。HBase 的內部管理會移除超出最大版本數的數據。通過如下方法獲取或設置該值:
    
        int getMaxVersions()
        HColumnDescriptor setMaxVersions(int maxVersions)

    默認值爲 1,由 hbase.column.max.version 配置屬性設置。默認值適用於大多數應用場景。如果需要,可以增加這個數量,例如,對於存儲密碼的列,
    可以將這個值設爲 10 來保留使用過的密碼歷史。
    
    
    ● 最小版本數 (Minimum Versions)
    -------------------------------------------------------------------------------------------------------------------------------------    
    指定一個列總是保留的版本數量。這個值與 time-to-live 配合使用,避免移除列中最後存儲的值。默認值爲 0,意爲禁用該特性:
    
        int getMinVersions()
        HColumnDescriptor setMinVersions(int minVersions)
    
    
    ● 保留刪除的單元 (Keep Deleted Cells)
    -------------------------------------------------------------------------------------------------------------------------------------
    控制後臺 housekeeping 進程是否移除已刪除的 cell:
    
        KeepDeletedCells getKeepDeletedCells()
        HColumnDescriptor setKeepDeletedCells(boolean keepDeletedCells)
        HColumnDescriptor setKeepDeletedCells(KeepDeletedCells keepDeletedCells)    
    
    使用的 KeepDeletedCells 是個枚舉類型,有如下選項:
    
    The KeepDeletedCells enumeration
    +-------+--------------------------------------------------------------------------------------------------------------------------
    | Value    | Description
    +-------+--------------------------------------------------------------------------------------------------------------------------
    | FALSE    | Deleted cells are not retained.
    +-------+--------------------------------------------------------------------------------------------------------------------------
    | TRUE    | Deleted cells are retained until they are removed by other means such as time-to-live (TTL) or the max number of versions.
    |        | If no TTL is specified or no new versions of delete cells are written, they are retained forever
    +-------+--------------------------------------------------------------------------------------------------------------------------
    | TTL    | Deleted cells are retained until the delete marker expires due to TTL. This is useful when TTL is combined with the number
    |        | of minimum versions, and you want to keep a minimum number of versions around, but at the same time remove deleted cells
    |        | after the TTL.
    +-------+--------------------------------------------------------------------------------------------------------------------------
    
    默認值爲 FALSE, 意爲在 housekeeping 操作期間,不保留已刪除的 cell.
    
    
    ● 壓縮 (Compression)
    -------------------------------------------------------------------------------------------------------------------------------------    
    HBase 支持插件式壓縮算法,允許用戶爲存儲在特定列族中的數據選擇最合適的壓縮算法,或者選擇不壓縮。可用的算法列於下表:
    
    Supported compression algorithms
    +-------+-------------------------------------------------------------------------------------------
    | Value    | Description
    +-------+-------------------------------------------------------------------------------------------
    | NONE    | Disables compression (default).
    +-------+-------------------------------------------------------------------------------------------
    | GZ    | Uses the Java-supplied or native GZip compression (which needs to be installed separately).
    +-------+-------------------------------------------------------------------------------------------
    | LZO    | Enables LZO compression; must be installed separately
    +-------+-------------------------------------------------------------------------------------------
    | LZ4    | Enables LZ4 compression; must be installed separately
    +-------+-------------------------------------------------------------------------------------------
    | SNAPPY| Enables Snappy compression; binaries must be installed separately
    +-------+-------------------------------------------------------------------------------------------
    
    默認值爲 NONE, 換句話說,創建列族時沒有啓用壓縮。使用 API 和列描述符實例,可以通過如下方法改變設置:
    
        Compression.Algorithm getCompression()
        Compression.Algorithm getCompressionType()
        HColumnDescriptor setCompressionType(Compression.Algorithm type)
        
        Compression.Algorithm getCompactionCompression()
        Compression.Algorithm getCompactionCompressionType()
        HColumnDescriptor setCompactionCompressionType(Compression.Algorithm type)
    
    注意參數類型爲 Compression.Algorithm 枚舉類型,其選項爲上表所列。另外注意到的是,這裏有兩套方法,一套是常規的壓縮(general compression)
    設置,另一套是緊湊壓縮(compaction compression)設置。
    
    
    ● 編碼 (Encoding)
    -------------------------------------------------------------------------------------------------------------------------------------    
    設置數據塊的編碼。如果啓用,可以進一步影響是否使用相同的設置應用到 cell 標記(tag). 方法如下:
    
        DataBlockEncoding getDataBlockEncoding()
        HColumnDescriptor setDataBlockEncoding(DataBlockEncoding type)
    
    這兩個方法控制使用的編碼類型,使用的 DataBlockEncoding 枚舉類型包含如下選項:
    
    Options of the DataBlockEncoding enumeration
    +---------------+------------------------------------------------------------------------------------------
    | Option        | Description
    +---------------+------------------------------------------------------------------------------------------
    | NONE            | No prefix encoding takes place (default).
    +---------------+------------------------------------------------------------------------------------------
    | PREFIX        | Represents the prefix compression algorithm, which removes repeating common prefixes
    |                | from subsequent cell keys.
    +---------------+------------------------------------------------------------------------------------------
    | DIFF            | The diff algorithm, which further compresses the key of subsequent cells by storing
    |                | only differences to previous keys.
    +---------------+------------------------------------------------------------------------------------------
    | FAST_DIFF        | An optimized version of the diff encoding, which also omits repetitive cell value data
    +---------------+------------------------------------------------------------------------------------------
    | PREFIX_TREE    | Trades increased write time latencies for faster read performance. Uses a tree structure
    |                | to compress the cell key.
    +---------------+------------------------------------------------------------------------------------------
    
    除了爲每個 cell key 設置編碼之外,cell 可能會攜帶用於不同目的的標記列表(list of tags), 例如安全信息和 cell
    級別的 TTL 等。下面的方法可以設置是否將編碼屬性也應用到這些標記上:
    
        HColumnDescriptor setCompressTags(boolean compressTags)
        boolean isCompressTags()
        
    默認值爲 true, 因此所有可選的 cell 標記也作爲整個 cell 編碼的一部分編碼。
    
    
    ● 塊大小 (Block Size)
    -------------------------------------------------------------------------------------------------------------------------------------
    HBase 中,在 get() 或 scan() 操作期間,所有存儲文件都被劃分爲很小的數據塊載入,類似於 RDBMS 中的頁(page)。數據塊大小默認被設置爲 64KB
    可以通過如下方法調整:
    
        synchronized int getBlocksize()
        HColumnDescriptor setBlocksize(int s)

    該值以字節爲單位設置,用於控制在獲取數據時,要求 HBase 從存儲文件中一次讀取多少數據放入到內存中緩存起來,以用於後續的訪問。

        NOTE
        ---------------------------------------------------------------------------------------------------------------------------------
        注意,列族的數據塊大小,或者說是 HFile 塊大小,與 HDFS 級別的數據塊大小之間有着重要的區別。Hadoop 和 HDFS 使用的數據塊大小,默認
        爲 128 MB,用於拆分較大的文件以提供分佈式存儲,以便於 YARN 框架進行併發處理。對於 HBase, HFile 數據塊大小,默認爲 64 KB, 是 HDFS
        數據塊大小的 2048 分之一,是爲了在塊操作中高效加載和緩存數據,與 HDFS 塊大小不相關,並且只爲內部使用。


    ● 塊緩存 (Block Cache)
    -------------------------------------------------------------------------------------------------------------------------------------
    由於爲了高效利用 I/O, HBase 讀取整塊的數據到內存中緩存下來,這樣後續的讀取就不需要任何的磁盤操作。默認爲 true, 爲每次讀取操作啓用塊緩
    存。但如果用戶的應用場景是要順序地讀取某個列族,最好將這個屬性設置爲 false, 從而禁止其使用塊緩存。下列方法用於控制該屬性:
    
        boolean isBlockCacheEnabled()
        HColumnDescriptor setBlockCacheEnabled(boolean blockCacheEnabled)
    
    還有其它方法可用於影響塊緩存的使用,例如,在 scan() 操作時,可以通過 setCacheBlocks(false) 調用來禁用塊緩存。這在全表掃描時很有用,這
    樣就不會搞亂緩存。
    
    除了緩存本身,也可以配置系統的行爲:數據被寫入時,存儲文件要關閉或打開時,下列方法定義這些屬性:
    
        boolean isCacheDataOnWrite()
        HColumnDescriptor setCacheDataOnWrite(boolean value)
        
        boolean isCacheDataInL1()
        HColumnDescriptor setCacheDataInL1(boolean value)
        
        boolean isCacheIndexesOnWrite()
        HColumnDescriptor setCacheIndexesOnWrite(boolean value)
        
        boolean isCacheBloomsOnWrite()
        HColumnDescriptor setCacheBloomsOnWrite(boolean value)
        
        boolean isEvictBlocksOnClose()
        HColumnDescriptor setEvictBlocksOnClose(boolean value)
        
        boolean isPrefetchBlocksOnOpen()
        HColumnDescriptor setPrefetchBlocksOnOpen(boolean value)    
        
    注意,目前爲止,這些屬性默認設置爲 false, 意爲這些屬性都沒有激活,除非某個列族啓用它們。
    
    
    ● 生存期 (Time-to-Live)
    -------------------------------------------------------------------------------------------------------------------------------------
    HBase 支持每個值在版本數量上斷言刪除,也支持基於時間的刪除。生存期(time-to-live, TTL) 設置了一個基於時間戳的臨界值,內部管理(internal
    housekeeping)程序自動檢查值的生存期是否超過其 TTL 設置。如果超出,會在 major 合併過程中丟棄這個數據。下面的方法用於讀寫 TTL:
    
        int getTimeToLive()
        HColumnDescriptor setTimeToLive(int timeToLive)
    
    該值以秒爲單位指定,默認值爲 HConstants.FOREVER, 設置爲 Integer.MAX_VALUE, 即 2,147,483,647 秒,意爲永遠保留該數據,即任何小於該默認
    值的正數都會啓用該特性。
    
    
    ● 在內存中 (In-Memory)
    -------------------------------------------------------------------------------------------------------------------------------------
    之前提到過快緩存,以及如何利用塊緩存來將整塊的數據保留在內存中,以提高順序訪問數據的效率。in-memory 標誌默認爲 false, 但可以通過如下
    方法讀取或修改該屬性:
    
        boolean isInMemory()
        HColumnDescriptor setInMemory(boolean inMemory)
    
    將該值設爲 true 並不能保證整個列族的所有數據塊載入到內存中,也不能保證其一直保留。把它當做承諾,或者較高的優先級,只要在正常的獲取操作,
    就會將數據載入保留到內存中,直到堆內存的壓力太大,這時就需要丟掉它們。
    
    
    ● 布隆過濾器 (Bloom Filter)
    -------------------------------------------------------------------------------------------------------------------------------------
    布隆過濾器是 HBase 系統的高級功能,它通過特定訪問模式減少查詢時間。雖然會增加存儲和內存佔用的開銷,但會提升查找和讀取性能。
    
    Supported Bloom Filter Types
    +-----------+--------------------------------------------------------------------------------------------------------------
    | Type        | Description
    +-----------+--------------------------------------------------------------------------------------------------------------
    | NONE        | Disables the filter.
    +-----------+--------------------------------------------------------------------------------------------------------------
    | ROW        | Use the row key for the filter (default).
    +-----------+--------------------------------------------------------------------------------------------------------------
    | ROWCOL    | Use the row key and column key (family+qualifier) for the filter
    +-----------+--------------------------------------------------------------------------------------------------------------

    從 HBase 0.96 開始,對所有用戶表的所有列族默認設置爲 ROW, 對系統目錄表沒有啓用該功能。
    可以通過如下方法獲取或改變布隆過濾器,其中 BloomType 枚舉類型如上表所示:
    
        BloomType getBloomFilterType()
        HColumnDescriptor setBloomFilterType(final BloomType bt)
    
    
    ● 複製範圍 (Replication Scope)
    -------------------------------------------------------------------------------------------------------------------------------------    
    HBase 的另一個高級功能時複製(replication)。它提供了跨集羣同步的功能,本地集羣的數據更新可以及時同步到其它集羣。默認情況下,複製功能是
    禁用的,複製範圍(replication scop) 設置爲 0,意爲禁用複製功能。可以通過如下方法改變設置:
    
        int getScope()
        HColumnDescriptor setScope(int scope)

    另一個支持的值是 1,意爲啓用到遠程集羣的複製。
    
    Supported Replication Scopes
    +-------+---------------------------+----------------------------------------------------------------
    | Scope    | Constant                    | Description
    +-------+---------------------------+----------------------------------------------------------------
    | 0        | REPLICATION_SCOPE_LOCAL    | Local scope, i.e., no replication for this family (default).
    +-------+---------------------------+-------------------------------------------------------------------
    | 1        | REPLICATION_SCOPE_GLOBAL    | Global scope, i.e., replicate family to a remote cluster.
    +-------+---------------------------+----------------------------------------------------------------


    ● 加密 (Encryption)
    -------------------------------------------------------------------------------------------------------------------------------------
    設置加密相關的信息,方法如下:
    
        String getEncryptionType()
        HColumnDescriptor setEncryptionType(String algorithm)
        byte[] getEncryptionKey()
        HColumnDescriptor setEncryptionKey(byte[] keyBytes)    


    ● 描述符參數 (Descriptor Parameters)
    -------------------------------------------------------------------------------------------------------------------------------------
    下列方法用於設置任意的 key/value 對屬性:
    
        byte[] getValue(byte[] key)
        String getValue(String key)
        Map<ImmutableBytesWritable, ImmutableBytesWritable> getValues()
        HColumnDescriptor setValue(byte[] key, byte[] value)
        HColumnDescriptor setValue(String key, String value)
        void remove(final byte[] key)

    可以利用這些方法訪問所有配置的值,以上提及的所有方法都是通過這個列表中的方法設置它們的參數的。這些方法的另一個應用場景是,用於存儲應用
    相關的元數據(metadata), 因爲它們持久化到服務器上,因此之後可以由客戶端讀取。

    
    ● 配置 (Configuration)
    -------------------------------------------------------------------------------------------------------------------------------------
    允許用戶在列族級別覆蓋任何 HBase 的配置屬性。這些屬性在運行時與默認值、集羣範圍的配置文件、以及表級別的設置合併。注意,只有與 region
    或 table 相關的屬性可以設置,其它不相關屬性,即便已被覆蓋,也不會讀取。

    方法如下:
    
        String getConfigurationValue(String key)
        Map<String, String> getConfiguration()
        HColumnDescriptor setConfiguration(String key, String value)
        void removeConfiguration(final String key)

        
    ● 雜項調用 (Miscellaneous Calls)
    -------------------------------------------------------------------------------------------------------------------------------------
        static Unit getUnit(String key)
        static Map<String, String> getDefaultValues()
        String toString()
        String toStringCustomizedValues()    

    目前支持的 Unit 只有 TTL。

下面的示例利用 API 創建了一個描述符,設置自定義屬性,並以各種方法打印出來:

示例: Example how to create a HColumnDescriptor in code

    HColumnDescriptor desc = new HColumnDescriptor("colfam1")
                                .setValue("test-key", "test-value")
                                .setBloomFilterType(BloomType.ROWCOL);

    System.out.println("Column Descriptor: " + desc);
    System.out.print("Values: ");

    for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> entry : desc.getValues().entrySet()) {
        System.out.print(Bytes.toString(entry.getKey().get()) +
        " -> " + Bytes.toString(entry.getValue().get()) + ", ");
    }

    System.out.println();
    System.out.println("Defaults: " + HColumnDescriptor.getDefaultValues());
    System.out.println("Custom: " + desc.toStringCustomizedValues());
    System.out.println("Units:");
    System.out.println(HColumnDescriptor.TTL + " -> " + desc.getUnit(HColumnDescriptor.TTL));
    System.out.println(HColumnDescriptor.BLOCKSIZE + " -> " + desc.getUnit(HColumnDescriptor.BLOCKSIZE));

輸出結果:

    Column Descriptor: {NAME => 'colfam1', DATA_BLOCK_ENCODING =>'NONE',
    BLOOMFILTER => 'ROWCOL', REPLICATION_SCOPE => '0',COMPRESSION => 'NONE', VERSIONS => '1', TTL => 'FOREVER',
    MIN_VERSIONS => '0', KEEP_DELETED_CELLS => 'FALSE',    BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true',
    METADATA => {'test-key' => 'test-value'}}
    Values: DATA_BLOCK_ENCODING -> NONE, BLOOMFILTER -> ROWCOL,    REPLICATION_SCOPE -> 0, COMPRESSION -> NONE, VERSIONS -> 1,
    TTL -> 2147483647, MIN_VERSIONS -> 0, KEEP_DELETED_CELLS ->    FALSE,BLOCKSIZE -> 65536, IN_MEMORY -> false, test-key -> test-value,
    BLOCKCACHE -> true
    Defaults: {CACHE_BLOOMS_ON_WRITE=false, CACHE_DATA_IN_L1=false,    PREFETCH_BLOCKS_ON_OPEN=false, BLOCKCACHE=true,
    CACHE_INDEX_ON_WRITE=false, TTL=2147483647, DATA_BLOCK_ENCODING=NONE,BLOCKSIZE=65536, BLOOMFILTER=ROW, EVICT_BLOCKS_ON_CLOSE=false,
    MIN_VERSIONS=0, CACHE_DATA_ON_WRITE=false, KEEP_DELETED_CELLS=FALSE,COMPRESSION=none, REPLICATION_SCOPE=0, VERSIONS=1, IN_MEMORY=
    false}
    Custom: {NAME => 'colfam1', BLOOMFILTER => 'ROWCOL', METADATA => {'test-key' => 'test-value'}}
    Units:
    TTL -> TIME_INTERVAL
    BLOCKSIZE -> NONE

    
table 描述符中使用的序列化方法,在列族描述符中也存在,用於通過 RPC 發送經過配置的實例:

    byte[] toByteArray()
    static HColumnDescriptor parseFrom(final byte[] bytes) throws DeserializationException
    static HColumnDescriptor convert(final ColumnFamilySchema cfs)
    ColumnFamilySchema convert()

 

參考:

    《HBase - The Definitive Guide - 2nd Edition》Early release —— 2015.7 Lars George

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章