【HBase——陌陌海量存储案例】2. HBase表结构设计(中)

news2024/9/23 1:27:09

前言

本文是陌陌海量存储案例——HBase表结构设计(中),介绍ROWKEY设计原则、项目初始化。

4.5 ROWKEY设计原则

4.5.1 HBase官方的设计原则

避免使用递增行键/时序数据
如果ROWKEY设计的都是按照顺序递增(例如:时间戳),这样会有很多的数据写入时,负载都在一台机器上。我们尽量应当将写入大压力均衡到各个RegionServer

避免ROWKEY和列的长度过大

  • 在HBase中,要访问一个Cell(单元格),需要有ROWKEY、列蔟、列名,如果ROWKEY、列名太大,就会占用较大内存空间。所以ROWKEY和列的长度应该尽量短小
  • ROWKEY的最大长度是64KB,建议越短越好

使用long等类型比String类型更省空间
long类型为8个字节,8个字节可以保存非常大的无符号整数,例如:18446744073709551615。如果是字符串,是按照一个字节一个字符方式保存,需要快3倍的字节数存储。

ROWKEY唯一性

  • 设计ROWKEY时,必须保证RowKey的唯一性
  • 由于在HBase中数据存储是Key-Value形式,若向HBase中同一张表插入相同RowKey的数据,则原先存在的数据会被新的数据覆盖。

4.5.2 避免数据热点

  • 热点是指大量的客户端(client)直接访问集群的一个或者几个节点(可能是读、也可能是写)
  • 大量地访问量可能会使得某个服务器节点超出承受能力,导致整个RegionServer的性能下降,其他的Region也会受影响

预分区

  • 默认情况,一个HBase的表只有一个Region,被托管在一个RegionServer中
    在这里插入图片描述
  • 每个Region有两个重要的属性:Start Key、End Key,表示这个Region维护的ROWKEY范围
  • 如果只有一个Region,那么Start Key、End Key都是空的,没有边界。所有的数据都会放在这个Region中,但当数据越来越大时,会将Region分裂,取一个Mid Key来分裂成两个Region
  • 预分区个数 = 节点的倍数。默认Region的大小为10G,假设我们预估1年下来的大小为10T,则10000G / 10G = 1000个Region,所以,我们可以预设为1000个Region,这样,1000个Region将均衡地分布在各个节点上

ROWKEY避免热点设计

  1. 反转策略

    • 如果设计出的ROWKEY在数据分布上不均匀,但ROWKEY尾部的数据却呈现出了良好的随机性,可以考虑将ROWKEY的翻转,或者直接将尾部的bytes提前到ROWKEY的开头。
    • 反转策略可以使ROWKEY随机分布,但是牺牲了ROWKEY的有序性
    • 缺点:利于Get操作,但不利于Scan操作,因为数据在原ROWKEY上的自然顺序已经被打乱
  2. 加盐策略

    • Salting(加盐)的原理是在原ROWKEY的前面添加固定长度的随机数,也就是给ROWKEY分配一个随机前缀使它和之间的ROWKEY的开头不同
    • 随机数能保障数据在所有Regions间的负载均衡
    • 缺点:因为添加的是随机数,基于原ROWKEY查询时无法知道随机数是什么,那样在查询的时候就需要去各个可能的Regions中查找,加盐对比读取是无力的
  3. 哈希策略

    • 基于 ROWKEY的完整或部分数据进行 Hash,而后将Hashing后的值完整替换或部分替换原ROWKEY的前缀部分
    • 这里说的 hash 包含 MD5、sha1、sha256 或 sha512 等算法
    • 缺点:Hashing 也不利于 Scan,因为打乱了原RowKey的自然顺序

4.5.3 陌陌打招呼数据预分区

预分区
在HBase中,可以通过指定start key、end key来进行分区,还可以直接指定Region的数量,指定分区的策略。

  1. 指定 start key、end key来分区
hbase> create 'ns1:t1', 'f1', SPLITS => ['10', '20', '30', '40']
hbase> create 't1', 'f1', SPLITS => ['10', '20', '30', '40']
hbase> create 't1', 'f1', SPLITS_FILE => 'splits.txt', OWNER => 'johndoe'
  1. 指定分区数量、分区策略
