首页 > 其他分享 >HBase基础知识分享(一)

HBase基础知识分享(一)

时间:2024-11-13 08:57:47浏览次数:1  
标签:rs students scan 基础知识 new HBase 分享 getBytes

写在前面

今天来学习Hbase部分的知识!

Zookeeper的ZAB协议

ZAB(Zookeeper Atomic Broadcast)协议是Zookeeper的核心协议之一,用于保证集群中数据的一致性、顺序性和容错性。它包括以下几个关键阶段:

  • Leader选举:选举出一个Leader节点来协调集群内的操作。
  • 事务提案:客户端提交的事务会被提案并传播到集群中。
  • 投票与提交:集群中的所有节点投票确认事务,然后提交。

ZAB协议的设计灵感来自于Paxos协议,但简化了许多步骤,使其更加适合Zookeeper这种主要用作协调服务的分布式系统。

ZAB协议的特点

  • 保证数据一致性。
  • 通过Leader节点保证顺序性。
  • 容错性强,能应对节点故障或网络分区。
  • 为分布式系统提供强一致性,确保高可用性和稳定性。

HBase的特点

  1. 大规模:支持百万级别的列和行,适合存储海量数据。
  2. 面向列族:数据存储按列族进行分组,提供灵活的存储和权限控制。
  3. 稀疏:只对有数据的列分配存储空间,节省存储。
  4. 无模式(No Schema):每行可以有不同的列,不强制列的定义。
  5. 数据多版本:支持多版本数据,每个单元格有多个版本,可以根据时间戳查询不同版本。
  6. 数据单一类型:所有数据都以字节数组存储,无类型区分。

HBase的三维有序结构

HBase的数据按 行键、列族和时间戳 三个维度进行排序:

  1. 行键(Row Key):数据按行键的字典顺序排序,行键是HBase存储的基本粒度。
  2. 列族(Column Family):数据按列族进行分组,同一个列族内的数据按列名排序。
  3. 时间戳(Timestamp):同一个单元格内的数据可以有多个版本,按时间戳的顺序排序,支持多版本数据。

这个设计使得HBase在处理大数据时具有高效的查询、存储和写入能力。


如何定位到 HBase 的 Cell

  1. 行键(Row Key):HBase中的数据按行键顺序存储,因此要查询某个 Cell,需要知道它的行键。通过查询行键,可以定位到包含该行数据的 RegionServer

  2. 列族(Column Family)和列名(Column Qualifier):一旦确定了目标行,下一步是确定目标列。HBase按列族存储数据,每个列族包含多个列,查询时需要指定列族和列名。

  3. 时间戳(Timestamp):HBase中的每个单元格按时间戳版本排序。每次写入时,HBase会自动为每个单元格分配一个时间戳。如果没有显式指定时间戳,默认使用当前时间戳。

通过 行键、列族、列名和时间戳,可以精确地查询到一个 Cell


什么是 Region?通过 RK 定位到 Region

  • Region 是HBase存储数据的最小单元,负责存储一个连续范围的行数据。
  • Region 根据行键范围划分,HBase会根据行键自动将数据划分到不同的 Region
  • 通过 行键(Row Key),HBase可以定位到某个 Region。每个 Region 都有一个行键范围,当查询时,HBase会根据行键判断它所属的Region。
  • HBase通过 ZookeeperMaster节点 来管理Region和RegionServer的分配。查询时,客户端通过行键查询Zookeeper或Master,获得对应的Region和RegionServer信息。

HBase的数据模型

  1. RowKey:用于唯一标识一行数据,是HBase查询数据的主键。

    • 支持通过单个RowKey、RowKey范围或正则表达式等方式查询。
    • RowKey按字典顺序存储,最大长度64KB,通常应用中为10~100字节。
  2. 列簇(Column Family)

    • 列簇是表的结构部分,表创建时必须指定至少一个列簇。
    • 列簇内的数据按列名排序。
    • HBase中的数据存储、权限控制和版本控制都是按列簇进行的。
  3. 时间戳

    • 每条数据都会记录时间戳,支持多版本数据存储。
    • 按时间戳倒序存储,获取数据时默认返回最新版本。
    • 设置TTL(Time to Live)时,HBase会根据时间戳自动删除过期数据。
  4. Cell

    • RowKeyColumn(列簇+列名)Version(时间戳) 唯一标识。
    • HBase中的数据都以字节数组形式存储。

HBase的架构及读写流程

