HBase 的表设计

1 ColumnFamily 设计

追求的原则是:在合理的范围内能尽量少的减少列簇就尽量减少列簇。

最优设计是:将所有相关性很强的 Key-Value 都放在同一个列簇下,这样既能做到查询效率最高,也能保持尽可能少的访问不同的磁盘文件。

以用户信息为例,可以将必须的基本信息存放在一个列簇,而一些附加的额外信息可以放在另一个列簇。

 

2 RowKey 设计

HBase 中,表会被划分为 1...n 个 Region,被托管在 RegionServer 中。Region 两个重要的属性:StartKey 与 EndKey 表示这个 Region 维护的 RowKey 范围,当我们要读/写数据时,如果 RowKey 落在某个 Start-end Key 范围内,那么就会定位到目标 Region 并且读/写到相关的数据。

那怎么快速精准的定位到想要操作的数据,就在于 RowKey 的设计。

 

3. RowKey 设计三原则

3.1 RowKey 长度原则

RowKey 是一个二进制码流,RowKey 的长度被很多开发者建议说设计在 10-100 个字节,建议是越短越好,不要超过 16 个字节。原因如下:

  1. 数据的持久化文件 HFile 中是按照 KeyValue 存储的,如果 RowKey 过长,比如 100 个字节,如果有 1000 万行数据,光 RowKey 就要占用 100 * 1000 万 = 10 亿字节,将近 1G 数据,这会极大的影响 HFile 的存储效率。
  2. MemStore 将缓存部分数据到内存当中,如果 RowKey 字段过长,内存的有效利用率就会降低,系统将无法缓存更多的数据,从而降低数据检索效率。因此 RowKey 的字节长度越短越好。
  3. 目前操作系统都是 64 位系统,内存 8 字节对齐。控制在 16 个字节,是 8 字节的整数倍,利用操作系统的最佳特性。

 

3.2 RowKey 散列原则

如果 RowKey 是按时间戳的方式递增,不要将时间放在二进制码的前面,建议将 RowKey 的高位作为散列字段,由程序循环生成,低位放时间字段,这样将提高数据均衡分布在每个 RegionServer 实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息,将产生所有新数据都在一个 RegionServer 上堆积的热点现象,这样在做数据检索的时候负载会集中到个别的 RegionServer,降低查询效率。

 

3.3 RowKey 唯一原则

必须在设计上保证其具有唯一性。RowKey 是按照字典顺序进行排序存储的,因此,设计 RowKey 的时候,要充分利用这个排序特点,将经常读取的数据存储到一个 Region 中,将最近可能会被访问的数据放到一起。

 

数据热点:

HBase 中的行是按照 RowKey 的字典顺序进行排序的,这种设计优化了 scan 操作,可以将相关的行以及会被一起读取的行存储在临近的位置,便于 scan 操作。然而,糟糕的 RowKey 设计是热点的源头。大量访问会使热点 Region 所在的单个节点超出自身承受能力,引起性能下降甚至 Region 不可用,由于主机无法提供其它 Region 的请求,这也会影响同一个 RegionServer 上的其它的 Region 的访问。设计良好的数据访问模式以使集群被充分和均衡的利用。为了避免写热点,设计 RowKey 使得不同行在同一个 Region,但是在更多数据情况下,数据应该被写入集群的多个 Region,而不是一个 Region。

 

防止数据热点的有效措施:

1. 加盐

这里所说的加盐不是密码学中的加盐,而是在 RowKey 的前面都加随机数,就是给 RowKey 分配一个随机前缀以使得它和之前的 RowKey 的开头不同。分配的前缀各类数量应该和要使数据分散到的 Region 的数量一致。加盐之后的 RowKey 就会根据随机生成的前缀分散到各个 Region 上,以避免数据热点的现象产生。

2. 哈希

哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的 RowKey,可以使用 get 操作准确获取某一行的数据。

3. 反转

第三种防止热点的方法是反转固定升序或者数字格式的 Rowkey。这样就可以使得 RowKey 中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的产生随机的 Rowkey,但是牺牲了 RowKey 的有序性。

