16. HBase高级应用

作者: 奉先 | 来源:发表于2017-05-07 09:50 被阅读180次

    1. HBase存储中的3个核心机制

    1.flush机制:
    当MemStore达到阈值之后,会flush成一个StoreFile (也就是内存中的数据写入了磁盘)。
    2.compact机制:
    当StoreFile达到阈值时,合并StoreFile。合并过程中cell版本合并和数据删除。
    3.split机制:
    当region不断增大,达到阈值,region会分成两个新的region。

    2.HBase Java API使用

    1. 为HBase Java编程准备开发环境

    使用java进行HBase编程,pom文件需要添加2个依赖,分别是hbase-client 、 hbase-server(可以没有)、hadoop-client。

    查看HBase的API文档,以下几个类是比较常用的,需要熟悉:
    HBaseAdmin (管理操作、创建表等)
    HTable (操作表、上传数据)
    Configuration

    HBase的java API开发与HBase shell的命令基本上是一致的。例如shell中的put操作,对应着API中的Put对象。

    2. 添加IDE依赖的jar包:

    HBase的开发,需要在pom.xml中引入 hbase-client、hbase-server和hadoop-client几个依赖包(选取的版本是:hadoop: 2.5.0 ; hbase:0.98.6-hadoop2),如下是pom.xml定义:

    <properties>
        <hadoop.version>2.5.0</hadoop.version>
        <hbase.version>0.98.6-hadoop2</hbase.version>
    </properties>
    <dependencies>
        <!-- hbase client -->
        <dependency>
          <groupId>org.apache.hbase</groupId>
          <artifactId>hbase-client</artifactId>
          <version>${hbase.version}</version>
        </dependency>
        
        <dependency>
          <groupId>org.apache.hbase</groupId>
          <artifactId>hbase-server</artifactId>
          <version>${hbase.version}</version>
        </dependency>
        
        <!-- hadoop client -->
        <dependency>
          <groupId>org.apache.hadoop</groupId>
          <artifactId>hadoop-client</artifactId>
          <version>${hadoop.version}</version>
        </dependency>
    </dependencies>
    

    3. 添加配置文件:

    需要将HBase和Hadoop的配置文件,添加到项目的Classpath。新建“Source Folder”:src/main/resources,将hadoop和hbase安装目录下的配置文件挪到这个目录下(主要是core-site.xml、hdfs-site.xml和hbase-site.xml):


    Resources文件.png

    4. 获取HBase配置环境信息:

    在使用Java API时,Client端需要知道HBase的环境配置,使用Configuration类来封装该信息。

    Configuration conf = HBaseConfiguration.create();
    

    在创建该对象时,首先在classpath中寻找hbase-site.xml文件来读取配置,如果不存在该文件,则寻找hbase-default.xml文件来读取配置(也就是默认配置)。

    5. Get获取数据:

    使用Get对象获取数据:

          // 抽象的获取HTable对象的静态方法,返回HTable对象
        public static HTable getTable (String tablename) throws IOException {
            Configuration conf = HBaseConfiguration.create();
            HTable table = new HTable(conf,tablename);
            return table;
        }
        
        //根据row_key返回这条记录中的信息
        public static void getByRowKey(String tablename,String rowkey) 
                throws IOException
        {
            HTable table = HBaseAPIOper.getTable(tablename);
            
            //Get Object is bound to one row(identified by rowkey)
            Get get = new Get(Bytes.toBytes(rowkey));
            
            Result rs = table.get(get);
            
            Cell[] cells = rs.rawCells();
            for (Cell cell : cells){
                System.out.print( Bytes.toString(CellUtil.cloneFamily(cell)) + ":" );
                System.out.print( Bytes.toString(CellUtil.cloneQualifier(cell)) + "=>" );
                System.out.print( Bytes.toString(CellUtil.cloneValue(cell)) + "\n"  );
            }
            
            table.close();
        }
        
        //返回某个row_key、某个列族、某个列的数据(只返回指定列的信息)
        public static void getByColumns (String tablename,String rowkey,
                String family,String qualifier) throws IOException{
            HTable table = HBaseAPIOper.getTable(tablename);
            
            //Get Object is bound to one row(identified by rowkey)
            Get get = new Get(Bytes.toBytes(rowkey));
            
            get.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));
            
            Result rs = table.get(get);
            
            Cell[] cells = rs.rawCells();
            for (Cell cell : cells){
                System.out.print( Bytes.toString(CellUtil.cloneFamily(cell)) + ":" );
                System.out.print( Bytes.toString(CellUtil.cloneQualifier(cell)) + "=>" );
                System.out.print( Bytes.toString(CellUtil.cloneValue(cell)) + "\n"  );
            }
            
            table.close();
        }
    

    Get get = new Get(rowkey的字节数组)。 Get对象和rowkey进行绑定。Result result = HTable对象.get(Get对象)。下面遍历结果集,使用rawCells()方法,获取所有查到的单元格信息。CellUtil类,是用于操作单元格的工具类,CellUtil.cloneFamily()获取列族信息,CellUtil.cloneQualifier()获取列信息,CellUtil.cloneValue()获取对应的值。为了防止资源使用崩溃,一定要记得关闭table对象
    同时,也可以通过操作Get对象,来限定只显示部分列。get.addColumn("列族","列名")

    6. Put插入数据:

    实体信息的插入,通过put操作完成。

    // Put rows by rowkey (Auto Generated!!)
        public static void putRows(String tablename) throws IOException{        
            HTable table = HBaseAPIOper.getTable(tablename);
            long rowkey = System.currentTimeMillis();
            // The Integer rowkey must be cast to String.
            Put put0 = new Put(Bytes.toBytes(Long.toString(rowkey)));
            put0.add(
                    Bytes.toBytes("info"), 
                    Bytes.toBytes("name"), 
                    Bytes.toBytes("natty") 
                    )   ;
            put0.add(
                    Bytes.toBytes("info"), 
                    Bytes.toBytes("age"), 
                    Bytes.toBytes("31") 
                    )   ;
            
            // The Integer rowkey must be cast to String.
            Put put1 = new Put(Bytes.toBytes(Long.toString(rowkey + 1)));
            put1.add(
                    Bytes.toBytes("info"), 
                    Bytes.toBytes("name"), 
                    Bytes.toBytes("natty") 
                    )   ;
            put1.add(
                    Bytes.toBytes("info"), 
                    Bytes.toBytes("age"), 
                    Bytes.toBytes("31") 
                    )   ;
            
            ArrayList<Put> list = new ArrayList<Put>();
            list.add(put0);
            list.add(put1);
            table.put(list);
            table.close();
        }
    

    put操作对应于Put对象。创建Put对象, Put put = new Put(rowkey对应的字节数组);之后添加列信息,put.add("列族","列名","列值"),通过多次put.add()可以一次添加多个列值信息。将列信息添加到表格,表格对象.put(Put对象),或者添加多个put对象,表格对象.put(含有多个Put对象的list集合)。

    7. Delete删除数据和Update数据:

    删除数据需要使用Delete对象, Delete delete = new Delete(行键对应的字节数组)。指定要删除的列(列族),delete.deleteColumn("列族","列名")

        public static void deleteByRowkey(String tablename,String rowkey) 
                throws IOException{
            HTable table = HBaseAPIOper.getTable(tablename);
            Delete del = new Delete(Bytes.toBytes(rowkey));
            
            //delete all the family
            del.deleteFamily(Bytes.toBytes("info"));
            //delete just one column
            del.deleteColumn(Bytes.toBytes("info"), Bytes.toBytes("name"));
            table.delete(del);
            table.close();
        }
    

    HBase中Update操作也使用Put对象完成,操作方法与插入操作完全一致。

    8. Scan操作:

    ResultScanner是由查询结果Result对象组成的,可以通过2次遍历获取数据。getRow()获得行键。另外,也可以使用IOUtils.closeStream()来关闭table对象等资源。通过setStartRow()和setStopRow()方法,限定scan的查询范围。通过scan.addFamily()或者scan.addColumn()增加通过列族/列筛选数据。

        public static void scanByTable(String tablename) throws IOException
        {
            HTable table = HBaseAPIOper.getTable(tablename);
            
            Scan scan = new Scan();
            //make the scope of scan.
            // >= setStartRow()  AND  < setStopRow() 
            scan.setStartRow(Bytes.toBytes("10001"));
            scan.setStopRow(Bytes.toBytes("10004"));
            
            //filter the data through Family or Column
            scan.addFamily(Bytes.toBytes("info"));
            scan.addColumn(Bytes.toBytesBinary("info"), Bytes.toBytes("name"));
            
            ResultScanner resultscanner = table.getScanner(scan);
            
            for (Result result:resultscanner)
            {
                // getRow() method can get the rowkey.
                System.out.println(Bytes.toString(result.getRow()));
                Cell[] cells = result.rawCells();
                for (Cell cell : cells){
                    System.out.print( Bytes.toString(CellUtil.cloneFamily(cell)) + ":" );
                    System.out.print( Bytes.toString(CellUtil.cloneQualifier(cell)) + "=>" );
                    System.out.print( Bytes.toString(CellUtil.cloneValue(cell)) + "\n"  );
                }
            }
            IOUtils.closeStream(resultscanner);
            IOUtils.closeStream(table);
        }
    

    3.HBase架构深入总结

    1.客户端作用:

    1.整个HBase集群的访问入口;
    2.使用HBase RPC机制与HMaster 和 HRegionServer通信。
    3.与HMaser通信进行管理类操作。
    4.与HRegionServer通信进行数据读写类操作。

    2.Zookeeper作用:

    1.实现HMaster的HA,保证集群中只有一个HMaster。
    2.保存root region的位置(meta表),Region的寻址入口。
    客户端在访问表时,需要找到表的每个region对应的RegionServer(管理Region的角色)。Root(新版本是meta)表存储了Region的分布情况以及每个Region的详细信息。
    3.实时监控RegionServer的上下线信息,并及时通知Master。
    4.存储HBase的schema和table元数据(有哪些表、每个表有哪些列族)。

    3.HMaster作用和特点:

    1.HMaster作用:
    (1). HMaster负责Table和Region的管理工作,为RegionServer分配Region。
    (2). 管理Region Server的负载均衡(为每一个Region Server分配多少Region),调整Region分布。
    (3). 当某一个Region Server停机下线后,负责失效Region Server上的Region的迁移。
    (4). 监听zookeeper,基于zookeeper来得知Region Server上下线。
    (5). 监听zookeeper,基于zookeeper来保证Master的HA
    2.HMaster的特点:
    (1)HMaster没有单点故障问题(SPOF:Single Point Of Failure)。HBase可以启动多个HMaster,Zookeeper保证只有一个HMaster运行。
    启动backup master节点方法:在conf下修改配置文件backup-masters,通过hbase-daemons.sh脚本启动backup master。

    $bin/hbase-daemons.sh start master-backup
    

    (2)不参与客户端数据读写
    (3)HMaster的负载很低(在同一个主机上可以和NN、SNN等服务共同运行)。

    4.Region Server的作用:

    1. 维护Region(HMaster分配的),响应客户端的IO访问请求(读写),向HDFS读写数据。
    2. 负责处理region的 flush、compact、split 几个过程。
    3. 维护region的cache
    HBase与Zookeeper的关系.png

    4.HBase数据检索三种方式

    HBase的数据检索,主要提供了3种方式,分别是:Get方式检索、Scan范围检索、Scan全表扫描。

    1. Get方式:
      Get需要使用rowkey作为参数检索。
      在hbase shell中使用get命令
      在java API中使用Get对象。
    2. Scan 范围搜索:
      依据rowkey匹配查找,默认根据rowkey匹配
      在hbase shell中使用scan命令
      在java API中使用Scan对象。
    3. Scan 全部扫描:
      全表扫描
      和MapReduce/Spark一起使用。

    5.HBase与MapReduce集成

    1.HBase和MapReduce的整合场景:

    第一种应用场景: 文本文档txt或者csv文件导入到HBase中。
    第二种应用场景: HBase的表导成另外一个表。
    Data Source(数据源): 。本地、HBASE表、HDFS
    Data Sink: 数据写进哪个地方。
    Data Source & Data Sink:

    2.HBase和MapReduce的原因和方法:

    1. 为什么使用MapReduce导入:
      MapReduce是并行处理框架,比较快。
    2. HBase和MapReduce整合的方法:
      使用如下命令可以返回hbase的classpath的jar包:
    $ bin/hbase mapredcp
    

    查看命令的具体含义:

    $ bin/hbase 
    

    3.HBase的默认MapReduce程序:

    HBase默认集成了一些mapreduce程序。这些程序存放在这个jar包(HBase的安装目录下)中 :
    /opt/modules/hbase-0.98.6-cdh5.3.6/lib/hbase-server-0.98.6-cdh5.3.6.jar
    下面,我们执行这个jar包:
    (1) 导入HBASE_CLASS path环境变量:

    export HADOOP_HOME=/opt/modules/hadoop-2.5.0-cdh5.3.6
    export HBASE_HOME=/opt/modules/hbase-0.98.6-cdh5.3.6
    export HADOOP_CLASSPATH=`$HBASE_HOME/bin/hbase mapredcp`
    

    上边步骤设置HBase的CLASSPATH。变量引入,一般写进shell脚本,跟随job任务执行的命令一起。如果要写入/etc/profile 会永久生效,并且需要加export。

    (2)通过yarn执行mapreduce的jar包:
    查看整个jar包所提供的所有功能:

    $ /opt/modules/hadoop-2.5.0-cdh5.3.6/bin/yarn jar /opt/modules/hbase-0.98.6-cdh5.3.6/lib/hbase-server-0.98.6-cdh5.3.6.jar 
    
    Paste_Image.png

    (3)通过mapreduce查看某个表的行数(rowkey的个数):
    $ /opt/modules/hadoop-2.5.0-cdh5.3.6/bin/yarn jar /opt/modules/hbase-0.98.6-cdh5.3.6/lib/hbase-server-0.98.6-cdh5.3.6.jar rowcounter 'user'

    4.自定义HBase的MapReduce程序:

    5.HBase数据迁移工具importTsv:

    HBase存在较多数据迁移的场景:例如,需要将一个数据文件直接导入到HBase表中,还有将生产集群的数据迁移到测试集群等等。
    ImportTsv是HBase官方提供的基于MapReduce的批量数据导入工具。ImportTsv是一个命令行工具,可以将存储在HDFS上的自定义分隔符(默认\t)的数据文件,通过一条命令导入到HBase表中,非常适合大数据量导入。
    下面运行一个实例来演示导入过程:
    (1)创建一个将要导入的测试文件:
    (2)上传该文件到HDFS上的指定目录:
    (3)HBase建表:
    (4)开始运行MapReduce执行导入。
    (5)验证结果。

    6. 使用BulkLoad加载数据:

    6.创建HBase表

    创建HBase有常见的三种方式:
    1.创建表时,指定region划分方式(根据rowkey)

    create 'tb1','fa1',SPLITS => ['10','20','30','40']
    

    tb1表有五个Region。SPLITS根据rowkey来将记录分配到各自的region中:


    Region划分.png

    2.创建表时,通过文件来将表划分为多分区(最常用方式):
    将分区范围放在一个物理文件中,然后在创建表时指定这个文件。例如定义下面一个regions.txt文件:

    20170605
    20170606
    20170607
    20170608
    20170609
    20170610
    

    下面创建表,根据这个文件指定划分region。

    create table 'tb2','fa2',SPLITS_FILE => '/home/natty/hbase/regions.txt',OWNER => 'natty'
    

    需要注意,这里建议使用绝对路径来指定文件。
    3.指定分区的数量,创建表:

    create table 'tb3','fa3',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}
    

    如果指定region的起止范围,系统可以自动定义。

    7. HBase的RowKey设计

    1.表结构设计:

    最核心的内容是设计rowkey。设计rowkey的要点:
    1.根据需求设计,查询速度快。
    2.尽量覆盖更多业务场景,增加复用的可能性。
    3.离线设计,避免热点

    2.案例设计:

    下面介绍一个实例,订单历史表。这个表有以下的查询场景。

    相关文章

      网友评论

        本文标题:16. HBase高级应用

        本文链接:https://www.haomeiwen.com/subject/jzqyottx.html