深度剖析金仓数据库存储:物理与逻辑的完美结合

41 阅读27分钟


兼容 是对前人努力的尊重 是确保业务平稳过渡的基石 然而 这仅仅是故事的起点

嘿,各位数据库爱好者们,今天咱们就来好好唠唠金仓数据库的存储结构。这玩意儿可就像是数据库的骨架,要是搞不懂它,那数据库在你眼里就跟个黑盒子没啥区别。

物理存储结构:数据在磁盘上的安家之所

数据库初始化与默认数据库

金仓数据库初始化的时候,会创建一个数据库实例,同时自动生成 security、template0、template1 和 kingbase 这四个默认数据库。每个数据库里都能放好多数据库对象,像表、索引、序列啥的。就好比一个小区,每个数据库就是一栋楼,楼里的房间就是这些数据库对象。

data 目录:物理存储的核心地带

数据库实例管理的所有数据,在物理上都是以操作系统文件的形式存在于磁盘上的。这些文件大多都集中在一个叫 data 的目录里,就像是小区的中心花园,所有重要的东西都在这儿。

data 目录下的必要内容

类型描述
SYS_VERSION其他一个包含 KingbaseES 主版本号的文件,就像是小区的门牌,告诉别人这小区是啥版本的。
base数据文件包含每个数据库对应的子目录,记录每个数据库内对象的持久化数据或临时数据。每个子目录的名字就是该数据库在 sys_database 里的 OID,就好比每个楼的楼号。
current_logfiles控制文件记录当前被日志收集器写入的日志文件的文件,就像是小区的监控记录,告诉你现在正在记录哪些日志。
global数据文件及控制文件包含集簇范围的表的子目录,比如 sys_database。此外,sys_control 文件也存储在此目录下,该文件记录着数据集簇标识符及版本、检查点信息、块大小等信息,就像是小区的总控室,掌握着整个小区的重要信息。
sys_commit_ts日志文件包含事务提交时间戳数据的子目录,就像是小区里每个人的打卡记录,记录着事务提交的时间。
sys_csnlog日志文件包含事务提交序列号和子事务状态数据的子目录,就像是小区里每个人的编号和状态记录。
sys_dynshmem其他包含被动态共享内存子系统所使用的文件的子目录,就像是小区里的共享仓库,供各个进程共享使用。
sys_logical控制文件包含用于逻辑复制的状态数据的子目录,就像是小区里的复制工厂,负责数据的复制工作。
sys_multixact日志文件包含多事务(multi - transaction)状态数据的子目录(用于共享的行锁),就像是小区里的共享锁,保证多个事务之间的协调。
sys_notify日志文件包含 LISTEN/NOTIFY 状态数据的子目录,就像是小区里的通知栏,负责消息的通知。
sys_replslot其他包含复制槽数据的子目录,就像是小区里的复制插槽,保证复制的稳定性。
sys_serial日志文件包含已提交的可序列化事务信息的子目录,就像是小区里的事务档案,记录着已提交的可序列化事务。
sys_snapshots其他包含导出的快照的子目录,就像是小区里的快照照片,记录着某个时刻的状态。
sys_stat其他包含用于统计信息的永久文件的子目录,就像是小区里的统计报表,记录着各种统计信息。
sys_stat_tmp其他包含用于统计信息的临时文件的子目录,就像是小区里的临时统计报表,用于临时的统计工作。
sys_tblspc其他包含指向表空间目录的符号链接的子目录,该符号链接所指向的表空间目录中存储了所属该表空间的数据文件,就像是小区里的路标,指向不同的表空间。
sys_twophase日志文件包含用于预备事务状态文件的子目录,就像是小区里的预备事务档案,记录着预备事务的状态。
sys_wal日志文件包含 WAL(预写日志)文件的子目录,就像是小区里的预写日志仓库,保证数据的完整性。
sys_xact日志文件包含事务提交状态数据的子目录,就像是小区里的事务状态记录,记录着事务的提交状态。
kingbase.auto.conf配置文件一个用于存储由 ALTER SYSTEM 设置的配置参数的文件,就像是小区里的自动配置文件,记录着系统的自动配置信息。
kingbase.opts控制文件一个记录服务器最后一次启动时使用的命令行参数的文件,就像是小区里的启动记录,记录着服务器最后一次启动的参数。
kingbase.pid控制文件一个锁文件,记录着当前的 kingbase 进程 ID(PID)、集簇数据目录路径、kingbase 启动时间戳、端口号、Unix 域套接字目录路径(Windows 上为空)、第一个可用的 listen_address(IP 地址或者*,或者为空表示不在 TCP 上监听)以及共享内存段 ID(服务器关闭后该文件不存在),就像是小区里的门禁卡,只有持有正确 PID 的进程才能进入。