反转 RowKey 的例子以手机号为 RowKey,可以将手机号反转看到啦字符串作为 RowKey,这样就避免了以手机号那样比较固定的开头导致热点的问题。

4. 时间戳反转

一个常见的数据处理问题是快速获取数据的最近版本,使用反转的时间戳作为 RowKey 的一部分对这个问题十分有用,可以用 Long.Max_Value-timestamp 追加到 Key 的末尾,例如 [key][reverse_timestamp],[key] 的最新值可以通过 scan [key] 获得 [key] 的第一条记录,因为 HBase 中 RowKey 是有序的,第一条记录是最后录入的数据。比如需要保存一个用户的操作记录,按照操作时间倒序排序,在设计 RowKey 的时候,可以这样设计 [userId 反转][Long.Max_Value-timestamp],在查询用户的所有操作记录数据的时候,直接指定反转后的 userID,startRow 是 [userID 反转][000000000000],stopRow 是 [userID 反转][Long.Max_Value-timestamp]。如果需要查询某段时间的操作记录,startRow 是 [user 反转][Long.Max_Value - 起始时间],stopRow 是[userID 反转][Long.Max_Value - 结束时间]

 

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

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

相关文章

shiro原理及其运行流程介绍

什么是shiro shiro是apache的一个开源框架,是一个权限管理的框架,实现 用户认证、用户授权。 spring中有spring security (原名Acegi),是一个权限框架,它和spring依赖过于紧密,没有shiro使用简单。 shiro不依赖于sp…

shiro中文api_Shiro

1 shiro Apache shiro 是一个 Java 安全框架。 功能:认证、授权、加密和会话管理功能 应用环境:JavaEE、JavaSE Subject 可看做成一个用户 SecurityManager 框架的核心API Reaim 域对象,用于取数据库中的数据,进行权限比对。…

Java Lambda 表达式讲解

Lambda 表达式 Lambda 表达式的基础语法 Java8 中引入了一个新的操作符:-> 该操作符称为箭头操作符或者 Lambda 操作符 Lambda 操作符将表达式拆分成两部分: 左侧:Lambda 表达式的参数列表右侧: Lambda 表达式的"函数体" --&…

方法引用、构造器引用和数组引用

方法引用 若 Lambda 体中的内有方法已经实现了,我们可以使用“方法引用”(可以理解为方法引用是 Lambda 表达式的另外一种表现形式) 语法格式 主要有以下三种语法格式: 对象::实例方法名 注意&#xff1…

JVM 学习一:JVM 的构架模型及生命周期

JVM 的架构模型 Java 编译器输入的指令流基本上是一种基于栈的指令集架构,另外一种指令集架构则是基于寄存器的指令集架构。 具体来说,这两种架构之间的区别: 基于栈式架构的特点: 设计和实现更简单,适用于资源受限…

JVM 学习二:类加载器子系统

1 类加载器子系统的作用 类加载器子系统负责从文件系统或者网络中加载 Class 文件,Class 文件在文件开关有特定的文件标识ClassLoader 只负责 Class 文件的加载,至于它是否可以运行,则由 Execution Engine(执行引擎)决…

JVM 学习三:类加载器

类加载器 1 类加载器的分类 JVM 支持两种类型的类加载器:引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader) 从概念上来讲,自定义类加载器一般指的是程序中由开发人员自定…

JVM 学习四:类加载之双亲委派机制与沙箱安全机制

1 双亲委派机制 Java 虚拟机对 Class 文件的加载采用的是按需加载的方式,也就是说:当需要使用该类时才会将它的 Class 文件加载到内存生成 Class 对象,而且加载某个类的 Class 文件时,Java 虚拟机采用的是双亲委派模式&#xff0c…

数据结构之线性表:顺序线性表 Java 实现(底层基于数组)

