HBase 数据存储结构

HBase中, 从逻辑上来讲数据大概就长这样:

image-20210227123337628

单从图中的逻辑模型来看, HBase 和 MySQL 的区别就是:

  1. 将不同的列归属与同一个列族下
  2. 支持多版本数据

这看着感觉也没有那么太大的区别呀, 它解决了 MySQL 的那些问题呢? 每一个新事物的出现, 都是为了解决原本存在的问题.

  1. 对写入友好, 支持异步大批量并发写入
  2. 可动态添加列
  3. 按列存储数据, 不存在的列不会落盘, 节省空间. 而 MySQL 中不存在的内容也要用 null 填充
  4. 支持海量数据分布式存储(BigTable 最开始就是 Google 为了解决数据存储问题而提出来的)
  5. 等等

那么他是如何解决这些问题的呢? 他的数据是如何进行存储的呢?

HBase 数据物理结构

在介绍其物理结构之前, 要先简单提一下 LSM 树

LSM树

和 MySQL 所使用的B+树一样, 也是一种磁盘数据的索引结构. B+树是一种对读取友好的存储结构, 但是当大量写入的时候, 比如日志信息, 因为涉及到随机写入, 就显得捉襟见肘了.

LSM树就是针对这种大量写入的场景而提出的. 他的中文名字叫: 日志结构合并树. 文件存储的是对数据的修改操作, 数据会 append 但不会去修改原有的数据. 是顺序写入操作.

但是, 如果不管不顾的将所有的操作都顺序写入了, 那读取数据的时候没有任何根据, 需要扫描所有操作才能读到. LSM 树的做法是, 先在内存中维护一份小的有序的数据(内存不存在随机读写的问题), 当这份数据超过一定大小的时候, 将其整个放入磁盘中.

这样, 磁盘中就存在很多个有序的文件了, 但是会有大量的小文件, 读取数据时要依次查找, 导致读取性能降低. 这时就需要对多个小文件进行多路归并合成一个文件来优化读取的性能.

至此, 基本就是LSM 树的全部思想了.

  1. 在内存中维护一个有序的数据
  2. 将内存中的数据push 到磁盘中
  3. 将磁盘中的多个有序文件进行归并, 合成一个较大的有序文件

HBase存储

HBase中, 数据的存储就使用了 LSM 树进行存储. 其中每一条数据都是一条操作记录. 那么在HBase实现中的部分内容如下.

内存有序结构的实现

通过跳表来维护内存中的有序结构, 当一个跳表装满之后, 将禁止新的写入操作并将其 push 到磁盘中, 同时开一个新的数据结构来接收新到的操作请求.

每条数据的存储内容

存储了一个KV 键值对, 其中的 V 就是我们写入的值, 而这个 key 由以下部分组成:

  • row key
  • 列族
  • 列名
  • 时间戳
  • 操作类型: Put、Delete、DeleteColumn、DeleteFamily 等等

整个列表是 key 的顺序列表. 其排序规则如下:

  1. row key小的排在前面
  2. 同 row key 比较列族
  3. 同列族比较列名
  4. 同列名比较时间戳, 时间戳大的在前面.

按照这个顺序进行读取指定 row key 的某一列数据时, 最先拿到的数据就是最新的版本, 若是 delete 操作, 说明最后执行了删除操作, 即使后面有数据, 最新数据也是空.

磁盘文件的结构

由三部分组成:

image-20210227221614633

  1. 头信息: 存储文件大小, 文件块数量, 索引位置, 索引大小等信息
  2. 索引数据: 用户对文件中所有数据块进行索引, 其中每一个数据块都包含一条索引数据, 索引内容包括
    • 数据块的最后一条数据. 用于对索引进行二分查找, 快速定位到指定的数据块
    • 数据块在文件中的位置
    • 数据块的大小
    • 布隆过滤器. 用户在扫描时快速过滤不存在的数据块
  3. 数据块. 其中存储了每一条 KV 数据.

按照这个结构, 用户在进行指定row_key 读取的时候, 每个文件的操作如下:

  1. 根据头信息内容, 加载索引数据
  2. 通过二分查找, 找到 row_key 在哪一数据块下
  3. 根据布隆过滤器过滤掉不存在的数据块, 加速读取
  4. 根据数据块的位置和大小, 找到指定数据块并二分查找指定数据

HBase 数据列族式存储

先简单回顾一下行式存储和列式存储.

行式存储

行式存储, 将一行数据存储在一起, 一行数据写完了才会写下一行. 例如典型的 MySQL.

行式存储在读取一行数据的时候是比较快的, 但如果读取的是某一列数据, 也需要将整行读取到内存中进行过滤.

列式存储