HBase的架构主要包括以下组件:

  • Client:提交读写请求。
  • HMaster:负责管理Region和RegionServer的分配。
  • RegionServer:负责存储和处理Region数据。
  • Zookeeper:协调HBase集群中的节点,维护元数据。

HBase读写流程:

  • 写入流程:客户端请求写入数据,HBase首先将数据写入 MemStore,然后异步刷写到HFile中。当数据达到阈值时,会触发Region的分裂。
  • 读取流程:客户端请求读取数据,HBase根据行键定位到对应的RegionServer,并从MemStore或HFile中读取数据。
    HBase架构及读写流程

常用的HBase比较器与过滤器

比较器(Comparator)

  1. BinaryComparator:按字节索引顺序比较字节数组。
  2. BinaryPrefixComparator:比较字节数组的前缀是否匹配。
  3. RegexStringComparator:使用正则表达式比较字符串。
  4. SubstringComparator:判断一个子串是否存在于目标字符串中。
  • HBase有哪些常用的过滤器?

单列值过滤器:SingleColumnValueFilter
SingleColumnValueFilter会返回满足条件的cell所在行的所有cell的值(即会返回一行数据)
通过SingleColumnValueFilter与查询文科班所有学生信息

    @Test
    // 通过SingleColumnValueFilter与查询文科班所有学生信息
    public void RegexStringComparatorFilter() throws IOException {
        Table students = conn.getTable(TableName.valueOf("students"));
        SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(
                "info".getBytes(),
                "clazz".getBytes(),
                CompareFilter.CompareOp.EQUAL,
                new RegexStringComparator("^文科.*")
        );

        Scan scan = new Scan();
        scan.setFilter(singleColumnValueFilter);
        ResultScanner scanner = students.getScanner(scan);

        Result rs = scanner.next();
        while (rs != null) {
            String id = Bytes.toString(rs.getRow());
            String name = Bytes.toString(rs.getValue("info".getBytes(), "name".getBytes()));
            int age = Bytes.toInt(rs.getValue("info".getBytes(), "age".getBytes()));
            String gender = Bytes.toString(rs.getValue("info".getBytes(), "gender".getBytes()));
            String clazz = Bytes.toString(rs.getValue("info".getBytes(), "clazz".getBytes()));

            System.out.println(id + "\t" + name + "\t" + age + "\t" + gender + "\t" + clazz + "\t");

            rs = scanner.next();
        }

    }

列值排除过滤器:SingleColumnValueExcludeFilter
与SingleColumnValueFilter相反,会排除掉指定的列,其他的列全部返回
通过SingleColumnValueExcludeFilter与BinaryComparator查询文科一班所有学生信息,最终不返回clazz列

    @Test
    // 通过SingleColumnValueExcludeFilter与BinaryComparator查询文科一班所有学生信息,最终不返回clazz列
    public void RegexStringComparatorExcludeFilter() throws IOException {
        Table students = conn.getTable(TableName.valueOf("students"));
        SingleColumnValueExcludeFilter singleColumnValueExcludeFilter = new SingleColumnValueExcludeFilter(
                "info".getBytes(),
                "clazz".getBytes(),
                CompareFilter.CompareOp.EQUAL,
                new BinaryComparator("文科一班".getBytes())
        );

        Scan scan = new Scan();
        scan.setFilter(singleColumnValueExcludeFilter);
        ResultScanner scanner = students.getScanner(scan);

        Result rs = scanner.next();
        while (rs != null) {
            String id = Bytes.toString(rs.getRow());
            String name = Bytes.toString(rs.getValue("info".getBytes(), "name".getBytes()));
            int age = Bytes.toInt(rs.getValue("info".getBytes(), "age".getBytes()));
            String gender = Bytes.toString(rs.getValue("info".getBytes(), "gender".getBytes()));
            // clazz列为空
            String clazz = Bytes.toString(rs.getValue("info".getBytes(), "clazz".getBytes()));

            System.out.println(id + "\t" + name + "\t" + age + "\t" + gender + "\t" + clazz + "\t");

            rs = scanner.next();
        }

    }

