YashanDB 物理存储结构
本文内容来自 YashanDB 官网,原文内容请见 https://doc.yashandb.com/yashandb/23.3/zh/%E6%A6%82%E5%BF%B5%E6%89%8B%E5%86%8C/%E5%AD%98%E5%82%A8%E7%AE%A1%E7%90%86/%E7%89%A9%E7%90%86%E5%AD%98%E5%82%A8%E7%BB%93%E6%9E%84.html
物理存储结构用于承载 YashanDB 在存储介质上持久化数据(包括用户数据以及数据库元数据),用户可以直接在操作系统层面查看物理储存结构相关的文件。
YashanDB 物理存储结构主要包括以下文件:
数据存储文件:用于存储数据的物理文件,YashanDB 支持段页式和分片式两种不同组织格式的数据文件。
临时文件:用于临时数据(临时表空间的数据)的存储或中间计算结果的换出(交换表空间的数据)。
redo 重做日志文件:用于记录数据库变更的物理日志,通常用于故障恢复或主备同步。
控制文件:用于持久化数据库基本元数据的文件,例如其他物理文件的信息,是加载数据库的入口。
双写文件:用于数据的多副本写入,解决因文件系统缓存导致的数据块半写问题。
YashanDB 支持将物理存储结构部署到不同的存储介质上,主要包括:
通用文件系统:YashanDB 支持将物理存储结构部署到主流的文件系统上,例如 ext4、XFS、ZFS、NFS 等。
自研文件系统:YashanDB 自研文件系统 YFS 除了基本的物理文件存储能力之外,还提供多实例共享存储的能力。
云存储:YashanDB 支持将数据以对象存储的方式存储到远端,例如 S3、OBS、BLOB 等。
数据存储文件
YashanDB 支持行式和列式两种不同的数据存储格式,对应段页式和切片式两种不同格式的数据存储文件,分别为数据文件(DataFile)和切片文件(SliceFile)。
# 数据文件
数据文件在创建表空间时指定,每个表空间至少要包含一个数据文件。数据文件存储的数据不仅包括用户的数据,也包括数据库元数据(例如表的结构信息)、历史数据(undo 数据)等。
虽然 Linux 稀疏文件(只更新元数据不实际占用存储空间)的方式可以极大程度的提高文件创建效率,但会出现数据库运行过程中因为实际存储空间不足导致的异常,因此 YashanDB 创建数据文件时会使用预占空间的方式,同时会初始化所有存储空间,并通过自适应并行技术来加速创建的过程。
YashanDB 支持数据文件的各类运维 SQL 语句(包括创建、删除、属性修改、脱机等),但不允许从物理上直接操作数据文件(例如使用操作系统的 rm、mv、chmod 等命令),否则会导致数据库出现预期外的异常。
段页式空间管理依赖于基于数据文件的物理存储方式,因此数据文件在物理上也是被划分成了数据块,YashanDB 支持的数据块大小 8K、16K 和 32K。例如数据文件的大小为 1M,数据块的大小为 8K,那么这个数据文件就包括连续的 128 个数据块。
数据文件中存在多种不同用途的数据块,主要包括:
表空间头:用于记录所属表空间的相关信息。
数据文件头:用于记录当前数据文件的相关信息。
空间管理块:用于当前数据文件的空间管理,记录了每个数据块的使用情况。
数据块:实际用于存储数据的数据块。

# 切片文件
切片文件用于存储 LSC 表的稳态切片数据,采用文件存储,用户可以指定存储在 databucket 中。切片文件由列数据文件、列元数据文件和切片元数据文件组成:
列数据文件:数据按固定行数,被分为多个 block,多个 block 组成一个 extent,每一列相同位置的 block 被称为 RowGroup。
列元数据文件:存储 block、extent 的元数据,包含 block 最大最小值的 zone map 和一些其他的统计信息,若是字典编码,还会存储字典。
切片元数据文件:主要存储整个 slice 的列数量,crc 列存储位置等信息。

