
# HBase冷热分离相关命令介绍
此章节主要介绍HBase冷热分离相关命令的使用，包括Shell命令和Java API命令。
Shell命令在HBase客户端执行，需提前安装HBase客户端，详情请参见[安装MRS客户端](https://support.huaweicloud.com/cmpntguide-lts-mrs/mrs_01_2127.html)。
#### 设置HBase表的冷热分界线
- Shell
  - 创建冷热分离表。
    ```
    create 'hot_cold_table', {NAME=>'f', COLD_BOUNDARY=>'86400'}
    ```
    相关参数说明如下：
    - NAME：需要冷热分离的列族。
    
    - COLD_BOUNDARY：冷热分离时间点，单位为秒（s）。例如COLD_BOUNDARY值为86400，表示86400秒（一天）前写入的数据会被自动归档到冷存储。 **冷热分离时间点需大于Major Compaction执行周期，Major Compaction默认执行周期为7天。**
      
     
  
  - 取消冷热分离功能。
    ```
    alter 'hot_cold_table', {NAME=>'f', COLD_BOUNDARY=>""}
    ```
    
  
  - 为已经存在的表设置冷热分离，或者修改冷热分离分界线，单位为秒，可实现数据热存储转为冷存储或冷存储转为热存储，例如：
    - 将热存储数据转为冷存储数据：
      1. 将写入到**hot_cold_table** 表的**f** 列的超过一天（86400秒）的数据归档到冷存储中：
         ```
         alter 'hot_cold_table', {NAME=>'f', COLD_BOUNDARY=>'86400'}
         ```
         
      
      2. 在业务低峰期执行Major Compaction操作，避免影响业务性能：
         ```
         major_compact 'hot_cold_table'
         ```
         
       
    
    - 将冷存储数据转为热存储数据：
      1. 将写入到**hot_cold_table** 表的**f** 列超过一天不超过两天的数据从冷存储归档到热存储中，即修改"COLD_BOUNDARY"的值为"172800"，在实际业务场景中请根据实际需求进行设置：
         ```
         alter 'hot_cold_table', {NAME=>'f', COLD_BOUNDARY=>'172800'}
         ```
         
      
      2. 在业务低峰期行Major Compaction操作，避免影响业务性能：
         ```
         major_compact 'hot_cold_table'
         ```
         
       
     
  
  - 查询是否设置冷热分离或冷热分离是否修改成功。
    ```
    desc 'hot_cold_table'
    ```
    例如，命令执行后，回显结果如下：
    ```
    Table hot_cold_table is ENABLED
    hot_cold_table
    COLUMN FAMILIES DESCRIPTION
    {NAME => 'f', VERSIONS => '1', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', REPLICATION_SCOPE => '0', BLOOMFILTER => 'ROW', IN_MEMORY => 'false', COMPRE
    SSION => 'NONE', BLOCKCACHE => 'true', BLOCKSIZE => '65536', METADATA => {'COLD_BOUNDARY' => '1200'}}
    1 row(s)
    Quota is disabled
    Took 0.0339 seconds
    ```
    
   
- Java API方式
  - 新建冷热分离表。 COLD_BOUNDARY用于设置冷热分离时间分界点，单位为秒，示例表示1天之前的数据归档为冷数据。
    ```
    Admin admin = connection.getAdmin();
    TableName tableName = TableName.valueOf("hot_cold_table");
    HTableDescriptor descriptor = new HTableDescriptor(tableName);
    HColumnDescriptor cf = new HColumnDescriptor("f");
    cf.setValue(HColumnDescriptor.COLD_BOUNDARY, "86400");
    descriptor.addFamily(cf);
    admin.createTable(descriptor);
    ```
    
  
  - 取消冷热分离功能。
    ```
    HTableDescriptor descriptor = admin.getTableDescriptor(tableName);
    HColumnDescriptor cf = descriptor.getFamily("f".getBytes());
    cf.setValue(HColumnDescriptor.COLD_BOUNDARY, null);
    admin.modifyTable(tableName, descriptor);
    ```
    
  
  - 为已经存在的表设置冷热分离功能，或者修改冷热分离分界线。 COLD_BOUNDARY用于设置冷热分离时间分界点，单位为秒，示例表示1天之前的数据归档为冷数据。
    ```
    HTableDescriptor descriptor = admin.getTableDescriptor(tableName);
    HColumnDescriptor cf = descriptor.getFamily("f".getBytes());
    cf.setValue(HColumnDescriptor.COLD_BOUNDARY, "86400");
    admin.modifyTable(tableName, descriptor);
    ```
    
   
![](https://support.huaweicloud.com/cmpntguide-lts-mrs/public_sys-resources/note_3.0-zh-cn.png)
数据从热存储到冷存储或从冷存储到热存储，都需执行Major Compaction操作。
#### 数据写入
冷热分离的表与普通表的数据写入方式完全一致，数据会先存储在热存储（HDFS）中。随着时间的推移，如果一行数据满足：当前时间-时间列值 \> COLD_BOUNDARY设置的值，则会在执行Compaction时被归档到冷存储（OBS）中。
- 插入记录。 执行"put"命令向指定表插入一条记录，需要指定表的名称、主键、自定义列、及插入的具体值。例如：
  ```
  put 'hot_cold_table','row1','cf:a','value1'
  ```
  命令中各参数分别代表如下含义：
  - hot_cold_table：表的名称。
  
  - row1：主键。
  
  - cf:a：自定义的列。
  
  - value1：插入的值。
   
 
#### 数据查询
由于冷热数据都在同一张表中，因此用户所有的查询操作都只需在一张表内进行。在查询时，建议通过配置TimeRange来指定查询的时间范围，系统将会根据指定的时间范围决定查询模式，包括仅查询热存储、仅查询冷存储或同时查询冷存储和热存储。如果查询时未限定时间范围，则会导致查询冷数据。在这种情况下，查询吞吐量会受到冷存储的限制。
![](https://support.huaweicloud.com/cmpntguide-lts-mrs/public_sys-resources/caution_3.0-zh-cn.png)
- 冷存储中的数据常用于归档，会很少访问。如果冷存储中的数据被大量频繁请求访问，请检查冷热数据边界（COLD_BOUNDARY）配置是否正确。如果频繁查询的大量数据在冷存储中将会限制查询的性能。
- 如果冷存储中存储的一行数据中的某个字段更新，则更新的字段存储在热存储中。如果指定HOT_ONLY或TimeRange参数仅查询热存储中的数据，则只返回更新的字段。如果要返回整行的数据，则必须在不指定HOT_ONLY或TimeRange参数的情况下执行查询，或者确保TimeRange指定的时间范围涵盖从插入行的时间点到最后更新行的时间点的时间段。因此，建议不要更新存储在冷存储中的数据。
 
- 随机查询Get。
  - Shell
    - 不指定HOT_ONLY参数来查询数据。在这种情况下，将会查询冷存储中的数据。
      ```
      get 'hot_cold_table', 'row1'
      ```
      
    
    - 通过指定HOT_ONLY参数来查询数据。在这种情况下，只会查询热存储中的数据。
      ```
      get 'hot_cold_table', 'row1', {HOT_ONLY=>true}
      ```
      
    
    
    
    - 通过指定TimeRange参数来查询数据。在这种情况下，将会比较TimeRange和冷热边界值，以确定是只查询热存储还是冷存储中的数据，还是同时查询热冷存储中的数据。
      ```
      get 'hot_cold_table', 'row1', {TIMERANGE => [0, 1568203111265]}
      ```
      TimeRange：查询的时间范围。范围中的时间是UNIX时间戳，表示自1970年1月1日00:00 UTC以来经过的毫秒数。
      
     
  
  
  
  - Java API
    - 不指定HOT_ONLY参数来查询数据。在这种情况下，将会查询冷存储中的数据。
      ```
      Get get = new Get("row1".getBytes());
      ```
      
    
    - 通过指定HOT_ONLY参数来查询数据。在这种情况下，只会查询热存储中的数据。
      ```
      Get get = new Get("row1".getBytes());
      get.setAttribute(HBaseConstants.HOT_ONLY, Bytes.toBytes(true));
      ```
      
    
    
    
    - 通过指定TimeRange参数来查询数据。在这种情况下，将会比较TimeRange和冷热边界值（COLD_BOUNDARY ），以确定是只查询热存储还是冷存储中的数据，还是同时查询热冷存储中的数据。
      ```
      Get get = new Get("row1".getBytes());
      get.setTimeRange(0, 1568203111265)
      ```
      TimeRange：查询的时间范围。范围中的时间是UNIX时间戳，表示自1970年1月1日00:00 UTC以来经过的毫秒数。
      
     
   
- 范围查询。
  - Shell
    - 不指定HOT_ONLY参数来查询数据。在这种情况下，将会查询冷存储中的数据。
      ```
      scan 'hot_cold_table', {STARTROW =>'row1', STOPROW=>'row9'}
      ```
      
    
    - 通过指定HOT_ONLY参数来查询数据。在这种情况下，只会查询热存储中的数据。
      ```
      scan 'hot_cold_table', {STARTROW =>'row1', STOPROW=>'row9', HOT_ONLY=>true}
      ```
      
    
    
    
    - 通过指定TimeRange参数来查询数据。在这种情况下，将会比较TimeRange和冷热边界值，以确定是只查询热存储还是冷存储中的数据，还是同时查询热冷存储中的数据。
      ```
      scan 'hot_cold_table', {STARTROW =>'row1', STOPROW=>'row9', TIMERANGE => [0, 1568203111265]}
      ```
      TimeRange：查询的时间范围。范围中的时间是UNIX时间戳，表示自1970年1月1日00:00 UTC以来经过的毫秒数。
      
     
  
  
  
  - Java API
    - 不指定HOT_ONLY参数来查询数据。在这种情况下，将会查询冷存储中的数据。
      ```
      TableName tableName = TableName.valueOf("chsTable");
      Table table = connection.getTable(tableName);
      Scan scan = new Scan();
      ResultScanner scanner = table.getScanner(scan);
      ```
      
    
    - 通过指定HOT_ONLY参数来查询数据。在这种情况下，只会查询热存储中的数据。
      ```
      Scan scan = new Scan();
      scan.setAttribute(HBaseConstants.HOT_ONLY, Bytes.toBytes(true));
      ```
      
    
    
    
    - 通过指定TimeRange参数来查询数据。在这种情况下，将会比较TimeRange和冷热边界值（COLD_BOUNDARY ），以确定是只查询热存储还是冷存储中的数据，还是同时查询热冷存储中的数据。
      ```
      Scan scan = new Scan();
      scan.setTimeRange(0, 1568203111265);
      ```
      TimeRange：查询的时间范围。范围中的时间是UNIX时间戳，表示自1970年1月1日00:00 UTC以来经过的毫秒数。
      
     
   
- 优先查询热数据。 在查询客户所有记录等信息的范围查询中，HBase可以扫描热存储和冷存储中的数据。查询结果将根据数据行按写入表时的时间戳降序返回。在大多数情况下，热数据出现在冷数据之前。如果在范围查询中没有配置HOT_ONLY参数，HBase将会扫描热存储和冷存储中的数据，查询响应时间将会增加。如果启用热数据优先特性，HBase会优先查询热存储中的数据。只有当热存储中的行数小于要查询的最小行数时，才会查询冷存储中的数据，减少了冷存储的访问提高了响应速度。
  - Shell
    ```
    scan 'hot_cold_table', {STARTROW =>'row1', STOPROW=>'row9',COLD_HOT_MERGE=>true}
    ```
    
  
  
  
  - Java API
    ```
    TableName tableName = TableName.valueOf("hot_cold_table");
    Table table = connection.getTable(tableName);
    Scan scan = new Scan();
    scan.setAttribute(HBaseConstants.COLD_HOT_MERGE, Bytes.toBytes(true));
    scanner = table.getScanner(scan);
    ```
    
   
- Major Compaction操作。
  - Shell
    - 合并表所有分区的热数据区。
      ```
      major_compact 'hot_cold_table', nil, 'NORMAL', 'HOT'
      ```
      
    
    
    
    - 合并表所有分区的冷数据区。
      ```
      major_compact 'hot_cold_table', nil, 'NORMAL', 'COLD'
      ```
      
    
    
    
    - 合并表所有分区的热冷数据区。
      ```
      major_compact 'hot_cold_table', nil, 'NORMAL', 'ALL'
      ```
      
     
  
  
  
  - Java API
    - 合并表所有分区的热数据区。
      ```
      Admin admin = connection.getAdmin();
      TableName tableName = TableName.valueOf("hot_cold_table");
      admin. majorCompact (tableName,null, CompactType.NORMAL, CompactionScopeType.HOT);
      ```
      
    
    
    
    - 合并表所有分区的冷数据区。
      ```
      Admin admin = connection.getAdmin();
      TableName tableName = TableName.valueOf("hot_cold_table");
      admin. majorCompact (tableName,null, CompactType.NORMAL, CompactionScopeType.COLD);
      ```
      
    
    
    
    - 合并表所有分区的热冷数据区。
      ```
      Admin admin = connection.getAdmin();
      TableName tableName = TableName.valueOf("hot_cold_table");
      admin. majorCompact (tableName,null, CompactType.NORMAL, CompactionScopeType.ALL);
      ```
      
     
   
 