rowkey前缀过滤器:PrefixFilter
通过PrefixFilter查询以150010008开头的所有前缀的rowkey

    @Test
    // 通过PrefixFilter查询以150010008开头的所有前缀的rowkey
    public void PrefixFilterFilter() throws IOException {
        Table students = conn.getTable(TableName.valueOf("students"));
        PrefixFilter prefixFilter = new PrefixFilter("150010008".getBytes());
        Scan scan = new Scan();
        scan.setFilter(prefixFilter);
        ResultScanner scanner = students.getScanner(scan);
        Result rs = scanner.next();
        while (rs != null) {
            String id = Bytes.toString(rs.getRow());
            String name = Bytes.toString(rs.getValue("info".getBytes(), "name".getBytes()));
            int age = Bytes.toInt(rs.getValue("info".getBytes(), "age".getBytes()));
            String gender = Bytes.toString(rs.getValue("info".getBytes(), "gender".getBytes()));
            // clazz列为空
            String clazz = Bytes.toString(rs.getValue("info".getBytes(), "clazz".getBytes()));

            System.out.println(id + "\t" + name + "\t" + age + "\t" + gender + "\t" + clazz + "\t");

            rs = scanner.next();
        }
    }

分页过滤器PageFilter

通过PageFilter查询第三页的数据,每页10条
使用PageFilter分页效率比较低,每次都需要扫描前面的数据,直到扫描到所需要查的数据
可设计一个合理的rowkey来实现分页需求

    @Test
    // 通过PageFilter查询第三页的数据,每页10条
    public void PageFilter() throws IOException {
        Table students = conn.getTable(TableName.valueOf("students"));
        int PageNum = 3;
        int PageSize = 10;
        Scan scan = new Scan();
        if (PageNum == 1) {
            scan.withStartRow("".getBytes());
            //使用分页过滤器,实现数据的分页
            PageFilter pageFilter = new PageFilter(PageSize);
            scan.setFilter(pageFilter);
            ResultScanner scanner = students.getScanner(scan);
            printRS(scanner);
        } else {
            String current_page_start_rows = "";
            int scanDatas = (PageNum - 1) * PageSize + 1;
            PageFilter pageFilter = new PageFilter(scanDatas);
            scan.setFilter(pageFilter);
            ResultScanner scanner = students.getScanner(scan);
            for (Result rs : scanner) {
                current_page_start_rows = Bytes.toString(rs.getRow());
            }
            scan.withStartRow(current_page_start_rows.getBytes());
            PageFilter pageFilter1 = new PageFilter(PageSize);
            scan.setFilter(pageFilter1);
            ResultScanner scanner1 = students.getScanner(scan);
            printRS(scanner1);

        }

    }

通过合理的设置rowkey来实现分页功能

    @Test
    // 通过合理的设置rowkey来实现分页功能,提高效率
    public void PageFilterTest2() throws IOException {
        Table students = conn.getTable(TableName.valueOf("students"));
        int PageSize = 10;
        int PageNum = 3;

        int baseId = 1500100000;
        int start_row = baseId + (PageNum - 1) * PageSize + 1;
        int end_row = start_row + PageSize;
        Scan scan = new Scan();
        scan.withStartRow(String.valueOf(start_row).getBytes());
        scan.withStopRow(String.valueOf(end_row).getBytes());

        ResultScanner scanner = students.getScanner(scan);

        printRS(scanner);


    }

多过滤器综合查询

查询文科班中的学生中学号以150010008开头并且年龄小于23的学生信息

    @Test
    // 查询文科班中的学生中学号以150010008开头并且年龄小于23的学生信息
    public void FilterListFilter() throws IOException {
        Table students = conn.getTable(TableName.valueOf("students"));
        Scan scan = new Scan();
        SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(
                "info".getBytes()
                , "clazz".getBytes()
                , CompareFilter.CompareOp.EQUAL
                , new RegexStringComparator("^文科.*"));
        PrefixFilter prefixFilter = new PrefixFilter("150010008".getBytes());
        SingleColumnValueFilter singleColumnValueFilter1 = new SingleColumnValueFilter(
                "info".getBytes()
                , "age".getBytes()
                , CompareFilter.CompareOp.LESS
                , new BinaryComparator(Bytes.toBytes(23)));

        FilterList filterList = new FilterList();
        filterList.addFilter(singleColumnValueFilter);
        filterList.addFilter(prefixFilter);
        filterList.addFilter(singleColumnValueFilter1);
        scan.setFilter(filterList);
        ResultScanner scanner = students.getScanner(scan);
        printRS(scanner);

    }

今天的分享就到这了,之后会继续分享hbase相关的内容。

标签:rs,students,scan,基础知识,new,HBase,分享,getBytes
From: https://www.cnblogs.com/cjybigdatablog/p/18542550