# 临时文件
临时文件用于存储非持久化的数据(数据库重启后会丢失),存储结构与数据文件一致但临时文件的相关修改不会产生 redo 重做日志,也没有通过检查点机制刷盘。
临时文件存储的数据主要包括:
临时表空间数据:YashanDB 将临时表、索引等非持久化对象存储到临时表空间,当临时内存不足时,会临时将此类对象信息写入临时文件,使用时再加载。
交换表空间数据:交换表空间用于计算中间结果的换入换出,例如排序、分组等中间结果。
redo 重做日志文件
在线 redo 重做日志用于存储重做条目(又称为重做日志记录),存储数据库发生的更改(主要是数据文件的更改)。
redo 重做日志的主要目的是恢复。当数据库异常退出后,redo 重做日志可以恢复已提交但未写入数据文件的数据,从而避免数据丢失。
# redo 重做日志文件的结构
YashanDB 的 redo 文件记录了数据库产生的物理日志,用于数据库宕机重演和主备复制。
redo 文件的结构如图:

redo head
记录元数据,包括序列号、块大小、时间等。
redo pack
日志刷盘的基本单位,它内部包含若干个分区,每个分区内包含多个 redo group。
redo group:一个 session 执行业务产生的一批 record 集合。
record:一条条具体的日志操作,例如 insert,update 等。
# redo 重做日志的写入
每个实例存在一个独立的 redo 重做日志写入线程(LGWR),当日志写到一定阈值时会触发该线程将重做条目写入 redo 文件中。
当业务量很大时,重做条目的产生速度很快,若整个 REDO BUFFER 被写满,用户 SESSION 也会主动将重做条目写入 redo 文件中。
YashanDB 数据库要求至少并存三个 redo 重做日志文件。
# redo 重做日志切换
redo 重做日志文件有如下 4 种状态:
NEW:未使用过的文件。
CURRENT:当前正在写入的文件。
ACTIVE:该文件不可被复用。
INACTIVE:该文件可复用。
数据库只能往一个 redo 重做日志文件中写入重做条目,正在写入的文件被称为 CURRENT redo 重做日志文件。
当数据库停止向一个重做文件中写入,开始向下一个文件写入时,则说明发生了日志切换,通常发生在 CURRENT redo 重做日志文件写满且要写入新的重做条目时。支持手动强制切换日志,手动切换时无需关注 CURRENT 的 redo 重做日志文件是否已写满。
redo 重做日志切换时,只能选取重做文件状态为 NEW 或 INACTIVE 的文件作为下一个 CURRENT redo 重做日志。如果此时不存在 NEW 或 INACTIVE 的重做文件则无法切换,会出现“日志追尾”现象。
# 归档日志文件
归档日志文件是在线 redo 重做日志的副本,常用于备库的同步复制或恢复数据库至指定时间点,数据库处于归档模式才会产生归档日志。
在主备部署形态或需要生成备份集的情况下,必须打开归档使数据库处于归档模式。
控制文件
# 控制文件概述
控制文件是 YashanDB 的大脑,是数据库实例挂载数据库的入口。控制文件包含以下重要的信息:
数据库的基础元数据,包括数据库名称、数据库实例个数、时间戳信息(SCN)等。
数据库检查点信息,例如数据库回放起始点、回放一致性点等。
数据库各类物理文件的路径、大小等信息。
数据库在运行期间,会实时更新控制文件。例如创建数据文件的操作需要在控制文件中写入新数据库的信息、检查点机制需要定期更新控制文件中的恢复点。
控制文件损坏会导致数据库完全不可用,因此 YashanDB 采用多副本控制文件的机制,保证单一文件损坏不会导致数据库异常。
控制文件的信息由数据库自动维护,不允许手动操作控制文件,否则会导致数据库出现预期外的异常。
# 控制文件结构
控制文件内部通过划分不同区域(section)来存储不同的元数据,主要包括以下几类:
引导区:用于存储数据库的基础信息,例如版本、ID、角色、数据块大小、字符集等。
实例区:用于实例级的启动信息(共享集群形态中同一个数据库会包括多个实例),例如恢复点、SCN、一致性点等。
存储结构区:用于存储表空间、数据文件、redo 重做日志、归档日志等存储结构信息。
双写文件
YashanDB 的数据块规格大于主流文件系统的 page size,因此,数据块无法进行原子写,在掉电等场景可能会出现半写的情况(partitial write),从而导致出现断裂页(fractured block)。
YashanDB 通过双写技术解决数据块半写问题,在数据块落盘时,会先写入双写区。数据库启动时会通过双写区恢复异常退出导致的断裂页。
双写文件是双写区的存储载体,在建库时创建,用户可以独立指定双写文件的路径、大小等信息。
版权声明: 本文为 InfoQ 作者【YashanDB】的原创文章。
原文链接:【http://xie.infoq.cn/article/601f9f3bc676802ec62597511】。文章转载请联系作者。
评论