data 目录下的可选内容

类型描述
kingbase.conf配置文件一个用于存储用户自设置的配置参数的文件,就像是小区里的自定义配置文件,用户可以根据自己的需求进行配置。
sys_hba.conf配置文件一个用于配置客户端认证方式的文件,就像是小区里的门禁系统,控制着客户端的访问权限。
sys_ident.conf配置文件一个用于配置客户端认证所需的用户名映射的文件,就像是小区里的用户名映射表,将客户端的用户名映射到数据库的用户名。
sys_log日志文件包含数据库在线日志文件的子目录,就像是小区里的在线日志记录,记录着数据库的在线操作。

数据文件:数据的小窝

在金仓数据库中,数据文件是按照一个个页面(Page)来组织的,每个页面大小为 8k。对数据文件的 I/O 操作都是以页面为单位,就好比每次搬家都是以房间为单位来搬东西。

数据文件的命名与存储位置

对于实例里的每个数据库,在 data/base 目录里都有一个子目录对应,子目录的名字为该数据库在 sys_database 里的 OID。在这个子目录下,每个表和索引都存储在独立的文件里。对于普通关系,这些文件以表或索引的 filenode 号命名,它可以在 sys_class.relfilenode 中找到。但是对于临时关系,文件名的形式为 tBBB_FFF,其中 BBB 是创建该文件的后台会话的后台 ID,FFF 是文件节点号。

数据文件的分支

每个表和索引,在其主文件(或者说主分支)之外,都有一个空闲空间映射分支,它存储关系中可用空闲空间的信息。空闲空间映射存储在一个文件中,该文件以节点号加上后缀 _fsm 命名。此外,每个表还有一个可见性映射分支,存储在一个后缀为 _vm 的文件中,它用于跟踪哪些页面已知含有非死亡元组。不被日志记录的表和索引还有第三个分支,即初始化分支,它存储在后缀为 _init 的分支中。

大文件的分段存储

当表或者索引超过 1GB 之后,它就被划分成 1G 大小的段。第一个段的文件名和文件节点相同;随后的段被命名为 filenode.1、filenode.2 等等。这样的安排避免了在某些有文件大小限制的平台上的问题(实际上,1GB 只是默认的段尺寸。段尺寸可以在编译 KingbaseES 时使用配置选项 --with - segsize 进行调整)。

控制文件:数据库的指挥中心

金仓数据库服务器使用的控制信息记录在 data 目录及子目录下的控制文件中。这些控制文件就像是数据库的大脑,指挥着数据库的正常运行。比如 sys_control 文件,它记录着数据集簇标识符及版本、检查点信息、块大小等重要信息,就像是数据库的身份证和体检报告。

日志文件:数据库的黑匣子

日志文件记录数据库的历史操作信息,包含恢复数据库中的所有事务所需的信息。在金仓数据库中,日志文件主要有 WAL 日志、事务日志和在线日志三类。

WAL 日志:预写式日志的守护者

预写式日志(Write - Ahead Logging(WAL))是保证数据完整性、实现事务日志的一种标准方法。WAL 的中心思想是对数据文件的修改(它们是表和索引的载体)当且仅当只能发生在这些修改已经被记录在日志中之后,即在描述这些变化的日志被刷到持久存储以后。如果遵循这种过程,将不需要在每个事务提交时刷写数据页面到磁盘,因为知道在发生崩溃时可以使用日志来恢复数据库:任何还没有被应用到数据页面的改变可以根据其日志记录重做。

