zoukankan      html  css  js  c++  java
  • 海量列式非关系数据库HBase 架构,shell与API

    HBase的特点:

    • 海量存储: 底层基于HDFS存储海量数据
    • 列式存储:HBase表的数据是基于列族进行存储的,一个列族包含若干列
    • 极易扩展:底层依赖HDFS,当磁盘空间不足的时候,只需要动态增加DataNode服务节点就可以
    • 高并发:支持高并发的读写请求
    • 稀疏:稀疏主要是针对HBase列的灵活性,在列族中,你可以指定任意多的列,在列数据为空的情 况下,是不会占用存储空间的。
    • 数据的多版本:HBase表中的数据可以有多个版本值,默认情况下是根据版本号去区分,版本号就 是插入数据的时间戳
    • 数据类型单一:所有的数据在HBase中是以字节数组进行存储

    HBase的应用场景:

      HBase适合海量明细数据的存储,并且后期需要有很好的查询性能(单表超千万、上亿, 且并发要求高)

    HBase数据模型:

    HBase整体架构:

     Zookeeper

    • 实现了HMaster的高可用
    • 保存了HBase的元数据信息,是所有HBase表的寻址入口
    • 对HMaster和HRegionServer实现了监控

    HMaster(Master)

    • 为HRegionServer分配Region 维护整个集群的负载均衡
    • 维护集群的元数据信息
    • 发现失效的Region,并将失效的Region分配到正常的HRegionServer上

    HRegionServer(RegionServer)

    • 负责管理Region 接受客户端的读写数据请求
    • 切分在运行过程中变大的Region

    Region

    • 每个HRegion由多个Store构成, 每个Store保存一个列族(Columns Family),表有几个列族,则有几个Store,
    • 每个Store由一个MemStore和多个StoreFile组成,MemStore是Store在内存中的内容,写到文件 后就是StoreFile。
    • StoreFile底层是以HFile的格式保存

    HBase shell 基本操作:

    入口:hbase shell

    hbase(main):001:0> create 'lagou', 'base_info', 'extra_info'
    或者(Hbase建表必须指定列族信息)
    create 'lagou', {NAME => 'base_info', VERSIONS => '3'},{NAME =>
    'extra_info',VERSIONS => '3'}
    VERSIONS 是指此单元格内的数据可以保留最近的 3 个版本

    添加数据操作:

    向lagou表中插入信息,row key为 rk1,列族base_info中添加name列标示符,值为wang
    put 'lagou', 'rk1', 'base_info:name', 'wang'
    
    向lagou表中插入信息,row key为rk1,列族base_info中添加age列标示符,值为30
    put 'lagou', 'rk1', 'base_info:age', 30
    向lagou表中插入信息,row key为rk1,列族extra_info中添加address列标示符,值为shanghai put 'lagou', 'rk1', 'extra_info:address', 'shanghai'

    查询,更新,删除:

    获取表中row key为rk1的所有信息
    get 'lagou', 'rk1'
    获取lagou表中row key为rk1,base_info列族的所有信息
    get 'lagou', 'rk1', 'base_info'
    获取表中row key为rk1,base_info列族的name、age列标示符的信息
    get 'lagou', 'rk1', 'base_info:name', 'base_info:age'
    
    获取lagou表中row key为rk1,base_info、extra_info列族的信息
    hbase(main):010:0> get 'lagou', 'rk1', 'base_info', 'extra_info'
    或者
    hbase(main):011:0> get 'lagou', 'rk1', {COLUMN => ['base_info', 'extra_info']}
    或者
    hbase(main):012:0> get 'lagou', 'rk1', {COLUMN => ['base_info:name',
    'extra_info:address']}
    
    获取表中row key为rk1,cell的值为wang的信息
    get 'lagou', 'rk1', {FILTER => "ValueFilter(=,
    'binary:wang')"}
    
    获取表中row key为rk1,列标示符中含有a的信息
    get 'lagou', 'rk1', {FILTER => "
    (QualifierFilter(=,'substring:a'))"}
    
    查询lagou表中的所有信息:
     scan 'lagou'
    
    查询表中列族为 base_info 的信息:
    hbase(main):001:0> scan 'lagou', {COLUMNS => 'base_info'}
    hbase(main):002:0> scan 'lagou', {COLUMNS => 'base_info', RAW => true, VERSIONS
    => 3}
    ## Scan时可以设置是否开启Raw模式,开启Raw模式会返回包括已添加删除标记但是未实际删除的数据
    ## VERSIONS指定查询的最大版本数
    
    指定多个列族与按照数据值模糊查询:
    查询lagou表中列族为 base_info 和 extra_info且列标示符中含有a字符的信息
    
    hbase(main):001:0> scan 'lagou', {COLUMNS => ['base_info', 'extra_info'], FILTER
    => "(QualifierFilter(=,'substring:a'))"}
    
    rowkey的范围值查询(非常重要)
    查询lagou表中列族为base_info,rk范围是[rk1, rk3)的数据(rowkey底层存储是字典序)
    按rowkey顺序存储。
    scan 'lagou', {COLUMNS => 'base_info', STARTROW => 'rk1',
    ENDROW => 'rk3'}
    
    查询lagou表中row key以rk字符开头的
    hbase(main):001:0> scan 'lagou',{FILTER=>"PrefixFilter('rk')"}
    
     更新数据值:
    把lagou表中rowkey为rk1的base_info列族下的列name修改为liang
    put 'lagou', 'rk1', 'base_info:name', 'liang'
    
    
    删除数据和表:
    删除lagou表row key为rk1,列标示符为 base_info:name 的数据
    > delete 'lagou', 'rk1', 'base_info:name'
    
    指定rowkey,列名以及时间戳信息进行删除
    删除lagou表row key为rk1,列标示符为base_info:name的数据
    delete 'lagou', 'rk1', 'base_info:name',1600660619655
    
    删除 base_info 列族
     alter 'lagou', 'delete' => 'base_info'
    
    删除lagou表数据
    truncate 'lagou'
    
    删除lagou表
    #先disable 再drop
    hbase(main):036:0> disable 'lagou'
    hbase(main):037:0> drop 'lagou'
    #如果不进行disable,直接drop会报错
    ERROR: Table user is enabled. Disable it first.

    HBase JAVA  API:

    <dependencies>
    <dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-client</artifactId>
    <version>1.3.1</version>
    </dependency>
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
    </dependency>
    <dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>6.14.3</version>
    <scope>test</scope>
    </dependency>
    </dependencies>

    创建连接:

    package com.lagou.hbase.client;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.hbase.*;
    import org.apache.hadoop.hbase.client.*;
    import org.apache.hadoop.hbase.util.Bytes;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    import java.io.IOException;
    
    public class HbaseClientDemo {
        Configuration conf = null;
        Connection conn = null;
    
        @Before
        public void init() throws IOException {
            //获取一个配置文件对象
            conf = HBaseConfiguration.create();
    
            conf.set("hbase.zookeeper.quorum", "linux121,linux122");
            conf.set("hbase.zookeeper.property.clientPort", "2181");
            //通过conf获取到hbase集群的连接
            conn = ConnectionFactory.createConnection(conf);
        }
    
        //释放连接
        @After
        public void realse() {
            if (conn != null) {
                try {
                    conn.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    创建表:

     //创建一张hbase表
        @Test
        public void createTable() throws IOException {
            //获取HbaseAdmin对象用来创建表
            HBaseAdmin admin = (HBaseAdmin) conn.getAdmin();
            //创建Htabledesc描述器,表描述器
            final HTableDescriptor worker = new HTableDescriptor(TableName.valueOf("worker"));
            //指定列族
            worker.addFamily(new HColumnDescriptor("info"));
            admin.createTable(worker);
            System.out.println("worker表创建成功!!");
        }

    插入数据:

      //插入一条数据
        @Test
        public void putData() throws IOException {
            //需要获取一个table对象
            final Table worker = conn.getTable(TableName.valueOf("worker"));
    
            //准备put对象
            final Put put = new Put(Bytes.toBytes("110"));//指定rowkey
    
            put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("addr"), Bytes.toBytes("beijing"));
            //插入数据,参数类型是put
            worker.put(put);
            //准备list<puts>,可以执行批量插入
            //关闭table对象
            worker.close();
            System.out.println("插入数据到worker表成功!!");
        }

    查询数据:

    //查询数据
        @Test
        public void getData() throws IOException {
            //准备table对象
            final Table worker = conn.getTable(TableName.valueOf("worker"));
            //准备get对象
            final Get get = new Get(Bytes.toBytes("110"));
            //指定查询某个列族或者列
            get.addFamily(Bytes.toBytes("info"));
            //执行查询
            final Result result = worker.get(get);
            //获取到result中所有cell对象
            final Cell[] cells = result.rawCells();
            //遍历打印
            for (Cell cell : cells) {
                final String rowkey = Bytes.toString(CellUtil.cloneRow(cell));
                final String f = Bytes.toString(CellUtil.cloneFamily(cell));
                final String column = Bytes.toString(CellUtil.cloneQualifier(cell));
                final String value = Bytes.toString(CellUtil.cloneValue(cell));
    
                System.out.println("rowkey-->" + rowkey + "--;cf-->" + f + "---;column--->" + column + "--;value-->" + value);
            }
            worker.close();
        }

    删除数据:

       //删除一条数据
        @Test
        public void deleteData() throws IOException {
            //需要获取一个table对象
            final Table worker = conn.getTable(TableName.valueOf("worker"));
    
            //准备delete对象
            final Delete delete = new Delete(Bytes.toBytes("110"));
    //执行删除
            worker.delete(delete);
            //关闭table对象
            worker.close();
            System.out.println("删除数据成功!!");
        }

    通过Scan全表扫描:

    /**
    * 全表扫描
    */
    @Test
    public void scanAllData() throws IOException {
    HTable teacher = (HTable) conn.getTable(TableName.valueOf("teacher"));
    Scan scan = new Scan();
    ResultScanner resultScanner = teacher.getScanner(scan);
    for (Result result : resultScanner) {
    Cell[] cells = result.rawCells();//获取改行的所有cell对象
    for (Cell cell : cells) {
    //通过cell获取rowkey,cf,column,value
    String cf = Bytes.toString(CellUtil.cloneFamily(cell));
    String column = Bytes.toString(CellUtil.cloneQualifier(cell));
    String value = Bytes.toString(CellUtil.cloneValue(cell));
    String rowkey = Bytes.toString(CellUtil.cloneRow(cell));
    System.out.println(rowkey + "----" + cf + "--" + column + "---"
    + value);
    }
    }
    teacher.close();
    
    }

    通过startRowKey和endRowKey进行扫描:

    //指定scan 开始rowkey和结束rowkey,这种查询方式建议使用,指定开始和结束rowkey区间避免全表扫描
    @Test
    public void scanStartEndData() throws IOException {
        //准备table对象
        final Table worker = conn.getTable(TableName.valueOf("worker"));
        //准备scan对象
        final Scan scan = new Scan();
        //指定查询的rowkey区间,rowkey在hbase中是以字典序排序
        scan.setStartRow(Bytes.toBytes("001"));
        scan.setStopRow(Bytes.toBytes("004"));
        //执行扫描
        final ResultScanner resultScanner = worker.getScanner(scan);
        for (Result result : resultScanner) {
            //获取到result中所有cell对象
            final Cell[] cells = result.rawCells();
            //遍历打印
            for (Cell cell : cells) {
                final String rowkey = Bytes.toString(CellUtil.cloneRow(cell));
                final String f = Bytes.toString(CellUtil.cloneFamily(cell));
                final String column = Bytes.toString(CellUtil.cloneQualifier(cell));
                final String value = Bytes.toString(CellUtil.cloneValue(cell));
                System.out.println("rowkey-->" + rowkey + "--;cf-->" + f + ";column--->" + column + "--;value-->" + value);
            }
        }
    
        worker.close();
    }
  • 相关阅读:
    ES10(2019)有哪些更新和新特性?
    搞不懂JS中赋值·浅拷贝·深拷贝的请看这里
    Vue Nginx反向代理配置 解决生产环境跨域
    react的事件处理为什么要bind this 改变this的指向?
    没有用到React,为什么我需要import引入React?
    git的基本使用和多人协作合并管理
    JSON对象和JavaScript对象直接量的区别--不同之处
    (Demo分享)利用原生JavaScript-ScrollLeft-实现做轮播广告通知
    (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
    软件测试行业的职业发展路线如何?如何快速突破职业瓶颈?
  • 原文地址:https://www.cnblogs.com/wanghzh/p/15270164.html
Copyright © 2011-2022 走看看