hbase> create 't1', 'f1', {NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}

分区策略

  • HexStringSplit: ROWKEY是十六进制的字符串作为前缀的
  • DecimalStringSplit: ROWKEY是10进制数字字符串作为前缀的
  • UniformSplit: ROWKEY前缀完全随机

Region的数量可以按照数据量来预估。本次案例,因为受限于虚拟机,所以我们设计为6个Region。因为ROWKEY我们是使用多个字段拼接,而且前缀不是完全随机的,所以需要使用HexStringSplit。

ROWKEY设计

  • 为了确保数据均匀分布在每个Region,需要以MD5Hash作为前缀
  • ROWKEY = MD5Hash_发件人账号_收件人账号_时间戳
    在这里插入图片描述

业务分区脚本
create 'MOMO_CHAT:MSG', {NAME => "C1", COMPRESSION => "GZ"}, { NUMREGIONS => 6, SPLITALGO => 'HexStringSplit'}

执行完命令后,我们发现该表已经分为6个分区。这样将来数据就可以均匀地分布到不同的分区中了
注意:勾选ShowDetailName&Start/EndKey,点击Recorder

在这里插入图片描述
HDFS中,也有对应的6个文件夹。
URL:/hbase/data/MOMO_CHAT/MSG

在这里插入图片描述

4.6 项目初始化

4.6.1 导入POM依赖

<repositories><!-- 代码库 -->
    <repository>
        <id>aliyun</id>
        <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
            <updatePolicy>never</updatePolicy>
        </snapshots>
    </repository>
</repositories>

<dependencies>
    <!-- HBase客户端 -->
    <dependency>
        <groupId>org.apache.hbase</groupId>
        <artifactId>hbase-client</artifactId>
        <version>2.1.0</version>
    </dependency>
    <!-- Xml操作相关 -->
    <dependency>
        <groupId>com.github.cloudecho</groupId>
        <artifactId>xmlbean</artifactId>
        <version>1.5.5</version>
    </dependency>
    <!-- 操作Office库 -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>4.0.1</version>
    </dependency>
    <!-- 操作Office库 -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>4.0.1</version>
    </dependency>
    <!-- 操作Office库 -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml-schemas</artifactId>
        <version>4.0.1</version>
    </dependency>
    <!-- 操作JSON -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.62</version>
    </dependency>
    <!-- phoenix core -->
    <dependency>
        <groupId>org.apache.phoenix</groupId>
        <artifactId>phoenix-core</artifactId>
        <version>5.0.0-HBase-2.0</version>
    </dependency>
    <!-- phoenix 客户端 -->
    <dependency>
        <groupId>org.apache.phoenix</groupId>
        <artifactId>phoenix-queryserver-client</artifactId>
        <version>5.0.0-HBase-2.0</version>
    </dependency>
</dependencies>


<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <target>1.8</target>
                <source>1.8</source>
            </configuration>
        </plugin>
    </plugins>
</build>

4.6.2 拷贝配置文件

将配套资料中的以下几个文件拷贝到resources目录。

  • core-site.xml
  • hbase-site.xml
  • log4j.properties

4.6.3 创建包结构

cn.itcast.momo_chat.service用于存放数据服务接口相关代码,例如:查询的API代码
cn.itcast.momo_chat.service.impl用于存放数据服务接口实现类相关代码,例如:查询的API代码
cn.itcast.momo_chat.tool工具类
cn.itcast.momo_chat.entity存放实体类

4.6.4 导入ExcelReader工具类

在资料包中有一个ExcelReader.java文件,ExcelReader工具类可以读取Excel中的数据称为HashMap这样,方便我们快速生成数据。

ExcelReader工具类主要有两个方法:

1.readXlsx——用于将指定路径的Excel文件中的工作簿读取为Map结构
2.randomColumn——随机生成某一列中的数据。

将ExcelReader添加到cn.itcast.momo_chat.tool包中。

4.6.5 创建实体类