WAL 日志记录在 sys_wal 中。使用 WAL 显著减少了磁盘写的次数,因为只有日志文件需要被刷出到磁盘以保证事务被提交。而被事务改变的每一个数据文件不必被刷出。日志文件被按照顺序写入,因此同步日志的代价要远小于刷写数据页面的代价。在处理很多影响数据存储不同部分的小事务的服务器上这一点尤其明显。同时,使用 WAL 能够保证数据页的完整性,还提供数据库在线备份和恢复的可能。通过归档的 WAL 文件,可以支持恢复到手头的 WAL 文件包含的任意时刻:只需要简单地安装以前的数据库的物理备份,然后重放 WAL 到自己希望的时间。另外,物理备份还不必是数据库状态的一个即时快照——如果它是花了一段时间制作的话,因为 WAL 日志的重放将修复任何内部的不一致。

在金仓数据库中,主要通过设置 kingbase.conf 文件中相关参数来配置 WAL。部分 WAL 相关的参数还会影响数据库的性能,参考服务器配置可获取有关服务器配置的一般信息。

事务日志:事务的忠实记录者

在金仓数据库中,事务的状态及可见性等信息记录在事务日志文件中,只有通过事务日志信息才能从数据文件中得到有效的数据。因此事务日志对数据一致性是十分重要的。主要的事务日志文件有 sys_xact、sys_csnlog、sys_multixact 等。这些日志文件就像是事务的日记,记录着事务的每一个细节。

在线日志:数据库的实时监控

在金仓数据库中,用户的 SQL 操作以及数据库的运行中的事件会以文本的形式记录在在线日志中,用于使用户可以了解和分析数据库当前状态,并分析可能产生的异常。在线日志文件默认记录在 sys_log 中,并可以存放在用户指定的其他地方。就像是数据库的实时监控摄像头,记录着数据库的一举一动。

配置文件:数据库的个性化设置

金仓数据库主服务器的配置主要通过修改配置文件 kingbase.conf 完成。由 ALTER SYSTEM 修改的配置参数会被数据库服务器自动记录在 kingbase.auto.conf 中。配置文件 sys_hba.conf 和 sys_ident.conf 主要用于控制客户端认证。这些配置文件就像是数据库的个性化设置面板,用户可以根据自己的需求进行各种配置。

逻辑存储结构:数据的有序组织

数据字典:数据库的百科全书

每个金仓数据库的只读引用表和视图的中心集合统称为数据字典。数据字典包含了数据库中所有对象的定义、分配给模式对象的空间量及当前已使用量、金仓数据库用户的名称、授予用户的权限和角色和与用户相关的审计信息等。就像是数据库的百科全书,你想知道的关于数据库的信息,在数据字典里都能找到。

数据字典的组成

数据字典包含基表和视图。基表存储有关数据库的信息,只应该由数据库写入和读取这些表。用户很少直接访问基础表,因为他们已被规范化,且大多数数据存储为一种特定的格式。视图则通过使用联接和 WHERE 子句来简化信息,将基础表的数据解码成有用的信息(如用户或表名等)。这些视图包含数据字典中的所有对象的名称和描述。一些视图可以被所有数据库用户访问,而其他一些则仅供管理员访问。

数据字典的存储

数据字典基表是在数据库初始化时创建的第一批对象。所有数据库的数据字典表和视图都存储在 sys_global 表空间中。当数据库打开时,sys_global 表空间始终处于联机状态,数据字典总是可用的。

数据字典的使用

在数据库运行期间,数据库读取数据字典,以确定存在模式对象,且用户对它们具有适当的访问权限。金仓数据库也会不断地更新数据字典,以反映对数据库结构、审计、授权和数据等所做的更改。数据字典由系统用户自行维护,其他用户不能修改系统表或系统视图。很多数据字典信息存在于数据字典缓存中,因为数据库需要这些信息,来不断验证用户的访问权限,并验证模式对象的状态。解析信息通常保存在缓存中。

动态性能视图:数据库的实时体检报告

动态性能视图是在数据库打开和使用时不断更新的特殊视图。它们就像是数据库的实时体检报告,记录着数据库的各种性能指标和运行状态。

动态性能视图的内容

动态性能视图包含了系统和会话参数、内存使用和分配、CPU 和 IO 优化点分析、文件状态、会话和事务进度、SQL 运行、统计和度量等信息。数据库管理器可以使用这些视图,来获取有关数据库的信息;管理员可以使用这些视图,用于性能监控和调试。

