写点什么

从读写角度,带你了解数仓的 IO 基本框架

  • 2022 年 3 月 16 日
  • 本文字数:2044 字

    阅读完需:约 7 分钟

本文分享自华为云社区《GaussDB(DWS)基本IO框架》,作者: Naibaoofficial。

行存 IO 管理框架

存储结构

  • OID(Object identifiers):对象的唯一标识。

  • 每个表存在对应数据库的文件夹中,用 relfilenode 标识。



例如表row1,可以直接查询对应的文件

test=# select pg_relation_filepath('row1'); pg_relation_filepath---------------------- base/16385/55984(1 row)
复制代码
  • 每个表的读取写入以页(文件块)为基本单位,页的大小是一个 BLCKSZ,默认 8KB,其结构如下:

  • Tuple 保存了当前一行的数据,分为 Header 和 Data 两块,头部保存元组的相关信息(列数,事务信息,是否有 Toast 表等)。

  • 每个 Tuple 最大为 2kb,若 Data 过大无法压缩至 2KB,则采用额外的 Toast 表存储,此时 Tuple 内的 Data 保存 Toast 表的相关信息。

GaussDB 行存框架:



这里面涉及到几个比较大的内核机制:

  • 本地缓存:

这里面的本地缓存介绍了三个比较常用的缓存结构,这里直接引用了官方的英文解释。

temp_buffers: Sets the maximum number of temporary buffers used by each database session. These are session-local buffers used only for access to temporary tables.

work_mem: Specifies the amount of memory to be used by internal sort operations and hash tables before writing to temporary disk files.

maintenance_work_mem: Specifies the maximum amount of memory to be used by maintenance operations, such as VACUUM, CREATE INDEX, and ALTER TABLE ADD FOREIGN KEY.

  • 共享内存:可由整个 Gaussdb 共享

包括shared_bufferwal_buffer, 分别用来存放 Page 和 Clog,Wal Segment。

  • WalWriter,BgWriter:

主要是将共享内存的内容落盘,WalWriter一般是在事务提交时就需要落盘,但是有时候可以放弃一定的事务一致性原则,从而让WalWriter异步落盘加快速度。BgWriter负责将 shared_buffer 中的内容落盘。

  • 外存管理:

负责上层与外存之间的文件交互。

IO 管理框架:读取

读取的过程相对简单,就是从物理文件先装到 shared_buffer 中,然后从shared_buffers返回相关的结果。



shared_buffers中就是以 Page 为单位进行存储的,因为每个 Page 的大小是固定的,所以shared_buffers能存放的 page 个数也就是确定的。这里面就需要考虑一个问题,因为这个资源是共享的,如果一个线程读取了大量的文件,这样势必会使得其他线程的缓存命中率下降。


GaussDB 在这里引入了 Ringbuffer 的机制,可以限制一个线程所使用的 shared_buffers 的大小,从而解决掉这个问题。

IO 管理框架:写入

  • 写入操作是增加的新的元组,Update 操作相当于先 Delete,再 Insert。

  • INSERT

  • UPDATE

  • 将旧元组标记为 Dead,然后插入新的元组,由 Vacuum 负责清理。当然,这里面 Data 变为DELETE只是用来描述删除的是此 Tuple,实际上 Data 当中的值是不变的。

  • 写入的整体逻辑:


GaussDB 行存在写入时,将元组信息先写入到shared_buffers,然后用 bgwriter 刷入磁盘,这样在事务提交时就可以避免磁盘的 IO 开销,提升性能,为了保证一致性和恢复,使用 wal 日志和 checkpoints 可以实现日志先落盘(也可以异步)和 redo 等操作。

列存的 IO 管理框架

列存的存储单元

  • 列存的存储单元为 CU(CStore Unit)

  • CU 的大小为 8k 对齐

  • 适合大批量导入的场景

  • 同一列的 CU 存在一个新文件中,大于 1GB 时,切换到新文件中。

  • 列存用一个 CUDesc 的行存表描述 CU 的相关信息,可以理解成为一个 Toast 表。

  • CUDesc:行存表,记录 CU 的相关信息, 主要属性如下:

  • col_id,cu_id: 第 col_id 列,第 cu_id 个 CU

  • min, max, row_count, size

  • cu_mode: information mask(RLE,LZ4,Delta 表等)

  • cu_pointer:指向每一个 CU,记录 delete bitmap

  • magic:和 CU 头部的 magic 相同,校验使用

CU 结构



列存索引

这里介绍两个索引,C-Btree 和 Psort,这里不做过多介绍。主要涉及的是 IO 相关的内容。

C-Btree

  • 索引结构和行存无差别,同样以行存形式存储

  • C-Btree 可以提升点查效率

  • 存储 key->ctid(cu_id, offset)

  • 过程:

  • 根据 B-tree 索引找到 ctid 集合

  • 对集合进行批量排序(减少 IO 开销)

  • 在 CUDesc 找到对应的 cu_id,根据 offset 找到数据

  • 举例,等值查询 n=49, 范围查询 23<n<64。



PSort

PSort 是一个聚簇索引,对索引进行排序,然后将排序后的索引和行号存入一个新的表,用单独的列存表存储。简单示意如下,图片来源:https://www.modb.pro/db/108155


IO 管理框架:读取

  • 读取过程:

    根据 where 条件,做 MIN/MAX 过滤的谓词条件

    加载 CUDesc

    MIN/MAX 过滤

    读取 CU 到 CU Cache 中

    解析并填充

  • CacheMgr: 用来缓存 CU 到内存中,可以提高重复查询的性能。

  • CU 的物理文件:

  1. CStore_1.0: 当前基本不怎么实用

  2. CStore_2.0: 重整了 CU 的文件结构,避免列数过多导致文件结构复杂。



IO 管理框架:写入

列存的插入要分两种情况,少量的插入和大量的插入,列存主要是对大批量数据设计的,因此为了弥补小量插入的打包 CU 性能开销,设计了一个 delta 行存表,用来记录插入结果,可以减少膨胀和提升性能,最后定期的整理。

  • 写入框架如下



列存的删除比较简单,如果是 delta 表,先从 delta 表中删除满足谓词条件的记录,然后在 CUDesc 表中更新待删除 CU 的 delete_bitmap。


点击关注,第一时间了解华为云新鲜技术~​

发布于: 刚刚阅读数: 2
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
从读写角度,带你了解数仓的IO基本框架_io_华为云开发者社区_InfoQ写作平台