hbase_2

====HBase API=========================================================

** 配置maven依赖(pom.xml),不需要hadoop依赖包
<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-server</artifactId>
    <version>0.98.6-hadoop2</version>
</dependency>
<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-client</artifactId>
    <version>0.98.6-hadoop2</version>
</dependency>

PS:
1.如果出现报错,右键项目名--Maven--Update Project...
  需要勾选force update of...选项,然后点OK(耐心点)

2.其他低版本
<version>0.98.6-hadoop2</version>
        
----增删改查------------------------------------

** 插入/更新:Put
** 删除数据:Delete
** 读数据:Get、Scan

package com.myblue.myhbase;

import java.io.IOException;
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.client.Delete;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
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.util.Bytes;

public class MyHbaseOperation{

    public static HTable getTable(String tableName) throws IOException {
        Configuration conf = HBaseConfiguration.create();
        HTable table = new HTable(conf, tableName);
        return table;
    }

    public static void putData() throws IOException {
        HTable table = MyHbaseOperation.getTable("emp");

        Put put = new Put(Bytes.toBytes("1006"));
        put.add(Bytes.toBytes("info"),Bytes.toBytes("name"),Bytes.toBytes("zhaoliu"));
        put.add(Bytes.toBytes("info"),Bytes.toBytes("age"),Bytes.toBytes("50"));
        put.add(Bytes.toBytes("info"),Bytes.toBytes("sex"),Bytes.toBytes("male"));
        
        table.put(put);
        table.close();
    }
    
    public static void deleteData() throws IOException {
        HTable table = MyHbaseOperation.getTable("emp");
        
        Delete delete = new Delete(Bytes.toBytes("1006"));
        //删除所有的时间戳版本
        delete.deleteColumns(Bytes.toBytes("info"),Bytes.toBytes("sex"));
        
        table.delete(delete);
        table.close();
    }

    public static void getData(String rowkey) throws IOException {
        System.out.println("---------------------------------");    
        HTable table = MyHbaseOperation.getTable("emp");

        Get get = new Get(Bytes.toBytes(rowkey));
        Result row = table.get(get);
        Cell[] cells = row.rawCells();
        for (Cell cell : cells) {
            System.out.print(Bytes.toString(CellUtil.cloneFamily(cell)) + ":");
            System.out.print(Bytes.toString(CellUtil.cloneQualifier(cell)) + "==>");
            System.out.println(Bytes.toString(CellUtil.cloneValue(cell)));
        }
        
        table.close();
    }

    public static void scanTable() throws IOException {
        HTable table = MyHbaseOperation.getTable("emp");

        Scan scan = new Scan();
        scan.setStartRow(Bytes.toBytes("1001"));
        scan.setStopRow(Bytes.toBytes("1009"));
        ResultScanner resultScanner = table.getScanner(scan);

        //取出每一行
        for (Result row : resultScanner) {
            System.out.println("row:");
            //取出单元格
            Cell[] cells = row.rawCells();
            for (Cell cell : cells) {
                System.out.print(Bytes.toString(CellUtil.cloneRow(cell)) + "\t");
                System.out.print(Bytes.toString(CellUtil.cloneFamily(cell)) + ":");
                System.out.print(Bytes.toString(CellUtil.cloneQualifier(cell)) + "==>");
                System.out.println(Bytes.toString(CellUtil.cloneValue(cell)));
            }
        }

        table.close();
    }

    public static void main(String[] args) throws IOException {
        MyHbaseOperation.putData();
//        MyHbaseOperation.getData("1006");
//        MyHbaseOperation.scanTable();
//        MyHbaseOperation.deleteData();
    }
}

----创建、删除、修改表--------------

package com.myblue.myhbase;

import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.io.compress.Compression.Algorithm;

public class Example{

    public static void createSchemaTables(Configuration config)
            throws IOException {
        
        Connection connection = null;
        Admin admin = null;
        try {
            connection = ConnectionFactory.createConnection(config);
            admin = connection.getAdmin();
            HTableDescriptor table = new HTableDescriptor(TableName.valueOf("mytable"));
            table.addFamily(new HColumnDescriptor("mycf"));
                    //.setCompressionType(Algorithm.NONE));
            
            if (admin.tableExists(table.getTableName())) {
                admin.disableTable(table.getTableName());
                admin.deleteTable(table.getTableName());
            }
            admin.createTable(table);
            System.out.println("Creating table Done.");
        } finally {
            admin.close();
            connection.close();
        }
    }

    public static void modifySchema(Configuration config) throws IOException {
        Connection connection = null;
        Admin admin = null;
        try {
            connection = ConnectionFactory.createConnection(config);
            admin = connection.getAdmin();

            TableName tableName = TableName.valueOf("mytable");
            if (!admin.tableExists(tableName)) {
                System.out.println("Table does not exist.");
                System.exit(-1);
            }

            HTableDescriptor table = admin.getTableDescriptor(tableName);

            //添加列族
            HColumnDescriptor newColumn = new HColumnDescriptor("mycf02");
            admin.addColumn(tableName, newColumn);

            //删除column family
//            admin.deleteColumn(tableName, "mycf02".getBytes("UTF-8"));
            
            //Delete a table (Need to be disabled first)
//            admin.disableTable(tableName);
//            admin.deleteTable(tableName);
        } finally {
            admin.close();
            connection.close();
        }
    }

