最新动态
kudu之tablet设计原理
2024-12-21 10:49

Tablet是Kudu表的水平分区,就像是BigTable中的tablets和Hbase中的regions一样。每个tablet中都由一系列连续的行组成,这些行不会与任何其他tablet重叠。所有tablet一起构成了整张表。

每个tablet进一步细分为多个称为RowSet的行集。每个RowSet由一组行的数据组成。RowSet是不相交的,即不同RowSet的行集不相交,因此任何给定的key最多存在于一个RowSet中。虽然RowSets是不相交的,但它们的key空间可能会重叠。

保存在内存中的RowSet,称为MemRowSet。所有插入都直接进入MemRowSet,它是一个按表的主键排序的内存中的B-Tree。在插入数据时,它会在MemRowSet中累积,数据一旦进入MenRowSet中就立刻对读可见,并且遵守MVCC(多版本并发控制)。

注意:与BigTable不同,只有插入的数据和最近数据的更新才会进入MemRowSet - 本文后面的部分将讨论诸如磁盘中数据更新和删除之类的操作。

每个行数据只存在于MemRowSet中的一个实体中。这个实体的值由一个特定的header信息,以及行数据的打包格式组成(下面有更多详细信息)。由于MemRowSet完全在内存中,它最终将被填满并“刷新”到磁盘 - 此过程将在本文档的后面部分详细介绍。

Kudu使用多版本并发控制来提供许多有用的功能

  • 快照查询:当一个查询被创建时,它将查询某个时间点的快照数据。将忽略在查询过程中对tablet进行的任何更新。此外,该时间点的快照可以存储并重新用于同一tablet上的其他查询,例如,如果应用程序想要执行分析,需要在一致的数据视图上进行多次传递。
  • 历史快照查询:与上边的快照查询一样。用户可以指定历史的一个时间点创建一个查询,MVCC可以保证历史快照的一致性。这个功能可以被用来在某个时间点上的一致性备份。
  • 历史变更查询:给定两个MVCC快照,用户可以查询任意给定行的这两个快照之间的增量集。可以利用此功能来执行增量备份,执行跨群集同步或进行离线审计分析。
  • tablet中的多行原子更新:单个操作可以修改tablet中的多个行,并且它将在单个原子动作中可见。

为了提供MVCC,每个操作都标有时间戳。时间戳由一个名为TS-wide Clock 的实例生成,并通过tablet的MvccManager确保在tablet中是唯一的。经过MvccManager确认时间戳后的状态被称为已提交状态,已提交状态的数据可以被后来的查询可见。查询创建后,会获取MvccManager状态的快照,然后将该查询看到的任何数据与MvccSnapshot进行比较,以确定哪些插入,更新和删除后的数据应被视为可见。

每个tablet的时间戳单调递增的。我们使用一种名为HybridTime的技术来创建时间戳,这些时间戳对应于真正的挂钟时间,但也反映了节点之间的因果关系。

