HBase

HBase

各数据库中的差别比较

在这里插入图片描述

Hive特点

1.Hive是数据仓库,Hive是基于Hdfs强大的存储能力,保证了可存储的数据量非常大,数据存储的文件为普通的文件;
2.Hive的运算是基于mapreduce运算模型,可对仓库中的数据进行查询;
3.查询速度比较慢,适用于数据清洗,数据分析等,不适用于联机事务处理(联机事务处理(OLTP)是指利用计算机网络,将分布于不同地理位置的业务处理计算机设备或网络与业务管理中心网络连接,以便于在任何一个网络节点上都可以进行统一、实时的业务处理活动或客户服务。);

普通数据库(sql/nosql)

1.mysql数据库依赖于本地文件系统,数据存储文件不是普通的文件,而是通过精心设计的文件,每条记录都具有索引,查询速度非常快,适用于联机事务处理。
2.HBase为nosql数据库,是基于hdfs文件系统,存储容量很大,数据存储文件是经过设计的文件,虽然查询数据需要通过网络传输,但查询速度依然很快,适用于联机事务处理。

什么是HBase

概念特性 :HBASE是一个数据库----可以提供数据的实时随机读写。
HBASE与mysql、oralce、db2、sqlserver等关系型数据库不同,它是一个NoSQL数据库(非关系型数据库)。
在这里插入图片描述
1.Hbase的表模型与关系型数据库的表模型不同:
2.Hbase的表模型中有:行的概念;但没有字段的概念
3.Hbase的表中每行存储的都是一些key-value对
4.Hbase的表中有列族的划分,用户可以指定将哪些kv插入哪个列族(base_info,extra_info)
5.Hbase的表在物理存储上,是按照列族来分割的,不同列族的数据一定存储在不同的文件中
6.Hbase的表中的每一行都固定有一个行键,而且每一行的行键在表中不能重复
7.Hbase中的数据,包含行键,包含key,包含value,都是byte[ ]类型,hbase不负责为用户维护数据类型
8.HBASE对事务的支持很差
9.行中存的都是key-value对,每行中的key-value对中的key可以是各种各样,每行中的key-value对的数量也可以是各种各样

HBASE相比于其他nosql数据库(mongodb、redis、cassendra、hazelcast)的特点

Hbase的表数据存储在HDFS文件系统中,从而hbase具备如下特性:存储容量可以线性扩展; 数据存储的安全性可靠性极高!

HBase安装流程

其中有一个管理角色: HMaster(一般2台,一台active,一台backup)
其他的数据节点角色: HRegionServer(很多台,看数据容量)

安装准备:
首先,要有一个HDFS集群,并正常运行; regionserver应该跟hdfs中的datanode在一起
其次,还需要一个zookeeper集群,并正常运行
然后,安装HBASE
角色分配如下:
Hdp01: namenode datanode regionserver hmaster zookeeper
Hdp02: datanode regionserver zookeeper
Hdp03: datanode regionserver zookeeper

安装步骤

参考:https://blog.csdn.net/wuliu_forever/article/details/87966901
1.解压hbase安装包:tar -zxvf hbase-1.2.1-bin.tar.gz -C apps/
2.修改conf/hbase-env.sh
export JAVA_HOME=/root/apps/jdk
export HBASE_MANAGES_ZK=false
3.修改conf/hbase-site.xml

<configuration>
<!-- 指定hbase在HDFS上存储的路径 -->
        <property>
                <name>hbase.rootdir</name>
                <value>hdfs://n1:9000/hbase</value>
        </property>
<!-- 指定hbase是分布式的 -->
        <property>
                <name>hbase.cluster.distributed</name>
                <value>true</value>
        </property>
<!-- 指定zk的地址,多个用“,”分割 -->
        <property>
                <name>hbase.zookeeper.quorum</name>
                <value>n1:2181,n2:2181,n3:2181</value>
        </property>
</configuration>

4.修改 conf/regionservers
n1
n2
n3

5.启动hbase集群:
bin/start-hbase.sh
启动完后,还可以在集群中找任意一台机器启动一个备用的master
bin/hbase-daemon.sh start master
新启的这个master会处于backup状态

6.启动hbase的命令行客户端
bin/hbase shell