    public static void main(String... args) throws IOException {
        Configuration config = HBaseConfiguration.create();
//        config.addResource(new Path(System.getenv("HBASE_CONF_DIR"),"hbase-site.xml"));
//        config.addResource(new Path(System.getenv("HADOOP_CONF_DIR"),"core-site.xml"));
        createSchemaTables(config);
//        modifySchema(config);
    }
}

====HBase物理架构=========================================

HBase物理架构:
    1、Master通常是Hadoop里面的一台或者两台服务器(HA)
    2、regionserver服务器通常是Hadoop集群里面的一部分/全部服务器(在conf/regionservers配置)
    3、zookeeper通常是另外几台独立服务器的集群

HBase重要名词解释:
** Client
    ** 访问HBase数据库的表用户
    ** 读、写
** zookeeper
    ** 是client访问HBase的入口
    ** 存储了元数据表的位置
    ** 监控master和regionserver的状态
    ** 保证HBase的高可用性(HA)
** HMater
    ** 管理regionserver服务器,合理分配region
    ** 保证region的负载均衡
    ** Master会借助zookeeper感知regionserver的上下线
    ** regionserver宕机以后,会重新分配这台服务器上的region
    ** Master一般会有两台(HA),保证master高可用
    ** Master不参与数据读写,负载通常很低
** HRegionServer    
    ** 管理当前服务器上的所有region
    ** 响应客户端的数据读写请求
    ** 同一台服务器会有多个HRegion
        ** 每个表对应多个region,这些region被分配到不同regionserver管理
        ** 同一个HRegion又有多个store
        ** 每个store包含memstore和多个storefile
            memstore: 内存缓存区, 用来缓存写入的数据
            storefile:memstore达到阀值,会把数据写入HBase,生成HFile文件
    ** HLOG
        ** WAL[write-ahead log],二进制文件
        ** regionserver服务器意外宕机,可以防止数据丢失
** Hadoop
    ** 存储HBase数据,将数据储存在HDFS上

-------------------------------
    
HBase表:
1.用户表
用户自定义的表

2.元数据表
a) hbase:meta
> scan 'hbase:meta'    
hbase:meta保存着所有用户表的信息,如:一张表有哪些region,每个region的startkey和endkey ...

b) hbase:namespace
> scan 'hbase:namespace'
保存着命名空间信息


两类文件:
** HFile 
    以Key-Value形式存储HBase中的数据,HFile是Hadoop二进制格式文件
** HLOG  
    HBase中WAL(Write-Ahead Log)文件

----HBase结构-----------------------------------------

1、同一张表的多个region被master分配到多个regionserver管理
        region1        --> regionserverA
        region2        --> regionserverB
        region3        --> regionserverA

2、当表初写数据时,此时只有一个region ,随着数据的增多,region开始变大,等到达到限定阀值大小,会把region 分裂为两个大小基本相同的region,而这个阀值就是storefile的设定大小(属性:hbase.hregion.max.filesize,新版本默认10G) region是Hbase集群分布数据的最小单位。
这也就是为什么region比较少的时候,导致region分配不均,数据总是分派到少数节点上,读写并发效果并不显著,这就是hbase 读写效率比较低的原因之一。
    
3、同一个regionserver可以管理不同表的region

4、当regionserver宕机,或者执行balance时,才可能会将这部分region的数据转移到其它节点上。

5、每个HRegion由多个HStore组成,会对应创建一个新的HStore

6、MemStore 是有序的内存缓冲区 ,client写入的数据先写入MemStore,当达到MemStore的阀值时,将其Flush 成为一个StoreFile(HFile),StoreFile存储在硬盘上,阀值默认128M(hbase.hregion.memstore.flush.size),
此时需考虑每个RS负担的Region个数。

----读写流程-----------------------

HBase读数据流程:
1、client先去访问zookeeper,从zookeeper里面获取meta表所在位置信息(以前的版本有--root--,.meta.)
2、client向这台regionserver发起访问,从meta表获取元数据
3、client找到了当前需要访问的数据对应的regionserver服务器(IP)和region
4、client向这台regionserver服务器发起请求
5、regionserver收到client访问请求,先扫描memstore,再去storefile[HDFS]查询数据
6、regionserver把数据响应给client

HBase写数据流程:
1、client先访问zookeeper,找到meta表,并获取meta表元数据
2、确认当前写入数据对应的region,和regionserver服务器
3、client向这台regionserver服务器发起写入请求
4、regionserver收到client请求,并响应
5、client先把数据写入HLog
6、再把输入写入memstore,内存缓存区(默认128M),当Hlog和memstore都写入成功,则这条数据写入成功
7、当memstore达到阀值[128M],会把memstore里面的数据Flush进HFile
8、当HFile越来越多,会触发合并操作,把多HFile合并为一个大的HFile   
9、当HFile越来越大,达到阀值会触发split操作,region会被被一分为二

