
# 使用JAVA API配置HBase冷热分离
HBase支持冷热分离功能，可以将冷热数据存储在不同的介质中，有效提升数据的查询效率，同时降低数据存储成本。此章节主要介绍通过JAVA API配置HBase冷热分离。
#### 前提条件
- 已创建[HBase集群](https://support.huaweicloud.com/usermanual-cloudtable/cloudtable_01_0020.html)。
- 已安装HBase客户端。
 
#### 步骤一：开启HBase冷热分离
1. 登录[表格存储服务控制台](https://console.huaweicloud.com/cloudtable)。
2. 控制台左上角，选择区域。
3. 单击集群管理界面右上角的"购买集群"，
4. 进入创建集群界面，在集群购买页面选择HBase数据库引擎并勾选高级特性"冷热分离"，创建后的集群就开启了冷热分离特性。 
   图1开启冷热分离   
   ![](https://support.huaweicloud.com/usermanual-cloudtable/zh-cn_image_0000002342704360.png)
   
   
 
#### 步骤二：设置表的冷热分界线
1. 通过[Java API](https://support.huaweicloud.com/devg-cloudtable/cloudtable_01_0048.html)接口访问HBase集群。
2. 设置冷热分界线。 
   - 新建冷热分离表。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);
     ```
     
   
   
   
   
 
#### 步骤三：插入数据
冷热分离的表与普通表的数据写入方式完全一致，数据会先存储在热存储（云硬盘）中。随着时间的推移，如果一行数据满足：当前时间-时间列值\>COLD_BOUNDARY设置的值条件，则会在执行Compaction时被归档到冷存储（对象存储）中。
使用[Java API](https://support.huaweicloud.com/devg-cloudtable/cloudtable_01_0048.html)写入数据。
#### 步骤四：数据查询
由于冷热数据都在同一张表中，因此用户所有的查询操作都只需在一张表内进行。在查询时，建议通过配置TimeRange来指定查询的时间范围，系统将会根据指定的时间范围决定查询模式，即仅查询热存储、仅查询冷存储或同时查询冷存储和热存储。如果查询时未限定时间范围，则会导致查询冷数据。在这种情况下，查询吞吐量会受到冷存储的限制。
冷存储中的数据常用于归档，会很少访问。如果冷存储中的数据被大量频繁请求访问，请检查冷热数据边界（COLD_BOUNDARY）配置是否正确。如果频繁查询的大量数据在冷存储中将会限制查询的性能。
如果冷存储中存储的一行数据中的某个字段更新，则更新的字段存储在热存储中。如果指定HOT_ONLY或TimeRange参数仅查询热存储中的数据，则只返回更新的字段。如果要返回整行的数据，则必须在不指定HOT_ONLY或TimeRange参数的情况下执行查询，或者确保TimeRange指定的时间范围涵盖从插入行的时间点到最后更新行的时间点的时间段。因此，建议您不要更新存储在冷存储中的数据。
- 随机查询Get。
  - 不指定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参数来查询数据。在这种情况下，CloudTable将会比较TimeRange和冷热边界值（COLD_BOUNDARY ），以确定是只查询热存储还是冷存储中的数据，还是同时查询热冷存储中的数据。
    ```
    Get get = new Get("row1".getBytes());
    get.setTimeRange(0, 1568203111265)
    ```
    TimeRange：查询的时间范围。范围中的时间是UNIX时间戳，表示自1970年1月1日00:00 UTC以来经过的毫秒数。
    
   
- 范围查询Scan。
  - 不指定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参数来查询数据。在这种情况下，CloudTable将会比较TimeRange和冷热边界值（COLD_BOUNDARY ），以确定是只查询热存储还是冷存储中的数据，还是同时查询热冷存储中的数据。
    ```
    Scan scan = new Scan();
    scan.setTimeRange(0, 1568203111265);
    ```
    TimeRange：查询的时间范围。范围中的时间是UNIX时间戳，表示自1970年1月1日00:00 UTC以来经过的毫秒数。
    
   
- 优先查询热数据。
  在查询客户所有记录等信息的范围查询中，CloudTable可以扫描热存储和冷存储中的数据。查询结果将根据数据行按写入表时的时间戳降序返回。在大多数情况下，热数据出现在冷数据之前。如果在范围查询中没有配置HOT_ONLY参数，CloudTable将会扫描热存储和冷存储中的数据，查询响应时间将会增加。如果启用热数据优先特性，CloudTable会优先查询热存储中的数据。只有当热存储中的行数小于要查询的最小行数时，才会查询冷存储中的数据。这样，减少了冷存储的访问提高了响应速度。
  ```
  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命令。
  - 合并表所有分区的热数据区。
    ```
    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);
    ```
    
   
 
