《PostgreSQL数据库内核分析》之存储管理(三)

举报
毛竹 发表于 2023/10/05 14:51:33 2023/10/05
【摘要】 数据库管理系统的任务本质是向存储设备写入数据或从存储设备上读出数据。PostgreSQL中,有专门的模块负责管理存储设备(包括内存和外存),我们称之为存储管理器。存储管理器提供了一组统一的管理外存与内存资源的功能模块,所有对外存与内存的操作都交由存储管理器处理,可以认为存储管理器是数据库管理系统与物理存储设备的接口。PostgreSQL体系结构图下图所示,本篇主要介绍PostgreSQL的存...

数据库管理系统的任务本质是向存储设备写入数据或从存储设备上读出数据PostgreSQL中,有专门的模块负责管理存储设备(包括内存和外存),我们称之为存储管理器。存储管理器提供了一组统一的管理外存与内存资源的功能模块,所有对外存与内存的操作都交由存储管理器处理,可以认为存储管理器是数据库管理系统与物理存储设备的接口。PostgreSQL体系结构图下图所示,本篇主要介绍PostgreSQL的存储管理相关内容。

图1 PostgreSQL体系结构

3.1存储管理器的体系结构

存储器的主要任务包括:

1.缓冲池管理

2.Cache机制

3.虚拟文件描述符管理

4.空闲空间管理

5.进程间通信机制(IPC

6.大数据存储管理

PostgreSQL的存储管理器主要包括两个功能:内存管理与外存管理。除了管理内存和外存的交互外,存储管理器的另一个主要任务是对内存进行统筹安排和规划。存储管理器的体系结构如下图所示:

图2 存储器的体系结构

内存管理包括共享内存的管理以及进程本地内存的管理。共享内存中存储所有进程的公共数据,如锁变量、进程通信状态、缓冲区等。而本地内存为每个后台进程所专有,是它们工作区域,存储属于该进程的Cache(高速缓存)、事务管理信息、进程信息等。为防止多个进程并发访问共享内存中数据时产生冲突,Postgres提供了轻量级锁,用于支持对共享内存中同一数据的互斥访问PostgreSQL使用共享内存实现了IPC(进程间通信)以及无效消息共享,用以支持进程间的相互通信。此外,存储管理器还提供内存上下文用于统一管理内存的分配和回收,从而更加有效安全地对内存空间进行管理。

Note: 

共享内存:所有进程的公共数据,如锁变量、进程通信状态、缓冲区等。

本地内存管理:后台进程的Cache、事务管理信息、进程信息等。

外存管理包括表文件管理空闲空间管理虚拟文件描述符管理大数据存储管理等。在PostgreSQL中,每个表都用一个文件(表文件)存储,表文件以表的OID命名。对于超出OS文件大小限制(比如FAT32限制4G)的表文件,PostgreSQL自动切分多个文件存储。PostgreSQL 8.4以后,每个表除了表文件外还拥有两个附属文件:可见性映射文件(VM加快清理操作VACUUM的执行速度】和空闲空间映射表文件FSM)【表文件空闲空间的管理】。存储管理器提供虚拟文件描述符机制,避免了后台进程可以打开“无限多个”文件的限制。还提供了大对象机制TOAST机制,用于支持大数据存储。PG还在存储器选择器中封装了对具体存储器的操作接口,以便扩展支持多种存储介质(比如对闪存、光盘的支持)。

Note:

表文件管理、空闲空间管理、虚拟文件描述符管理及大数据存储管理等。

PostgreSQL存储器管理器采用分页存储管理方式,即数据在内存中以页面块的形式存在。每个表文件由多个BLCKSZ(一个可配置的常量)字节大小的文件块组成。每个文件块又可以包含多个元组。表文件以文件块为单位读入内存中,每一个文件块在内存中形成一个页面块。文件写入也是以块为单位。PostgreSQL采用传统的行式存储,即以元组为单位进行数据的存储。PostgreSQL不支持元组的跨块存储,每个元组最大为MaxHeapTupleSize,保证了每个文件中存储的是多个完整的元组。

PostgreSQL内存开辟了缓冲区域用于存储这些文件夹,我们将其在内存中开辟的缓冲区称为缓冲池,缓冲池被划分若干个固定大小(和文件块的尺寸相同,也是BLCKSZ)的缓冲区,磁盘上的文件快读入内存后被存放在缓冲区中,称之为页面块或缓冲块。BLCKSIZE的默认值是8192,因此一个标准缓冲块的大小默认为8KB

存储器的主要任务如下图所示:

图3 存储器的主要任务

3.2外存管理

外存管理负责处理数据库与外存介质(在PostgreSQL中只实现了磁盘的管理操作)的交互过程。PostgreSQL中外存管理由SMGR(存储介质管理器)提供对外操作的统一接口,SMGR负责统管各种介质管理器,会根据上层的请求选择一个具体的介质管理器进行操作。外存管理体系结构如下图所示:

图4 外存管理体系结构

3.2.1表和元组的组织方式

堆文件,元组插入数据形成表文件,可以是按顺序也可以无顺,形成的数据表文件称为堆。

PostgreSQL提供四种堆文件:普通堆、临时堆、序列和TOAST表

每个堆都是有由多个文件块组成,在物理磁盘中存储形式

1PageHeaderData是长度为20字节的页头数据,包含该文件块的一般信息

2LinpItemIdData类型的数组,每个ItemIdData结构用来指向文件块的一个元组,包含lp_offlp_flagslp_len三个属性组成

3Freespace未分配的空间,新插入页面的元组机器对应的Linp元素都将从这部分空间中分配

4Special space是特殊空间,用于存放于索引方法相关的特定数据,不同的索引方法在Special space中存放不同的数据

元组头部信息通过HeapTupleHeaderData结构描述,记录了操作此元组的事务ID和命令ID等信息。删除元组的删除标记就保存在HeadTupleHeader

3.2.2磁盘管理器

磁盘管理器是SMGR的一种具体实现,对外提供了管理磁盘介质的接口。通过VFD机制来进行文件操作。

3.2.3VFD机制

防止进程打开的文件数超过操作系统限制而引起不可预知的错误

3.2.4空闲空间映射表

PostgreSQL 8.4之后,对每个表文件,同时创建一个“关系表OID_fsm”的文件,用于记录该表的空闲空间大小,称之为空闲空间映射文件(FSM),目的是为了提高快速查找。

3.2.5可见性映射表

PostgreSQL 8.4.1为每个表文件定义了一个新的附属文件(可见性映射文件VM),解决了VACUUM查找包含无效元组的文件块的过程。VM中为表的每个文件块设置了一位,用来标记文件块是否存在无效元组。VM仅在Lazy Vacuum时使用。

3.2.6大数据存储

PostgreSQL中提供两种大数据存储方式:一种TOAST机制,使用数据压缩和线外存储来实现;另一种大对象机制,使用一个专门的系统表来存储大对象数据。

3.3内存管理

PostgreSQL内存管理包括共享内存和本地内存,PostgreSQL内存管理如下图所示:

图5 PostgreSQL内存管理

3.3.1内存上下文概述

PostgreSQL 7.1以后实现,内存分配操作在各种语义的内存上下文中进行,所有的内存上下文中分配的内存空间都通过内存上下文进行记录,可通过释放内存上下来释放其中的所有内容。内存上下文树如下图所示:

图6 内存上下文树

3.3.2高速缓存

为提高对系统表和普通表的访问效率,PostgreSQL设立了高速缓存(CacheCacheSysCache)和一个表模式信息CacheRelCache)。SysCache中存放的是最近使用过的系统表的元组,而RelCache中包含所有最近访问过的表的模式信息(包含系统表的信息)RelCache存放的不是元组,而是RelationData数据结构,每个RelationData结构表示一个表的模式信息,这些信息都由系统表元组中的信息构造而来。两种Cache都不是所有进程共享的,每个PG进程都维护者自己的SysCacheRelCache