在cn.itcast.momo_chat.entity包中创建一个名为Msg的实体类,使用Java代码描述陌陌消息。

字段名说明
msg_time消息时间
sender_nickyname发件人昵称
sender_account发件人账号
sender_sex发件人性别
sender_ip发件人IP
sender_os发件人系统
sender_phone_type发件人手机型号
sender_network发件人网络制式
sender_gps发件人GPS
receiver_nickyname收件人昵称
receiver_ip收件人IP
receiver_account收件人账号
receiver_os收件人系统
receiver_phone_type收件人手机型号
receiver_network收件人网络制式
receiver_gps收件人GPS
receiver_sex收件人性别
msg_type消息类型
distance双方距离
message消息

操作步骤:

1.使用列编辑,快速复制讲义中上述的表格字段给实体类添加成员变量
2.使用IDEA快捷键 Alt + Insert 键快速生成 getter/setter 方法,并重写toString方法

参考代码:

public class Msg {
    private String msg_time;
    private String sender_nickyname;
    private String sender_account;
    private String sender_sex;
    private String sender_ip;
    private String sender_os;
    private String sender_phone_type;
    private String sender_network;
    private String sender_gps;
    private String receiver_nickyname;
    private String receiver_ip;
    private String receiver_account;
    private String receiver_os;
    private String receiver_phone_type;
    private String receiver_network;
    private String receiver_gps;
    private String receiver_sex;
    private String msg_type;
    private String distance;
    private String message;

    public String getMsg_time() {
        return msg_time;
    }

    public void setMsg_time(String msg_time) {
        this.msg_time = msg_time;
    }

    public String getSender_nickyname() {
        return sender_nickyname;
    }

    public void setSender_nickyname(String sender_nickyname) {
        this.sender_nickyname = sender_nickyname;
    }

    public String getSender_account() {
        return sender_account;
    }

    public void setSender_account(String sender_account) {
        this.sender_account = sender_account;
    }

    public String getSender_sex() {
        return sender_sex;
    }

    public void setSender_sex(String sender_sex) {
        this.sender_sex = sender_sex;
    }

    public String getSender_ip() {
        return sender_ip;
    }

    public void setSender_ip(String sender_ip) {
        this.sender_ip = sender_ip;
    }

    public String getSender_os() {
        return sender_os;
    }

    public void setSender_os(String sender_os) {
        this.sender_os = sender_os;
    }

    public String getSender_phone_type() {
        return sender_phone_type;
    }

    public void setSender_phone_type(String sender_phone_type) {
        this.sender_phone_type = sender_phone_type;
    }

    public String getSender_network() {
        return sender_network;
    }

    public void setSender_network(String sender_network) {
        this.sender_network = sender_network;
    }

    public String getSender_gps() {
        return sender_gps;
    }

    public void setSender_gps(String sender_gps) {
        this.sender_gps = sender_gps;
    }

    public String getReceiver_nickyname() {
        return receiver_nickyname;
    }

    public void setReceiver_nickyname(String receiver_nickyname) {
        this.receiver_nickyname = receiver_nickyname;
    }

    public String getReceiver_ip() {
        return receiver_ip;
    }

    public void setReceiver_ip(String receiver_ip) {
        this.receiver_ip = receiver_ip;
    }

    public String getReceiver_account() {
        return receiver_account;
    }

    public void setReceiver_account(String receiver_account) {
        this.receiver_account = receiver_account;
    }

    public String getReceiver_os() {
        return receiver_os;
    }

    public void setReceiver_os(String receiver_os) {
        this.receiver_os = receiver_os;
    }

    public String getReceiver_phone_type() {
        return receiver_phone_type;
    }

    public void setReceiver_phone_type(String receiver_phone_type) {
        this.receiver_phone_type = receiver_phone_type;
    }

    public String getReceiver_network() {
        return receiver_network;
    }

    public void setReceiver_network(String receiver_network) {
        this.receiver_network = receiver_network;
    }

    public String getReceiver_gps() {
        return receiver_gps;
    }

    public void setReceiver_gps(String receiver_gps) {
        this.receiver_gps = receiver_gps;
    }

