PostgreSQL 体系结构

PostgreSQL 体系结构

  • 1、概念梳理
    • 1.1 PostgreSQL数据库文件组成:
    • 1.2 数据库实例
    • 1.3 PostgreSQL 内部组成
  • 2、逻辑和物理存储结构
    • 2.1 数据库集簇
    • 2.2 数据库的逻辑结构
    • 2.3 物理存储结构
      • 1)名词解释:
      • 2)用户自定义创建表空间
  • 3、进程结构
    • 3.1 守护进程 & 服务进程
    • 3.2 辅助进程
  • 4、内存结构
    • 4.1 本地内存
    • 4.2 共享内存

1、概念梳理

1.1 PostgreSQL数据库文件组成:

  • 物理文件

    由一系列位于操作系统上的物理文件组成,通常将这些文理文件称为数据库。

  • 逻辑文件

    在数据库的运行中通过整套高效严谨的逻辑管理这些物理文件。

1.2 数据库实例

  • 将物理文件、管理这些物理文件的进程、进程管理内存称为这个数据库的实例。

1.3 PostgreSQL 内部组成

  • 系统控制器、查询分析器、事物系统、恢复系统、文件系统
    • 系统控制器:负责接收外部连接请求。
    • 查询分析器:对连接请求查询进行分析并生成优化后的查询树。
    • 文件系统:从文件系统获取结果集或通过事物系统对数据做处理,并由文件系统持久化数据。

2、逻辑和物理存储结构

2.1 数据库集簇

  • 数据库集簇

    数据库集簇由单个PostgreSQL服务器实例管理的数据库集合,组成数据库集簇的这些数据库使用相同的全局配置文件监听端口共用进程内存结构

2.2 数据库的逻辑结构

创建一个Database时会为这个Database创建一个名为public的默认Schema,每个Database可以有多个Schema,在这个数据库中创建其他数据库对象时如果没有指定Schema,都会在public这个Schema中。Schema可以理解为一个数据库中的命名空间,在数据库中创建的所有对象都在Schema中创建,一个用户可以从同一个客户端连接中访问不同的Schema。不同的Schema中可以有多个相同名称的Table、Index、View、Sequence、Function等数据库对象。
PostgreSQL 体系结构_第1张图片

2.3 物理存储结构

数据库的文件默认保存在initdb时创建的数据目录中。在数据目录中有很多类型、功能不同的目录和文件,除了数据文件之外,还有参数文件、控制文件、数据库运行日志及预写日志等。

数据目录用来存放PostgreSQL持久化的数据,通常可以将数据目录路径配置为PGDATA环境变量,查看数据目录有哪些子目录和文件的命令如下所示:

目录文件:

[root@node03 ~]# tree -L 1 -d /var/lib/pgsql/12/data/
/var/lib/pgsql/12/data/
├── base
├── global
├── log
├── pg_commit_ts
├── pg_dynshmem
├── pg_logical
├── pg_multixact
├── pg_notify
├── pg_replslot
├── pg_serial
├── pg_snapshots
├── pg_stat
├── pg_stat_tmp
├── pg_subtrans
├── pg_tblspc
├── pg_twophase
├── pg_wal
└── pg_xact

18 directories

配置文件:

[root@node03 ~]# tree -L 1 -f /var/lib/pgsql/12/data/
/var/lib/pgsql/12/data
├── /var/lib/pgsql/12/data/base
├── /var/lib/pgsql/12/data/current_logfiles
├── /var/lib/pgsql/12/data/global
├── /var/lib/pgsql/12/data/log
├── /var/lib/pgsql/12/data/pg_commit_ts
├── /var/lib/pgsql/12/data/pg_dynshmem
├── /var/lib/pgsql/12/data/pg_hba.conf
├── /var/lib/pgsql/12/data/pg_ident.conf
├── /var/lib/pgsql/12/data/pg_logical
├── /var/lib/pgsql/12/data/pg_multixact
├── /var/lib/pgsql/12/data/pg_notify
├── /var/lib/pgsql/12/data/pg_replslot
├── /var/lib/pgsql/12/data/pg_serial
├── /var/lib/pgsql/12/data/pg_snapshots
├── /var/lib/pgsql/12/data/pg_stat
├── /var/lib/pgsql/12/data/pg_stat_tmp
├── /var/lib/pgsql/12/data/pg_subtrans
├── /var/lib/pgsql/12/data/pg_tblspc
├── /var/lib/pgsql/12/data/pg_twophase
├── /var/lib/pgsql/12/data/PG_VERSION
├── /var/lib/pgsql/12/data/pg_wal
├── /var/lib/pgsql/12/data/pg_xact
├── /var/lib/pgsql/12/data/postgresql.auto.conf
├── /var/lib/pgsql/12/data/postgresql.conf
├── /var/lib/pgsql/12/data/postmaster.opts
└── /var/lib/pgsql/12/data/postmaster.pid

18 directories, 8 files