动态性能视图的存储

动态性能视图基于从数据库内存结构生成的虚拟表。这些视图不是存储在数据库中的常规表。由于数据是动态更新的,所以不能保证视图的读一致性。因为动态性能视图并不是真正的表,其数据取决于数据库和实例的状态。

数据文件和临时文件管理:让数据各得其所

数据文件的管理指南

在金仓数据库中,数据文件的创建、命名和删除均由数据库内部进行管理,这些操作对用户是透明的。但用户仍可以依照一些建议来管理数据文件和临时文件。

关于数据文件

数据文件是一系列文件系统上的物理文件,用于存储数据库中的逻辑数据。在金仓数据库中的数据文件不需要显式创建,而是随着表和索引等对象操作而自动创建和维护。对于普通关系,这些文件会以表或索引的 filenode 号命名。对于临时关系,文件名的形式为 tBBB_FFF,其中 BBB 是创建该文件的后台会话的后台 ID,FFF 是文件节点号。此外关系中的数据超过 1GB 之后,该关系会被划分成 1G 大小的段,每个段是一个单独的数据文件,第一个段的文件名和文件节点相同;随后的段被命名为 filenode.1、filenode.2 等等。

选择适当的文件位置

数据文件的位置取决于其所属的表空间。为每个表指定合适的表空间就可以为数据文件选择合适的物理位置,合理地利用硬件资源。例如,如果有多个磁盘驱动器可用于存储数据,每个磁盘驱动器上创建了不同的表空间,请考虑将可能冲突访问的数据文件放在不同的磁盘上,这样用户执行查询时,两个磁盘驱动器可以同时工作,同时检索数据。

将数据文件和重做日志文件分开存储

数据文件和重做日志文件不应该存放在同一个磁盘驱动器上。如果数据文件和重做日志文件在同一个磁盘驱动器上,那么在该磁盘驱动器出现故障时,我们将无法通过日志重做而恢复到正确的数据,而只能通过备份文件进行恢复。如果我们的重做日志文件有多份副本,那么丢失所有副本的概率很低,这种情况我们才可以将重做日志文件和数据文件放在相同的磁盘驱动器上。

XML 数据类型:数据的特殊形态

XML 数据类型的优势

XML 类型可以用来存储 XML 数据。它比直接在一个 text 域中存储 XML 数据的优势在于,它会检查输入值的结构是否良好,并且有支持函数用于在其上执行类型安全的操作。XML 类型可以存储结构良好(如 XML 标准所定义)的“DOCUMENT”,以及“CONTENT”片段,通过引用 XPath 数据模型的“文档节点”来定义。这意味着内容片段中可以有多于一个的顶层元素或字符节点。表达式 xmlvalue IS DOCUMENT 可以用来评估一个特定的 XML 值是一个完整文档或者是一个文档片段。

创建 XML 值

要从字符数据中生成一个 XML 类型的值,可以使用函数 XMLPARSE:

XMLPARSE ( { DOCUMENT | CONTENT } value)

例如:

XMLPARSE (DOCUMENT '<?xml version="1.0"?><book><title>Manual</title><chapter>...</chapter></book>')
XMLPARSE (CONTENT 'abc<foo>bar</foo><bar>foo</bar>')

根据 SQL 标准,这是将字符串转换为 XML 值的唯一方法。当然,也可以使用以下方式进行转换:

xml '<foo>bar</foo>'
'<foo>bar</foo>'::xml

即便输入值指定了一个文档类型声明(DTD),XML 类型也不根据 DTD 来验证输入值。作为一个逆操作,从 XML 产生一个字符串可以使用函数 XMLSERIALIZE:

XMLSERIALIZE ( { DOCUMENT | CONTENT } value AS type )

其中,type 可以是 character 、character varying 或 text(或者其中之一的别名)。根据 SQL 标准,这也是在 XML 类型和字符类型间做转换的唯一方法,但是金仓数据库也允许简单地构造这些值。当一个字符串不是使用 XMLPARSE 构造成 XML 或者不是使用 XMLSERIALIZE 从 XML 构造得到,对于 DOCUMENT 和 CONTENT 两者的选择是根据“XML option” 会话配置参数决定的,可以使用以下命令进行设置:

