暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

JAVA连接HBase客户端及HBase写入数据和读取数据原理解析

Hadoop大数据开发 2021-07-05
2139

JAVA连接HBase客户端

接着上篇文章进行代码的实践,从JAVA 客户端对 HBase的客户端进行一系列操作

工具类:HbaseUtil

静态代码块一次性创建连接对象  并赋值

返回连接对象 Connection

Table对象的创建

Admin对象的创建

数据的展示

    package cn._doit19.hbase.utils;


    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.hbase.Cell;
    import org.apache.hadoop.hbase.CellUtil;
    import org.apache.hadoop.hbase.HBaseConfiguration;
    import org.apache.hadoop.hbase.TableName;
    import org.apache.hadoop.hbase.client.*;
    import org.apache.hadoop.hbase.util.Bytes;


    import java.io.IOException;




    /**
    * @author:tom
    * @Date:Created in 16:36 2020/11/24
    * 工具类
    */
    public class HbaseUtil {


    static Connection conn = null;


    static {


    //创建连接对象


    Configuration conf = HBaseConfiguration.create();
    conf.set("hbase.zookeeper.quorum", "linux01:2181,linux02:2181,linux03:2181");
    try {
    conn = ConnectionFactory.createConnection(conf);
    } catch (IOException e) {
    e.printStackTrace();
    }
    }


    public static Table getTable(String tableName) throws Exception {


    TableName tbName = TableName.valueOf(tableName);
    return conn.getTable(tbName);
    }


    public static Connection getConn() {
    return conn;
    }


    public static void showData(Result result) {
    while (result.advance()) {
    Cell cell = result.current();
    String row = Bytes.toString(CellUtil.cloneRow(cell));
    String cf = Bytes.toString(CellUtil.cloneFamily(cell));
    String qualifier = Bytes.toString(CellUtil.cloneQualifier(cell));
    String val = Bytes.toString(CellUtil.cloneValue(cell));
    System.out.println(row + "--->" + cf + "--->" + qualifier + "--->" + val);
    }
    }


    public static Admin getAdmin() throws Exception {
    return conn.getAdmin();
    }
    }


    创建表

      package cn._doit19.hbase.day01;


      import cn._doit19.hbase.utils.HbaseUtil;
      import org.apache.hadoop.hbase.TableName;
      import org.apache.hadoop.hbase.client.*;


      /**
      * @author:tom
      * @Date:Created in 17:44 2020/11/24
      * 创建表
      */
      public class Demo03 {
      public static void main(String[] args) throws Exception {
      Admin admin = HbaseUtil.getAdmin();
      TableDescriptorBuilder tb_builder = TableDescriptorBuilder.newBuilder(TableName.valueOf("test_a".getBytes()));
      ColumnFamilyDescriptorBuilder cf_builder = ColumnFamilyDescriptorBuilder.newBuilder("cf1".getBytes());
      ColumnFamilyDescriptor cf_desc = cf_builder.build();
      tb_builder.setColumnFamily(cf_desc);
      TableDescriptor tb_desc = tb_builder.build();
      admin.createTable(tb_desc);
      }
      }


      Scan  'table_name'  扫描表 数据  可添加参数 精准扫描查询

        package cn._doit19.hbase.day01;


        import cn._doit19.hbase.utils.HbaseUtil;
        import org.apache.hadoop.hbase.client.Result;
        import org.apache.hadoop.hbase.client.ResultScanner;
        import org.apache.hadoop.hbase.client.Scan;
        import org.apache.hadoop.hbase.client.Table;


        import java.util.Iterator;


        /**
        * @author:tom
        * @Date:Created in 11:56 2020/11/25
        * scan ‘tab_name’
        */
        public class Demo04 {
        public static void main(String[] args) throws Exception {


        //获取表对象
        Table table = HbaseUtil.getTable("tb_imp");


        //scan 扫描表,获取所有的数据
        Scan scan = new Scan();
        //添加了列族和属性 只要表中所有的 info列族的age属性
        scan.addColumn("info".getBytes(), "age".getBytes());
        ResultScanner scanner = table.getScanner(scan);
        Iterator<Result> iterator = scanner.iterator();
        while (iterator.hasNext()) {
        Result res = iterator.next();
        HbaseUtil.showData(res);
        }
        }
        }


        put 时的数据结构   put 'table_name','rowKey','cf_name:qualifier','value'

          package cn._doit19.hbase.day01;
          import org.apache.hadoop.hbase.Cell;
          import org.apache.hadoop.hbase.CellUtil;
          import org.apache.hadoop.hbase.client.Put;
          import java.util.List;
          import java.util.Map;
          import java.util.NavigableMap;
          import java.util.Set;


          /**
          * @author:tom
          * @Date:Created in 15:58 2020/11/25
          * put 数据结构
          */
          public class PutDetails {
          public static void main(String[] args) throws Exception {


          //put方法
          //put 'a','rk001','cf1:qualifier','value'
          //一个rowKey 对应多个单元格 List<Cell> 单元格(cf:qualifier)
          // Table tb_user = HbaseUtil.getTable("tb_user");
          Put put = new Put("rk001".getBytes());
          NavigableMap<byte[], List<Cell>> familyCellMap = put.getFamilyCellMap();
          Set<Map.Entry<byte[], List<Cell>>> entries = familyCellMap.entrySet();
          //k,v 一个rowKey 对应多个单元格 List<Cell>
          for (Map.Entry<byte[], List<Cell>> entry : entries) {
          //列族
          String cfName = new String(entry.getKey());
          List<Cell> cells = entry.getValue();
          for (Cell cell : cells) {
          //每个单元格的属性
          String qualifier = new String(CellUtil.cloneQualifier(cell));
          //每个单元格的值
          String value = new String(CellUtil.cloneValue(cell));
          }
          }

          // tb_user.put(put);
          }
          }


          HBase写入数据原理解析

          写入数据原理图

          步骤解析

          put 'a','rk001','cf:age',21    客户端要向Hbase中写入数据

          1)  客户端向Zookeeper(以下简称zk)发送请求向habse中的a表(default命名空间下)中写入数据

          2)zk向客户端返回元数据表meta的位置  (具体在哪个regionserver上)

          3)客户端向指定regionserver请求元数据表meta

          4)客户端下载缓存到自己的本地(下次就不必再找zk和regionserver要了)

          5)客户端进行解析meta表, 解析出rk001所在的hostname和regionname 

          6)请求指定的机器上的regionserver写数据

          7)regionserver接收到数据,并不是马上就写到hdfs中,首先数据是列式存储,每一个列族都有一个store(cf)---->regionserver接收到客户端传入的数据并写入到内存memorystore中

          8)memorystore内存中的数据达到128M或者人为强制的进行flush时,它将写入到store file并通过HDFS写入到hdfs的文件当中。store file即hfile

          注意点:

          1)flush的时机

          • 单个的MemoryStore的内存达到128M

          • 手动强制进行flush

          • 机器的内存达到阈值  所有的memorystore将会被flush走

          • 次数达到阈值

          2)hbase在hdfs中真实存在的路径为

          /hbase/data/namespace/table_name/region_name/cf_name/hfile

          HBase读取数据原理解析

          读取数据原理图

          步骤解析

          get 'a','rk001'   

          1)  向zk集群请求读取数据

          2)zk返回元数据meta表的位置

          3)客户端向指定regionserver请求下载元数据

          4)接收下载存储元数据

          5)解析

          6)请求对应的regionserver的region读取数据

          7)region先从自己的数据块缓存blockCache和内存memoryStore中找值,找到就直接返回

          8)找不到,去到HDFS中找,利用布隆过滤器进行查询,往自己的blockCache和memorystore中存储一份,客户端直接从内存中获取。

          注:

          布隆过滤器是一种算法,上述步骤中,一个列族下有很多个hfile文件,不可能遍历每个文件读查询,这里使用到了布隆过滤器,快速判断出哪些文件一定不可能或极有可能存在我们需要的数据,

          从而大大提高效率。布隆过滤器原理见:你不知道的查找算法之布隆过滤器

          更多学习、面试资料尽在微信公众号:Hadoop大数据开发

          文章转载自Hadoop大数据开发,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

          评论