3.3.3缓冲池管理

当系统表元组在Cache中无法找到或需要访问普通表的元组时,需要访问对缓冲池进行访问。

任何对于表、元组、索引表等的操作都在缓冲池中进行,缓冲池的数据调度都以磁盘块为单位,需要访问的数据以磁盘块为单位调用函数smgrread写入缓冲池,而smgrwrite将缓冲池数据写回到磁盘。调入缓冲池中的磁盘块称为缓冲区、缓冲块或页面,多个缓冲区组成缓冲池。

PostgreSQL有两种缓冲池:共享缓冲池和本地缓冲池。共享缓冲池作普通可共享表的操作场所;本地缓冲池则用作仅本地可见的临时表的操作场所。对缓冲池中缓冲区的管理通过两种机制完成:pinlockpin对缓冲区的访问计数器。lock机制为缓冲区的并发访问提供了保障,当有进程对缓冲区进行写操作时加EXCLUSIVE锁,读才做时加SHARE锁,其意义和数据库的锁机制是类似的。缓冲池模型图如下图所示:

图7 缓冲池模型图

3.3.4IPC

IPC进程间通信,PostgreSQLIPC只考虑同一计算机上的进程间通信。PostgreSQLIPC主要采用共享内存方式来实现,即在系统中开辟一片所有进程都可以读写的内存空间,并约定好进程读写这片内存的时机和方式,这样进程间就可以通过这片共享的内存来交换数据。在共享内存的基础上,PostgreSQLIPC机制提供以下功能:

1)进程和Postermaster的通信机制

2)统一管理进程的相关变量和函数

3)提供了SI Message机制,即无效消息传递机制

4)有关消除的函数

3.4表操作与元祖操作

表操作对表的操作包括:打开、扫描、同步扫描、其他操作(创建表、关闭表、删除表),元组的操作包括:插入、删除、更新,顺序扫描表获取元组如下图所示:

图8 顺序扫描表获取元组

3.4.1表操作

对表的操作包括:打开、扫描、同步扫描、其他操作(创建表、关闭表、删除表),表的扫描流程如下图所示:

图9 表的扫描流程

3.4.2元组操作

元组的操作包括:插入、删除、更新,插入元组流程如下图所示:

图10 插入元组流程


3.5VACUUM机制

当修改元组属性、执行重建索引等操作时,特别是当时进行多次更新、删除操作时,磁盘上会出现很多无效的元组,占据了很多磁盘空间并会导致性能下降,就需要进行VACUUM操作清除掉这些“垃圾”。VACUUM包括Lazy VACUUM和Full VACUUM两种。

3.5.1Lazy VACUUM

Lazy VACUUM单个表进行清理,并清理去索引、更新页面数和元组数的统计值。

3.5.2Full VACUUM

Full VACUUM除了对文件块整理外,还实现了更加复杂的跨块移动元组的操作,其接口函数为full_vacuum_rel,可对单个关系表或索引进行清理操作。

3.6ResourceOwner资源跟踪

PostgreSQL中,每个事务在执行,需要跟踪其占用的内存资源。PostgreSQL使用ResourceOwner对象来对资源集中进行跟踪,我们称为ResourceOwner为资源跟踪器。ResourceOwner记录了大多数事务过程中使用到的资源。事务过程中的ResourceOwner树如下图所示:

图11 事务过程中的ResourceOwner树

小结:存储管理模块是整个系统的基础部分,对其他模块提供了访问数据的接口,尤其是内存管理模块与其他模块的交互最多。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。