SET XML OPTION { DOCUMENT | CONTENT };
SET xmloption TO { DOCUMENT | CONTENT };

默认值是 CONTENT,在默认情况下,CONTENT 和 DOCUMENT 的 XML 数据都被允许。

编码处理

在处理多字符编码于客户端、服务器及 XML 数据间时,需特别留意。在采用文本模式传输查询至服务器,以及反馈查询结果至客户端的过程中,金仓数据库会将跨客户端与服务器传送的所有字符数据转换为对应端点的字符编码。这同样适用于 XML 值的字符串表示。此过程可能导致 XML 数据内的编码声明失效,因为即使数据被转换,声明本身并未随之更新。为应对这一情况,当解析作为 XML 类型输入的字符串时,内含的编码声明将被忽略,其内容将被视为采用当前服务器的编码格式。因此,为确保正确处理,XML 数据的字符串应在当前客户端编码下由客户端发出,客户端有责任在发送文档前将其转换为当前客户端编码,或相应调整客户端的编码设置。在输出环节,XML 类型的值将不再包含编码声明,客户端将默认所有接收数据均采用当前客户端编码,以此简化处理流程,保持数据一致性和完整性。在使用二进制模式传送查询参数给服务器以及传回查询结果给客户端时,不会执行编码转换,因此情况就有所不同。在这种情况下,XML 数据中的编码声明将被注意到,并且如果缺少编码声明时该数据会被假定为 UTF - 8(由于 XML 标准的要求,注意金仓数据库不支持 UTF - 16)。在输出时,数据将会有一个编码声明来指定客户端编码,除非客户端编码为 UTF - 8(这种情况下编码声明会被忽略)。在金仓数据库中处理 XML 数据产生错误的可能性更小,并且在 XML 数据编码、客户端编码和服务器编码三者相同时效率更高。因为 XML 数据在内部是以 UTF - 8 处理的,如果服务器编码也是 UTF - 8 时,计算效率将会最高。当服务器编码不是 UTF - 8 时,某些 XML 相关的函数可能在非 ASCII 数据上完全无法工作。尤其在 XMLTABLE()和 XPATH()上。

访问 XML 值

XML 类型不提供任何比较操作符。这是因为对于 XML 数据不存在通用的比较算法,也无法通过比较一个 XML 和一个搜索值来检索行。XML 值通常伴随着一个独立键值域,如一个 ID。一种比较 XML 值的方案是将它们先转换为字符串。由于没有可以用于 XML 类型的比较操作符,因此无法直接在这种类型上创建索引。如果需要在 XML 中快速的搜索,需要将表达式构造为一个字符串类型或者在一个 XPath 表达式上索引。金仓数据库中的文本搜索功能也可以被用来加速 XML 数据的全文搜索。

实例结构:数据库的运行实体

数据库文件和实例的组成

金仓数据库管理系统,由数据库文件和金仓数据库实例组成。数据库文件为存储用户数据以及元数据的一组磁盘文件。元数据为描述数据库结构、配置和控制有关的信息。金仓数据库实例包含若干对存储的数据进行操作的数据库服务进程,还包括分配和管理内存,统计各种信息,以及实现各种协调工作的后台进程。一台设备上,可以同时运行多个实例。实例注册成实例服务后,会有唯一的名字标志一个实例。一个金仓数据库实例在操作系统上表现为一个金仓数据库进程,它可以由控制器启动,也可以单独用命令行启动。一个金仓数据库实例管理多个逻辑上的数据库。启动一个金仓数据库实例后,使用客户端可以访问到这个实例管理的任意一个数据库。

进程结构:数据库的工作团队

多进程架构的优势

金仓数据库服务进程采用多进程架构,一个实例中会包含多个进程。这些进程按照功能的不同可以分为后台进程和服务进程两类。这种多进程架构就像是一个分工明确的工作团队,每个进程都有自己的职责,协同工作,保证数据库的正常运行。

后台进程:默默奉献的幕后英雄

金仓数据库主进程

主进程负责统一管理各服务进程和其他后台进程。该进程负责启动服务进程和其他后台进程,并且在子进程退出的时候做清理工作。该进程负责分发来自操作系统的信号到各子进程。系统退出时,主进程负责发送信号通知各子进程退出,然后再停止自己。就像是团队的队长,指挥着整个团队的工作。

