Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【HBase】HBase迷你版MiniBase学习笔记

【HBase】HBase迷你版MiniBase学习笔记

原创
作者头像
皮皮熊
发布于 2020-05-16 13:15:08
发布于 2020-05-16 13:15:08
1.8K00
代码可运行
举报
运行总次数:0
代码可运行

MiniBase学习笔记

https://github.com/pierre94/minibase

HBase相对复杂,想要快速啃下来比较困难。而MiniBase吸收了HBase最核心的引擎部分的精华,希望可以通过学习MiniBase以小见大,能够对自己理解HBase这个庞然大物有所帮助。

接口

  • put/get/delete (点写\查\删)
  • scan(范围查询)

核心架构架构

MiniBase是一个标准的LSM树索引结构,分内存部分和磁盘部分。

MemStore

  • 客户端不断地写入数据,当MemStore的内存超过一定阈值时,MemStore会flush成一个磁盘文件。
  • MemStore分成MutableMemstore和ImmutableMemstore两部分
    • MutableMemstore由一个ConcurrentSkipListMap组成,容许写入
    • ImmutableMemstore也是一个ConcurrentSkipListMap,但是不容许写入
  • 这里设计两个小的MemStore,是为了防止在f lush的时候,MiniBase无法接收新的写入。假设只有一个MutableMemstore,那么一旦进入flush过程,MutableMemstore就无法写入,而此时新的写入就无法进行。

从源码不难看出,其实就是2个ConcurrentSkipListMap kvMap和snapshot,flush的时候将kvMap赋值给snapshot,然后启动一个新的ConcurrentSkipListMap

DiskStore

基本概念
  • DiskStore,由多个DiskFile组成,每一个DiskFile就是一个磁盘文件。
  • ImmutableMemstore执行完flush操作后,就会生成一个新的DiskFile,存放到DiskStore中.
  • 为了有效控制DiskStore中的DiskFile个数,我们为MiniBase设计了Compaction策略。目前的Compaction策略非常简单——当DiskStore的DiskFile数量超过一个阈值时,就把所有的DiskFile进行Compact,最终合并成一个DiskFile。
核心问题与结构设计
  • DiskFile必须支持高效的写入和读取。
    • 由于MemStore的写入是顺序写入,如果flush速度太慢,则可能会阻塞后续的写入,影响写入吞吐,因此flush操作最好也设计成顺序写。
    • LSM树结构的劣势就是读取性能会有所牺牲,如果在DiskFile上能实现高效的数据索引,则可以大幅提升读取性能,例如考虑布隆过滤器设计。
  • DiskFile的数据必须分成众多小块(内存小磁盘大)。
    • 一次IO操作只读取一小部分的数据

DiskFile由3种类型的数据块组成,分别是DataBlock、IndexBlock、MetaBlock。

DataBlock
  • 主要用来存储有序的KeyValue集合——KeyValue-1,KeyValue-2,…,KeyValue-N
  • 一个DiskFile内可能有多个Block,具体的Block数量取决于文件内存储的总KV数据量
IndexBlock

IndexBlock:一个DiskFile内有且仅有一个IndexBlock,它主要存储多个DataBlock的索引数据。每个索引数据又包含4个字段:

  • lastKV :该DataBlock的最后一个KV。方便直接读取这个DataBlock到内存。为什么不是第一个kv?
  • offset :该DataBlock在DiskFile中的偏移位置,查找时,用offset值去文件中Seek,并读取DataBlock的数据。
  • size:该DataBlock占用的字节长度。
  • bloomFilter:该DataBlock内所有KeyValue计算出的布隆过滤器字节数组。
MetaBlock

一个DiskFile中有且仅有一个MetaBlock;同时MetaBlock是定长的,因此可以直接通过定位diskf ile.f ilesize - len(MetaBlock)来读取MetaBlock,而无需任何索引.

  • fileSize :该DiskFile的文件总长度,可以通过对比这个值和当前文件真实长度,判断文件是否损坏
  • blockCount:该DiskFile拥有的Block数量
  • blockIndexOffset:该DiskFile内的IndexBlock的偏移位置,方便定位到IndexBlock。
  • blockIndexSize:IndexBlock的字节长度。
DiskStore读取示例

假设用户需要读取指定DiskFile中key='abc'对应的value数据,那么可以按照如下流程进行IO读取

  • 因为MetaBlock的长度是定长的,所以很容易定位到MetaBlock的位置并读取信息
  • 根据MetaBlock.blockIndexOffset等信息读取到IndexBlock信息
  • 由于IndexBlock中存储着每一个DataBlock对应的数据区间,通过二分查找可以很方便定位到key='abc'在哪个DataBlock中需要key有序,假如key无序怎么办?ConcurrentSkipListMap保证了数据集合内是有序的
  • 再根据对应的DataBlock的offset和size,就能顺利完成DataBlock的IO读取