Hbase> list // 查看表
Hbase> status // 查看集群状态
Hbase> version // 查看集群版本

7.浏览器查看hbase
n1:16010

hbase表模型的要点

在这里插入图片描述

master职责

1.管理HRegionServer,实现其负载均衡。
2.管理和分配HRegion,比如在HRegion split时分配新的HRegion;在HRegionServer退出时迁移其负责的HRegion到其他HRegionServer上。

admin职能

创建、删除、修改Table的定义。实现DDL操作(namespace和table的增删改,column familiy的增删改等)。
1.管理namespace和table的元数据(实际存储在HDFS上)。
2.权限控制(ACL)。
3.监控集群中所有HRegionServer的状态(通过Heartbeat和监听ZooKeeper中的状态)。

region server职责

1.管理自己所负责的region数据的读写。
2.读写HDFS,管理Table中的数据。
3.Client直接通过HRegionServer读写数据(从HMaster中获取元数据,找到RowKey所在的HRegion/HRegionServer后)。
在这里插入图片描述
1、一个表,有表名
2、一个表可以分为多个列族(不同列族的数据会存储在不同文件中)
3、表中的每一行有一个“行键rowkey”,而且行键在表中不能重复
4、表中的每一对kv数据称作一个cell
5、hbase可以对数据存储多个历史版本(历史版本数量可配置)
6、整张表由于数据量过大,会被横向切分成若干个region(用rowkey范围标识),不同region的数据也存储在不同文件中
7、hbase会对插入的数据按顺序存储:

hbase的表中能存储什么数据类型

hbase中只支持byte[]
此处的byte[] 包括了: rowkey,key,value,列族名,表名

HBASE表的物理存储结构

在这里插入图片描述

hbase命令行客户端操作

建表:

create ‘t_user_info’,‘base_info’,‘extra_info’
表名 列族名 列族名

插入数据:

put ‘t_user_info’,‘001’,‘base_info:username’,‘zhangsan’
put ‘t_user_info’,‘001’,‘base_info:age’,‘18’
put ‘t_user_info’,‘001’,‘base_info:sex’,‘female’
put ‘t_user_info’,‘001’,‘extra_info:career’,‘it’
put ‘t_user_info’,‘002’,‘extra_info:career’,‘actoress’
put ‘t_user_info’,‘002’,‘base_info:username’,‘liuyifei’
在这里插入图片描述

查询数据方式一:scan 扫描

scan ‘t_user_info’
在这里插入图片描述

查询数据方式二:get 单行数据

get ‘t_user_info’,‘001’
在这里插入图片描述

删除一个kv数据

delete ‘t_user_info’,‘001’,‘base_info:sex’
在这里插入图片描述
删除整行数据:
deleteall ‘t_user_info’,‘001’
在这里插入图片描述

删除整个表:

注意:将表删除前必须distable 表。
disable ‘t_user_info’
drop ‘t_user_info’
在这里插入图片描述

Hbase重要特性–排序特性(行键)

插入到hbase中去的数据,hbase会自动排序存储:
排序规则: 首先看行键,然后看列族名,然后看列(key)名; 按字典顺序

Hbase的这个特性跟查询效率有极大的关系
比如:一张用来存储用户信息的表,有名字,户籍,年龄,职业…等信息
然后,在业务系统中经常需要:
查询某个省的所有用户
经常需要查询某个省的指定姓的所有用户

思路:如果能将相同省的用户在hbase的存储文件中连续存储,并且能将相同省中相同姓的用户连续存储,那么,上述两个查询需求的效率就会提高。
做法:将查询条件拼到rowkey内

布隆过滤器工作原理

在这里插入图片描述
原理:(以网络爬虫为例)
1.将获取到的URL通过特定的算法计算,得到8个bit和索引角标,对应在64K(长度可以更长)的二进制数组中的8个索引上。
2.如果指定索引出现任意一个bit的数值为0,说明该URL没有被爬到,将改索引处的bit值更换为1。
3.如果指定索引处所有的值均为1,说明该URL已经被爬到。
作用:布隆过滤器对没有被保存的资源判断是准确的。对已经保存的资源做出的判断不是百分百准确(准确率与二进制数组的长度是有关系的)。

hbase客户端API