----HBase三个机制----------------------

** compact机制(合并)
    把几个小的HFile文件合并成一个大的HFile
    a) minor compaction(轻量级):    将符合条件的最早生成的几个storefile合并生成一个大的storefile文件,它不会删除被标记为“删除”的数据和已过期的数据,并且执行过一次minor合并操作后还会有多个storefile文件
    b) major compaction(重量级):    把所有的storefile合并成一个单一的storefile文件,在文件合并期间系统会删除标记为"删除"标记的数据和过期失效的数据,最终合并完成形成一个大的storefile文件

** split机制
    当region达到阀值,会把region一分为二
    
compact和split可以手动进行操作
什么场景我们会选择手动操作?
    ** 针对数据写入很频繁且数据量相对较大的应用
    ** 自动触发过多的compact和split会导致整个集群数据颠簸
    ** 手动操作compact和split通常会选择在业务低峰时段(凌晨)

** Flush机制
HStore由一个Memstore及多个HFile组成。当RS处理写请求时,数据首先写入到Memstore,然后当到达一定的阀值的时候,Memstore中的数据才会被刷到HFile中。

Memstore还充当内存级缓存。有一种常见的现象是:新插入数据总是比老数据更被频繁使用。每一次Memstore的flush,都会创建一个新的HFile。 

-- flush相关属性,http://192.168.122.128:60010/,点击右上角“HBase Configuration”

<!-- 当memstore大小超过指定值时进行flush,默认128M -->
<property>
    <name>hbase.hregion.memstore.flush.size</name>
    <value>134217728</value>
</property>

====HBase和MapReduce集成================================================================

** 应用场景
    ** 向HBase表加载数据
       MapReduce清洗过的数据 --> 加载到HBase表 --> mapreduce或者Hive分析
    ** 把HBase表数据可以读出来写入HDFS[Hive]
    ** 把HBase表数据读入RDBMS[mysql、oracle] JDBC
    
----HBase和MapReduce集成配置------------

** 准备工作:
** 找到HBase集成mapreduce所需要的jar包
$ bin/hbase mapredcp
-- 可以看到如下信息
/opt/modules/hbase-0.98.6-hadoop2/lib/hbase-common-0.98.6-hadoop2.jar:/opt/modules/hbase-0.98.6-hadoop2/lib/protobuf-java-2.5.0.jar:/opt/modules/hbase-0.98.6-hadoop2/lib/hbase-client-0.98.6-hadoop2.jar:/opt/modules/hbase-0.98.6-hadoop2/lib/hbase-hadoop-compat-0.98.6-hadoop2.jar:/opt/modules/hbase-0.98.6-hadoop2/lib/hbase-server-0.98.6-hadoop2.jar:/opt/modules/hbase-0.98.6-hadoop2/lib/hbase-protocol-0.98.6-hadoop2.jar:/opt/modules/hbase-0.98.6-hadoop2/lib/high-scale-lib-1.1.1.jar:/opt/modules/hbase-0.98.6-hadoop2/lib/zookeeper-3.4.5.jar:/opt/modules/hbase-0.98.6-hadoop2/lib/guava-12.0.1.jar:/opt/modules/hbase-0.98.6-hadoop2/lib/htrace-core-2.04.jar:/opt/modules/hbase-0.98.6-hadoop2/lib/netty-3.6.6.Final.jar

** 执行以下几个命令:
(因为是临时导入,这几个命令在哪个窗口执行,接下来的MapReduce代码就需要在哪个窗口里运行)
$ export HADOOP_HOME=/opt/modules/hadoop-2.5.0
$ export HBASE_HOME=/opt/modules/hbase-0.98.6-hadoop2
$ export HADOOP_CLASSPATH=`${HBASE_HOME}/bin/hbase mapredcp`

PS: $ echo $HADOOP_CLASSPATH

----示例1、统计表格有多少行------------

** 显示jar的功能
$ /opt/modules/hadoop-2.5.0/bin/yarn jar lib/hbase-server-0.98.6-hadoop2.jar

** 执行(最后一个参数为表名)
$ /opt/modules/hadoop-2.5.0/bin/yarn jar lib/hbase-server-0.98.6-hadoop2.jar rowcounter emp

----2、导入数据到HBase表(tsv格式)-------

TSV格式: 字段之间以\t分割
CSV格式: 字段之间以,分割

2.1、创建测试文件(间隔使用'\t')
$ vi student.txt
10001    zhangsan    female
20001    lisi    male
30001    wangwu    male

PS: $ cat -A student.txt  --查看特殊字符

2.2、上传到HDFS
$ bin/hdfs dfs -put student.txt /input

2.3、创建HBase表
$ bin/hbase shell
hbase(main):002:0> create 'student','info'

2.4、执行MapReduce,导入数据到HBase表
$ /opt/modules/hadoop-2.5.0/bin/yarn jar \
lib/hbase-server-0.98.6-hadoop2.jar importtsv \
-Dimporttsv.columns=HBASE_ROW_KEY,info:name,info:sex \
student hdfs://192.168.122.128:8020/input

猜你喜欢

转载自www.cnblogs.com/yin-fei/p/10778798.html