您的位置:

深入剖析HBase读写流程

一、数据存储和读取

HBase的数据存放在HDFS文件系统上,并且按照列族和行键进行组织。一行数据包含多个列族,每个列族包含多个列(也就是HBase中的列簇)。

HBase的读写流程如下:

  1. 客户端与HBase ZooKeeper进行连接,并获取到表的位置信息。
  2. 客户端向HRegionServer发送读/写请求,同时将请求中的行键转换为HRegion的位置信息。
  3. HRegionServer在本地缓存中查找数据。
  4. 如果缓存中没有数据,则根据HRegion的位置信息,向HDFS中的数据块获取数据。
  5. 如果客户端发送的是写请求,HRegionServer将数据保存到内存中,并异步地将数据刷写到HDFS。
  6. 如果客户端发送的是读请求,HRegionServer将数据返回给客户端。

上述流程中,客户端与ZooKeeper的交互是通过ZooKeeper中相应节点的监听事件驱动的。所有读写请求都先发送给HRegionServer,然后由HRegionServer根据请求的类型分发给对应的HRegion进行操作。

二、写入数据

接下来将分别介绍写入新数据和更新已有数据两种情况下的HBase写入流程。

写入新数据

写入新数据时,HBase的写入流程如下:

  1. 客户端构建Put对象,选择列族和行键,添加包含具体列值的键值对。
  2. 
    Put put = new Put(Bytes.toBytes("row1"));  
    put.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("name"), Bytes.toBytes("Tom")); 
      
  3. 客户端与ZooKeeper交互,获取表位置信息。
  4. 
    Configuration config = HBaseConfiguration.create();
    Connection connection = ConnectionFactory.createConnection(config);
    Admin admin = connection.getAdmin();
    TableName tableName = TableName.valueOf("testtable");
    HTableDescriptor tableDescriptor = new HTableDescriptor(tableName);
    HColumnDescriptor columnDescriptor = new HColumnDescriptor("cf");
    tableDescriptor.addFamily(columnDescriptor);
    admin.createTable(tableDescriptor);
    Table table = connection.getTable(tableName);
      
  5. 客户端向HRegionServer发送写请求,写请求中包括表的位置信息、Put对象的数据和操作类型。
  6. 
    table.put(put);
      
  7. HRegionServer接收到写请求后,将数据保存到内存中。
  8. 随着内存中的数据量逐渐积累,HRegionServer会将数据写入HDFS中。
  9. 在HDFS中生成新的HFile文件。
  10. 当HFile文件大小达到合适的大小时,HRegionServer会将多个HFile文件进行合并,生成一个更大的HFile文件。

更新已有数据

更新已有数据时,HBase的写入流程如下:

  1. 客户端构建Put对象,并添加需要更新的具体列值。
  2. 
    put.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("age"), Bytes.toBytes("30"));
      
  3. 客户端与ZooKeeper交互,获取表位置信息。
  4. 客户端向HRegionServer发送写请求,请求中包含数据、表的位置信息和操作类型。
  5. HRegionServer根据请求中的行键,找到要更新的数据。
  6. HRegionServer将新的数据更新到内存中。
  7. 随着内存中的数据量逐渐积累,HRegionServer会将数据写入到HDFS中。
  8. 在HDFS中生成新的HFile文件。
  9. 当HFile文件大小达到合适的大小时,HRegionServer会将多个HFile文件进行合并,生成一个更大的HFile文件。

三、读取数据

接下来将分别介绍获取指定行和范围扫描两种情况下的HBase读取数据流程。

获取指定行数据

获取指定行的数据时,HBase的读取流程如下:

  1. 客户端构造Get对象,设置列族和行键。
  2. 
    Get get = new Get(Bytes.toBytes("row1"));
    get.addFamily(Bytes.toBytes("cf"));
      
  3. 客户端与ZooKeeper交互,获取表位置信息。
  4. 客户端向HRegionServer发送读请求,请求中包含数据、表的位置信息和操作类型。
  5. HRegionServer根据请求中的行键,找到要读取的数据。
  6. HRegionServer从内存中或者HDFS中读取数据,并返回给客户端。

范围扫描数据

范围扫描数据时,HBase的读取流程如下:

  1. 客户端构造Scan对象,并设置要扫描的列族和范围。
  2. 
    Scan scan = new Scan();
    scan.setStartRow(Bytes.toBytes("row1"));
    scan.setStopRow(Bytes.toBytes("row5"));
    scan.addFamily(Bytes.toBytes("cf"));
      
  3. 客户端与ZooKeeper交互,获取表位置信息。
  4. 客户端向对应的HRegionServer发送范围扫描请求,请求中包含数据、表的位置信息和操作类型。
  5. HRegionServer查找内存中的块或者HDFS中的块,并返回数据给客户端。
  6. 如果需要合并多个HFile文件,HRegionServer会先进行内部合并操作,并返回给客户端。

四、总结

HBase的读写流程比较复杂,但是仍然是一个高效的分布式系统。对于数据量比较大的应用场景,使用HBase存储和读取数据是一个不错的选择。