相关文章

  • 【论文分享】三维景观格局如何影响城市居民的情绪
    本次带来一篇SCI论文的全文翻译!该论文以上海LivingLine项目为例,探索利用时空Wi-Fi数据分析街道层面的城市活力。【论文题目】Understandingstreet-levelurbanvibrancyviaspatial-temporalWi-Fidataanalytics:CaseLivingLineShanghai【题目翻译】利用时空Wi-Fi数......
  • 【数据分享】2000-2023年我国1km分辨率的逐日O3栅格数据
    空气质量数据是在我们日常研究中经常使用的数据!之前我们给大家分享了2000-2023年全国范围逐日的PM2.5栅格数据、2013-2023年全国范围逐日SO2栅格数据、2000-2023年全国范围逐日PM10栅格数据(均可查看之前的文章获悉详情)!本次我们给大家带来的是2000-2023年全国范围的逐日的O3栅......
  • 【数据分享】2024年我国各城市公交站点与线路数据
    公交线路与站点数据是我们做城市研究时经常会用到的基础数据。那么去哪里获取该数据呢?今天,我们就给大家分享一份2024年11月采集的全国所有城市的公交站点与线路数据,数据格式为shp矢量格式,数据坐标为wgs1984地理坐标。数据来源于开源公交信息查询网站。大家可以在公众号回复关......
  • 服务器测试基础知识---网卡篇
    bios基本输入输出系统,介于硬件和软件之间bmc用来检测和管理服务器计算机启动步骤加电自检,系统自举,加载引导程序,进入操作系统进入系统的步骤加载引导分区加载内核运行init进程初始化程序OS的启动顺序1,加电自检2,bios启动3,加载引导程序(硬件初始化,设备检测等)4,加载系......
  • 吉客云与用友BIP数据无缝对接案例分享
    吉客云数据集成到用友BIP的技术案例分享在企业日常运营中,数据的高效流转和准确对接是实现业务流程自动化的重要环节。本文将聚焦于一个具体的系统对接集成案例:吉客云-调拨出库--->YS-其他出库单-OK,详细探讨如何通过轻易云数据集成平台,将吉客云的数据无缝集成到用友BIP系统中。首......
  • 用PNGMaker.io快速生成透明PNG图像——使用者分享体验
    摘要:PNGMaker.io是一个在线的免费PNG制作工具,可以轻松将文字转换成透明背景的PNG图像,适合各类设计需求。在日常设计工作中,我们常常需要透明背景的PNG图像,但要用专业设计软件制作,步骤多且费时。最近我试用了PNGMaker.io,它可以在线、免费地生成带透明背景的PNG图像,操作简单,效果也......
  • 【大模型】HuggingFace模型转一键llamafile包完整教程,通义千问成功案例分享
    随着通义千问开源版的发布,越来越多的用户希望能在本地部署这款优秀的中文大模型。然而,传统的部署方式往往需要复杂的环境配置,让很多非技术背景的用户望而却步。今天,我要向大家介绍一个革命性的方案:将通义千问转换为Llamafile格式,实现真正的一键运行!有关llamafile的特点,我......
  • 通义灵码一周年测评:@workspace 和 @terminal 新功能体验分享
    通义灵码一周年测评:@workspace和@terminal新功能体验分享我是一位前端开发工程师,用通义灵码辅助项目开发和代码管理工作。最近体验了通义灵码的新功能@workspace和@terminal,快速上手项目和提升开发效率。以下是我的具体测评和使用心得。知识点必备官网:https://tongyi......
  • NVR接入录像回放平台EasyCVR视频分析设备平台视频监控热知识分享:2.4G和5G的路由器区别
    在当今数字化时代,无线网络已成为我们生活中不可或缺的一部分,而无线路由器作为连接数字世界的关键设备,其性能和功能直接影响着我们的网络体验。随着技术的发展,用户对无线路由器的需求不再仅限于基本的联网功能,而是开始追求更高速、更稳定、更安全的网络服务。同时,对于安防视频监控......
  • 【MySQL】MySQL基础知识复习(下)
    前言上一篇博客介绍了MySQL的库操作,表操作以及CRUD。【MySQL】MySQL基础知识复习(上)-CSDN博客本篇将进一步介绍CRUD操作,尤其是查找操作目录一.数据库约束1.约束类型1.1NULL约束1.2UNIQUE:唯一约束1.3DEFAULT:默认值约束1.4PRIMARYKEY:主键约束1.5FOREIGNKEY:外键约束......