为了支持这些快照查询,数据库中必须保持每行数据的多个版本。为了防止无限制的空间使用,用户可以配置保留期,超过该保留期可以对旧的事务记录进行回收(从而防止从历史记录中的那个点之前的任何快照读取)。(注意:历史GC目前尚未实现

为了在MemRowSet中支持MVCC,每行都标有插入行的时间戳。此外,该行包含一个单链表,其中包含插入后对该行进行的任何进一步操作,每个操作都标记有操作的时间戳

 

在传统的数据库术语中,人们可以认为操作列表形成了一种“REDO日志”,其中包含影响该行的所有变化。

任何遍历MemRowSet的读者都需要通过以下逻辑应用这些操作来读取行的正确快照

  • 如果这行数据插入时的timestamp,不在scanner 的MVCC snapshot里(即scanner快照指定的timestamp小于数据插入的时间戳,数据还没创建,忽略该行
  • 否则将这行数据放入output缓存里
  • 对于列表中的每个操作
    • 如果mutation的timestamp在MVCC snapshot里,在内存的缓存中执行这个更新。如果不在,则跳过此mutation
    • 如果mutation是一个DELETe操作,则在buffer中标记为已经被删除了,并清空之前加载缓存里的数据。

请注意,操作可以是以下三种类型之一

  • 更新:更改一列或多列的值
  • DELETE:从数据库中删除行
  • REINSERT:重新插入行(仅发生在先前有DELETE操作的MemRowSet行上

作为一个具体示例,请看表结构为key STRING, val UINT32)的如下操作

INSERT INTO t VALUES (“row”, 1); [timestamp 1]
UPDATE t SET val = 2 WHERe key = “row”; [timestamp 2]
DELETE FROM t WHERe key = “row”; [timestamp 3]
INSERT INTO t VALUES (“row”, 3); [timestamp 4]
以上一系列的操作会在MemRowSet生成如下结构

 

请注意,当更新频率较高时,这会有一些不良影响

  • 读操作必须通过单链表追逐指针,可能导致许多CPU缓存未命中。
  • 更新必须附加到单个链表的末尾,时间复杂度为O(n,其中“n”是此行已更新的次数。

但是,考虑到以下假设,我们认为上述低效率是可以容忍的

  • Kudu的目标使用场景具有相对较低的更新率:我们假设单行不会有高频率的更新
  • 只有总数据库的一小部分将在MemRowSet中 - 一旦MemRowSet达到某个目标大小阈值,它将刷新。因此,即使由于更新频繁导致MemRowSet很慢,它也只占整个查询时间的一小部分。

如果事实证明上述低效率会影响实际应用程序,则可以在将来应用各种优化以减少开销。

当MemRowSet填满时,会发生Flush,将数据保存到磁盘。

 

当数据被刷新,它将会以CFiles的形式被存储在磁盘中。数据中的每一行都可以通过有序的rowid被定位,该rowid在此DiskRowSet中是密集的,不可变的和唯一的。例如,如果给定的DiskRowSet包含5行,则按升序的顺序为它们分配rowid 0到4。在不同的DiskRowSet中,将有不同的行具有相同的rowid。

读取可以使用索引结构在主键(用户可见)和rowid(内部)之间进行映射。在主键是简单键的情况下,键结构嵌入在主键列的CFile中。否则,用独立的索引CFile存储编码后的复合键并提供类似的功能。

注意:rowid不是与每一行显式存储,而是基于文件中行的序数索引的隐式标识符。源代码的某些部分将rowid称为“row indexes” 或者 “ordinal indexes”。

注意:其他系统(如C-Store)将MemRowSet称为“写入优化存储”(WOS,磁盘上的文件称为“读取优化存储”(ROS)。

为了继续为磁盘数据提供MVCC,每个磁盘上的RowSet不仅包含当前的列数据,还包含“UNDO”记录,这些记录提供了将行数据回滚到早期版本的能力。

 

当用户想要在刷新后立即读取最新版本的数据时,只需要基础数据。由于基础数据以列式存储,因此这种查询性能是很好的。相反,如果用户想要运行历史数据查询,则需要查询UNDO记录,以便将可见数据回滚到较早的时间点。

当查询过程中遇到一行时,它会按如下方式处理MVCC信息

  • 读取行的基本数据
  • 对于每个UNDO记录: 如果相关的操作timestamp还未提交,则执行回滚操作。即查询指定的快照timestamp小于mutation的timestamp,mutation还未发生。

例如,回想一下上面“MemRowSet中的MVCC Mutations”中使用的一系列操作

 

将此行刷新到磁盘时,我们将按以下方式将其存储在磁盘上

 

UNDO中的操作都是与真实的操作相反的 - 例如,事务1中的INSERT在保存为UNDO记录时变为“DELETE”。

此处使用UNDO保留插入时间戳:查询的MVCC快照指定的时间早于Tx1时,Tx1还未提交,此时将会执行DELETE操作,那么这时这条数据是不存在的。

看以下两个例子

 

每个案例处理正确的UNDO记录集,以获取所需时间点的行数据。

最常见的情况就是查询当前数据。在这种情况下,我们希望通过避免处理任何UNDO记录来优化查询执行。为了达到这个目标,我们引入文件级别的元数据,指向UNDO record的数据范围。如果查询的MVCC快照符合的所有事务都已经提交了(查询最新的数据,这组deltas就会短路(不处理UNDO record,这时查询将没有MVCC开销。

已刷新到磁盘中的数据的更新或删除不会进入MemRowSet。而是在所有RowSet中搜索更新的key,以便找到保存该keyt的唯一RowSet。此过程首先使用区间树来定位可能包含要查询的key的一组候选RowSet。在此之后,用boom filter去判断候选RowSet中是否包含这个key。对于通过两个检查的RowSet,再用索引找到目标行的rowId。

一旦确定了数据所在的RowSet,mutation将拿到主键对应的rowid,然后mutation会被写入到一个称为DeltaMemStore的内存结构中。

DeltaMemStore是一个在内存中的并行BTree,BTree的key是使用rowid和mutation的timestamp混合成的。在读取时,以与新插入数据的mutation相同的方式处理这些mutation。

当Delta MemStore变得太大时,它会对将数据刷新到磁盘上​​的DeltaFile中,并将自身重置为空

 

DeltaFiles包含与Delta MemStore相同类型的信息,但是压缩为密集的磁盘序列化格式。由于这些增量文件中包含将基础数据更新到最新版本的事务记录,因此它们被称为“REDO”文件,而其中包含的mutations 称为“REDO”记录。与驻留在MemRowSet中的数据类似,需要应用REDOmutations 来读取更新版本的数据。

给定行可以具有多个delta结构中的delta信息。在这种情况下,deltas 是有序的,后来的修改优先于早期的修改。

注意,给定行的mutation 跟踪结构不需要包括整行数据。如果仅更新行中的单个列,则mutation 结构将仅包括更新的列。这允许快速更新少数的列而无需读取或重写大量的列(与C-Store和PostgreSQL等系统使用的MVCC技术相比具有优势)。

每个DiskRowSet由3个部分组成

 

base data: RowSet刷新后的列数据

UNDO records:历史数据,用于将当期数据回滚到之前的某个版本

REDO records:用于将数据更新到最新版本的数据,它包含了数据刷新之后的改动

UNDO records 和 REDO records 是用相同的格式存储的,称为DeltaFile

在RowSet中,随着越来越多的操作在delta跟踪结构中累积,读取效率会越来越低; 特别是,当读取base data时,每个刷新过的delta文件都会被搜索和合并。此外,如果数据已多次更新,则必须获取许多REDO记录才能得到最新版本的数据。

为了减轻这种影响并提高读取性能,Kudu执行后台处理,将RowSet从低效的物理布局转换为更高效的布局,同时保持相同的逻辑内容。这些类型的转换称为“delta compactions”。Delta压缩有几个主要目标

1、减少增量文件的数量
RowSet拥有的delta文件越多,获取最新版本数据时需要读取的文件就越多。每次随机读取都会导致每个增量文件的磁盘搜索,从而导致性能下降。

2、将REDO记录合并到UNDO记录
如上所述,RowSet由base data(按列存储,一组“undo”记录(用于回滚到以前版本)和一组“REDO”记录(用于更新到最新版本)。鉴于大多数查询将针对当前版本的数据库进行,我们希望尽量减小REDO记录存储。

在任何时候,行的REDO记录可以合并到base data中,并由等效UNDO记录集替换。

3、回收旧的UNDO记录。
UNDO记录只需保留在用户配置的历史保留期之后。在此期间之后,我们可以删除旧的“撤消”记录以节省磁盘空间。

注意:在BigTable设计中,时间戳与数据相关联,而不是与更改相关联。在Kudu设计中,时间戳与更改相关联,而不是与数据相关联。删除历史UNDO日志后,没有剩余的记录显示何时插入或更新了任何行或单元格。如果用户需要此功能,他们应该保留自己的“inserted_on”时间戳列,就像在传统的RDBMS中一样。

REDO delta压缩可以分为“minor”或“major”

‘minor’ compaction不包含base data的压缩。在这种类型的压缩中,生成的文件本身就是一个增量文件。

 

minor REDO delta压缩仅用于目标1:因为它们不读取或重写基础数据,所以它们无法将REDO记录转换为UNDO。

Major REDO压缩是包含基础数据以及任意数量的REDO delta文件的压缩。

 

‘major’ REDO满足delta压缩的目标1和2,但由于它们必须读取和重写base data(通常大于delta数据,因此成本高于次要delta压缩。

可以对DiskRowSet中的所有列的任意子集执行major REDO delta压缩 - 如果只有单个列接收到大量更新,则可以只对这列的数据做压缩。在企业级应用中会经常遇到这种情况,例如更新订单的状态、更新用户的访问量。

请注意,这两种类型的delta压缩都在RowSet中维护了row ID:因此,它们可以完全在后台完成而不进行锁定。compact的结果文件会采用原子swapping的方式被引入进RowSet。Swap操作结束后,compact前的那些老文件将会被删除。

随着更多数据插入tablet,越来越多的DiskRowSets将会累积。这可能会影响以下情况的性能

a)随机访问(通过主键获取或更新单行

在这种情况下,为了定位key的具体位置,所有key范围包含查询key的rowSet将会被访问。 bloom 过滤器可以减少物理搜索的次数,但增加的 bloom 过滤器访问会影响CPU并且还会增加内存使用量。

b)使用指定范围扫描(例如查询“A”和“B”之间的主键

在这种情况下,所有key范围与查询范围有重叠的RowSet都会被搜索。特定的索引结构可能会有所帮助,但同样会以消耗内存为代价等。

c)排序查询
如果用户查询要求以主键排序顺序生成查询结果,则那么查询结果一定需要经过合并。Merge的消耗通常与输入的数据量成对数级增长,即随着数据量的增大,merge将越耗性能。

鉴于上述情况,最好将RowSet合并在一起以减少RowSet的数量

    以上就是本篇文章【kudu之tablet设计原理】的全部内容了,欢迎阅览 ! 文章地址:http://ww.kub2b.com/news/9688.html
     栏目首页      相关文章      动态      同类文章      热门文章      网站地图      返回首页 企库往资讯移动站 http://ww.kub2b.com/mobile/ , 查看更多   
最新文章
核心城市土地市场升温 地块成交楼面价频创新高
  随着楼市逐步显现企稳迹象,土地市场也持续升温。3月份,北京、杭州、成都等核心一线、二线城市均有地块成交楼面价创出新高
欧洲将为乌克兰提供价值两百万枚炮弹的资金
据乌克兰国家通讯社报道,乌克兰总理什米哈尔在电视上称,在布鲁塞尔举行的欧盟-乌克兰联盟理事会会谈期间,讨论了为乌克兰国防
咸宁佳能发布EOS R5 Mark II,摄影爱好者迎...工业手机「咸宁佳能发布EOS R5 Mark II,摄影爱好者迎...」
烟台惠诚佳业电子科技有限公司成立于2017年,公司从计算机软、硬件营销,发展成为现今以投影机、数码相机、摄像机营销,多媒体投
拳皇VS街霸街头霸王下载手机版「拳皇VS街霸」
拳皇VS街霸是一款动作格斗游戏,在游戏中玩家会体验到丰富的皇斗玩法,一切都值得玩家去体验,成为一名格斗高手,不断地进行在手
陪嫁火缸是啥?杭州有饭店收藏这份“时光密码”,炭火煨出娘家味道
潮新闻客户端 记者 孙韵在浙江部分地区,上世纪80年代还有陪嫁火缸。它们看着像水缸,但其实里面烧炭,上面可以用砂锅或者瓦罐煨
朝鲜有5条奇葩规矩,千万不能碰!一不小心有可能“小命不保”朝鲜手机「朝鲜有5条奇葩规矩,千万不能碰!一不小心有可能“小命不保”」
朝鲜是全世界最神秘的国家之一,也是我们的邻居,许多游客都想去朝鲜旅游,看一看这个神秘的国度。不过,去之前一定要了解当地这
小米手机怎么投屏电视小米手机怎么投屏到电视「小米手机怎么投屏电视」
使用小米手机投屏电视的步骤:确保手机和电视连接到同一 Wi-Fi 网络。在小米手机上开启投屏功能(从屏幕顶部向下滑动,点击“投
小屏旗舰复兴:除了OVM,华为、荣耀也要加入战局!小屏旗舰手机「小屏旗舰复兴:除了OVM,华为、荣耀也要加入战局!」
回顾过去几年,随着大屏幕、高刷新率和全面屏技术的普及,智能手机屏幕尺寸逐渐膨胀至6.7英寸左右,这也让新机的堆料程度变得很
手机运行内存有什么用手机运行内存是什么意思「手机运行内存有什么用」
在智能手机日益普及的今天,我们经常会听到“运行内存”这个词。对于很多非专业人士来说,可能并不清楚手机运行内存(RAM)到底
手机进水了怎么排水手机进水了「手机进水了怎么排水」
手机进水了是很多人都可能遇到的情况,比如不小心把手机掉进水里,或者在下雨天被淋湿了。手机进水了会影响手机的性能,甚至导致