    public String getReceiver_sex() {
        return receiver_sex;
    }

    public void setReceiver_sex(String receiver_sex) {
        this.receiver_sex = receiver_sex;
    }

    public String getMsg_type() {
        return msg_type;
    }

    public void setMsg_type(String msg_type) {
        this.msg_type = msg_type;
    }

    public String getDistance() {
        return distance;
    }

    public void setDistance(String distance) {
        this.distance = distance;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/181854.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

信息论复习—差错控制编码

目录 差错控制编码的基本概念&#xff1a; 差错控制编码的主要类型和方式&#xff1a; 差错控制编码的主要类型&#xff1a; 差错控制方式&#xff1a; 简单的差错控制方法&#xff1a; 奇偶校验码&#xff1a; 重复码&#xff1a; 信道编码的基本概念和定理*: 信道编…

4 反向传播

文章目录问题提出计算图中的神经网络改进&#xff08;激活函数&#xff09;反向传播前馈计算反向传播pytorch当中的前馈与反馈Tensor张量课程代码课后作业课程来源&#xff1a; 链接课程内容部分来源&#xff08;觉得归纳的非常好的&#xff09;&#xff1a; 链接以及&#xff…

MySQL中的运算符

目录 一.运算符 简介 算术运算符 比较运算法 逻辑运算符 位运算符 实例演示 一.运算符 简介 数据库中的表结构确立后&#xff0c;表中的数据代表的意义就已经确定。通过MySQL运算符进行运算&#xff0c;就可以获取到表结构以外的另一种数据。 例如&#xff0c;学生表中…

[数据结构笔记]二叉树初阶

基本知识 树 -节点的度&#xff1a;一个节点含有的子树的个数称为该节点的度&#xff1b; -叶节点或终端节点&#xff1a;度为0的节点称为叶节点&#xff1b; -非终端节点或分支节点&#xff1a;度不为0的节点&#xff1b; -父节点&#xff1a;若一个节点含有子节点&#xff…

Mybatis 通过接口实现 sql 执行原理解析

使用过 mybatis 框架的小伙伴们都知道&#xff0c;mybatis 是个半 orm 框架&#xff0c;通过写 mapper 接口就能自动实现数据库的增删改查&#xff0c;但是对其中的原理一知半解&#xff0c;接下来就让我们深入框架的底层一探究竟1、环境搭建首先引入 mybatis 的依赖&#xff0…

Consul服务注册与发现

目录 一、Consul简介 &#xff08;一&#xff09;官网 &#xff08;二&#xff09;特点 二、安装并运行Consul &#xff08;一&#xff09;官网安装说明 &#xff08;二&#xff09;下载 &#xff08;三&#xff09;使用开发模式启动 三、服务提供者 四、服务消费者 …

怎么压缩pdf文件?选对方法其实很简单!

相信许多人在使用设备的时候都会面对这样一个问题&#xff0c;那就是设备内存不足。仿佛不管我们多么努力的节省空间&#xff0c;总是会到头来遇到储存空间不足得难题&#xff0c;尤其是一些比较大的pdf文件&#xff0c;特别占据我们的设备内存&#xff0c;那么你知道怎么压缩p…

0128 Web API基本认知

作用使用JS去操作html和浏览器分类DOM&#xff08;文档对象模型&#xff09;BOM&#xff08;浏览器对象模型&#xff09;DOM是什么&#xff1a;Document Object Model-----文档对象模型&#xff0c;用来呈现以及与任意HTML或XML文档交互的API&#xff0c;浏览器提供的一套专门用…

【Linux】一文掌握Linux权限

环境&#xff1a;centos7&#xff0c;腾讯云服务器Linux文章都放在了专栏&#xff1a;【Linux】欢迎支持订阅&#x1f339;前言权限 一词相信大家都不陌生&#xff0c;与我们的生活密切相关。小区里的门禁制度、公司里的管理制度、学校里的校规规定、甚至是社交平台上的一些设置…

python 手机相机传感器信息计算

传感器信息计算 输入传感器尺寸以上已红米12pro为例 输入传感器尺寸 1/1.4英寸 0.7142857 输入像素2亿 200000000 得到以下结果 和宣传中的传感器信息一致 附源码 import sympyclass CMosInfo(object):"""传感器信息计算"""def __init__(…

C 程序设计教程(19)—— 数组和指针(二):字符数组与字符串

C 程序设计教程&#xff08;19&#xff09;—— 数组和指针&#xff08;二&#xff09;&#xff1a;字符数组与字符串 该专栏主要介绍 C 语言的基本语法&#xff0c;作为《程序设计语言》课程的课件与参考资料&#xff0c;用于《程序设计语言》课程的教学&#xff0c;供入门级用…

word实用操作:几个关于录入和排版的小妙招

对于职场人来说&#xff0c;工作中使用Word早已成了习惯。而如何提高Word的技术&#xff0c;那简直是职场人一生都需要研究探索的课题。因此&#xff0c;今天小编将为大家分享几个实用的Word小技巧&#xff0c;这些技巧貌似不起眼&#xff0c;但是学会后&#xff0c;可以大大提…

如何查linux服务器的带宽占用?哪些进程占用带宽?

前言操作系统&#xff1a; Linux操作环境&#xff1a; Centos7 / ubuntulinux查看服务器带宽具体方法   一、使用speedtest-cli命令查看下载和上传最大流量值因为命令是python的&#xff0c;所以需要先下载一个python&#xff0c;用pip下载次命令&#xff1b;123yum -y insta…

七个 Vue 项目用得上的 JavaScript 库分享

文章目录前言一、vueuse二、vue-js-modal三、vue-wait四、good-table五、vue-notification六、tree select七、egjs-infinite grid总结前言 借助开源库加速 Vue 项目的开发进度是现代前端开发比较常见的方式&#xff0c;平常收集一些 JavaScript 库介绍&#xff0c;在遇到需要的…

上古神兵,先天至宝,Win11平台安装和配置NeoVim0.8.2编辑器搭建Python3开发环境(2023最新攻略)

毫无疑问&#xff0c;我们生活在编辑器的最好年代&#xff0c;Vim是仅在Vi之下的神级编辑器&#xff0c;而脱胎于Vim的NeoVim则是这个时代最好的编辑器&#xff0c;没有之一。异步支持、更好的内存管理、更快的渲染速度、更多的编辑命令&#xff0c;是大神Thiago de Arruda对开…

第九层(5):STL之stack

文章目录前情回顾stack概念stack容器需要注意的地方stack类内的构造函数stack类内的赋值操作stack类内的插入stack类内的删除stack类内的访问stack类内的大小操作下一座石碑&#x1f389;welcome&#x1f389; ✒️博主介绍&#xff1a;一名大一的智能制造专业学生&#xff0c;…

Knowledge-based-BERT(三)

多种预训练任务解决NLP处理SMILES的多种弊端&#xff0c;代码&#xff1a;Knowledge-based-BERT&#xff0c;原文&#xff1a;Knowledge-based BERT: a method to extract molecular features like computational chemists&#xff0c;代码解析继续downstream_task。模型框架如…

HTML中的div和span标签

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>HTML中的div和span标签</title> </head> <body> <!-- 1、div和span是什么&#xff1f;有什么用…

【linux】文件操作(IO)详述

文件操作一、引入二、系统调用接口2.1 open与close2.2 write2.3 read三、文件描述符3.1 分配规则四、重定向4.1 输出重定向4.2 追加重定向4.3 输入重定向4.4 独立性五、缓冲区5.1 缓冲区刷新策略5.2 缓冲区位置5.3 现象解释六、文件系统6.1 文件系统分区6.1.1 分区图6.1.2 介绍…

实时推荐业务介绍 grpc接口对接

5.1 实时推荐业务介绍 学习目标 目标 无应用 无 5.1.1 实时推荐逻辑 逻辑流程 1、后端发送推荐请求&#xff0c;实时推荐系统拿到请求参数 grpc对接2、根据用户进行ABTest分流 ABTest实验中心&#xff0c;用于进行分流任务&#xff0c;方便测试调整不同的模型上线3、推荐中心…