数据目录中子目录和文件的用途:
PostgreSQL 体系结构_第2张图片

数据目录中的base子目录是我们的数据文件默认保存的位置,是数据库初始化后的默认表空间。

1)名词解释:

OID:PostgreSQL中的所有数据库对象都由各自的对象标识符。OID 进行内部管理,它们是无符号的4字节整数。数据库对象和各个OID之间的关系存储在适当的系统目录中,具体取决于对象的类型。数据库的OID存储在pg_database系统表中。

  • 查询数据库 OID:
mydb=# select oid, datname from pg_database where datname = 'mydb';
  oid  | datname 
-------+---------
 16384 | mydb
(1 row)
  • 查询表的OID:
mydb=# select oid, relname, relkind from pg_class where relname ~ 'user';
  oid  |              relname              | relkind 
-------+-----------------------------------+---------
   174 | pg_user_mapping_oid_index         | i
   175 | pg_user_mapping_user_server_index | i
 16432 | users_id_seq                      | S
 16434 | users                             | r
 16441 | users_pkey                        | i
  1418 | pg_user_mapping                   | r
  • 表空间:

在PostgreSQL中最大的逻辑存储单位是表空间,数据库中创建的对象都保存在表空间中,例如表、索引和整个数据库都可以被分配到特定的农空间。#霭费猴距对象的文件的以指定数据库对象的表空间,如果不指定则使用默认表空间,也就是数据库对象的文件的位置。

初始化数据库目录时会自动创建pg_default和 pg_global两个表空间。如下所示:

mydb=# \db
       List of tablespaces
    Name    |  Owner   | Location 
------------+----------+----------
 pg_default | postgres | 
 pg_global  | postgres | 
(2 rows)

① pg_global表空间的物理文件位置在数据目录的global目录中,它用来保存系统表。

② pg_default表空间的物理文件位置在数据目录中的base目录,是template0和template1 数据库的默认表空间,我们知道创建数据库时,默认从template1数据库进行克隆,因此除非特别指定了新建数据库的表空间,默认使用template1的表空间,也就是pg_default。

2)用户自定义创建表空间

  • 口通过创建表空间解决已有表空间磁盘不足并无法逻辑扩展的问题;
  • 将索引、WAL、数据文件分配在性能不同的磁盘上,使硬件利用率和性能最大化。由于现在固态存储已经很普遍,这种文件布局方式反倒会增加维护成本。
[root@node03 ~]# mkdir -p /pgdata/10/mytblspc
[root@node03 ~]# su - postgres
-bash-4.2$ /usr/pgsql-12/bin/psql  mydb
mydb=# create tablespace myspc location '/pgdata/10/mytblspc';
CREATE TABLESPACE
mydb=# \db
             List of tablespaces
    Name    |  Owner   |      Location       
------------+----------+---------------------
 myspc      | postgres | /pgdata/10/mytblspc
 pg_default | postgres | 
 pg_global  | postgres | 
(3 rows)
mydb=# create table t1(id serial primary key, ival int) tablespace myspc;
CREATE TABLE
mydb=# \d t1
                            Table "public.t1"
 Column |  Type   | Collation | Nullable |            Default             
--------+---------+-----------+----------+--------------------------------
 id     | integer |           | not null | nextval('t1_id_seq'::regclass)
 ival   | integer |           |          | 
Indexes:
    "t1_pkey" PRIMARY KEY, btree (id)
Tablespace: "myspc"

由于表空间定义了存储的位置,在创建数据库对象时,会在当前的表空间目录创建一个以数据库OID命名的目录,该数据库的所有对象将保存在这个目录中,除非单独指定表空间。例如我们一直使用的数据库mydb,从pg_database系统表查询它的OID,如下所示:

mydb=# select oid,datname from pg_database where datname = 'mydb';
  oid  | datname 
-------+---------
 16384 | mydb
(1 row)

通过以上查询可知mydb 的OID为16384,我们就可以知道mydb的表、索引都会保存在$PGDATA/base/16384这个目录中,如下所示:

-bash-4.2$ ll /var/lib/pgsql/12/data/base/16384/ -d
drwx------ 2 postgres postgres 8192 Jul  8 16:38 /var/lib/pgsql/12/data/base/16384/

表看users表 OID

mydb=# select oid, relfilenode from pg_class where relname = 'users';
  oid  | relfilenode 
-------+-------------
 16434 |       16434
(1 row)
mydb-# \! ls -l /var/lib/pgsql/12/data/base/16384/16434
-rw------- 1 postgres postgres 8192 Jul  2 15:26 /var/lib/pgsql/12/data/base/16384/16434
mydb=# truncate users;
mydb=# checkpoint;
mydb=# \! ls -l /var/lib/pgsql/12/data/base/16384/16434
ls: cannot access /var/lib/pgsql/12/data/base/16384/16434: No such file or directory

mydb=# select oid, relfilenode from pg_class where relname = 'users';
  oid  | relfilenode 
-------+-------------
 16434 |       16479