package com.initialize;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
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.regionserver.BloomType;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
/**
 *  
 *  1、构建连接
 *  2、从连接中取到一个表DDL操作工具admin
 *  3、admin.createTable(表描述对象);
 *  4、admin.disableTable(表名);
	5、admin.deleteTable(表名);
	6、admin.modifyTable(表名,表描述对象);	
 *  
 * @author hunter.d
 *
 */
public class HbaseClientDemo {

    Connection conn = null;

    @Before
    public void getConn() throws IOException {
        //构建一个连接对象
        Configuration conf = HBaseConfiguration.create();//会自动加载hbase-site.xml
        conf.set("hbase.zookeeper.quorum","n1:2181,n2:2181,n3:2181");

        conn = ConnectionFactory.createConnection(conf);
    }

    /**
     * DDL
     * 创建表
     */
    @Test
    public void testCreateTable() throws  Exception{

        //从连接中构造一个DDL操作器
        Admin admin = conn.getAdmin();

        //创建一个标定义描述对象
        HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf("user_info"));

        //创建列族定义描述对象
        HColumnDescriptor hColumnDescriptor_1 = new HColumnDescriptor("base_info");
        hColumnDescriptor_1.setMaxVersions(3);

        HColumnDescriptor hColumnDescriptor_2 = new HColumnDescriptor("extra_info");

        //将列族定义信息对象放入表定义对象中
        hTableDescriptor.addFamily(hColumnDescriptor_1);
        hTableDescriptor.addFamily(hColumnDescriptor_2);

        //用ddl操作器对象:admin来创建表
        admin.createTable(hTableDescriptor);

        //关闭连接
        admin.close();
        conn.close();

    }

    /**
     * 删除表
     */
    @Test
    public void testDropTable() throws  Exception{

        Admin admin = conn.getAdmin();

        //停用表
        admin.disableTable(TableName.valueOf("user_info"));
        //删除表
        admin.deleteTable(TableName.valueOf("user_info"));

        admin.close();
        conn.close();
    }

    /**
     * 修改表定义--添加一个列族
     */
    @Test
    public void testAlterTable() throws  Exception{

        Admin admin = conn.getAdmin();

        //取出旧的表定义信息
        HTableDescriptor tableDescriptor = admin.getTableDescriptor(TableName.valueOf("user_info"));

        //新构造一个列族定义
        HColumnDescriptor hColumnDescriptor = new HColumnDescriptor("other_info");
        hColumnDescriptor.setBloomFilterType(BloomType.ROWCOL);//设置该列族的布隆过滤器类型

        //将列族定义添加到表定义对象中
        tableDescriptor.addFamily(hColumnDescriptor);

        //将修改过的表定义交给admin去提交
        admin.modifyTable(TableName.valueOf("user_info"), tableDescriptor);

        admin.close();
        conn.close();
    }
}
package com.initialize;


import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellScanner;
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 org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

public class HbaseClientDML {

    Connection conn = null;

    @Before
    public void getConn() throws IOException {
        //构建一个连接对象
        Configuration conf = HBaseConfiguration.create();//会自动加载hbase-site.xml
        conf.set("hbase.zookeeper.quorum","n1:2181,n2:2181,n3:2181");

        conn = ConnectionFactory.createConnection(conf);
    }