kv设计

在MiniBase中,只容许两种更新操作:

  • Put操作
  • Delete操作

结构设计

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  private KeyValue(byte[] key, byte[] value, Op op, long sequenceId) {
    assert key != null;
    assert value != null;
    assert op != null;
    assert sequenceId >= 0;
    this.key = key;
    this.value = value;
    this.op = op;
    this.sequenceId = sequenceId;
  }
  • Op有Put和Delete两种操作类型
  • 每一次Put/Delete操作分配一个自增的唯一sequenceId. 读取的时候,只能得到小于等于当前sequenceId的Put/Delete操作,这样保证了本次读取不会得到未来某个时间点的数据,实现了最简单的Read Committed的事务隔离级别。

KeyValue在MemStore和DiskFile中都是有序存放的,所以需要为KeyValue实现Comparable接口,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  @Override
  public int compareTo(KeyValue kv) {
    if (kv == null) {
      throw new IllegalArgumentException("kv to compare should not be null");
    }
    int ret = Bytes.compare(this.key, kv.key);
    if (ret != 0) {
      return ret;
    }
    if (this.sequenceId != kv.sequenceId) {
      return this.sequenceId > kv.sequenceId ? -1 : 1;
    }
    if (this.op != kv.op) {
      return this.op.getCode() > kv.op.getCode() ? -1 : 1;
    }
    return 0;
  }
  • k小的在前面。后面读取的时候就像二分查找了。
  • 注意在Key相同的情况下,sequenceId更大的KeyValue排在更前面,这是因为sequenceId越大,说明这个Put/Delete操作版本越新,它更可能是用户需要读取的数据
  • 再比较op code (锦上添花,防止上游数据错乱发来一样的sequenceId?)

写入流程详细剖析

写入过程需要构造一个kv结构(put/delete),并加上一个自增的sequenceId.详见MStore#put

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  @Override
  public void put(byte[] key, byte[] value) throws IOException {
    this.memStore.add(KeyValue.createPut(key, value, sequenceId.incrementAndGet()));
  }

(MiniBase是本地生成,HBase应该要由服务端生成?)

kv数据是写到kvMap中,其中kvMap就是ConcurrentSkipListMap结构。这里我们需要关注:

  • dataSize更新问题 由于ConcurrentSkipListMap在put进数据后会返回相同key的旧value,所以需要考虑一下dataSize的更新(当前MemStore内存占用字节数,用于判断是否达到Flush阈值)。
  • 锁 需要使用一个读写锁updateLock来控制写入操作和Flush操作的互斥

这里详见:MemStore#add

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  public void add(KeyValue kv) throws IOException {
    // add前需要阻塞flush
    flushIfNeeded(true);
    updateLock.readLock().lock();
    try {
      KeyValue prevKeyValue;
      // ConcurrentSkipListMap特性 put后的返回值 the old value, or null if newly inserted
      if ((prevKeyValue = kvMap.put(kv, kv)) == null) {
        // 之前kv不存在则直接加
        dataSize.addAndGet(kv.getSerializeSize());
      } else {
        // 之前kv存在,需要计算差值(可能有更新)
        dataSize.addAndGet(kv.getSerializeSize() - prevKeyValue.getSerializeSize());
      }
    } finally {
      updateLock.readLock().unlock();
    }
    flushIfNeeded(false);
  }

写入MemStore后,当数据量达到一定阈值就要将flush到DiskStore

读取流程详细剖析

读取流程相对要复杂很多。

我们需要从多个有序集合中读取数据:

  • MemStore
    • MutableMemstore:kvMap
    • ImmutableMemstore:snapshot
  • DiskStore:多个DiskFile

在Scan的时候,需要把多个有序集合通过多路归并算法合并成一个有序集合,然后过滤掉不符合条件的版本,将正确的KV返回给用户。

以上图为例,我们要将上面7个KV数据再次处理得到最终的结果。

对于同一个Key的不同版本,我们只关心最新的版本。假设用户读取时能看到的sequenceld≤101的数据,那么读取流程逻辑如下:

  • Key=A的版本 我们们只关注(A,Delete,100)这个版本,该版本是删除操作,说明后面所有key=A的版本都不会被用户看到。
  • Key=B的版本 我们只关心(B,Put,101)这个版本,该版本是Put操作,说明该Key没有被删除,可以被用户看到。
  • Key=C的版本 我们只关心(C,Put,95)这个版本,该版本是Put操作,说明该Key没有被删除,可以被用户看到。