与行式存储相对应的就是列式存储, 既将一列数据存储在一起, 不同列的数据分别存储.

列式存储对于只读取某一列比较友好, 但相对的, 如果要读取多列数据, 需要读取多次并进行合并.

列族式存储

而 HBase 中选用了一种折中的方案, 列族式存储, 将列族放到一起存储, 不同列族分别存储.

那么也就是说, 如果一个表有多个列族, 每个列族下只有一列, 那么就等同于列式存储

如果一个表只有一个列族, 该列族下有多个列, 那么就等同与行式存储.

HBase 会将一张表同一列族的数据, 分配到同一个 region 上, 这个region 分配在集群中的某一个 regionServer. 所有的 region 存储在表: hbase:meta 表中, 表结构如下:

image-20210227234232984

表不同列含义如下:

  • row_key 由以下字段拼接(逗号)而成
    • 表名
    • 起始 row_key
    • 创建时间戳
    • 上面三个字段的md5
  • info:regioninfo 主要存储以下数据(json)
    • STARTKEY: 起始 row_key
    • ENDKEY: 结束 row_key
    • NAME: region 名
    • ENCODED: 不清楚是什么
  • info:seqnumDuringOpen 表示regionServer 在线时长
  • info:server 落在哪个 regionServer 上
  • info:serverstartcode regionServer 的启动时间
  • 等等

总结

简单了解了HBase的数据落盘格式, 也大概解释 HBase 的很多疑惑, 比如:

  1. 为什么只支持 row key 索引查询
    • 因为整个文件是按照 row key 排序的
  2. 为什么读取效率比 MySQL 低
    • 因为要依次读取文件进行查找
  3. 为什么支持高效率的写入操作
    • 因为全部都是顺序读写操作
  4. 应该如何设置 HBase 的列族
    • 将同一场景读取的放到同一列族下, 不同场景读取的放到不同列族下
  5. 等等

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

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

相关文章

HBase 文件合并

HBase在存储时, 使用了LSM树来进行数据存储, 会定期将文件进行合并, 以提升数据的查询效率, LSM树都是这么处理的. 那么到这里就有一个问题了, HBase在进行文件合并的时候, 势必会占用大量 IO, 难道不会对正常的业务产生影响么? 抱着这个疑问, 我去找了找HBase文件合并的方式.…

spark计算操作整理

spark 的计算流程大概如图: 其中, 通过多次处理, 生成多个中间数据, 最后对结果进行操作获得数据. 本文不涉及任何原理, 仅总结spark在处理的时候支持的所有操作, 方便后面使用的时候, 可以参照本文进行数据的处理. 以下函数整理, 基与Python中RDD对象. 数据的转换操作 数据…

软件工程模型

你在工作中, 软件的开发流程是怎样的? 你是否想过, 除了你当前使用的流程, 还存在其他怎样的流程? 现在的流程有哪些问题, 又能够如何解决? 别说, 前辈们已经给出了一些项目流程的模型, 既软件工程. 可以简单了解一下, 带动一下我这生了锈的脑子. 在很久以前, 一个软件的从…

关于对接需求的思考

产品说想要一个登录注册的功能, 你一想, 好说, 不就是用户名密码嘛, 然后开发完成 产品看到成果后: 我要的是手机验证码登录结果写好的功能基本废了 产品又想要一个登录注册的功能, 这回你学乖了, 确认了一下, 是手机验证码登录, 没问题, 然后开发完成 产品拿到成果: 怎么没有验…

路径.git下的文件

用了这么久的git, 可以毫不谦虚地说对git是一无所知. 每天用来用去的就是commit, add, merge 等几个有限的命令, 这不符合我这刨根问底的性格啊. 不行, 得研究研究, 从哪里下手呢? 别的咱先不说, 所有 git 项目都有这么一个文件夹.git, 不如就从它入手 ? 那咱就看看这个文件夹…

git 操作二进制文件

平常用git进行项目管理已经稀松平常了, 今天咱来点不一样的. 平常管理的都是普通的文本文件, 如果是二进制文件, git能够处理么? 比如word文档. 测试一下. 新建一个项目, 在其中创建test1.docx, test2.txt两个空文件并提交. 之后编辑文件并添加标题, git diff看一下效果: 效…

Go 常量定义

定义常量在各个语言中都是不可或缺的语法了. 而有些语言在常量的基础上, 增加了枚举类型, 比如C. enum Weekday {SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY };上面的枚举, 对应的值依次为0到6. 而在Go中, 是没有提供枚举类型的. 如果实现上面相同的功能, 难…

搭建个人博客