后台写进程

在这个进程中,共享缓冲池上的脏页会逐渐定期地写入持久存储(例如 HDD、SSD)。就像是团队里的清洁工,定期清理缓冲池里的脏页。

检查点进程

用来执行检查点过程。就像是团队里的质检员,定期检查数据库的状态。

自动 vacuum 进程

会定期地在服务器上执行清理和回收工作。就像是团队里的回收员,定期清理和回收数据库里的垃圾数据。

WAL 日志写进程

这个进程周期性地将 WAL 缓冲区上的 WAL 数据写入和刷新到持久存储。就像是团队里的记录员,定期将 WAL 数据写入磁盘。

统计进程

在此进程中,会收集 sys_stat_activity 和 sys_stat_database 等统计信息。就像是团队里的统计员,收集数据库的各种统计信息。

归档进程

归档进程负责将日志文件归档到指定的位置。就像是团队里的档案管理员,将日志文件归档保存。

日志收集进程

日志收集进程负责将数据库运行中的输出信息写入日志文件。就像是团队里的记录员,记录数据库的运行信息。

其他后台进程

除以上后台进程外,在特定时机或使用一些特性时会有额外的后台进程,例如恢复进程、WAL 日志发送、接收进程、kwr、ksh 进程、自动作业进程等。这些进程就像是团队里的特殊队员,在特定的情况下发挥作用。

服务进程:与用户直接交互的前台人员

金仓数据库使用客户端/服务器的模型。对于每个客户端的连接,金仓数据库主进程接收到客户端连接后,会为其创建一个新的服务进程。金仓数据库用服务进程来处理连接到数据库服务的客户端请求。该进程负责实际处理客户端的数据库请求,连接断开时退出。就像是团队里的前台人员,直接与用户进行交互。

内存结构:数据库的临时存储空间

共享内存的分配与使用

金仓数据库统一管理实例所用的内存资源。配置参数 shared_buffers 决定了数据库实例使用多少内存。当系统启动时,数据库实例向操作系统申请一块大内存(大小由 shared_buffers 决定)作为共享内存。在这之后各个进程对内存资源的使用都在这块内存里操作。

共享内存的主要部分

数据页面缓存

在内存里缓存数据页面,shared_buffers 越大,在内存里保存的数据页面就越多。相同条件下操作数据时进行的 IO 操作更少。就像是数据库的临时仓库,缓存着常用的数据页面。

日志页面缓存

日志缓冲区,操作数据时产生的日志都放在这个缓冲区上,由写日志线程和服务线程刷到磁盘。参数 wal_buffers 设置日志页面缓存大小。就像是数据库的临时日志仓库,缓存着操作数据时产生的日志。

排序和连接运算使用的缓存

服务器对元组进行排序或者连接运算时,需要用到内存缓存数据。如果所需的运算还需更大的空间,金仓数据库会借助于临时文件完成。参数 work_mem 设置每个服务进程排序和连接运算使用的缓存大小。就像是数据库的临时运算仓库,用于排序和连接运算。

锁缓存

多线程并发操作会用到锁,金仓数据库从共享内存开辟独立的内存空间用于存放锁信息。锁缓存的大小由总的共享内存大小决定。就像是数据库的临时锁仓库,存放着多线程并发操作时的锁信息。

临时分配的内存

服务器在处理数据流程中,用于临时存放数据所使用的内存,也从共享内存里分配。就像是数据库的临时储物箱,用于临时存放数据。

存储结构的协同关系:物理与逻辑的完美结合

金仓数据库的物理与逻辑存储结构形成紧密协同。逻辑层面,表空间规划存储位置,段拆分关系数据,数据块作为最小 IO 单元;物理层面,表空间对应 sys_tblspc 中的符号链接指向的目录,段对应具体的数据文件,数据块对应物理文件中的 8KB 页面。这种架构既保证了数据在磁盘上的可靠存储,又通过逻辑组织实现了存储资源的灵活分配与性能优化,为数据库的稳定运行与高效访问提供了核心支撑。

好了,今天关于金仓数据库存储结构的深度体验就到这儿啦。要是你还想了解更多关于金仓数据库的知识,不妨去金仓数据库的博客站(kingbase.com.cn/explore)看看,…