    /**
     * 增,改:put来覆盖
     */
    @Test
    public void testPut() throws  Exception{

        //获取一个操作指定表的table对象,进行DML操作
        Table table = conn.getTable(TableName.valueOf("user_info"));

        //构造要插入的数据为一个Put类型(一个put对象只能对应一个rowkey)的对象
        Put put = new Put(Bytes.toBytes("001"));
        put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("username"),Bytes.toBytes("张三"));
        put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("age"), Bytes.toBytes("18"));
        put.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"), Bytes.toBytes("北京"));

        Put put2 = new Put(Bytes.toBytes("002"));
        put2.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("username"), Bytes.toBytes("李四"));
        put2.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("age"), Bytes.toBytes("28"));
        put2.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"), Bytes.toBytes("上海"));

        ArrayList<Put> puts = new ArrayList<>();
        puts.add(put);
        puts.add(put2);

        //插进去
        table.put(puts);

        table.close();
        conn.close();
    }

    /***
     * 循环插入大量数据
     */
    @Test
    public void testManyPuts() throws Exception{

        Table table = conn.getTable(TableName.valueOf("user_info"));
        ArrayList<Put> puts = new ArrayList<>();

        for(int i=0;i<10000;i++){
            Put put = new Put(Bytes.toBytes(""+i));
            put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("usernaem"), Bytes.toBytes("张三" +i));
            put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("age"), Bytes.toBytes((18+i) + ""));
            put.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"), Bytes.toBytes("北京"));

            puts.add(put);
        }

        table.put(puts);
    }

    /**
     * 删
     */
    @Test
    public void testDelete() throws Exception{
        Table table = conn.getTable(TableName.valueOf("user_info"));

        //构造一个对象封装要删除的数据信息
        Delete delete1 = new Delete(Bytes.toBytes("001"));

        Delete delete2 = new Delete(Bytes.toBytes("002"));
        delete2.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"));

        ArrayList<Delete> dels = new ArrayList<>();
        dels.add(delete1);
        dels.add(delete2);

        table.delete(dels);

        table.close();
        conn.close();
    }

    /**
     * 查
     */
    @Test
    public void  testGet() throws Exception{

        Table table = conn.getTable(TableName.valueOf("user_info"));

        Get get = new Get("002".getBytes());

        Result result = table.get(get);

        //从结果中取用户指定的某个key和value的值
        byte[] value = result.getValue("base_info".getBytes(), "age".getBytes());
        System.out.println(new String(value));

        System.out.println("======================");

        //遍历整行结果中的所有kv单元格
        CellScanner cellScanner = result.cellScanner();
        while(cellScanner.advance()){
            Cell cell = cellScanner.current();

            byte[] rowArray = cell.getRowArray();//本kv所属行键的字节数组
            byte[] familyArray = cell.getFamilyArray();//列族名的字节数组
            byte[] qualifierArray = cell.getQualifierArray();//列明的字节数组
            byte[] valueArray = cell.getValueArray();//value字节数组
            
            System.out.println("行键:" + new String(rowArray, cell.getRowOffset(), cell.getRowLength()));
            System.out.println("列族名:" + new String(familyArray, cell.getFamilyOffset(), cell.getFamilyLength()));
            System.out.println("列名:" + new String(qualifierArray, cell.getQualifierOffset(), cell.getQualifierLength()));
            System.out.println("value:" + new String(valueArray, cell.getValueOffset(), cell.getValueLength()));

        }
        table.close();
        conn.close();

    }


    /**
     * 按行键范围查询数据
     */
    @Test
    public void testScan() throws Exception{

        Table table = conn.getTable(TableName.valueOf("user_info"));

        //包含起始行键,不包含结束行键,但是如果真的是想要查询出末尾的那个行键,可以在尾行键上拼接一个不可见的字符(\000)
        Scan scan = new Scan("10".getBytes(), "10000\001".getBytes());

        ResultScanner scanner =table.getScanner(scan);

        Iterator<Result> iterator = scanner.iterator();

        while(iterator.hasNext()){

            Result result =iterator.next();
            //遍历整行结果中的所有kv单元格
            CellScanner cellScanner = result.cellScanner();
            while(cellScanner.advance()){
                Cell cell = cellScanner.current();

                byte[] rowArray = cell.getRowArray();//本kv所属行键的字节数组
                byte[] familyArray = cell.getFamilyArray();//列族名的字节数组
                byte[] qualifierArray = cell.getQualifierArray();//列明的字节数组
                byte[] valueArray = cell.getValueArray();//value字节数组

                System.out.println("行键:" + new String(rowArray, cell.getRowOffset(), cell.getRowLength()));
                System.out.println("列族名:" + new String(familyArray, cell.getFamilyOffset(), cell.getFamilyLength()));
                System.out.println("列名:" + new String(qualifierArray, cell.getQualifierOffset(), cell.getQualifierLength()));
                System.out.println("value:" + new String(valueArray, cell.getValueOffset(), cell.getValueLength()));

            }
            System.out.println("----------------------");
        }



    }

    @Test
    public void test(){
        String a = "000";
        String b = "000\0";

        System.out.println(a);
        System.out.println(b);

        byte[] bytes = a.getBytes();
        byte[] bytes2 = b.getBytes();
        
        System.out.println("");
    }




}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值