#物理存储结构

物理存储结构用于承载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通过双写技术解决数据块半写问题,在数据块落盘时,会先写入双写区。数据库启动时会通过双写区恢复异常退出导致的断裂页。

双写文件是双写区的存储载体,在建库时创建,用户可以独立指定双写文件的路径、大小等信息。