(1 row)

mydb=# \! ls -l /var/lib/pgsql/12/data/base/16384/16479
-rw------- 1 postgres postgres 0 Jul  8 17:08 /var/lib/pgsql/12/data/base/16384/16479

在这里插入图片描述

如前文所述,数据文件的命名规则为,<顺序号>,tbl表的大小超过1GB,tbl表的relfilenode为24591,超出1GB之外的数据会按每GB切割,在文件系统中查看时就是名称为24591.1的数据文件。在上述输出结果中,后缀为_fsm和_vm的这两个表文件的附属文件是空闲空间映射表文件可见性映射表文件

  • 空闲空间映射用来映射表文件中可用的空间;

  • 可见性映射表文件跟踪哪些页面只包含已知对所有活动事务可见的元组,它也跟踪哪些页面只包含未被冻结的元组。

PostgreSQL数据目录、表空间以及文件的结构概貌:

PostgreSQL 体系结构_第3张图片

  • 标文件内部结构:

在PostgreSQL中,将保存在磁盘中的块称为Page,而将内存中的块称为Buffer表和索引称为Relation行称为Tuple,如图5-3所示。数据的读写是以 Page为最小单位,每个Page默认大小为8kB,在编译PostgreSQL 时指定的BLCKSZ大小决定Page 的大小。每个表文件由多个BLCKSZ字节大小的Page组成,每个Page包含若干Tuple。对于I/O性能较好的硬件,并且以分析为主的数据库,适当增加BLCKSZ大小可以小幅提升数据库性能。

page 内部结构

PostgreSQL 体系结构_第4张图片

3、进程结构

3.1 守护进程 & 服务进程

PostgreSQL是一用户一进程的客户端/服务器的应用程序。数据库启动时会启动若干个进程,其中有postmaster(守护进程)、postgres(服务进程)、syslogger、checkpointer,bgwriter、walwriter等辅助进程。

postmaster 职责:

  • 数据库的启停。
  • 监听客户端连接。
  • 为每个客户端连接fork 单独的postgres服务进程。当服务进程出错时进行修复。
  • 管理数据文件。
  • 管理与数据库运行相关的辅助进程。

当客户端调用接口库向数据库发起连接请求,守护进程postmaster 会 fork单独的服务进程postgres为客户端提供服务,此后将由postgres进程为客户端执行各种命令,客户端也不再需要postmaster 中转,直接与服务进程postgres通信,直至客户端断开连接。

PostgreSQL 体系结构_第5张图片

PostgreSQL使用基于消息的协议用于前端和后端(服务器和客户端)之间通信。通信都是通过一个消息流进行,消息的第一个字节标识消息类型,后面跟着的四个字节声明消息剩下部分的长度,该协议在TCP/IP和Unix域套接字上实现。服务器作业之间通过信号和共享内存通信,以保证并发访问时的数据完整性。
PostgreSQL 体系结构_第6张图片

3.2 辅助进程

除了守护进程postmaster和服务进程postgres外,PostgreSQL在运行期间还需要一些辅助进程才能工作,这些进程包括:

  • background writer :也可以称为bgwriter进程,bgwriter进程很多时候都是在休眠状态,每次唤醒后它会搜索共享缓冲池找到被修改的页,并将它们从共享缓冲池刷出。
  • autovacuum launcher:自动清理回收垃圾进程。
  • WAL writer:定期将WAL缓冲区上的WAL数据写入磁盘。statistics collector:统计信息收集进程。
  • logging collector:日志进程,将消息或错误信息写入日志。archiver: WAL归档进程。
  • checkpointer:检查点进程。

服务器端进程与辅助进程和 postmaster守护进程的关系:

PostgreSQL 体系结构_第7张图片

4、内存结构

PostgreSQL的内存分为两大类:本地内存和共享内存,另外还有一些为辅助进程分配的内存等。

4.1 本地内存

本地内存由每个后端服务进程分配以供自己使用,当后端服务进程被fork时,每个后端进程为查询分配一个本地内存区域。本地内存由三部分组成: work_mem、maintwork_mem和 temp_buffers。

  • work mem:当使用ORDERBY或DISTINCT 操作对元组进行排序时会使用这部分内存。
  • VACUUM、REINDEX、CREATE IND等操作使用这部分内存。
  • temp_buffers:临时表相关操作使用这部分内存。

4.2 共享内存

共享内存在PostgreSQL服务器启动时分配,由所有后端进程共同使用。共享内存主要由三部分组成:

  • shared buffer pool : PostgreSQL将表和索引中的页面从持久存储装载到这里,并直接操作它们。
  • WAL buffer : WAL文件持久化之前的缓冲区。
  • CommitLog buffer : PostgreSQL在 Commit Log中保存事务的状态,并将这些状态保留在共享内存缓冲区中,在整个事务处理过程中使用。

内存结构:

PostgreSQL 体系结构_第8张图片

你可能感兴趣的:(PostgreSQL,PostgreSQL,体系结构)