对于全表扫描的scan操作,MiniBase将返回(B,Put,101)和(C,Put,95)这两个KeyValue给用户。

详情见: MStore#ScanIter

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
HBase写入全流程剖析
HBase采用LSM树架构,天生适用于写多读少的应用场景。在真实生产环境中,也正是因为HBase集群出色的写入能力,才能支持当下很多数据激增的业务。需要说明的是,HBase服务端并没有提供update、delete接口,HBase中对数据的更新、删除操作在服务器端也认为是写入操作,不同的是,更新操作会写入一个最新版本数据,删除操作会写入一条标记为deleted的KV数据。所以HBase中更新、删除操作的流程与写入流程完全一致。当然,HBase数据写入的整个流程随着版本的迭代在不断优化,但总休流程变化不大。
Flink实战剖析
2022/06/10
1.4K0
HBase写入全流程剖析
HBase原理 | HBase内存管理之MemStore进化论
Java工程中内存管理总是一个绕不过去的知识模块,无论HBase、Flink还是Spark等,如果使用的JVM堆比较大同时对读写延迟等性能有较高要求,一般都会选择自己管理内存,而且一般都会选择使用部分堆外内存。HBase系统中有两块大的内存管理模块,一块是MemStore ,一块是BlockCache,这两块内存的管理在HBase的版本迭代过程中不断进行过各种优化,接下来笔者结合自己的理解,将这两个模块的内存管理迭代过程通过几篇文章梳理一遍,相信很多优化方案在各个系统中都有,举一反三,个人觉得对内核开发有很大的学习意义。本篇文章重点集中介绍MemStore内存管理优化。
大数据技术架构
2020/04/21
1.7K0
HBase原理 | HBase内存管理之MemStore进化论
HBase底层原理及读写流程
1 包含访问hbase的接口,client维护着一些cache来加快对hbase的访问,比如regione的位置信息。
硅谷子
2020/12/23
8650
HBase底层原理及读写流程
HBASE 技术细节 读取与写入 Region Split与合并介绍
Hbase Rowkey CF 架构 概述 预分区及Rowkey设计 学习笔记介绍了Region类似于数据库的分片和分区的概念,每个Region负责一小部分Rowkey范围的数据的读写和维护,Region包含了对应的起始行到结束行的所有信息。master将对应的region分配给不同的RergionServer,由RegionSever来提供Region的读写服务和相关的管理工作。
大鹅
2020/07/31
2.3K0
HBase架构详解及读写流程
Master是所有Region Server的管理者,其实现为HRegionServer,主要作用有:
一个会写诗的程序员
2022/12/02
7.6K0
HBase 底层原理详解(深度好文,建议收藏)
HBase 是一个分布式的、面向列的开源数据库。建立在 HDFS 之上。Hbase的名字的来源是 Hadoop database,即 Hadoop 数据库。HBase 的计算和存储能力取决于 Hadoop 集群。
五分钟学大数据
2021/03/04
1.7K0
HBase 底层原理详解(深度好文,建议收藏)
HBase 底层原理详解(深度好文,建议收藏)
HBase 是一个分布式的、面向列的开源数据库。建立在 HDFS 之上。Hbase的名字的来源是 Hadoop database,即 Hadoop 数据库。HBase 的计算和存储能力取决于 Hadoop 集群。
五分钟学大数据
2021/01/13
4K0
HBase 底层原理详解(深度好文,建议收藏)
hbase源码系列(十)HLog与日志恢复
HLog概述 hbase在写入数据之前会先写入MemStore,成功了再写入HLog,当MemStore的数据丢失的时候,还可以用HLog的数据来进行恢复,下面先看看HLog的图。 旧版的HLog是实
岑玉海
2018/03/01
1.3K0
hbase源码系列(十)HLog与日志恢复
HBase容错性和Hbase使用场景、Hbase读写过程详解
该机制用于数据的容错和恢复: 每个HRegionServer中都有一个HLog对象,HLog是一个实现Write Ahead Log的类,在每次用户操作写入MemStore的同时,也会写一份数据到HLog文件中(HLog文件格式见后续),HLog文件定期会滚动出新的,并删除旧的文件(已持久化到StoreFile中的数据)。当HRegionServer意外终止后,HMaster会通过Zookeeper感知到,HMaster首先会处理遗留的 HLog文件,将其中不同Region的Log数据进行拆分,分别放到相应region的目录下,然后再将失效的region重新分配,领取 到这些region的HRegionServer在Load Region的过程中,会发现有历史HLog需要处理,因此会Replay HLog中的数据到MemStore中,然后flush到StoreFiles,完成数据恢复。
Java架构师必看
2021/08/12
8060
HFile文件格式与HBase读写
HFile是HBase存储数据的文件组织形式。HFile文件的特点: 1)HFile由DataBlock、Meta信息(Index、BloomFilter)、Info等信息组成。 2)整个DataBlock由一个或者多个KeyValue组成。 3)在文件内按照Key排序。
大数据真好玩
2020/06/12
2.3K0
【HBase】HBase之how
(1)创建Connection是重量级的,并且,创建过多Connection会导致HBase拒绝连接。
章鱼carl
2022/03/31
3.4K0
【HBase】HBase之how
面试头条:HBASE 存储设计
5、Hbase的表在物理存储上,是按照列族来分割的,不同列族的数据一定存储在不同的文件中
木野归郎
2020/06/12
1.1K0
Hbase 技术细节笔记(上)
飞鸿无痕
2017/09/28
19.1K9
Hbase 技术细节笔记(上)
HBase底层原理(多维度分析)
也就是我们所谓的"客户端",Client作为访问数据的入口,包含访问hbase的API接口,维护着一些cache(高速缓存存储器)来加快hbase的访问。
大数据梦想家
2021/01/26
5230
HBase底层原理(多维度分析)
HBase工作原理
HBASE原理 一、原理 1、物理存储 1.hregion     hbase表中的数据按照行键的字典顺序排序,hbase表中的数据按照行的的方向切分为多个region。     最开始只有一个region随着数据量的增加,产生分裂,这个过程不停的进行。一个表可能对应一个或多个region。     region是hbase表分布式存储和负载均衡的基本单元,一个表的多个region可能分布在多台HRegionServer上。 2.Store     region是分布式存储的基本单元,但不是存储的基本单元,
云飞扬
2018/05/11
3K1
hbase源码系列(九)StoreFile存储格式
从这一章开始要讲Region Server这块的了,但是在讲Region Server这块之前得讲一下StoreFile,否则后面的不好讲下去,这块是基础,Region Sever上面的操作,大部分都
岑玉海
2018/03/01
1.7K0
hbase源码系列(九)StoreFile存储格式
Hadoop HBase存储原理结构学习
hbase是bigtable的开源山寨版本。是建立的hdfs之上,提供高可靠性、高性能、列存储、可伸缩、实时读写的数据库系统。 它介于nosql和RDBMS之间,仅能通过主键(row key)和主键的range来检索数据,仅支持单行事务(可通过hive支持来实现多表join等复杂操作)。主要用来存储非结构化和半结构化的松散数据。 与hadoop一样,Hbase目标主要依靠横向扩展,通过不断增加廉价的商用服务器,来增加计算和存储能力。 HBase中的表一般有这样的特点: 1 大:一个表可以有上亿行,上百万列 2 面向列:面向列(族)的存储和权限控制,列(族)独立检索。 3 稀疏:对于为空(null)的列,并不占用存储空间,因此,表可以设计的非常稀疏。 二、逻辑视图
哲洛不闹
2018/09/14
1.8K0
Hadoop HBase存储原理结构学习
HBase常见面试题[通俗易懂]
读: 找到要读数据的region所在的RegionServer,然后按照以下顺序进行读取:先去BlockCache读取,若 BlockCache没有,则到Memstore读取,若Memstore中没有,则到HFile中去读。 写: 找到要写数据的region所在的RegionServer,然后先将数据写到WAL(Write-Ahead Logging,预写日志系统)中,然后再将数据写到Memstore等待刷新,回复客户端写入完成。
全栈程序员站长
2022/09/03
9980
Hbase
最近在逐步跟进Hbase的相关工作,由于之前对Hbase并不怎么了解,因此系统地学习了下Hbase,为了加深对Hbase的理解,对相关知识点做了笔记,并在组内进行了Hbase相关技术的分享,由于Hbase涵盖的内容比较多,因此计划分享2期,下面就是针对第一期Hbase技术分享整体而成,第一期的主要内容如下:
大学里的混子
2019/03/11
4.4K0
hbase源码系列(十一)Put、Delete在服务端是如何处理?
在讲完之后HFile和HLog之后,今天我想分享是Put在Region Server经历些了什么?相信前面看了《HTable探秘》的朋友都会有印象,没看过的建议回去先看看,Put是通过MultiServerCallable来提交的多个Put,好,我们就先去这个类吧,在call方法里面,我们找到了这句。 responseProto = getStub().multi(controller, requestProto); 它调用了Region Server的multi方法。好,我们立即杀到HRegionServ
岑玉海
2018/03/01
1.9K0
相关推荐
HBase写入全流程剖析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验