代码实现 package top.gldwolf.java.datastructure.lineartable;/*** 顺序线性表* param <T> 存储的元素类型*/ public class LinearTable<T> {private static final int INITIAL_SIZE 20; // 线性表的初始容量private Object[] data null; // 真正存储数据的数…

Java8新特性:Stream介绍和总结

Java8新特性&#xff1a;Stream介绍和总结 什么是Stream 流&#xff08;Stream&#xff09;是数据渠道&#xff0c;用于操作数据源&#xff08;集合、数组等&#xff09;所生成的元素序列。 集合讲的是数据&#xff0c;流讲的是计算 注意&#xff1a; Stream自己不会存储元素…

数据结构之线性表:单链表

代码实现 package top.gldwolf.java.datastructure.linkedtable;/*** author: Gldwolf* email: ZengqiangZhaosina.com* date: 2020/4/15 12:39*//*** 线性表的链式存储结构** param <T> 存储的数据类型*/ public class LinkedTable<T> {private Node head new N…

使用 Akka 实现 Master 与 Worker 之间的通信

MessageProtocol.scala package top.gldwolf.scala.akkademo.sparkmasterandworker.common/*** author: Gldwolf* email: ZengqiangZhaosina.com* date: 2020/4/17 10:54*//*** 用于 Work 注册时发送注册信息*/ case class WorkerRegisterInfo(id: String, cpu: Int, ram: Int…

URL传Base64 造成报错 Illegal base64 character 20

报错如下&#xff1a; errorInternal Server Error, messageIllegal base64 character 20, tracejava.lang.IllegalArgumentException: Illegal base64 character 20 at java.util.Base64Decoder.decode0(Base64.java:714)atjava.util.Base64Decoder.decode0(Base64.java:714) …

Linux 中使用 sort 指令分组排序详解

Linux 中使用 sort 指令分组排序详解 sort 中进行分组排序主要用到的选项为 -k&#xff0c;此文&#xff0c;我们着重于该选项的使用方式&#xff0c;用到的其它选项不做解释&#xff0c;有兴趣的同学可以查看帮助文档 1. 数据准备 现有数据如下&#xff0c;文件名 sort_so…

Shiro-单点登录原理

单点登录原理 一、单系统登录机制 1、http无状态协议 web应用采用browser/server架构&#xff0c;http作为通信协议。http是无状态协议&#xff0c;浏览器的每一次请求&#xff0c;服务器会独立处理&#xff0c;不与之前或之后的请求产生关联&#xff0c;这个过程用下图说明…

关于 Java 同名类加载顺序问题排查方案

排查背景 最近在生产上部署 UDF 时&#xff0c;遇到一个两个环境完全相同&#xff0c;但是一个客户端报错另一个正常的情况&#xff0c;经过多次调试问题终于得以解决&#xff0c;现将解决思路记录一下&#xff0c;希望能对后来者有所帮助。(生产环境不便于截图。。。暂不展示…

Arrays.asList() 详解

Arrays.asList() 详解 【1. 要点】 该方法是将数组转化成List集合的方法。 List list Arrays.asList(“a”,“b”,“c”); 注意&#xff1a; &#xff08;1&#xff09;该方法适用于对象型数据的数组&#xff08;String、Integer…&#xff09; &#xff08;2&#xff0…

Vim 编码问题详解

Vim 编码问题详解 vim 中有 4 个与编码相关的配置&#xff0c;分别是 encoding、termencoding、fileencoding 和 fileencodings。在实际使用中任何一个配置有问题都可能会导致乱码&#xff0c;因此我们应该清楚每个配置的含义。 1. encoding encoding 是 vim 内部使用的字符编…

@Autowired作用在普通方法上

Autowired作用在普通方法上 Autowired作用在普通方法上&#xff0c;会在注入的时候调用一次该方法&#xff0c;如果方法中有实体参数&#xff0c;会对方法里面的参数进行装配&#xff0c;并调用一次该方法。这个可以用来在自动注入的时候做一些初始化操作。

@Autowired注解作用在方法上

Autowired注解作用在方法上 Autowired注解作用在方法上 &#xff08;1&#xff09;该方法如果有参数&#xff0c;会使用autowired的方式在容器中查找是否有该参数 &#xff08;2&#xff09;会执行该方法