一直都想着搞一个自己的个人博客, 拖着这么久, 最近终于开始动手了. 故留下一篇完整的记录, 若你也刚好有相同的需要, 那这篇文章应该恰好能够帮助到你. 准备 云服务器个人域名 如果没有云服务器, 将应用跑在自己的电脑上, 通过内网穿透大概也能达到效果, 但是个人电脑实在没…

nginx 配置文件的匹配规则

引出 之前在对php-fpm 进行nginx代理时, 为了对后台限定 IP 访问, 添加了如下配置: location ^~ /admin {allow 127.0.0.1;deny all; }结果呢? 所有admin路径下的php文件, 全都没有解析, 变成文件下载了. 当时我不知道是什么问题, 不过将这段配置去掉之后, 问题就消失了. 所…

分库后如何分页

前言 在实际应用中, 为了降低单表的数据量, 会对较大的表进行水平切分, 将单表的数据切分到多表多库中. 既然要切分, 就要有一个切分的依据, 比如说按照 ID 取模等. 那么多张表联合分页是如何做到的呢? 如果分表的依据是字段 A, 但是需要根据字段 B 进行分页查询, 针对这种…

计算机是如何进行时间同步的

WHY 在网络世界中, 各个计算机之间要想协同工作, 时间同步是一个十分重要的基础. 在计算机内部是有自己的时间的, 这个时间通过内部的晶体振荡器差生的固定频率, 来模拟时间流逝进行计算. 虽然频率十分稳定, 但也是有误差的, 虽然现在的工艺水平误差已经十分小了. (关于震荡的…

WordPress架构简单剖析

前言 最近在搭建自己的博客站点时, 选择了网站使用较多的WordPress, 随着慢慢的使用, 它灵活的插件和主题令我折服. 基本上任何想要实现的功能, 都可以在上面通过插件的形式进行添加. 无论是在访问前的缓存、访问后的统计、访问中的过滤、各种流程的修改等等, 几乎都能够以插件…

Gale-Shapley算法

前言 最近看了一档综艺《心动的信号》(唉, 单身久了, 开始喜欢看别人谈恋爱了) 节目中共有n男n女, 他们会在节目的最后进行表白, 如果我喜欢你, 恰好你也喜欢我, 那么便就会在一起, 自此传为一段佳话. 于是, 我就在想, 如何用算法来实现这个匹配的过程呢? 单一匹配 将信息…

阿里云定时任务并自动释放

前言 最近写了一个爬虫脚本, 脚本跑在一台北京的 ecs 上. 但奈何因某种未知力量, 需要连接代理才能访问目标网站. 本来想着自己搭代理, 但是太贵了, 就暂时搁置了. 直到我发现了这个: 阿里云香港的服务器, 一个小时才5分钱. 如果脚本直接跑在香港服务器上不就可以了咩, 按照这…

智能优化算法应用:基于金豺算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于金豺算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于金豺算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.金豺算法4.实验参数设定5.算法结果6.参考文献7.MA…

pixiv小控件

前言 最近看到一个大佬, 开源了一款博客小插件, 地址. 可以将pixiv网站的日榜放到博客侧边栏. 看上去很炫酷. 于是我也引入到了自己的博客中. 在此向大佬表示感谢. 但是在使用过程中, 经常遇到访问很慢的情况, 查看之后才发现, 大佬的服务器架设在韩国, 难怪访问比较慢, 都走…

PHP-PDO参数绑定问题

前言 今天在执行这样一段代码: $data [username > hujingnb,address > beijing, ]; $dbh new PDO("mysql:host{$host};dbname{$dbname}", $username, $password); $statement $dbh->prepare(INSERT INTO test_user (username, address) VALUES (:usern…

Python 的协程

前言 最近在看部分Python源码时, 发现了async 这个关键字. 查了一下发现了Python中的协程. 协程这玩意, 在GO中我用过啊, 简单说, 就是一个轻量级的线程嘛, 由语言自己来实现不同协程的调度. 想着Python中可能也是差不多的东西吧. 但是我Google搜了一下, 前面的说明都给出了下…

PHP脚本调用命令获取实时输出

在写脚本的时候, 经常会有需要调用其他命令. 而在调用一些耗时命令的时候, 我们是需要能够实时掌握脚本进度的. 一般来说, 脚本的进度通常是通过脚本的输出来获得. 如果是一个bash脚本, 那么直接调用命令 A就可以将执行权交出去, 然后命令 A的输出就可以实时显示出来了. 如果…

如何使用git管理crontab任务

前言 在Linux系统上执行定时任务, 使用crontab还是很方便的(有关crontab的使用可看crontab指令笔记). 只需要一行命令就完成了. 但是, 美中不足的是, crontab通过命令行管理任务, 无法通过代码库对任务进行管理. 若要更换机器, 所有任务都要重新增加一遍. 更糟的是若服务器突…